Merge "msm9625_defconfig: Enable watchdog" into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
new file mode 100644
index 0000000..1ec3081
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -0,0 +1,34 @@
+MSM Bus Scaling Driver
+
+The msm bus scaling driver provides the ability to configure
+bus performance parameters across the entire chip-set.
+Various clients use MSM scaling APIs to request bandwidth
+between multiple master-slave pairs. The bus driver then finds
+the optimal path between the master and the slave, and aggregates
+the bandwidth and clock requests for all master-slave pairs on
+that path, and programs hardware accordingly.
+
+The device-tree data required for bus-scaling can be embedded within
+the clients' device nodes. The clients can register with the bus driver
+using the following properties:
+
+- qcom,msm_bus,name:		String representing the client-name
+- qcom,msm_bus,num_cases:	Total number of usecases
+- qcom,msm_bus,active_only:	Context flag for requests in active or
+				dual (active & sleep) contex
+- qcom,msm_bus,num_paths:	Total number of master-slave pairs
+- qcom,msm_bus,vectors:		Arrays of unsigned integers representing:
+				master-id, slave-id, arbitrated bandwidth,
+				instantaneous bandwidth
+
+Example:
+
+	qcom,msm_bus,name = "client-name";
+	qcom,msm_bus,num_cases = <3>;
+	qcom,msm_bus,active_only = <0>;
+	qcom,msm_bus,num_paths = <2>;
+	qcom,msm_bus,vectors =
+			<22 512 0 0>, <26 512 0 0>,
+			<22 512 320000 320000000>, <26 512 3200000 320000000>,
+			<22 512 160000 160000000>, <26 512 1600000 160000000>;
+
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 75916e5..6b03fab 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -1,5 +1,6 @@
 * Qualcomm MSM CCI
 
+[First level nodes]
 Required properties:
 - cell-index: cci hardware core index
 - compatible :
@@ -11,6 +12,102 @@
 - interrupt-names : should specify relevant names to each interrupts
   property defined.
 
+[Second level nodes]
+* Qualcomm MSM Sensor
+
+MSM sensor node contains properties of camera sensor
+
+Required properties:
+- compatible : should be "qcom" followed by sensor name
+    - "qcom,s5k3l1yx"
+- reg : should contain i2c slave address of the camera sensor and
+    length of data field which is 0x0
+- qcom,csi-if : should contain number of csid cores required at the receiver
+    side
+    - 1 for 2D sensor
+    - 2 for 3D sensor
+- qcom,csid-core : should contain csid core instance that will used to receive
+    sensor data
+    - 0, 1, 2, 3
+- qcom,is-vpe : should be enabled if VPE module is required for post processing
+    of this sensor
+    - 1 if required, 0 otherwise
+- qcom,sensor-name : should contain unique sensor name to differentiate from
+    other sensor
+    - "s5k3l1yx"
+- cam_vdig-supply : should contain regulator from which digital voltage is
+    supplied
+- cam_vana-supply : should contain regulator from which analog voltage is
+    supplied
+- cam_vio-supply : should contain regulator from which IO voltage is supplied
+- qcom,cam-vreg-name : should contain names of all regulators needed by this
+    sensor
+    - "cam_vdig", "cam_vana", "cam_vio", "cam_vaf"
+- qcom,cam-vreg-type : should contain regulator type for regulators mentioned in
+    qcom,cam-vreg-name property (in the same order)
+    - 0 for LDO and 1 for LVS
+- qcom,cam-vreg-min-voltage : should contain minimum voltage level for
+    regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-max-voltage : should contain maximum voltage level for
+    regulators mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,cam-vreg-op-mode : should contain optimum voltage level for regulators
+    mentioned in qcom,cam-vreg-name property (in the same order)
+- qcom,camera-type : should contain sensor type
+    - 0 -> back camera 2D
+    - 1 -> front camera 2D
+    - 2 -> back camera 3D
+    - 3 -> back camera int 3D
+- qcom,sensor-type : should contain format of data that sensor streams
+    - 0 -> bayer format
+    - 1 -> yuv format
+
+Optional properties:
+- qcom,flash-type : should contain flash type if flash is supported for this
+    sensor
+    - 0 if flash is not supported, 1 if flash is supported
+- qcom,mount-angle : should contain the physical mount angle of the sensor on
+    the target
+    - 0, 90, 180, 360
+- qcom,gpio-no-mux : should contain field to indicate whether gpio mux table is
+    available
+    - 1 if gpio mux is not available, 0 otherwise
+- cam_vaf-supply : should contain regulator from which AF voltage is supplied
+- gpios : should contain phandle to gpio controller node and array of
+    #gpio-cells specifying specific gpio (controller specific)
+- qcom,gpio-common-tbl-num : should contain index to gpios shared between
+    different sensors
+- qcom,gpio-common-tbl-flags : should contain direction of gpios present in
+    qcom,gpio-common-tbl-num property (in the same order)
+- qcom,gpio-common-tbl-label : should contain name of gpios present in
+    qcom,gpio-common-tbl-num property (in the same order)
+- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor
+- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-req-tbl-label : should contain name of gpios present in
+    qcom,gpio-req-tbl-num property (in the same order)
+- qcom,gpio-set-tbl-num : should contain index of gpios that need to be
+    configured by msm
+- qcom,gpio-set-tbl-flags : should contain value to be configured for the gpios
+    present in qcom,gpio-set-tbl-num property (in the same order)
+- qcom,gpio-set-tbl-delay : should contain amount of delay after configuring
+    gpios as specified in gpio_set_tbl_flags property (in the same order)
+- qcom,csi-lane-assign : should contain lane assignment value to map CSIPHY
+    lanes to CSID lanes
+    - 0x4320
+- qcom,csi-lane-mask : should contain lane mask that specifies CSIPHY lanes to
+    be enabled
+- qcom,csi-phy-sel : should contain CSIPHY core instance from which CSID should
+    receive data
+- qcom,actuator-cam-name : should contain actuator cam name associated with
+    this sensor
+    - If actuator does not exist, this property should not be initialized
+    - If actuator exist, this field should indicate the index of actuator to
+      be used
+- qcom,actuator-vcm-pwd : should contain the gpio pin of vcm power to be enabled
+    for actuator
+- qcom,actuator-vcm-enable : should contain value to be set for actuator vcm
+    gpio
+
 Example:
 
    qcom,cci@0xfda0c000 {
@@ -20,4 +117,43 @@
        reg-names = "cci";
        interrupts = <0 50 0>;
        interrupt-names = "cci";
+       qcom,s5k3l1yx@6e {
+               compatible = "qcom,s5k3l1yx";
+               reg = <0x6e 0x0>;
+               qcom,csi-if = <1>;
+               qcom,csid-core = <0>;
+               qcom,is-vpe = <1>;
+               qcom,flash-type = <0>;
+               qcom,mount-angle = <90>;
+               qcom,sensor-name = "s5k3l1yx";
+               cam_vdig-supply = <&pm8941_l3>;
+               cam_vana-supply = <&pm8941_l17>;
+               cam_vio-supply = <&pm8941_lvs3>;
+               cam_vaf-supply = <&pm8941_l23>;
+               qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio", "cam_vaf";
+               qcom,cam-vreg-type = <0 0 1 0>;
+               qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
+               qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
+               qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
+               qcom,gpio-no-mux = <0>;
+               gpios = <&msmgpio 15 0>,
+                       <&msmgpio 19 0>,
+                       <&msmgpio 20 0>,
+                       <&msmgpio 90 0>;
+               qcom,gpio-common-tbl-num = <0 1 2>;
+               qcom,gpio-common-tbl-flags = <1 1 1>;
+               qcom,gpio-common-tbl-label = "CAMIF_MCLK", "CAMIF_I2C_DATA",
+                                            "CAMIF_I2C_CLK";
+               qcom,gpio-req-tbl-num = <3>;
+               qcom,gpio-req-tbl-flags = <0>;
+               qcom,gpio-req-tbl-label = "CAM_RESET1";
+               qcom,gpio-set-tbl-num = <3 3>;
+               qcom,gpio-set-tbl-flags = <0 2>;
+               qcom,gpio-set-tbl-delay = <1000 4000>;
+               qcom,csi-lane-assign = <0x4320>;
+               qcom,csi-lane-mask = <0x1F>;
+               qcom,csi-phy-sel = <0>;
+               qcom,camera-type = <0>;
+               qcom,sensor-type = <0>;
+       };
    };
diff --git a/Documentation/devicetree/bindings/media/video/msm-sensor.txt b/Documentation/devicetree/bindings/media/video/msm-sensor.txt
deleted file mode 100644
index e242d51..0000000
--- a/Documentation/devicetree/bindings/media/video/msm-sensor.txt
+++ /dev/null
@@ -1,137 +0,0 @@
-* Qualcomm MSM Sensor
-
-MSM sensor node contains properties of camera sensor
-
-Required properties:
-- compatible : should be "qcom" followed by sensor name
-    - "qcom,s5k3l1yx"
-- reg : should contain i2c slave address of the camera sensor and
-    length of data field which is 0x0
-- qcom,csi-if : should contain number of csid cores required at the receiver
-    side
-    - 1 for 2D sensor
-    - 2 for 3D sensor
-- qcom,csid-core : should contain csid core instance that will used to receive
-    sensor data
-    - 0, 1, 2, 3
-- qcom,is-vpe : should be enabled if VPE module is required for post processing
-    of this sensor
-    - 1 if required, 0 otherwise
-- qcom,sensor-name : should contain unique sensor name to differentiate from
-    other sensor
-    - "s5k3l1yx"
-- cam_vdig-supply : should contain regulator from which digital voltage is
-    supplied
-- cam_vana-supply : should contain regulator from which analog voltage is
-    supplied
-- cam_vio-supply : should contain regulator from which IO voltage is supplied
-- qcom,cam-vreg-name : should contain names of all regulators needed by this
-    sensor
-    - "cam_vdig", "cam_vana", "cam_vio", "cam_vaf"
-- qcom,cam-vreg-type : should contain regulator type for regulators mentioned in
-    qcom,cam-vreg-name property (in the same order)
-    - 0 for LDO and 1 for LVS
-- qcom,cam-vreg-min-voltage : should contain minimum voltage level for
-    regulators mentioned in qcom,cam-vreg-name property (in the same order)
-- qcom,cam-vreg-max-voltage : should contain maximum voltage level for
-    regulators mentioned in qcom,cam-vreg-name property (in the same order)
-- qcom,cam-vreg-op-mode : should contain optimum voltage level for regulators
-    mentioned in qcom,cam-vreg-name property (in the same order)
-- qcom,camera-type : should contain sensor type
-    - 0 -> back camera 2D
-    - 1 -> front camera 2D
-    - 2 -> back camera 3D
-    - 3 -> back camera int 3D
-- qcom,sensor-type : should contain format of data that sensor streams
-    - 0 -> bayer format
-    - 1 -> yuv format
-
-Optional properties:
-- qcom,flash-type : should contain flash type if flash is supported for this
-    sensor
-    - 0 if flash is not supported, 1 if flash is supported
-- qcom,mount-angle : should contain the physical mount angle of the sensor on
-    the target
-    - 0, 90, 180, 360
-- qcom,gpio-no-mux : should contain field to indicate whether gpio mux table is
-    available
-    - 1 if gpio mux is not available, 0 otherwise
-- cam_vaf-supply : should contain regulator from which AF voltage is supplied
-- gpios : should contain phandle to gpio controller node and array of
-    #gpio-cells specifying specific gpio (controller specific)
-- qcom,gpio-common-tbl-num : should contain index to gpios shared between
-    different sensors
-- qcom,gpio-common-tbl-flags : should contain direction of gpios present in
-    qcom,gpio-common-tbl-num property (in the same order)
-- qcom,gpio-common-tbl-label : should contain name of gpios present in
-    qcom,gpio-common-tbl-num property (in the same order)
-- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor
-- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
-    qcom,gpio-req-tbl-num property (in the same order)
-- qcom,gpio-req-tbl-label : should contain name of gpios present in
-    qcom,gpio-req-tbl-num property (in the same order)
-- qcom,gpio-set-tbl-num : should contain index of gpios that need to be
-    configured by msm
-- qcom,gpio-set-tbl-flags : should contain value to be configured for the gpios
-    present in qcom,gpio-set-tbl-num property (in the same order)
-- qcom,gpio-set-tbl-delay : should contain amount of delay after configuring
-    gpios as specified in gpio_set_tbl_flags property (in the same order)
-- qcom,csi-lane-assign : should contain lane assignment value to map CSIPHY
-    lanes to CSID lanes
-    - 0x4320
-- qcom,csi-lane-mask : should contain lane mask that specifies CSIPHY lanes to
-    be enabled
-- qcom,csi-phy-sel : should contain CSIPHY core instance from which CSID should
-    receive data
-- qcom,actuator-cam-name : should contain actuator cam name associated with
-    this sensor
-    - If actuator does not exist, this property should not be initialized
-    - If actuator exist, this field should indicate the index of actuator to
-      be used
-- qcom,actuator-vcm-pwd : should contain the gpio pin of vcm power to be enabled
-    for actuator
-- qcom,actuator-vcm-enable : should contain value to be set for actuator vcm
-    gpio
-
-Example:
-
-qcom,s5k3l1yx@6e {
-        compatible = "qcom,s5k3l1yx";
-        reg = <0x6e 0x0>;
-        qcom,csi-if = <1>;
-        qcom,csid-core = <0>;
-        qcom,is-vpe = <1>;
-        qcom,flash-type = <0>;
-        qcom,mount-angle = <90>;
-        qcom,sensor-name = "s5k3l1yx";
-        cam_vdig-supply = <&pm8941_l3>;
-        cam_vana-supply = <&pm8941_l17>;
-        cam_vio-supply = <&pm8941_lvs3>;
-        cam_vaf-supply = <&pm8941_l23>;
-        qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio", "cam_vaf";
-        qcom,cam-vreg-type = <0 0 1 0>;
-        qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
-        qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
-        qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
-        qcom,gpio-no-mux = <0>;
-        gpios = <&msmgpio 15 0>,
-                <&msmgpio 19 0>,
-                <&msmgpio 20 0>,
-                <&msmgpio 90 0>;
-        qcom,gpio-common-tbl-num = <0 1 2>;
-        qcom,gpio-common-tbl-flags = <1 1 1>;
-        qcom,gpio-common-tbl-label = "CAMIF_MCLK", "CAMIF_I2C_DATA",
-                "CAMIF_I2C_CLK";
-        qcom,gpio-req-tbl-num = <3>;
-        qcom,gpio-req-tbl-flags = <0>;
-        qcom,gpio-req-tbl-label = "CAM_RESET1";
-        qcom,gpio-set-tbl-num = <3 3>;
-        qcom,gpio-set-tbl-flags = <0 2>;
-        qcom,gpio-set-tbl-delay = <1000 4000>;
-        qcom,csi-lane-assign = <0x4320>;
-        qcom,csi-lane-mask = <0x1F>;
-        qcom,csi-phy-sel = <0>;
-        qcom,camera-type = <0>;
-        qcom,sensor-type = <0>;
-};
-
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
new file mode 100644
index 0000000..e394b56
--- /dev/null
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -0,0 +1,45 @@
+* Qualcomm WCNSS Platform Driver
+
+WCNSS driver is the platform driver. It is used for performing the cold
+boot-up of the wireless device. It is responsible for adjusting
+the necessary I/O rails and enabling appropriate gpios for wireless
+connectivity subsystem.
+
+Required properties:
+- compatible: "wcnss_wlan"
+- reg: offset and length of the register set for the device. The pair
+  corresponds to PRONTO.
+- interupts: Pronto to Apps interrupts for tx done and rx pending.
+- qcom,pronto-vddmx-supply: regulator to supply pronto pll.
+- qcom,pronto-vddcx-supply: regulator to supply WLAN/BT/FM digital module.
+- qcom,pronto-vddpx-supply: regulator to supply WLAN DAC.
+- qcom,iris-vddxo-supply  : regulator to supply RF XO.
+- qcom,iris-vddrfa-supply : regulator to supply RFA digital.
+- qcom,iris-vddpa-supply  : regulator to supply RF PA.
+- qcom,iris-vdddig-supply : regulator to supply RF digital(BT/FM).
+- gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
+- qcom,has_48mhz_xo: boolean flag to determine the usage of 24MHz XO from RF
+- qcom,has_pronto_hw: boolean flag to determine the revId of the WLAN subsystem
+
+Example:
+
+    qcom,wcnss-wlan@fb000000 {
+        compatible = "qcom,wcnss_wlan";
+        reg = <0xfb000000 0x280000>;
+        reg-names = "wcnss_mmio";
+        interrupts = <0 145 0 0 146 0>;
+        interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+        qcom,pronto-vddmx-supply = <&pm8841_s1>;
+        qcom,pronto-vddcx-supply = <&pm8841_s2>;
+        qcom,pronto-vddpx-supply = <&pm8941_s3>;
+        qcom,iris-vddxo-supply = <&pm8941_l6>;
+        qcom,iris-vddrfa-supply = <&pm8941_l11>;
+        qcom,iris-vddpa-supply = <&pm8941_l19>;
+        qcom,iris-vdddig-supply = <&pm8941_l3>;
+
+        gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>,
+                <&msmgpio 39 0>, <&msmgpio 40 0>;
+        qcom,has_48mhz_xo;
+        qcom,has_pronto_hw;
+    };
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
old mode 100644
new mode 100755
index 6347b51..751a823
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -378,7 +378,18 @@
 				label = "usb_in";
 				qcom,channel-num = <0>;
 				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <20>;
+				qcom,pre-div-channel-scaling = <4>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@1 {
+				label = "dc_in";
+				qcom,channel-num = <1>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <4>;
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <0>;
 				qcom,hw-settle-time = <0>;
@@ -389,6 +400,28 @@
 				label = "vchg_sns";
 				qcom,channel-num = <2>;
 				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <3>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@3 {
+				label = "spare1";
+				qcom,channel-num = <3>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <6>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@4 {
+				label = "spare2";
+				qcom,channel-num = <4>;
+				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <6>;
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <0>;
@@ -400,7 +433,7 @@
 				label = "vcoin";
 				qcom,channel-num = <5>;
 				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <3>;
+				qcom,pre-div-channel-scaling = <1>;
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <0>;
 				qcom,hw-settle-time = <0>;
@@ -411,7 +444,7 @@
 				label = "vbat_sns";
 				qcom,channel-num = <6>;
 				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <3>;
+				qcom,pre-div-channel-scaling = <1>;
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <0>;
 				qcom,hw-settle-time = <0>;
@@ -422,18 +455,29 @@
 				label = "vph_pwr";
 				qcom,channel-num = <7>;
 				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <3>;
+				qcom,pre-div-channel-scaling = <1>;
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <0>;
 				qcom,hw-settle-time = <0>;
 				qcom,fast-avg-setup = <0>;
 			};
 
+			chan@8 {
+				label = "die_temp";
+				qcom,channel-num = <8>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <3>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
 			chan@9 {
 				label = "ref_625mv";
 				qcom,channel-num = <9>;
 				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <1>;
+				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <0>;
 				qcom,hw-settle-time = <0>;
@@ -441,15 +485,48 @@
 			};
 
 			chan@10 {
-				label = "ref_1125v";
+				label = "ref_1250v";
 				qcom,channel-num = <10>;
 				qcom,decimation = <0>;
-				qcom,pre-div-channel-scaling = <1>;
+				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
 				qcom,scale-function = <0>;
 				qcom,hw-settle-time = <0>;
 				qcom,fast-avg-setup = <0>;
 			};
+
+			chan@48 {
+				label = "batt_therm";
+				qcom,channel-num = <48>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <1>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@49 {
+				label = "batt_id";
+				qcom,channel-num = <49>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@50 {
+				label = "xo_therm1";
+				qcom,channel-num = <49>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <4>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
 		};
 
 		iadc@3600 {
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index fd35103..c92188a 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -254,7 +254,7 @@
 			qcom,csi-lane-assign = <0x4320>;
 			qcom,csi-lane-mask = <0x7>;
 			qcom,csi-phy-sel = <1>;
-			qcom,camera-type = <0>;
+			qcom,camera-type = <1>;
 			qcom,sensor-type = <0>;
 		};
 	};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index c28ef9e..0b09bc8 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -13,12 +13,15 @@
 / {
 	tmc_etr: tmc@fc322000 {
 		compatible = "arm,coresight-tmc";
-		reg = <0xfc322000 0x1000>;
+		reg = <0xfc322000 0x1000>,
+		      <0xfc37c000 0x3000>;
+
+		qcom,memory-reservation-type = "EBI1";
+		qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
 
 		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
 		coresight-nr-inports = <1>;
-		coresight-default-sink;
 	};
 
 	tpiu: tpiu@fc318000 {
@@ -52,6 +55,7 @@
 		coresight-outports = <0>;
 		coresight-child-list = <&replicator>;
 		coresight-child-ports = <0>;
+		coresight-default-sink;
 	};
 
 	funnel_merg: funnel@fc31b000 {
@@ -174,4 +178,13 @@
 		coresight-child-list = <&funnel_kpss>;
 		coresight-child-ports = <3>;
 	};
+
+	csr: csr@fc302000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0xfc302000 0x1000>;
+
+		coresight-id = <14>;
+		coresight-name = "coresight-csr";
+		coresight-nr-inports = <0>;
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index bf73e30..3a2c9f2 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -710,6 +710,26 @@
 		qcom,firmware-name = "wcnss";
 	};
 
+	qcom,wcnss-wlan@fb000000 {
+		compatible = "qcom,wcnss_wlan";
+		reg = <0xfb000000 0x280000>;
+		reg-names = "wcnss_mmio";
+		interrupts = <0 145 0 0 146 0>;
+		interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+
+		qcom,pronto-vddmx-supply = <&pm8841_s1>;
+		qcom,pronto-vddcx-supply = <&pm8841_s2>;
+		qcom,pronto-vddpx-supply = <&pm8941_s3>;
+		qcom,iris-vddxo-supply = <&pm8941_l6>;
+		qcom,iris-vddrfa-supply = <&pm8941_l11>;
+		qcom,iris-vddpa-supply = <&pm8941_l19>;
+		qcom,iris-vdddig-supply = <&pm8941_l3>;
+
+		gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>;
+		qcom,has_48mhz_xo;
+		qcom,has_pronto_hw;
+	};
+
 	qcom,ocmem@fdd00000 {
 		compatible = "qcom,msm-ocmem";
 		reg = <0xfdd00000 0x2000>,
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index 82d317d..9582e78 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -305,14 +305,14 @@
 	qcom,mpm@fc4281d0 {
 		compatible = "qcom,mpm-v2";
 		reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
-		    <0xfa006000 0x1000>;   /* MSM_APCS_GCC_BASE 4K */
+		    <0xf9011008 0x4>;   /* MSM_APCS_GCC_BASE 4K */
 		reg-names = "vmpm", "ipc";
 		interrupts = <0 171 1>;
 
-		qcom,ipc-bit-offset = <0>;
+		qcom,ipc-bit-offset = <1>;
 
 		qcom,gic-parent = <&intc>;
-		qcom,gic-map = <41 180>, /* usb2_hsic_async_wakeup_irq */
+		qcom,gic-map = <47 180>, /* usb2_hsic_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 5ec9517..43d8ffa 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -420,11 +420,11 @@
 CONFIG_USB_STORAGE_KARMA=y
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_SERIAL=y
-CONFIG_USB_SERIAL_QUALCOMM=y
 CONFIG_USB_SERIAL_CSVT=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_QCOM_DIAG_BRIDGE=y
 CONFIG_USB_QCOM_MDM_BRIDGE=y
+CONFIG_USB_QCOM_KS_BRIDGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_CI13XXX_MSM=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 023114e..25b3e83 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -422,11 +422,11 @@
 CONFIG_USB_STORAGE_KARMA=y
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_SERIAL=y
-CONFIG_USB_SERIAL_QUALCOMM=y
 CONFIG_USB_SERIAL_CSVT=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_QCOM_DIAG_BRIDGE=y
 CONFIG_USB_QCOM_MDM_BRIDGE=y
+CONFIG_USB_QCOM_KS_BRIDGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_CI13XXX_MSM=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 875446e..d3257bc 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -51,6 +51,7 @@
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_QDSS=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -109,6 +110,10 @@
 CONFIG_IPV6_MIP6=y
 CONFIG_IPV6_MULTIPLE_TABLES=y
 CONFIG_IPV6_SUBTREES=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
 CONFIG_GENLOCK=y
 CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_BLK_DEV_LOOP=y
@@ -130,6 +135,7 @@
 CONFIG_DUMMY=y
 CONFIG_KS8851=m
 # CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
@@ -164,7 +170,9 @@
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_MSM is not set
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
 CONFIG_REGULATOR_STUB=y
@@ -187,6 +195,10 @@
 CONFIG_MSM_ISPIF=y
 CONFIG_S5K3L1YX=y
 CONFIG_OV2720=y
+CONFIG_MSM_JPEG=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_RADIO_ADAPTERS=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
@@ -308,3 +320,11 @@
 CONFIG_RADIO_IRIS=y
 CONFIG_RADIO_IRIS_TRANSPORT=m
 CONFIG_MSM_BAM_DMUX=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_CFG80211=m
+CONFIG_RFKILL=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_MEDIA=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index b8417fe..2cc801e 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -215,9 +215,9 @@
 CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MDM9615=y
-# CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_EHSET=y
 CONFIG_USB_EHCI_MSM=y
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 0d0103a..88d0872 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -113,7 +113,6 @@
 	struct mutex	reserve_mutex;
 	u64		max_period;
 	struct platform_device	*plat_device;
-	u32		from_idle;
 	irqreturn_t	(*handle_irq)(int irq_num, void *dev);
 	int     	(*request_pmu_irq)(int irq, irq_handler_t *irq_h);
 	void    	(*free_pmu_irq)(int irq);
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index e97aef2..3f6a6d3 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -41,6 +41,7 @@
  */
 #define ARMPMU_MAX_HWEVENTS		32
 
+static DEFINE_PER_CPU(u32, from_idle);
 static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
 static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
 static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
@@ -602,7 +603,7 @@
 	int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
 	int idx;
 
-	if (armpmu->from_idle) {
+	if (__get_cpu_var(from_idle)) {
 		for (idx = 0; idx <= cpu_pmu->num_events; ++idx) {
 			struct perf_event *event = hw_events->events[idx];
 
@@ -613,9 +614,12 @@
 		}
 
 		/* Reset bit so we don't needlessly re-enable counters.*/
-		armpmu->from_idle = 0;
+		__get_cpu_var(from_idle) = 0;
 	}
 
+	/* So we don't start the PMU before enabling counters after idle. */
+	barrier();
+
 	if (enabled)
 		armpmu->start();
 }
@@ -731,7 +735,6 @@
  * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
  * junk values out of them.
  */
-
 static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
 					unsigned long action, void *hcpu)
 {
@@ -805,7 +808,7 @@
 			 * Flip this bit so armpmu_enable knows it needs
 			 * to re-enable active counters.
 			 */
-			cpu_pmu->from_idle = 1;
+			__get_cpu_var(from_idle) = 1;
 			cpu_pmu->reset(NULL);
 			perf_pmu_enable(&cpu_pmu->pmu);
 		}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 6f0a7e7..d2a5c23 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -275,6 +275,30 @@
 	select SPARSE_IRQ
 	select MSM_NOPM
 
+config ARCH_MSM8226
+	bool "MSM8226"
+	select ARCH_MSM_KRAITMP
+	select GPIO_MSM_V3
+	select ARM_GIC
+	select CPU_V7
+	select MSM_SCM if SMP
+	select MSM_GPIOMUX
+	select MULTI_IRQ_HANDLER
+	select MSM_MULTIMEDIA_USE_ION
+	select MSM_PIL
+	select MSM_SPM_V2
+	select MSM_L2_SPM
+	select MSM_PM8X60 if PM
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
+	select MSM_RPM_SMD
+	select REGULATOR
+	select MSM_QDSP6_APRV2
+	select MSM_QDSP6V2_CODECS
+	select MSM_AUDIO_QDSP6V2 if SND_SOC
+	select MSM_RPM_REGULATOR_SMD
+	select ARM_HAS_SG_CHAIN
+
 config ARCH_FSM9XXX
 	bool "FSM9XXX"
 	select ARCH_MSM_SCORPION
@@ -333,7 +357,6 @@
 	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
 	select GPIO_MSM_V3
-
 endmenu
 
 choice
@@ -902,6 +925,7 @@
 	default "0x80200000" if ARCH_MSM8930
 	default "0x00000000" if ARCH_MSM8974
 	default "0x00000000" if ARCH_MPQ8092
+	default "0x00000000" if ARCH_MSM8226
 	default "0x10000000" if ARCH_FSM9XXX
 	default "0x20200000" if ARCH_MSM9625
 	default "0x00200000" if !MSM_STACKED_MEMORY
@@ -2010,6 +2034,15 @@
 	 gss hardware watchdog interrupt lines and plugs into the subsystem
 	 restart and PIL drivers.
 
+config MSM_MODEM_SSR_8974
+	bool "MSM 8974 Modem restart driver"
+	depends on (ARCH_MSM8974)
+	help
+	 This option enables the modem subsystem restart driver for the MSM8974.
+	 It monitors the modem SMSM status bits and the modem watchdog line and
+	 restarts the modem or the 8974 when the modem encounters a fatal error,
+	 depending on the restart level selected in the subsystem restart driver.
+
 config SCORPION_Uni_45nm_BUG
 	bool "Scorpion Uni 45nm(SC45U): Workaround for ICIMVAU and BPIMVA"
 	depends on ARCH_MSM7X30 || (ARCH_QSD8X50 && MSM_SOC_REV_A)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 524ec89..29bef02 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -210,6 +210,7 @@
 endif
 obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
 obj-$(CONFIG_MSM_MODEM_8960) += modem-8960.o
+obj-$(CONFIG_MSM_MODEM_SSR_8974) += modem-ssr-8974.o
 obj-$(CONFIG_MSM_LPASS_8960) += lpass-8960.o
 obj-$(CONFIG_MSM_WCNSS_SSR_8960) += wcnss-ssr-8960.o
 obj-$(CONFIG_MSM_GSS_SSR_8064) += gss-8064.o
diff --git a/arch/arm/mach-msm/audio-7627a-devices.c b/arch/arm/mach-msm/audio-7627a-devices.c
index 798c118..3a636e8 100644
--- a/arch/arm/mach-msm/audio-7627a-devices.c
+++ b/arch/arm/mach-msm/audio-7627a-devices.c
@@ -198,6 +198,8 @@
 			(SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
 	CAD(FM_DIGITAL_SPEAKER_PHONE_MONO, 67, \
 			(SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+	CAD(FM_DIGITAL_SPEAKER_PHONE_MIC, 68, \
+			(SNDDEV_CAP_FM | SNDDEV_CAP_TX)),
 	CAD(FM_DIGITAL_BT_A2DP_SPKR, 69, \
 			(SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
 	CAD(MAX, 80, SNDDEV_CAP_NONE),
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 2a02450..f5dfefc 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -27,7 +27,7 @@
 #include <linux/spi/spi.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/qcom_crypto_device.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/memory.h>
 #include <linux/memblock.h>
 #include <linux/msm_thermal.h>
@@ -964,18 +964,14 @@
 };
 
 static struct epm_chan_properties ads_adc_channel_data[] = {
-	{10, 100}, {500, 50}, {1, 1}, {1, 1},
-	{20, 50}, {10, 100}, {1, 1}, {1, 1},
-	{10, 100}, {10, 100}, {100, 100}, {200, 100},
-	{100, 50}, {2000, 50}, {1000, 50}, {200, 50},
-	{200, 100}, {1, 1}, {20, 50}, {500, 50},
-	{50, 50}, {200, 100}, {500, 100}, {20, 50},
-	{200, 50}, {2000, 100}, {1000, 50}, {100, 50},
-	{200, 100}, {500, 50}, {1000, 100}, {200, 50},
-	{1000, 50}, {50, 50}, {100, 50}, {100, 50},
-	{1, 1}, {1, 1}, {20, 100}, {20, 50},
-	{500, 100}, {1000, 100}, {100, 50}, {1000, 50},
-	{100, 50}, {1000, 100}, {100, 50}, {100, 50},
+	{10, 100}, {1000, 1}, {10, 100}, {1000, 1},
+	{10, 100}, {1000, 1}, {10, 100}, {1000, 1},
+	{10, 100}, {20, 100}, {500, 100}, {5, 100},
+	{1000, 1}, {200, 100}, {50, 100}, {10, 100},
+	{510, 100}, {50, 100}, {20, 100}, {100, 100},
+	{510, 100}, {20, 100}, {50, 100}, {200, 100},
+	{10, 100}, {20, 100}, {1000, 1}, {10, 100},
+	{200, 100}, {510, 100}, {1000, 100}, {200, 100},
 };
 
 static struct epm_adc_platform_data epm_adc_pdata = {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 2cd654c..547b724 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -77,7 +77,7 @@
 #endif
 
 #include <linux/smsc3503.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <mach/ion.h>
 #include <mach/mdm2.h>
 #include <mach/mdm-peripheral.h>
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index fd2329f..b385db5 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -60,6 +60,19 @@
 	},
 };
 #endif
+
+static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5wire_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv  = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
 static struct gpiomux_setting gpio_i2c_config = {
 	.func = GPIOMUX_FUNC_3,
 	.drv = GPIOMUX_DRV_8MA,
@@ -411,6 +424,43 @@
 		},
 	},
 };
+static struct msm_gpiomux_config wcnss_5wire_interface[] = {
+	{
+		.gpio = 36,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 37,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 38,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 39,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 40,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &wcnss_5wire_active_cfg,
+			[GPIOMUX_SUSPENDED] = &wcnss_5wire_suspend_cfg,
+		},
+	},
+};
 
 static struct msm_gpiomux_config msm_taiko_config[] __initdata = {
 	{
@@ -435,6 +485,8 @@
 	msm_gpiomux_install(msm_eth_configs, ARRAY_SIZE(msm_eth_configs));
 #endif
 	msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+	msm_gpiomux_install(wcnss_5wire_interface,
+				ARRAY_SIZE(wcnss_5wire_interface));
 
 	msm_gpiomux_install(msm8974_slimbus_config,
 			ARRAY_SIZE(msm8974_slimbus_config));
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 3d92a72..2a51e66 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -38,7 +38,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c/sx150x.h>
 #include <linux/gpio.h>
-#include <linux/android_pmem.h>
 #include <linux/bootmem.h>
 #include <linux/mfd/marimba.h>
 #include <mach/vreg.h>
@@ -60,8 +59,8 @@
 #include "pm-boot.h"
 #include "board-msm7627a.h"
 
-#define PMEM_KERNEL_EBI1_SIZE	0x3A000
-#define MSM_PMEM_AUDIO_SIZE	0x1F4000
+#define RESERVE_KERNEL_EBI1_SIZE	0x3A000
+#define MSM_RESERVE_AUDIO_SIZE	0x1F4000
 
 #if defined(CONFIG_GPIO_SX150X)
 enum {
@@ -159,12 +158,11 @@
 };
 
 #ifdef CONFIG_ARCH_MSM7X27A
-#define MSM_PMEM_MDP_SIZE                0x1B00000
-#define MSM7x25A_MSM_PMEM_MDP_SIZE       0x1500000
-
-#define MSM_PMEM_ADSP_SIZE      0x1200000
-#define MSM7x25A_MSM_PMEM_ADSP_SIZE      0xB91000
-#define CAMERA_ZSL_SIZE		(SZ_1M * 60)
+#define MSM_RESERVE_MDP_SIZE		0x1B00000
+#define MSM7x25A_MSM_RESERVE_MDP_SIZE   0x1500000
+#define MSM_RESERVE_ADSP_SIZE		0x1200000
+#define MSM7x25A_MSM_RESERVE_ADSP_SIZE	0xB91000
+#define CAMERA_ZSL_SIZE			(SZ_1M * 60)
 #endif
 
 #ifdef CONFIG_ION_MSM
@@ -442,61 +440,23 @@
 	.v_addr = MSM_CFG_CTL_BASE,
 };
 
-static struct android_pmem_platform_data android_pmem_adsp_pdata = {
-	.name = "pmem_adsp",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 1,
-	.memory_type = MEMTYPE_EBI1,
-};
-
-static struct platform_device android_pmem_adsp_device = {
-	.name = "android_pmem",
-	.id = 1,
-	.dev = { .platform_data = &android_pmem_adsp_pdata },
-};
-
-static unsigned pmem_mdp_size = MSM_PMEM_MDP_SIZE;
-static int __init pmem_mdp_size_setup(char *p)
+static unsigned reserve_mdp_size = MSM_RESERVE_MDP_SIZE;
+static int __init reserve_mdp_size_setup(char *p)
 {
-	pmem_mdp_size = memparse(p, NULL);
+	reserve_mdp_size = memparse(p, NULL);
 	return 0;
 }
 
-early_param("pmem_mdp_size", pmem_mdp_size_setup);
+early_param("reserve_mdp_size", reserve_mdp_size_setup);
 
-static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
-static int __init pmem_adsp_size_setup(char *p)
+static unsigned reserve_adsp_size = MSM_RESERVE_ADSP_SIZE;
+static int __init reserve_adsp_size_setup(char *p)
 {
-	pmem_adsp_size = memparse(p, NULL);
+	reserve_adsp_size = memparse(p, NULL);
 	return 0;
 }
 
-early_param("pmem_adsp_size", pmem_adsp_size_setup);
-
-static struct android_pmem_platform_data android_pmem_audio_pdata = {
-	.name = "pmem_audio",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 0,
-	.memory_type = MEMTYPE_EBI1,
-};
-
-static struct platform_device android_pmem_audio_device = {
-	.name = "android_pmem",
-	.id = 2,
-	.dev = { .platform_data = &android_pmem_audio_pdata },
-};
-
-static struct android_pmem_platform_data android_pmem_pdata = {
-	.name = "pmem",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 1,
-	.memory_type = MEMTYPE_EBI1,
-};
-static struct platform_device android_pmem_device = {
-	.name = "android_pmem",
-	.id = 0,
-	.dev = { .platform_data = &android_pmem_pdata },
-};
+early_param("reserve_adsp_size", reserve_adsp_size_setup);
 
 static u32 msm_calculate_batt_capacity(u32 current_voltage);
 
@@ -690,9 +650,6 @@
 
 static struct platform_device *common_devices[] __initdata = {
 	&android_usb_device,
-	&android_pmem_device,
-	&android_pmem_adsp_device,
-	&android_pmem_audio_device,
 	&msm_device_nand,
 	&msm_device_snd,
 	&msm_device_cad,
@@ -723,38 +680,39 @@
 	&msm8625_kgsl_3d0,
 };
 
-static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+static unsigned reserve_kernel_ebi1_size = RESERVE_KERNEL_EBI1_SIZE;
+static int __init reserve_kernel_ebi1_size_setup(char *p)
 {
-	pmem_kernel_ebi1_size = memparse(p, NULL);
+	reserve_kernel_ebi1_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("reserve_kernel_ebi1_size", reserve_kernel_ebi1_size_setup);
 
-static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
-static int __init pmem_audio_size_setup(char *p)
+static unsigned reserve_audio_size = MSM_RESERVE_AUDIO_SIZE;
+static int __init reserve_audio_size_setup(char *p)
 {
-	pmem_audio_size = memparse(p, NULL);
+	reserve_audio_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_audio_size", pmem_audio_size_setup);
+early_param("reserve_audio_size", reserve_audio_size_setup);
 
 static void fix_sizes(void)
 {
 	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
-		pmem_mdp_size = MSM7x25A_MSM_PMEM_MDP_SIZE;
-		pmem_adsp_size = MSM7x25A_MSM_PMEM_ADSP_SIZE;
+		reserve_mdp_size = MSM7x25A_MSM_RESERVE_MDP_SIZE;
+		reserve_adsp_size = MSM7x25A_MSM_RESERVE_ADSP_SIZE;
 	} else {
-		pmem_mdp_size = MSM_PMEM_MDP_SIZE;
-		pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
+		reserve_mdp_size = MSM_RESERVE_MDP_SIZE;
+		reserve_adsp_size = MSM_RESERVE_ADSP_SIZE;
 	}
 
 	if (get_ddr_size() > SZ_512M)
-		pmem_adsp_size = CAMERA_ZSL_SIZE;
+		reserve_adsp_size = CAMERA_ZSL_SIZE;
 #ifdef CONFIG_ION_MSM
-	msm_ion_camera_size = pmem_adsp_size;
-	msm_ion_audio_size = (MSM_PMEM_AUDIO_SIZE + PMEM_KERNEL_EBI1_SIZE);
-	msm_ion_sf_size = pmem_mdp_size;
+	msm_ion_camera_size = reserve_adsp_size;
+	msm_ion_audio_size = (MSM_RESERVE_AUDIO_SIZE +
+					RESERVE_KERNEL_EBI1_SIZE);
+	msm_ion_sf_size = reserve_mdp_size;
 #endif
 }
 
@@ -780,7 +738,7 @@
 			.name	= ION_VMALLOC_HEAP_NAME,
 		},
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-		/* PMEM_ADSP = CAMERA */
+		/* ION_ADSP = CAMERA */
 		{
 			.id	= ION_CAMERA_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
@@ -788,7 +746,7 @@
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *)&co_ion_pdata,
 		},
-		/* PMEM_AUDIO */
+		/* ION_AUDIO */
 		{
 			.id	= ION_AUDIO_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
@@ -796,7 +754,7 @@
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *)&co_ion_pdata,
 		},
-		/* PMEM_MDP = SF */
+		/* ION_MDP = SF */
 		{
 			.id	= ION_SF_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
@@ -837,50 +795,6 @@
 }
 #endif
 
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
-		&android_pmem_adsp_pdata,
-		&android_pmem_audio_pdata,
-		&android_pmem_pdata,
-};
-#endif
-#endif
-
-static void __init size_pmem_devices(void)
-{
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	android_pmem_adsp_pdata.size = pmem_adsp_size;
-	android_pmem_pdata.size = pmem_mdp_size;
-	android_pmem_audio_pdata.size = pmem_audio_size;
-
-#endif
-#endif
-}
-
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static void __init reserve_memory_for(struct android_pmem_platform_data *p)
-{
-	msm7x27a_reserve_table[p->memory_type].size += p->size;
-}
-#endif
-#endif
-
-static void __init reserve_pmem_memory(void)
-{
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	unsigned int i;
-	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
-		reserve_memory_for(pmem_pdata_array[i]);
-
-	msm7x27a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
-#endif
-#endif
-}
-
 static void __init size_ion_devices(void)
 {
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -902,8 +816,6 @@
 static void __init msm7x27a_calculate_reserve_sizes(void)
 {
 	fix_sizes();
-	size_pmem_devices();
-	reserve_pmem_memory();
 	size_ion_devices();
 	reserve_ion_memory();
 	reserve_rtb_memory();
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 524a2ad..f6b0c4f 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -20,7 +20,6 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/i2c.h>
-#include <linux/android_pmem.h>
 #include <linux/bootmem.h>
 #include <linux/mfd/marimba.h>
 #include <linux/power_supply.h>
@@ -61,8 +60,8 @@
 #include "board-msm7x27a-regulator.h"
 #include "board-msm7627a.h"
 
-#define PMEM_KERNEL_EBI1_SIZE	0x3A000
-#define MSM_PMEM_AUDIO_SIZE	0x1F4000
+#define RESERVE_KERNEL_EBI1_SIZE	0x3A000
+#define MSM_RESERVE_AUDIO_SIZE	0x1F4000
 #define BAHAMA_SLAVE_ID_FM_REG 0x02
 #define FM_GPIO	83
 #define BT_PCM_BCLK_MODE  0x88
@@ -130,9 +129,10 @@
 };
 
 #ifdef CONFIG_ARCH_MSM7X27A
-#define MSM_PMEM_MDP_SIZE       0x1B00000
-#define MSM_PMEM_ADSP_SIZE      0x1200000
-#define CAMERA_ZSL_SIZE		(SZ_1M * 60)
+
+#define MSM_RESERVE_MDP_SIZE       0x1B00000
+#define MSM_RESERVE_ADSP_SIZE      0x1200000
+#define CAMERA_ZSL_SIZE            (SZ_1M * 60)
 
 #ifdef CONFIG_ION_MSM
 #define MSM_ION_HEAP_NUM	4
@@ -390,61 +390,23 @@
 	.v_addr = MSM_CFG_CTL_BASE,
 };
 
-static struct android_pmem_platform_data android_pmem_adsp_pdata = {
-	.name = "pmem_adsp",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 1,
-	.memory_type = MEMTYPE_EBI1,
-};
-
-static struct platform_device android_pmem_adsp_device = {
-	.name = "android_pmem",
-	.id = 1,
-	.dev = { .platform_data = &android_pmem_adsp_pdata },
-};
-
-static unsigned pmem_mdp_size = MSM_PMEM_MDP_SIZE;
-static int __init pmem_mdp_size_setup(char *p)
+static unsigned reserve_mdp_size = MSM_RESERVE_MDP_SIZE;
+static int __init reserve_mdp_size_setup(char *p)
 {
-	pmem_mdp_size = memparse(p, NULL);
+	reserve_mdp_size = memparse(p, NULL);
 	return 0;
 }
 
-early_param("pmem_mdp_size", pmem_mdp_size_setup);
+early_param("reserve_mdp_size", reserve_mdp_size_setup);
 
-static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
-static int __init pmem_adsp_size_setup(char *p)
+static unsigned reserve_adsp_size = MSM_RESERVE_ADSP_SIZE;
+static int __init reserve_adsp_size_setup(char *p)
 {
-	pmem_adsp_size = memparse(p, NULL);
+	reserve_adsp_size = memparse(p, NULL);
 	return 0;
 }
 
-early_param("pmem_adsp_size", pmem_adsp_size_setup);
-
-static struct android_pmem_platform_data android_pmem_audio_pdata = {
-	.name = "pmem_audio",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 0,
-	.memory_type = MEMTYPE_EBI1,
-};
-
-static struct platform_device android_pmem_audio_device = {
-	.name = "android_pmem",
-	.id = 2,
-	.dev = { .platform_data = &android_pmem_audio_pdata },
-};
-
-static struct android_pmem_platform_data android_pmem_pdata = {
-	.name = "pmem",
-	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
-	.cached = 1,
-	.memory_type = MEMTYPE_EBI1,
-};
-static struct platform_device android_pmem_device = {
-	.name = "android_pmem",
-	.id = 0,
-	.dev = { .platform_data = &android_pmem_pdata },
-};
+early_param("reserve_adsp_size", reserve_adsp_size_setup);
 
 static u32 msm_calculate_batt_capacity(u32 current_voltage);
 
@@ -636,9 +598,6 @@
 
 static struct platform_device *common_devices[] __initdata = {
 	&android_usb_device,
-	&android_pmem_device,
-	&android_pmem_adsp_device,
-	&android_pmem_audio_device,
 	&msm_batt_device,
 	&msm_device_adspdec,
 	&msm_device_snd,
@@ -698,30 +657,32 @@
 	&msm8625_kgsl_3d0,
 };
 
-static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+static unsigned reserve_kernel_ebi1_size = RESERVE_KERNEL_EBI1_SIZE;
+static int __init reserve_kernel_ebi1_size_setup(char *p)
 {
-	pmem_kernel_ebi1_size = memparse(p, NULL);
+	reserve_kernel_ebi1_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("reserve_kernel_ebi1_size", reserve_kernel_ebi1_size_setup);
 
-static unsigned pmem_audio_size = MSM_PMEM_AUDIO_SIZE;
-static int __init pmem_audio_size_setup(char *p)
+
+static unsigned reserve_audio_size = MSM_RESERVE_AUDIO_SIZE;
+static int __init reserve_audio_size_setup(char *p)
 {
-	pmem_audio_size = memparse(p, NULL);
+	reserve_audio_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_audio_size", pmem_audio_size_setup);
+early_param("reserve_audio_size", reserve_audio_size_setup);
 
 static void fix_sizes(void)
 {
 	if (get_ddr_size() > SZ_512M)
-		pmem_adsp_size = CAMERA_ZSL_SIZE;
+		reserve_adsp_size = CAMERA_ZSL_SIZE;
 #ifdef CONFIG_ION_MSM
-	msm_ion_camera_size = pmem_adsp_size;
-	msm_ion_audio_size = (MSM_PMEM_AUDIO_SIZE + PMEM_KERNEL_EBI1_SIZE);
-	msm_ion_sf_size = pmem_mdp_size;
+	msm_ion_camera_size = reserve_adsp_size;
+	msm_ion_audio_size = (MSM_RESERVE_AUDIO_SIZE +
+						RESERVE_KERNEL_EBI1_SIZE);
+	msm_ion_sf_size = reserve_mdp_size;
 #endif
 }
 
@@ -747,7 +708,7 @@
 			.name	= ION_VMALLOC_HEAP_NAME,
 		},
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-		/* PMEM_ADSP = CAMERA */
+		/* ION_ADSP = CAMERA */
 		{
 			.id	= ION_CAMERA_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
@@ -755,7 +716,7 @@
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *)&co_ion_pdata,
 		},
-		/* PMEM_AUDIO */
+		/* ION_AUDIO */
 		{
 			.id	= ION_AUDIO_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
@@ -763,7 +724,7 @@
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *)&co_ion_pdata,
 		},
-		/* PMEM_MDP = SF */
+		/* ION_MDP = SF */
 		{
 			.id	= ION_SF_HEAP_ID,
 			.type	= ION_HEAP_TYPE_CARVEOUT,
@@ -804,49 +765,6 @@
 }
 #endif
 
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
-		&android_pmem_adsp_pdata,
-		&android_pmem_audio_pdata,
-		&android_pmem_pdata,
-};
-#endif
-#endif
-
-static void __init size_pmem_devices(void)
-{
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	android_pmem_adsp_pdata.size = pmem_adsp_size;
-	android_pmem_pdata.size = pmem_mdp_size;
-	android_pmem_audio_pdata.size = pmem_audio_size;
-#endif
-#endif
-}
-
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static void __init reserve_memory_for(struct android_pmem_platform_data *p)
-{
-	msm7627a_reserve_table[p->memory_type].size += p->size;
-}
-#endif
-#endif
-
-static void __init reserve_pmem_memory(void)
-{
-#ifdef CONFIG_ANDROID_PMEM
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-	unsigned int i;
-	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
-		reserve_memory_for(pmem_pdata_array[i]);
-
-	msm7627a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
-#endif
-#endif
-}
-
 static void __init size_ion_devices(void)
 {
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -868,8 +786,6 @@
 static void __init msm7627a_calculate_reserve_sizes(void)
 {
 	fix_sizes();
-	size_pmem_devices();
-	reserve_pmem_memory();
 	size_ion_devices();
 	reserve_ion_memory();
 	reserve_rtb_memory();
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index f3ac7d7..8cce34b 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -239,7 +239,6 @@
 		.rate = 19200000,
 		.ops = &clk_ops_tcxo,
 		CLK_INIT(tcxo_clk.c),
-		.warned = true,
 	},
 };
 
@@ -266,7 +265,6 @@
 		.rate = 24576000,
 		.ops = &clk_ops_lpxo,
 		CLK_INIT(lpxo_clk.c),
-		.warned = true,
 	},
 };
 
@@ -281,7 +279,6 @@
 		.rate = 768000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll1_clk.c),
-		.warned = true,
 	},
 };
 
@@ -296,7 +293,6 @@
 		.rate = 806400000, /* TODO: Support scaling */
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll2_clk.c),
-		.warned = true,
 	},
 };
 
@@ -325,7 +321,6 @@
 		.rate = 891000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
-		.warned = true,
 	},
 };
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 2ec4e38..92ceabe 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -519,7 +519,6 @@
 		.rate = 800000000,
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll2_clk.c),
-		.warned = true,
 	},
 };
 
@@ -533,7 +532,6 @@
 		.vdd_class = &vdd_sr2_hdmi_pll,
 		.fmax[VDD_SR2_HDMI_PLL_ON] = ULONG_MAX,
 		CLK_INIT(pll3_clk.c),
-		.warned = true,
 	},
 };
 
@@ -548,7 +546,6 @@
 		.rate = 393216000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
-		.warned = true,
 	},
 };
 
@@ -563,7 +560,6 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll8_clk.c),
-		.warned = true,
 	},
 };
 
@@ -578,7 +574,6 @@
 		.rate = 480000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll14_clk.c),
-		.warned = true,
 	},
 };
 
@@ -590,7 +585,6 @@
 		.rate = 975000000,
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll15_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2720,7 +2714,6 @@
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
 		CLK_INIT(csi0_src_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2738,7 +2731,6 @@
 		.dbg_name = "csi0_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(csi0_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2778,7 +2770,6 @@
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
 		CLK_INIT(csi1_src_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2796,7 +2787,6 @@
 		.dbg_name = "csi1_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(csi1_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2836,7 +2826,6 @@
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP2(LOW, 86000000, NOMINAL, 178000000),
 		CLK_INIT(csi2_src_clk.c),
-		.warned = true,
 	},
 };
 
@@ -2854,7 +2843,6 @@
 		.dbg_name = "csi2_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(csi2_clk.c),
-		.warned = true,
 	},
 };
 
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 7ced65c..b96f856 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -526,7 +526,7 @@
 #define dsipll_750_mm_source_val 1
 #define dsipll0_byte_mm_source_val 1
 #define dsipll0_pixel_mm_source_val 1
-#define hdmipll_297_mm_source_val 3
+#define hdmipll_mm_source_val 3
 
 #define F(f, s, div, m, n) \
 	{ \
@@ -550,6 +550,17 @@
 			| BVAL(10, 8, s##_mm_source_val), \
 	}
 
+#define F_HDMI(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
 #define F_MDSS(f, s, div, m, n) \
 	{ \
 		.freq_hz = (f), \
@@ -638,13 +649,13 @@
 #define OXILI_ID	0x1
 #define OCMEM_ID	0x2
 
-enum {
-	D0_ID = 1,
-	D1_ID,
-	A0_ID,
-	A1_ID,
-	A2_ID,
-};
+#define D0_ID		 1
+#define D1_ID		 2
+#define A0_ID		 3
+#define A1_ID		 4
+#define A2_ID		 5
+#define DIFF_CLK_ID	 7
+#define DIV_CLK_ID	11
 
 DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
 DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
@@ -667,6 +678,8 @@
 DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a0, cxo_a0_a, A0_ID);
 DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a1, cxo_a1_a, A1_ID);
 DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a2, cxo_a2_a, A2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk, div_a_clk, DIV_CLK_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(diff_clk, diff_a_clk, DIFF_CLK_ID);
 
 DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d0_pin, cxo_d0_a_pin, D0_ID);
 DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d1_pin, cxo_d1_a_pin, D1_ID);
@@ -684,7 +697,6 @@
 		.rate = 600000000,
 		.dbg_name = "gpll0_clk_src",
 		.ops = &clk_ops_pll_vote,
-		.warned = true,
 		CLK_INIT(gpll0_clk_src.c),
 	},
 };
@@ -700,7 +712,6 @@
 		.rate = 480000000,
 		.dbg_name = "gpll1_clk_src",
 		.ops = &clk_ops_pll_vote,
-		.warned = true,
 		CLK_INIT(gpll1_clk_src.c),
 	},
 };
@@ -716,7 +727,6 @@
 		.rate = 491520000,
 		.dbg_name = "lpapll0_clk_src",
 		.ops = &clk_ops_pll_vote,
-		.warned = true,
 		CLK_INIT(lpapll0_clk_src.c),
 	},
 };
@@ -732,7 +742,6 @@
 		.dbg_name = "mmpll0_clk_src",
 		.rate = 800000000,
 		.ops = &clk_ops_pll_vote,
-		.warned = true,
 		CLK_INIT(mmpll0_clk_src.c),
 	},
 };
@@ -748,7 +757,6 @@
 		.dbg_name = "mmpll1_clk_src",
 		.rate = 846000000,
 		.ops = &clk_ops_pll_vote,
-		.warned = true,
 		CLK_INIT(mmpll1_clk_src.c),
 	},
 };
@@ -762,7 +770,6 @@
 		.dbg_name = "mmpll3_clk_src",
 		.rate = 1000000000,
 		.ops = &clk_ops_local_pll,
-		.warned = true,
 		CLK_INIT(mmpll3_clk_src.c),
 	},
 };
@@ -1987,9 +1994,9 @@
 	.en_mask = BIT(0),
 	.base = &virt_bases[GCC_BASE],
 	.c = {
-		.dbg_name = "gcc_ce1_ahb_clk",
+		.dbg_name = "gcc_ce2_ahb_clk",
 		.ops = &clk_ops_vote,
-		CLK_INIT(gcc_ce1_ahb_clk.c),
+		CLK_INIT(gcc_ce2_ahb_clk.c),
 	},
 };
 
@@ -1999,7 +2006,7 @@
 	.en_mask = BIT(1),
 	.base = &virt_bases[GCC_BASE],
 	.c = {
-		.dbg_name = "gcc_ce1_axi_clk",
+		.dbg_name = "gcc_ce2_axi_clk",
 		.ops = &clk_ops_vote,
 		CLK_INIT(gcc_ce2_axi_clk.c),
 	},
@@ -2382,7 +2389,7 @@
 		.dbg_name = "axi_clk_src",
 		.ops = &clk_ops_rcg,
 		VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 282000000,
-				  HIGH, 320000000),
+				  HIGH, 400000000),
 		CLK_INIT(axi_clk_src.c),
 	},
 };
@@ -2996,14 +3003,84 @@
 	},
 };
 
+static int hdmi_pll_clk_enable(struct clk *c)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	ret = hdmi_pll_enable();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+	return ret;
+}
+
+static void hdmi_pll_clk_disable(struct clk *c)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	hdmi_pll_disable();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+}
+
+static int hdmi_pll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	rc = hdmi_pll_set_rate(rate);
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return rc;
+}
+
+static struct clk *hdmi_pll_clk_get_parent(struct clk *c)
+{
+	return &cxo_clk_src.c;
+}
+
+static struct clk_ops clk_ops_hdmi_pll = {
+	.enable = hdmi_pll_clk_enable,
+	.disable = hdmi_pll_clk_disable,
+	.set_rate = hdmi_pll_clk_set_rate,
+	.get_parent = hdmi_pll_clk_get_parent,
+};
+
+static struct clk hdmipll_clk_src = {
+	.dbg_name = "hdmipll_clk_src",
+	.ops = &clk_ops_hdmi_pll,
+	CLK_INIT(hdmipll_clk_src),
+};
+
 static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
-	F_MDSS(148500000, hdmipll_297,   2,   0,   0),
+	/*
+	 * The zero rate is required since suspend/resume wipes out the HDMI PHY
+	 * registers. This entry allows the HDMI driver to switch the cached
+	 * rate to zero before suspend and back to the real rate after resume.
+	 */
+	F_HDMI(        0, hdmipll, 1, 0, 0),
+	F_HDMI( 25200000, hdmipll, 1, 0, 0),
+	F_HDMI( 27030000, hdmipll, 1, 0, 0),
+	F_HDMI( 74250000, hdmipll, 1, 0, 0),
+	F_HDMI(148500000, hdmipll, 1, 0, 0),
+	F_HDMI(297000000, hdmipll, 1, 0, 0),
 	F_END
 };
 
+/*
+ * Unlike other clocks, the HDMI rate is adjusted through PLL
+ * re-programming. It is also routed through an HID divider.
+ */
+static void set_rate_hdmi(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
+{
+	clk_set_rate(nf->src_clk, nf->freq_hz);
+	set_rate_hid(rcg, nf);
+}
+
 static struct rcg_clk extpclk_clk_src = {
 	.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
-	.set_rate = set_rate_hid,
+	.set_rate = set_rate_hdmi,
 	.freq_tbl = ftbl_mdss_extpclk_clk,
 	.current_freq = &rcg_dummy_freq,
 	.base = &virt_bases[MMSS_BASE],
@@ -4966,6 +5043,7 @@
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-lpass"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-mss"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-mba"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"fb000000.qcom,wcnss-wlan"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil_pronto"),
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
@@ -5013,6 +5091,7 @@
 	CLK_LOOKUP("core_clk", gcc_blsp2_uart5_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp2_uart6_apps_clk.c, ""),
 
+	CLK_LOOKUP("core_clk_src", ce1_clk_src.c, ""),
 	CLK_LOOKUP("core_clk", gcc_ce1_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_ce2_clk.c, ""),
 	CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, ""),
@@ -5062,6 +5141,7 @@
 	CLK_LOOKUP("sleep_clk", gcc_usb30_sleep_clk.c, "msm_dwc3"),
 	CLK_LOOKUP("sleep_a_clk", gcc_usb2a_phy_sleep_clk.c, "msm_dwc3"),
 	CLK_LOOKUP("sleep_b_clk", gcc_usb2b_phy_sleep_clk.c, "msm_dwc3"),
+	CLK_LOOKUP("ref_clk", diff_clk.c, "msm_dwc3"),
 	CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c,     "msm_otg"),
 	CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c,   "msm_otg"),
 	CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c,	  "msm_hsic_host"),
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index bc57c3b..24c06c9 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -313,7 +313,6 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll8_clk.c),
-		.warned = true,
 	},
 };
 
@@ -325,7 +324,6 @@
 		.rate = 800000000,
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll2_clk.c),
-		.warned = true,
 	},
 };
 
@@ -337,7 +335,6 @@
 		.rate = 0, /* TODO: Detect rate dynamically */
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll3_clk.c),
-		.warned = true,
 	},
 };
 
@@ -387,7 +384,6 @@
 		.rate = 540672000,
 		.ops = &clk_ops_pll4,
 		CLK_INIT(pll4_clk.c),
-		.warned = true,
 	},
 };
 
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 494823b..648a8d4 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -272,7 +272,6 @@
 		.rate = 276000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll0_clk.c),
-		.warned = true,
 	},
 };
 
@@ -288,7 +287,6 @@
 		.rate = 276000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll0_activeonly_clk.c),
-		.warned = true,
 	},
 };
 
@@ -303,7 +301,6 @@
 		.rate = 393216000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll4_clk.c),
-		.warned = true,
 	},
 };
 
@@ -322,7 +319,6 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll8_clk.c),
-		.warned = true,
 	},
 };
 
@@ -338,7 +334,6 @@
 		.rate = 384000000,
 		.ops = &clk_ops_pll_acpu_vote,
 		CLK_INIT(pll8_activeonly_clk.c),
-		.warned = true,
 	},
 };
 
@@ -349,7 +344,6 @@
 		.rate = 440000000,
 		.ops = &clk_ops_local_pll,
 		CLK_INIT(pll9_activeonly_clk.c),
-		.warned = true,
 	},
 };
 
@@ -364,7 +358,6 @@
 		.rate = 480000000,
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(pll14_clk.c),
-		.warned = true,
 	},
 };
 
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 807d587..c996ff4 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -175,16 +175,18 @@
 {
 	char *start = "";
 
-	if (!c || !c->count)
+	if (!c || !c->prepare_count)
 		return 0;
 
 	pr_info("\t");
 	do {
 		if (c->vdd_class)
-			pr_cont("%s%s [%ld, %lu]", start, c->dbg_name, c->rate,
+			pr_cont("%s%s:%u:%u [%ld, %lu]", start, c->dbg_name,
+				c->prepare_count, c->count, c->rate,
 				c->vdd_class->cur_level);
 		else
-			pr_cont("%s%s [%ld]", start, c->dbg_name, c->rate);
+			pr_cont("%s%s:%u:%u [%ld]", start, c->dbg_name,
+				c->prepare_count, c->count, c->rate);
 		start = " -> ";
 	} while ((c = clk_get_parent(c)));
 
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index e203028..7952a33 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -110,7 +110,6 @@
 			.dbg_name = #name, \
 			.rate = (r), \
 			CLK_INIT(name.c), \
-			.warned = true, \
 		}, \
 	}; \
 	static struct rpm_clk active = { \
@@ -129,7 +128,6 @@
 			.dbg_name = #active, \
 			.rate = (r), \
 			CLK_INIT(active.c), \
-			.warned = true, \
 		}, \
 	};
 
@@ -148,7 +146,6 @@
 			.ops = &clk_ops_rpm, \
 			.dbg_name = #name, \
 			CLK_INIT(name.c), \
-			.warned = true, \
 		}, \
 	}; \
 	static struct rpm_clk active = { \
@@ -164,7 +161,6 @@
 			.ops = &clk_ops_rpm, \
 			.dbg_name = #active, \
 			CLK_INIT(active.c), \
-			.warned = true, \
 		}, \
 	};
 
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index a0367b0..27f2405 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -186,6 +186,7 @@
 	int ret = 0;
 	unsigned long flags;
 	struct clk *parent;
+	const char *name = clk ? clk->dbg_name : NULL;
 
 	if (!clk)
 		return 0;
@@ -193,10 +194,8 @@
 		return -EINVAL;
 
 	spin_lock_irqsave(&clk->lock, flags);
-	if (WARN(!clk->warned && !clk->prepare_count,
-				"%s: Don't call enable on unprepared clocks\n",
-				clk->dbg_name))
-		clk->warned = true;
+	WARN(!clk->prepare_count,
+			"%s: Don't call enable on unprepared clocks\n", name);
 	if (clk->count == 0) {
 		parent = clk_get_parent(clk);
 
@@ -207,7 +206,7 @@
 		if (ret)
 			goto err_enable_depends;
 
-		trace_clock_enable(clk->dbg_name, 1, smp_processor_id());
+		trace_clock_enable(name, 1, smp_processor_id());
 		if (clk->ops->enable)
 			ret = clk->ops->enable(clk);
 		if (ret)
@@ -230,23 +229,22 @@
 
 void clk_disable(struct clk *clk)
 {
+	const char *name = clk ? clk->dbg_name : NULL;
 	unsigned long flags;
 
 	if (IS_ERR_OR_NULL(clk))
 		return;
 
 	spin_lock_irqsave(&clk->lock, flags);
-	if (WARN(!clk->warned && !clk->prepare_count,
-				"%s: Never called prepare or calling disable "
-				"after unprepare\n",
-				clk->dbg_name))
-		clk->warned = true;
-	if (WARN(clk->count == 0, "%s is unbalanced", clk->dbg_name))
+	WARN(!clk->prepare_count,
+			"%s: Never called prepare or calling disable after unprepare\n",
+			name);
+	if (WARN(clk->count == 0, "%s is unbalanced", name))
 		goto out;
 	if (clk->count == 1) {
 		struct clk *parent = clk_get_parent(clk);
 
-		trace_clock_disable(clk->dbg_name, 0, smp_processor_id());
+		trace_clock_disable(name, 0, smp_processor_id());
 		if (clk->ops->disable)
 			clk->ops->disable(clk);
 		clk_disable(clk->depends);
@@ -260,23 +258,20 @@
 
 void clk_unprepare(struct clk *clk)
 {
+	const char *name = clk ? clk->dbg_name : NULL;
+
 	if (IS_ERR_OR_NULL(clk))
 		return;
 
 	mutex_lock(&clk->prepare_lock);
-	if (!clk->prepare_count) {
-		if (WARN(!clk->warned, "%s is unbalanced (prepare)",
-				clk->dbg_name))
-			clk->warned = true;
+	if (WARN(!clk->prepare_count, "%s is unbalanced (prepare)", name))
 		goto out;
-	}
 	if (clk->prepare_count == 1) {
 		struct clk *parent = clk_get_parent(clk);
 
-		if (WARN(!clk->warned && clk->count,
+		WARN(clk->count,
 			"%s: Don't call unprepare when the clock is enabled\n",
-				clk->dbg_name))
-			clk->warned = true;
+			name);
 
 		if (clk->ops->unprepare)
 			clk->ops->unprepare(clk);
@@ -318,6 +313,7 @@
 {
 	unsigned long start_rate;
 	int rc = 0;
+	const char *name = clk ? clk->dbg_name : NULL;
 
 	if (IS_ERR_OR_NULL(clk))
 		return -EINVAL;
@@ -331,7 +327,7 @@
 	if (clk->rate == rate)
 		goto out;
 
-	trace_clock_set_rate(clk->dbg_name, rate, raw_smp_processor_id());
+	trace_clock_set_rate(name, rate, raw_smp_processor_id());
 	if (clk->prepare_count) {
 		start_rate = clk->rate;
 		/* Enforce vdd requirements for target frequency. */
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 4e3d83b..45d2f71 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -114,7 +114,6 @@
  * @depends: non-direct parent of clock to enable when this clock is enabled
  * @vdd_class: voltage scaling requirement class
  * @fmax: maximum frequency in Hz supported at each voltage level
- * @warned: true if the clock has warned of incorrect usage, false otherwise
  */
 struct clk {
 	uint32_t flags;
@@ -128,7 +127,6 @@
 	struct list_head children;
 	struct list_head siblings;
 
-	bool warned;
 	unsigned count;
 	spinlock_t lock;
 	unsigned prepare_count;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 1ef8793..4ad5580 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2832,7 +2832,7 @@
 static struct coresight_platform_data coresight_funnel_pdata = {
 	.id		= 2,
 	.name		= "coresight-funnel",
-	.nr_inports	= 4,
+	.nr_inports	= 8,
 	.outports	= coresight_funnel_outports,
 	.child_ids	= coresight_funnel_child_ids,
 	.child_ports	= coresight_funnel_child_ports,
@@ -2864,7 +2864,7 @@
 static struct coresight_platform_data coresight_etm2_pdata = {
 	.id		= 6,
 	.name		= "coresight-etm2",
-	.nr_inports	= 1,
+	.nr_inports	= 0,
 	.outports	= coresight_etm2_outports,
 	.child_ids	= coresight_etm2_child_ids,
 	.child_ports	= coresight_etm2_child_ports,
@@ -2896,7 +2896,7 @@
 static struct coresight_platform_data coresight_etm3_pdata = {
 	.id		= 7,
 	.name		= "coresight-etm3",
-	.nr_inports	= 3,
+	.nr_inports	= 0,
 	.outports	= coresight_etm3_outports,
 	.child_ids	= coresight_etm3_child_ids,
 	.child_ports	= coresight_etm3_child_ports,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 377ecae..d22690c 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -15,7 +15,7 @@
 #include <linux/list.h>
 #include <linux/platform_device.h>
 #include <linux/msm_rotator.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 #include <linux/gpio.h>
 #include <linux/coresight.h>
 #include <asm/clkdev.h>
diff --git a/arch/arm/mach-msm/include/mach/irqs-8226.h b/arch/arm/mach-msm/include/mach/irqs-8226.h
new file mode 100644
index 0000000..3665697
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-8226.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_8226_H
+#define __ASM_ARCH_MSM_IRQS_8226_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define AVS_SVICINT				(GIC_PPI_START + 6)
+#define AVS_SVICINTSWDONE			(GIC_PPI_START + 7)
+#define INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
+/* PPI 15 is unused */
+
+#define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
+#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
+#define SPS_BAM_DMA_IRQ			(GIC_SPI_START + 105)
+
+#define NR_MSM_IRQS 256
+#define NR_GPIO_IRQS 146
+#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index cc1fb69..f562c40 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -66,6 +66,8 @@
 #include "irqs-9615.h"
 #elif defined(CONFIG_ARCH_MSM9625)
 #include "irqs-9625.h"
+#elif defined(CONFIG_ARCH_MSM8226)
+#include "irqs-8226.h"
 #elif defined(CONFIG_ARCH_MSM7X30)
 #include "irqs-7x30.h"
 #elif defined(CONFIG_ARCH_QSD8X50)
diff --git a/arch/arm/mach-msm/include/mach/msm_bus.h b/arch/arm/mach-msm/include/mach/msm_bus.h
index 6d7a533..c94bf80 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus.h
@@ -15,6 +15,7 @@
 
 #include <linux/types.h>
 #include <linux/input.h>
+#include <linux/platform_device.h>
 
 /*
  * Macros for clients to convert their data to ib and ab
@@ -77,11 +78,24 @@
 uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata);
 int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index);
 void msm_bus_scale_unregister_client(uint32_t cl);
+struct msm_bus_scale_pdata *msm_bus_cl_get_pdata(struct platform_device *pdev);
+void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata);
 /* AXI Port configuration APIs */
 int msm_bus_axi_porthalt(int master_port);
 int msm_bus_axi_portunhalt(int master_port);
 
 #else
+static inline struct msm_bus_scale_pdata
+*msm_bus_cl_get_pdata(struct platform_device *pdev)
+{
+	return NULL;
+}
+
+static inline void
+msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata)
+{
+}
+
 static inline uint32_t
 msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata)
 {
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8226.h b/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
new file mode 100644
index 0000000..c03b513
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8226.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_MSM8226_H
+#define __ASM_ARCH_MSM_IOMAP_MSM8226_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM8226_MSM_SHARED_RAM_PHYS	0x0FA00000
+
+#define MSM8226_QGIC_DIST_PHYS	0xF9000000
+#define MSM8226_QGIC_DIST_SIZE	SZ_4K
+
+#define MSM8226_QGIC_CPU_PHYS	0xF9002000
+#define MSM8226_QGIC_CPU_SIZE	SZ_4K
+
+#define MSM8226_APCS_GCC_PHYS	0xF9011000
+#define MSM8226_APCS_GCC_SIZE	SZ_4K
+
+#define MSM8226_TLMM_PHYS	0xFD510000
+#define MSM8226_TLMM_SIZE	SZ_16K
+
+#define MSM8226_IMEM_PHYS	0xFC42B000
+#define MSM8226_IMEM_SIZE	SZ_4K
+
+#ifdef CONFIG_DEBUG_MSM8226_UART
+#define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS	0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
index 7f04be8..15be294 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
@@ -54,4 +54,13 @@
 #define MSM_DEBUG_UART_PHYS	0xF991E000
 #endif
 
+/*
+ * IMEM is retained for secure watchdog reset
+ * Debug Image looks at actual IMEM to
+ * do memory dumping.
+ */
+
+#define MSM8974_DBG_IMEM_PHYS	0xFE805000
+#define MSM8974_DBG_IMEM_SIZE	SZ_4K
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index e961dfc..21bea4f 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -53,7 +53,8 @@
 	defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM7X27) || \
 	defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
 	defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
-	defined(CONFIG_ARCH_MSM9625) || defined(CONFIG_ARCH_MPQ8092)
+	defined(CONFIG_ARCH_MSM9625) || defined(CONFIG_ARCH_MPQ8092) || \
+	defined(CONFIG_ARCH_MSM8226)
 
 /* Unified iomap */
 
@@ -97,6 +98,7 @@
 #define MSM_MDC_BASE		IOMEM(0xFA400000)	/*  1M */
 #define MSM_AD5_BASE		IOMEM(0xFA900000)	/*  13M (D00000)
 							  0xFB600000 */
+#define MSM_DBG_IMEM_BASE	IOMEM(0xFB600000)	/*  4K */
 
 #define MSM_STRONGLY_ORDERED_PAGE	0xFA0F0000
 #define MSM8625_SECONDARY_PHYS		0x0FE00000
@@ -119,6 +121,7 @@
 #include "msm_iomap-8974.h"
 #include "msm_iomap-9625.h"
 #include "msm_iomap-8092.h"
+#include "msm_iomap-8226.h"
 
 #else
 /* Legacy single-target iomap */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 7570fef..546cbaf 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -48,7 +48,12 @@
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,mpq8092")
 #define machine_is_mpq8092_sim()           \
 	of_machine_is_compatible("qcom,mpq8092-sim")
-
+#define early_machine_is_msm8226()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8226")
+#define machine_is_msm8226()		\
+	of_machine_is_compatible("qcom,msm8226")
+#define machine_is_msm8226_sim()		\
+	of_machine_is_compatible("qcom,msm8226-sim")
 #else
 #define early_machine_is_msm8974()	0
 #define machine_is_msm8974()		0
@@ -58,6 +63,10 @@
 #define machine_is_msm9625()		0
 #define early_machine_is_mpq8092()	0
 #define machine_is_mpq8092_sim()	0
+#define early_machine_is_msm8226()	0
+#define machine_is_msm8226()		0
+#define machine_is_msm8226_sim()	0
+
 #endif
 
 #define PLATFORM_SUBTYPE_SGLTE	6
@@ -88,7 +97,8 @@
 	MSM_CPU_8627,
 	MSM_CPU_8625,
 	MSM_CPU_9625,
-	MSM_CPU_8092
+	MSM_CPU_8092,
+	MSM_CPU_8226
 };
 
 enum pmic_model {
@@ -382,4 +392,17 @@
 #endif
 
 }
+
+static inline int cpu_is_msm8226(void)
+{
+#ifdef CONFIG_ARCH_MSM8226
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_8226;
+#else
+	return 0;
+#endif
+}
+
 #endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index a2e46ca..9dff013 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -310,6 +310,7 @@
 #ifdef CONFIG_DEBUG_MSM8974_UART
 	MSM_DEVICE(DEBUG_UART),
 #endif
+	MSM_CHIP_DEVICE(DBG_IMEM, MSM8974),
 };
 
 void __init msm_map_8974_io(void)
@@ -500,3 +501,28 @@
 	msm_map_io(mpq8092_io_desc, ARRAY_SIZE(mpq8092_io_desc));
 }
 #endif /* CONFIG_ARCH_MPQ8092 */
+
+#ifdef CONFIG_ARCH_MSM8226
+static struct map_desc msm_8226_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, MSM8226),
+	MSM_CHIP_DEVICE(QGIC_CPU, MSM8226),
+	MSM_CHIP_DEVICE(APCS_GCC, MSM8226),
+	MSM_CHIP_DEVICE(TLMM, MSM8226),
+	MSM_CHIP_DEVICE(IMEM, MSM8226),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+#ifdef CONFIG_DEBUG_MPQ8226_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+
+void __init msm_map_msm8226_io(void)
+{
+	msm_shared_ram_phys = MSM8226_MSM_SHARED_RAM_PHYS;
+	msm_map_io(msm_8226_io_desc, ARRAY_SIZE(msm_8226_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8226 */
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index bf5857c..3b7c5d6 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.c
@@ -1070,6 +1070,20 @@
 
 	cpu = raw_smp_processor_id();
 
+	/* Attempt restore only if save has been done. If power collapse
+	 * is disabled, hotplug off of non-boot core will result in WFI
+	 * and hence msm_jtag_save_state will not occur. Subsequently,
+	 * during hotplug on of non-boot core when msm_jtag_restore_state
+	 * is called via msm_platform_secondary_init, this check will help
+	 * bail us out without restoring.
+	 */
+	if (msm_jtag_save_cntr[cpu] == msm_jtag_restore_cntr[cpu])
+		return;
+	else if (msm_jtag_save_cntr[cpu] != msm_jtag_restore_cntr[cpu] + 1)
+		pr_err_ratelimited("jtag imbalance, save:%lu, restore:%lu\n",
+				   (unsigned long)msm_jtag_save_cntr[cpu],
+				   (unsigned long)msm_jtag_restore_cntr[cpu]);
+
 	msm_jtag_restore_cntr[cpu]++;
 	/* ensure counter is updated before moving forward */
 	mb();
diff --git a/arch/arm/mach-msm/modem-ssr-8974.c b/arch/arm/mach-msm/modem-ssr-8974.c
new file mode 100644
index 0000000..fec578f
--- /dev/null
+++ b/arch/arm/mach-msm/modem-ssr-8974.c
@@ -0,0 +1,141 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+
+static int crash_shutdown;
+static struct subsys_device *modem_ssr_dev;
+
+#define MAX_SSR_REASON_LEN 81U
+#define Q6SS_WDOG_ENABLE		0xFC802004
+#define MSS_Q6SS_WDOG_EXP_IRQ		56
+
+static void log_modem_sfr(void)
+{
+	u32 size;
+	char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+	if (!smem_reason || !size) {
+		pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+		return;
+	}
+	if (!smem_reason[0]) {
+		pr_err("modem subsystem failure reason: (unknown, empty string found).\n");
+		return;
+	}
+
+	strlcpy(reason, smem_reason, min(size, sizeof(reason)));
+	pr_err("modem subsystem failure reason: %s.\n", reason);
+
+	smem_reason[0] = '\0';
+	wmb();
+}
+
+static void restart_modem(void)
+{
+	log_modem_sfr();
+	subsystem_restart("modem");
+}
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+	/* Ignore if we're the one that set SMSM_RESET */
+	if (crash_shutdown)
+		return;
+
+	if (new_state & SMSM_RESET) {
+		pr_err("Probable fatal error on the modem.\n");
+		restart_modem();
+	}
+}
+
+static int modem_shutdown(const struct subsys_desc *subsys)
+{
+	return 0;
+}
+
+static int modem_powerup(const struct subsys_desc *subsys)
+{
+	return 0;
+}
+
+void modem_crash_shutdown(const struct subsys_desc *subsys)
+{
+	crash_shutdown = 1;
+	smsm_reset_modem(SMSM_RESET);
+}
+
+static int modem_ramdump(int enable,
+				const struct subsys_desc *crashed_subsys)
+{
+	return 0;
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+	pr_err("Watchdog bite received from modem software!\n");
+	restart_modem();
+	return IRQ_HANDLED;
+}
+
+static struct subsys_desc modem_8974 = {
+	.name = "modem",
+	.shutdown = modem_shutdown,
+	.powerup = modem_powerup,
+	.ramdump = modem_ramdump,
+	.crash_shutdown = modem_crash_shutdown
+};
+
+static int __init modem_8974_init(void)
+{
+	int ret;
+
+	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+		smsm_state_cb, 0);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to register SMSM callback! (%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	ret = request_irq(MSS_Q6SS_WDOG_EXP_IRQ, modem_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, "modem_wdog_sw", NULL);
+
+	if (ret < 0) {
+		pr_err("%s: Unable to request q6sw watchdog IRQ. (%d)\n",
+				__func__, ret);
+		goto out;
+	}
+
+	modem_ssr_dev = subsys_register(&modem_8974);
+
+	if (IS_ERR_OR_NULL(modem_ssr_dev)) {
+		pr_err("%s: Unable to reg with subsystem restart. (%ld)\n",
+				__func__, PTR_ERR(modem_ssr_dev));
+		ret = PTR_ERR(modem_ssr_dev);
+		goto out;
+	}
+
+	pr_info("%s: modem subsystem restart driver init'ed.\n", __func__);
+out:
+	return ret;
+}
+
+arch_initcall(modem_8974_init);
diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
index 924577f..bdc6fac 100644
--- a/arch/arm/mach-msm/msm_bus/Makefile
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -2,7 +2,7 @@
 # Makefile for msm-bus driver specific files
 #
 obj-y += msm_bus_core.o msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o
-obj-y += msm_bus_bimc.o msm_bus_noc.o
+obj-y += msm_bus_bimc.o msm_bus_noc.o msm_bus_of.o
 obj-$(CONFIG_MSM_RPM) += msm_bus_rpm.o
 obj-$(CONFIG_MSM_RPM_SMD) += msm_bus_rpm_smd.o
 obj-$(CONFIG_ARCH_MSM8X60) += msm_bus_board_8660.o
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
index 265716d..1b8c07e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
@@ -804,7 +804,7 @@
 		.num_tiers = ARRAY_SIZE(tier2),
 		.hw_sel = MSM_BUS_NOC,
 		.perm_mode = NOC_QOS_MODES_ALL_PERM,
-		.mode = NOC_QOS_MODE_FIXED,
+		.mode = NOC_QOS_MODE_BYPASS,
 		.ws = 10000,
 		.qport = qports_oxili,
 		.mas_hw_id = MAS_GFX3D,
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 e6ec722..049e8c7 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -189,10 +189,10 @@
 }
 
 static void noc_set_qos_mode(struct msm_bus_noc_info *ninfo, uint32_t mport,
-	uint8_t mode)
+	uint8_t mode, uint8_t perm_mode)
 {
 	if (mode < NOC_QOS_MODE_MAX &&
-		((1 << mode) & ninfo->mas_modes[mport])) {
+		((1 << mode) & perm_mode)) {
 		uint32_t reg_val;
 
 		reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
@@ -297,13 +297,13 @@
 }
 
 uint8_t msm_bus_noc_get_qos_mode(struct msm_bus_noc_info *ninfo,
-	uint32_t mport)
+	uint32_t mport, uint32_t mode, uint32_t perm_mode)
 {
-	if (NOC_QOS_MODES_ALL_PERM == ninfo->mas_modes[mport])
+	if (NOC_QOS_MODES_ALL_PERM == perm_mode)
 		return readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
 			mport)) & NOC_QOS_MODEn_MODE_BMSK;
 	else
-		return 31 - __CLZ(ninfo->mas_modes[mport] &
+		return 31 - __CLZ(mode &
 			NOC_QOS_MODES_ALL_PERM);
 }
 
@@ -320,9 +320,9 @@
 }
 
 void msm_bus_noc_get_qos_bw(struct msm_bus_noc_info *ninfo,
-	uint32_t mport, struct msm_bus_noc_qos_bw *qbw)
+	uint32_t mport, uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw)
 {
-	if (ninfo->mas_modes[mport] & (NOC_QOS_PERM_MODE_LIMITER |
+	if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
 		NOC_QOS_PERM_MODE_REGULATOR)) {
 		uint32_t bw_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->
 			base, mport)) & NOC_QOS_BWn_BW_BMSK;
@@ -375,7 +375,7 @@
 		}
 
 		noc_set_qos_mode(ninfo, info->node_info->qport[i], info->
-			node_info->mode);
+			node_info->mode, info->node_info->perm_mode);
 	}
 
 	return 0;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.h b/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
index 407d3ec..35af884 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
@@ -64,10 +64,10 @@
 
 void msm_bus_noc_init(struct msm_bus_noc_info *ninfo);
 uint8_t msm_bus_noc_get_qos_mode(struct msm_bus_noc_info *ninfo,
-	uint32_t mport);
+	uint32_t mport, uint32_t mode, uint32_t perm_mode);
 void msm_bus_noc_get_qos_priority(struct msm_bus_noc_info *ninfo,
 	uint32_t mport, struct msm_bus_noc_qos_priority *qprio);
 void msm_bus_noc_get_qos_bw(struct msm_bus_noc_info *ninfo,
-	uint32_t mport, struct msm_bus_noc_qos_bw *qbw);
+	uint32_t mport, uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw);
 
 #endif /*_ARCH_ARM_MACH_MSM_BUS_NOC_H */
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
new file mode 100644
index 0000000..24b0ce2
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
@@ -0,0 +1,150 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <mach/msm_bus.h>
+
+/**
+ * msm_bus_cl_get_pdata() - Generate bus client data from device tree
+ * provided by clients.
+ *
+ * of_node: Device tree node to extract information from
+ *
+ * The function returns a valid pointer to the allocated bus-scale-pdata
+ * if the vectors were correctly read from the client's device node.
+ * Any error in reading or parsing the device node will return NULL
+ * to the caller.
+ */
+struct msm_bus_scale_pdata *msm_bus_cl_get_pdata(struct platform_device *pdev)
+{
+	struct device_node *of_node;
+	struct msm_bus_scale_pdata *pdata = NULL;
+	struct msm_bus_paths *usecase = NULL;
+	int i = 0, j, ret, num_usecases = 0, num_paths, len;
+	const uint32_t *vec_arr = NULL;
+	bool mem_err = false;
+
+	if (!pdev) {
+		pr_err("Error: Null Platform device\n");
+		return NULL;
+	}
+
+	of_node = pdev->dev.of_node;
+	pdata = devm_kzalloc(&pdev->dev, sizeof(struct msm_bus_scale_pdata),
+		GFP_KERNEL);
+	if (!pdata) {
+		pr_err("Error: Memory allocation for pdata failed\n");
+		mem_err = true;
+		goto err;
+	}
+
+	ret = of_property_read_string(of_node, "qcom,msm_bus,name",
+		&pdata->name);
+	if (ret) {
+		pr_err("Error: Client name not found\n");
+		goto err;
+	}
+
+	ret = of_property_read_u32(of_node, "qcom,msm_bus,num_cases",
+		&num_usecases);
+	if (ret) {
+		pr_err("Error: num_usecases not found\n");
+		goto err;
+	}
+
+	pdata->num_usecases = num_usecases;
+	ret = of_property_read_u32(of_node, "qcom,msm_bus,active_only",
+		&pdata->active_only);
+	if (ret) {
+		pr_info("active_only flag absent.\n");
+		pr_info("Using dual context by default\n");
+	}
+
+	usecase = devm_kzalloc(&pdev->dev, (sizeof(struct msm_bus_paths) *
+		pdata->num_usecases), GFP_KERNEL);
+	if (!usecase) {
+		pr_err("Error: Memory allocation for paths failed\n");
+		mem_err = true;
+		goto err;
+	}
+
+	ret = of_property_read_u32(of_node, "qcom,msm_bus,num_paths",
+		&num_paths);
+	if (ret) {
+		pr_err("Error: num_paths not found\n");
+		goto err;
+	}
+
+	vec_arr = of_get_property(of_node, "qcom,msm_bus,vectors", &len);
+	if (len != num_usecases * num_paths * sizeof(struct msm_bus_vectors)) {
+		pr_err("Error: Length-error on getting vectors\n");
+		goto err;
+	}
+
+	for (i = 0; i < num_usecases; i++) {
+		usecase[i].num_paths = num_paths;
+		usecase[i].vectors = devm_kzalloc(&pdev->dev, num_paths *
+			sizeof(struct msm_bus_vectors), GFP_KERNEL);
+		if (!usecase[i].vectors) {
+			mem_err = true;
+			pr_err("Error: Mem alloc failure in vectors\n");
+			goto err;
+		}
+
+		for (j = 0; j < num_paths; j++) {
+			int index = ((i * num_paths) + j) * 4;
+			usecase[i].vectors[j].src = be32_to_cpu(vec_arr[index]);
+			usecase[i].vectors[j].dst =
+				be32_to_cpu(vec_arr[index + 1]);
+			usecase[i].vectors[j].ab =
+				be32_to_cpu(vec_arr[index + 2]);
+			usecase[i].vectors[j].ib =
+				be32_to_cpu(vec_arr[index + 3]);
+		}
+	}
+
+	pdata->usecase = usecase;
+	return pdata;
+err:
+	if (mem_err) {
+		for (; i > 0; i--)
+			kfree(usecase[i-1].vectors);
+
+		kfree(usecase);
+		kfree(pdata);
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(msm_bus_cl_get_pdata);
+
+/**
+ * msm_bus_cl_clear_pdata() - Clear pdata allocated from device-tree
+ * of_node: Device tree node to extract information from
+ */
+void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata)
+{
+	int i;
+
+	for (i = 0; i < pdata->num_usecases; i++)
+		kfree(pdata->usecase[i].vectors);
+
+	kfree(pdata->usecase);
+	kfree(pdata);
+}
+EXPORT_SYMBOL(msm_bus_cl_clear_pdata);
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index 2604d47..6e094fd 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -131,6 +131,7 @@
 	return __ocmem_allocate_range(client_id, size, size,
 					size, can_block, can_wait);
 }
+EXPORT_SYMBOL(ocmem_allocate);
 
 struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size)
 {
@@ -162,6 +163,7 @@
 	return __ocmem_allocate_range(client_id, size, size,
 					size, can_block, can_wait);
 }
+EXPORT_SYMBOL(ocmem_allocate_nowait);
 
 struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
 		unsigned long goal, unsigned long step)
@@ -202,6 +204,7 @@
 	return __ocmem_allocate_range(client_id, min, goal,
 				step, can_block, can_wait);
 }
+EXPORT_SYMBOL(ocmem_allocate_range);
 
 struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size)
 {
@@ -242,6 +245,7 @@
 						can_block, can_wait);
 
 }
+EXPORT_SYMBOL(ocmem_allocate_nb);
 
 int ocmem_free(int client_id, struct ocmem_buf *buffer)
 {
@@ -263,6 +267,7 @@
 
 	return __ocmem_free(client_id, buffer);
 }
+EXPORT_SYMBOL(ocmem_free);
 
 int ocmem_shrink(int client_id, struct ocmem_buf *buffer, unsigned long len)
 {
@@ -279,6 +284,7 @@
 
 	return __ocmem_shrink(client_id, buffer, len);
 }
+EXPORT_SYMBOL(ocmem_shrink);
 
 int pre_validate_chunk_list(struct ocmem_map_list *list)
 {
@@ -350,6 +356,7 @@
 	mutex_unlock(&handle->handle_mutex);
 	return ret;
 }
+EXPORT_SYMBOL(ocmem_map);
 
 int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
 			struct ocmem_map_list *list)
@@ -390,6 +397,7 @@
 	mutex_unlock(&handle->handle_mutex);
 	return ret;
 }
+EXPORT_SYMBOL(ocmem_unmap);
 
 unsigned long get_max_quota(int client_id)
 {
@@ -427,6 +435,7 @@
 	mutex_unlock(&ocmem_eviction_lock);
 	return ret;
 }
+EXPORT_SYMBOL(ocmem_evict);
 
 int ocmem_restore(int client_id)
 {
@@ -448,6 +457,7 @@
 	mutex_unlock(&ocmem_eviction_lock);
 	return ret;
 }
+EXPORT_SYMBOL(ocmem_restore);
 
 /* Wrappers until power control is transitioned to clients */
 enum ocmem_power_state ocmem_get_power_state(int client_id,
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 40929cc..8ddb9e1 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -685,6 +685,7 @@
 
 		switch (mode) {
 		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		case MSM_PM_SLEEP_MODE_RETENTION:
 			if (!allow)
 				break;
 
@@ -699,15 +700,6 @@
 				break;
 			/* fall through */
 
-		case MSM_PM_SLEEP_MODE_RETENTION:
-			if (!allow)
-				break;
-			if (num_online_cpus() > 1) {
-				allow = false;
-				break;
-			}
-			/* fall through */
-
 		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
 			if (!allow)
 				break;
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index cd5556a..b112c90 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -490,13 +490,14 @@
 
 	pkt_sz = smd_cur_packet_size(msm_rpm_data.ch_info);
 
+	if (!pkt_sz)
+		return -EAGAIN;
+
 	BUG_ON(pkt_sz > MAX_ERR_BUFFER_SIZE);
 
 	if (pkt_sz != smd_read_avail(msm_rpm_data.ch_info))
 		return -EAGAIN;
 
-	BUG_ON(pkt_sz == 0);
-
 	do {
 		int len;
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index c614086..86de130 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -280,6 +280,9 @@
 	[143] = MSM_CPU_8930AA,
 	[144] = MSM_CPU_8930AA,
 
+	/* 8226 IDs */
+	[145] = MSM_CPU_8226,
+
 	/* 8092 IDs */
 	[146] = MSM_CPU_8092,
 
@@ -716,6 +719,10 @@
 		dummy_socinfo.id = 134;
 		strlcpy(dummy_socinfo.build_id, "msm9625 - ",
 			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm8226()) {
+		dummy_socinfo.id = 145;
+		strlcpy(dummy_socinfo.build_id, "msm8226 - ",
+			sizeof(dummy_socinfo.build_id));
 	} else if (machine_is_msm8625_rumi3())
 		dummy_socinfo.id = 127;
 	else if (early_machine_is_mpq8092()) {
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index d3938a0..cc3b956 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -150,28 +150,16 @@
 static const char * const _order_8x60_modems[] = {"external_modem", "modem"};
 DEFINE_SINGLE_RESTART_ORDER(orders_8x60_modems, _order_8x60_modems);
 
-/* MSM 8960 restart ordering info */
-static const char * const order_8960[] = {"modem", "lpass"};
 /*SGLTE restart ordering info*/
 static const char * const order_8960_sglte[] = {"external_modem",
 						"modem"};
 
-static struct subsys_soc_restart_order restart_orders_8960_one = {
-	.subsystem_list = order_8960,
-	.count = ARRAY_SIZE(order_8960),
-	.subsys_ptrs = {[ARRAY_SIZE(order_8960)] = NULL}
-	};
-
 static struct subsys_soc_restart_order restart_orders_8960_fusion_sglte = {
 	.subsystem_list = order_8960_sglte,
 	.count = ARRAY_SIZE(order_8960_sglte),
 	.subsys_ptrs = {[ARRAY_SIZE(order_8960_sglte)] = NULL}
 	};
 
-static struct subsys_soc_restart_order *restart_orders_8960[] = {
-	&restart_orders_8960_one,
-	};
-
 static struct subsys_soc_restart_order *restart_orders_8960_sglte[] = {
 	&restart_orders_8960_fusion_sglte,
 	};
@@ -205,9 +193,13 @@
 		return ret;
 
 	switch (restart_level) {
-	case RESET_SOC:
-	case RESET_SUBSYS_COUPLED:
 	case RESET_SUBSYS_INDEPENDENT:
+		if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+			pr_info("Phase 3 is currently unsupported. Using phase 2 instead.\n");
+			restart_level = RESET_SUBSYS_COUPLED;
+		}
+	case RESET_SUBSYS_COUPLED:
+	case RESET_SOC:
 		pr_info("Phase %d behavior activated.\n", restart_level);
 		break;
 	default:
@@ -754,21 +746,14 @@
 		n_restart_orders = ARRAY_SIZE(orders_8x60_all);
 	}
 
-	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
-	    cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627() ||
-	    cpu_is_msm8960ab()) {
-		if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
-			restart_orders = restart_orders_8960_sglte;
-			n_restart_orders =
-				ARRAY_SIZE(restart_orders_8960_sglte);
-		} else {
-			restart_orders = restart_orders_8960;
-			n_restart_orders = ARRAY_SIZE(restart_orders_8960);
-		}
-		for (i = 0; i < n_restart_orders; i++) {
-			mutex_init(&restart_orders[i]->powerup_lock);
-			mutex_init(&restart_orders[i]->shutdown_lock);
-		}
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+		restart_orders = restart_orders_8960_sglte;
+		n_restart_orders = ARRAY_SIZE(restart_orders_8960_sglte);
+	}
+
+	for (i = 0; i < n_restart_orders; i++) {
+		mutex_init(&restart_orders[i]->powerup_lock);
+		mutex_init(&restart_orders[i]->shutdown_lock);
 	}
 
 	if (restart_orders == NULL || n_restart_orders < 1) {
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index bded488..4ee93cf 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -1,3 +1,3 @@
 
 obj-$(CONFIG_OF) += of_coresight.o
-obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o
+obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-csr.o coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
new file mode 100644
index 0000000..e9ac904
--- /dev/null
+++ b/drivers/coresight/coresight-csr.c
@@ -0,0 +1,202 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define csr_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
+#define csr_readl(drvdata, off)		__raw_readl(drvdata->base + off)
+
+#define CSR_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	csr_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define CSR_UNLOCK(drvdata)						\
+do {									\
+	csr_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
+
+#define CSR_SWDBGPWRCTRL	(0x000)
+#define CSR_SWDBGPWRACK		(0x004)
+#define CSR_SWSPADREG0		(0x008)
+#define CSR_SWSPADREG1		(0x00C)
+#define CSR_STMTRANSCTRL	(0x010)
+#define CSR_STMAWIDCTRL		(0x014)
+#define CSR_STMCHNOFST0		(0x018)
+#define CSR_STMCHNOFST1		(0x01C)
+#define CSR_STMEXTHWCTRL0	(0x020)
+#define CSR_STMEXTHWCTRL1	(0x024)
+#define CSR_STMEXTHWCTRL2	(0x028)
+#define CSR_STMEXTHWCTRL3	(0x02C)
+#define CSR_USBBAMCTRL		(0x030)
+#define CSR_USBFLSHCTRL		(0x034)
+#define CSR_TIMESTAMPCTRL	(0x038)
+#define CSR_AOTIMEVAL0		(0x03C)
+#define CSR_AOTIMEVAL1		(0x040)
+#define CSR_QDSSTIMEVAL0	(0x044)
+#define CSR_QDSSTIMEVAL1	(0x048)
+#define CSR_QDSSTIMELOAD0	(0x04C)
+#define CSR_QDSSTIMELOAD1	(0x050)
+#define CSR_DAPMSAVAL		(0x054)
+#define CSR_QDSSCLKVOTE		(0x058)
+#define CSR_QDSSCLKIPI		(0x05C)
+#define CSR_QDSSPWRREQIGNORE	(0x060)
+#define CSR_QDSSSPARE		(0x064)
+#define CSR_IPCAT		(0x068)
+
+#define BLKSIZE_256		0
+#define BLKSIZE_512		1
+#define BLKSIZE_1024		2
+#define BLKSIZE_2048		3
+
+struct csr_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+};
+
+static struct csr_drvdata *csrdrvdata;
+
+void msm_qdss_csr_enable_bam_to_usb(void)
+{
+	struct csr_drvdata *drvdata = csrdrvdata;
+	uint32_t usbbamctrl, usbflshctrl;
+
+	CSR_UNLOCK(drvdata);
+
+	usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
+	usbbamctrl = (usbbamctrl & ~0x3) | BLKSIZE_256;
+	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
+
+	usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
+	usbflshctrl = (usbflshctrl & ~0x3FFFC) | (0x1000 << 2);
+	csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
+	usbflshctrl |= 0x2;
+	csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
+
+	usbbamctrl |= 0x4;
+	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
+
+	CSR_LOCK(drvdata);
+}
+EXPORT_SYMBOL_GPL(msm_qdss_csr_enable_bam_to_usb);
+
+void msm_qdss_csr_disable_bam_to_usb(void)
+{
+	struct csr_drvdata *drvdata = csrdrvdata;
+	uint32_t usbbamctrl;
+
+	CSR_UNLOCK(drvdata);
+
+	usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
+	usbbamctrl &= (~0x4);
+	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
+
+	CSR_LOCK(drvdata);
+}
+EXPORT_SYMBOL_GPL(msm_qdss_csr_disable_bam_to_usb);
+
+static int __devinit csr_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct csr_drvdata *drvdata;
+	struct resource *res;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	/* Store the driver data pointer for use in exported functions */
+	csrdrvdata = drvdata;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_NONE;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "CSR initialized\n");
+	return 0;
+}
+
+static int __devexit csr_remove(struct platform_device *pdev)
+{
+	struct csr_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id csr_match[] = {
+	{.compatible = "qcom,coresight-csr"},
+	{}
+};
+
+static struct platform_driver csr_driver = {
+	.probe          = csr_probe,
+	.remove         = __devexit_p(csr_remove),
+	.driver         = {
+		.name   = "coresight-csr",
+		.owner	= THIS_MODULE,
+		.of_match_table = csr_match,
+	},
+};
+
+static int __init csr_init(void)
+{
+	return platform_driver_register(&csr_driver);
+}
+module_init(csr_init);
+
+static void __exit csr_exit(void)
+{
+	platform_driver_unregister(&csr_driver);
+}
+module_exit(csr_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight CSR driver");
diff --git a/drivers/coresight/coresight-etb.c b/drivers/coresight/coresight-etb.c
index 56cee06..bd5bf8e 100644
--- a/drivers/coresight/coresight-etb.c
+++ b/drivers/coresight/coresight-etb.c
@@ -127,7 +127,9 @@
 	ETB_UNLOCK(drvdata);
 
 	ffcr = etb_readl(drvdata, ETB_FFCR);
-	ffcr |= (BIT(12) | BIT(6));
+	ffcr |= BIT(12);
+	etb_writel(drvdata, ffcr, ETB_FFCR);
+	ffcr |= BIT(6);
 	etb_writel(drvdata, ffcr, ETB_FFCR);
 	for (count = TIMEOUT_US; BVAL(etb_readl(drvdata, ETB_FFCR), 6) != 0
 				&& count > 0; count--)
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 46d3e5d..182e50c 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/smp.h>
 #include <linux/wakelock.h>
-#include <linux/pm_qos.h>
 #include <linux/sysfs.h>
 #include <linux/stat.h>
 #include <linux/mutex.h>
@@ -156,7 +155,6 @@
 	struct clk			*clk;
 	struct mutex			mutex;
 	struct wake_lock		wake_lock;
-	struct pm_qos_request		qos_req;
 	int				cpu;
 	uint8_t				arch;
 	uint8_t				nr_addr_cmp;
@@ -195,6 +193,8 @@
 	uint32_t			timestamp_event;
 };
 
+static struct etm_drvdata *etm0drvdata;
+
 /* ETM clock is derived from the processor clock and gets enabled on a
  * logical OR of below items on Krait (pass2 onwards):
  * 1.CPMR[ETMCLKEN] is 1
@@ -258,9 +258,10 @@
 	     etm_readl(drvdata, ETMSR));
 }
 
-static void __etm_enable(struct etm_drvdata *drvdata)
+static void __etm_enable(void *info)
 {
 	int i;
+	struct etm_drvdata *drvdata = info;
 
 	ETM_UNLOCK(drvdata);
 	/* Vote for ETM power/clock enable */
@@ -305,6 +306,8 @@
 
 	etm_clr_prog(drvdata);
 	ETM_LOCK(drvdata);
+
+	dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
 }
 
 static int etm_enable(struct coresight_device *csdev)
@@ -313,36 +316,31 @@
 	int ret;
 
 	wake_lock(&drvdata->wake_lock);
-	/* 1. causes all online cpus to come out of idle PC
-	 * 2. prevents idle PC until save restore flag is enabled atomically
-	 *
-	 * we rely on the user to prevent hotplug on/off racing with this
-	 * operation and to ensure cores where trace is expected to be turned
-	 * on are already hotplugged on
-	 */
-	pm_qos_update_request(&drvdata->qos_req, 0);
 
 	ret = clk_prepare_enable(drvdata->clk);
 	if (ret)
 		goto err_clk;
 
 	mutex_lock(&drvdata->mutex);
-	__etm_enable(drvdata);
+	/* executing __etm_enable on the cpu whose ETM is being enabled
+	 * ensures that register writes occur when cpu is powered.
+	 */
+	smp_call_function_single(drvdata->cpu, __etm_enable, drvdata, 1);
 	mutex_unlock(&drvdata->mutex);
 
-	pm_qos_update_request(&drvdata->qos_req, PM_QOS_DEFAULT_VALUE);
 	wake_unlock(&drvdata->wake_lock);
 
 	dev_info(drvdata->dev, "ETM tracing enabled\n");
 	return 0;
 err_clk:
-	pm_qos_update_request(&drvdata->qos_req, PM_QOS_DEFAULT_VALUE);
 	wake_unlock(&drvdata->wake_lock);
 	return ret;
 }
 
-static void __etm_disable(struct etm_drvdata *drvdata)
+static void __etm_disable(void *info)
 {
+	struct etm_drvdata *drvdata = info;
+
 	ETM_UNLOCK(drvdata);
 	etm_set_prog(drvdata);
 
@@ -352,6 +350,8 @@
 	/* Vote for ETM power/clock disable */
 	etm_set_pwrdwn(drvdata);
 	ETM_LOCK(drvdata);
+
+	dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
 }
 
 static void etm_disable(struct coresight_device *csdev)
@@ -359,22 +359,16 @@
 	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
 	wake_lock(&drvdata->wake_lock);
-	/* 1. causes all online cpus to come out of idle PC
-	 * 2. prevents idle PC until save restore flag is disabled atomically
-	 *
-	 * we rely on the user to prevent hotplug on/off racing with this
-	 * operation and to ensure cores where trace is expected to be turned
-	 * off are already hotplugged on
-	 */
-	pm_qos_update_request(&drvdata->qos_req, 0);
 
 	mutex_lock(&drvdata->mutex);
-	__etm_disable(drvdata);
+	/* executing __etm_disable on the cpu whose ETM is being disabled
+	 * ensures that register writes occur when cpu is powered.
+	 */
+	smp_call_function_single(drvdata->cpu, __etm_disable, drvdata, 1);
 	mutex_unlock(&drvdata->mutex);
 
 	clk_disable_unprepare(drvdata->clk);
 
-	pm_qos_update_request(&drvdata->qos_req, PM_QOS_DEFAULT_VALUE);
 	wake_unlock(&drvdata->wake_lock);
 
 	dev_info(drvdata->dev, "ETM tracing disabled\n");
@@ -1459,6 +1453,16 @@
 	return ret;
 }
 
+static void __devinit etm_copy_arch_data(struct etm_drvdata *drvdata)
+{
+	drvdata->arch = etm0drvdata->arch;
+	drvdata->nr_addr_cmp = etm0drvdata->nr_addr_cmp;
+	drvdata->nr_cntr = etm0drvdata->nr_cntr;
+	drvdata->nr_ext_inp = etm0drvdata->nr_ext_inp;
+	drvdata->nr_ext_out = etm0drvdata->nr_ext_out;
+	drvdata->nr_ctxid_cmp = etm0drvdata->nr_ctxid_cmp;
+}
+
 static void __devinit etm_init_default_data(struct etm_drvdata *drvdata)
 {
 	int i;
@@ -1545,8 +1549,6 @@
 
 	mutex_init(&drvdata->mutex);
 	wake_lock_init(&drvdata->wake_lock, WAKE_LOCK_SUSPEND, "coresight-etm");
-	pm_qos_add_request(&drvdata->qos_req, PM_QOS_CPU_DMA_LATENCY,
-			   PM_QOS_DEFAULT_VALUE);
 
 	drvdata->clk = devm_clk_get(dev, "core_clk");
 	if (IS_ERR(drvdata->clk)) {
@@ -1564,9 +1566,20 @@
 	if (ret)
 		goto err0;
 
-	ret = etm_init_arch_data(drvdata);
-	if (ret)
-		goto err1;
+	/* Use CPU0 to populate read-only configuration data for ETM0. For other
+	 * ETMs copy it over from ETM0.
+	 */
+	if (drvdata->cpu == 0) {
+		ret = etm_init_arch_data(drvdata);
+		if (ret)
+			goto err1;
+		etm0drvdata = drvdata;
+	} else {
+		if (etm0drvdata)
+			etm_copy_arch_data(drvdata);
+		else
+			goto err1;
+	}
 	etm_init_default_data(drvdata);
 
 	clk_disable_unprepare(drvdata->clk);
@@ -1598,7 +1611,6 @@
 err1:
 	clk_disable_unprepare(drvdata->clk);
 err0:
-	pm_qos_remove_request(&drvdata->qos_req);
 	wake_lock_destroy(&drvdata->wake_lock);
 	mutex_destroy(&drvdata->mutex);
 	return ret;
@@ -1609,7 +1621,6 @@
 	struct etm_drvdata *drvdata = platform_get_drvdata(pdev);
 
 	coresight_unregister(drvdata->csdev);
-	pm_qos_remove_request(&drvdata->qos_req);
 	wake_lock_destroy(&drvdata->wake_lock);
 	mutex_destroy(&drvdata->mutex);
 	return 0;
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index a28a3a5..2b00242 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -36,4 +36,12 @@
 #define BMVAL(val, lsb, msb)	((val & BM(lsb, msb)) >> lsb)
 #define BVAL(val, n)		((val & BIT(n)) >> n)
 
+#ifdef CONFIG_MSM_QDSS
+extern void msm_qdss_csr_enable_bam_to_usb(void);
+extern void msm_qdss_csr_disable_bam_to_usb(void);
+#else
+static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
+static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
+#endif
+
 #endif
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
index e366918..70b2c43 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -150,7 +150,10 @@
 {
 	STM_UNLOCK(drvdata);
 
-	stm_writel(drvdata, 0x0, STMHETER);
+	/* Program STMHETER to ensure TRIGOUTHETE (fed to CTI) is asserted
+	   for HW events.
+	*/
+	stm_writel(drvdata, 0xFFFFFFFF, STMHETER);
 	stm_writel(drvdata, 0xFFFFFFFF, STMHEER);
 	stm_writel(drvdata, 0x5, STMHEMCR);
 
@@ -187,7 +190,7 @@
 {
 	STM_UNLOCK(drvdata);
 
-	stm_writel(drvdata, 0xFFFFFFFF, STMSPTER);
+	stm_writel(drvdata, 0x10, STMSPTRIGCSR);
 	stm_writel(drvdata, 0xFFFFFFFF, STMSPER);
 
 	STM_LOCK(drvdata);
@@ -214,9 +217,9 @@
 
 	STM_UNLOCK(drvdata);
 
-	stm_writel(drvdata, 0x80, STMSYNCR);
+	stm_writel(drvdata, 0xFFF, STMSYNCR);
 	/* SYNCEN is read-only and HWTEN is not implemented */
-	stm_writel(drvdata, 0x30003, STMTCSR);
+	stm_writel(drvdata, 0x100003, STMTCSR);
 
 	STM_LOCK(drvdata);
 }
@@ -243,9 +246,9 @@
 {
 	STM_UNLOCK(drvdata);
 
-	stm_writel(drvdata, 0x0, STMHETER);
-	stm_writel(drvdata, 0x0, STMHEER);
 	stm_writel(drvdata, 0x0, STMHEMCR);
+	stm_writel(drvdata, 0x0, STMHEER);
+	stm_writel(drvdata, 0x0, STMHETER);
 
 	STM_LOCK(drvdata);
 }
@@ -263,7 +266,7 @@
 	STM_UNLOCK(drvdata);
 
 	stm_writel(drvdata, 0x0, STMSPER);
-	stm_writel(drvdata, 0x0, STMSPTER);
+	stm_writel(drvdata, 0x0, STMSPTRIGCSR);
 
 	STM_LOCK(drvdata);
 }
@@ -280,7 +283,7 @@
 {
 	STM_UNLOCK(drvdata);
 
-	stm_writel(drvdata, 0x30000, STMTCSR);
+	stm_writel(drvdata, 0x100000, STMTCSR);
 
 	STM_LOCK(drvdata);
 
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 1c85aff..995ad86 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -28,7 +28,10 @@
 #include <linux/clk.h>
 #include <linux/of_coresight.h>
 #include <linux/coresight.h>
+#include <linux/usb/usb_qdss.h>
 #include <mach/memory.h>
+#include <mach/sps.h>
+#include <mach/usb_bam.h>
 
 #include "coresight-priv.h"
 
@@ -74,6 +77,8 @@
 #define TMC_ITATBCTR0		(0xEF8)
 
 #define BYTES_PER_WORD		4
+#define TMC_ETR_BAM_PIPE_INDEX	0
+#define TMC_ETR_BAM_NR_PIPES	2
 
 enum tmc_config_type {
 	TMC_CONFIG_TYPE_ETB,
@@ -87,6 +92,12 @@
 	TMC_MODE_HARDWARE_FIFO,
 };
 
+enum tmc_etr_out_mode {
+	TMC_ETR_OUT_MODE_NONE,
+	TMC_ETR_OUT_MODE_MEM,
+	TMC_ETR_OUT_MODE_USB,
+};
+
 enum tmc_mem_intf_width {
 	TMC_MEM_INTF_WIDTH_32BITS	= 0x2,
 	TMC_MEM_INTF_WIDTH_64BITS	= 0x3,
@@ -94,6 +105,19 @@
 	TMC_MEM_INTF_WIDTH_256BITS	= 0x5,
 };
 
+struct tmc_etr_bam_data {
+	struct sps_bam_props	props;
+	uint32_t		handle;
+	struct sps_pipe		*pipe;
+	struct sps_connect	connect;
+	uint32_t		src_pipe_idx;
+	uint32_t		dest;
+	uint32_t		dest_pipe_idx;
+	struct sps_mem_buffer	desc_fifo;
+	struct sps_mem_buffer	data_fifo;
+	bool			enable;
+};
+
 struct tmc_drvdata {
 	void __iomem		*base;
 	struct device		*dev;
@@ -101,12 +125,18 @@
 	struct miscdevice	miscdev;
 	struct clk		*clk;
 	spinlock_t		spinlock;
+	struct mutex		read_lock;
 	int			read_count;
 	bool			reading;
 	char			*buf;
 	unsigned long		paddr;
 	void __iomem		*vaddr;
 	uint32_t		size;
+	struct mutex		usb_lock;
+	struct usb_qdss_ch	*usbch;
+	struct tmc_etr_bam_data	*bamdata;
+	enum tmc_etr_out_mode	out_mode;
+	bool			enable_to_bam;
 	bool			enable;
 	enum tmc_config_type	config_type;
 	uint32_t		trigger_cntr;
@@ -154,6 +184,151 @@
 	tmc_writel(drvdata, 0x0, TMC_CTL);
 }
 
+static void tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata)
+{
+	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
+
+	get_bam2bam_connection_info(0, PEER_PERIPHERAL_TO_USB,
+				    &bamdata->dest,
+				    &bamdata->dest_pipe_idx,
+				    &bamdata->src_pipe_idx,
+				    &bamdata->desc_fifo,
+				    &bamdata->data_fifo);
+}
+
+static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata)
+{
+	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
+	uint32_t axictl;
+
+	if (drvdata->enable_to_bam)
+		return;
+
+	/* Configure and enable required CSR registers */
+	msm_qdss_csr_enable_bam_to_usb();
+
+	/* Configure and enable ETR for usb bam output */
+
+	TMC_UNLOCK(drvdata);
+
+	tmc_writel(drvdata, bamdata->data_fifo.size / BYTES_PER_WORD,
+		   TMC_RSZ);
+	tmc_writel(drvdata, TMC_MODE_CIRCULAR_BUFFER, TMC_MODE);
+
+	axictl = tmc_readl(drvdata, TMC_AXICTL);
+	axictl |= (0xF << 8);
+	tmc_writel(drvdata, axictl, TMC_AXICTL);
+	axictl &= ~(0x1 << 7);
+	tmc_writel(drvdata, axictl, TMC_AXICTL);
+	axictl = (axictl & ~0x3) | 0x2;
+	tmc_writel(drvdata, axictl, TMC_AXICTL);
+
+	tmc_writel(drvdata, bamdata->data_fifo.phys_base, TMC_DBALO);
+	tmc_writel(drvdata, 0x0, TMC_DBAHI);
+	tmc_writel(drvdata, 0x133, TMC_FFCR);
+	tmc_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
+	__tmc_enable(drvdata);
+
+	TMC_LOCK(drvdata);
+
+	drvdata->enable_to_bam = true;
+}
+
+static int tmc_etr_bam_enable(struct tmc_drvdata *drvdata)
+{
+	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
+	int ret;
+
+	if (bamdata->enable)
+		return 0;
+
+	/* Configure and enable ndp bam */
+
+	bamdata->pipe = sps_alloc_endpoint();
+	if (!bamdata->pipe)
+		return -ENOMEM;
+
+	ret = sps_get_config(bamdata->pipe, &bamdata->connect);
+	if (ret)
+		goto err;
+
+	bamdata->connect.mode = SPS_MODE_SRC;
+	bamdata->connect.source = bamdata->handle;
+	bamdata->connect.event_thresh = 0x4;
+	bamdata->connect.src_pipe_index = TMC_ETR_BAM_PIPE_INDEX;
+	bamdata->connect.options = SPS_O_AUTO_ENABLE;
+
+	bamdata->connect.destination = bamdata->dest;
+	bamdata->connect.dest_pipe_index = bamdata->dest_pipe_idx;
+	bamdata->connect.desc = bamdata->desc_fifo;
+	bamdata->connect.data = bamdata->data_fifo;
+
+	ret = sps_connect(bamdata->pipe, &bamdata->connect);
+	if (ret)
+		goto err;
+
+	bamdata->enable = true;
+	return 0;
+err:
+	sps_free_endpoint(bamdata->pipe);
+	return ret;
+}
+
+static void __tmc_etr_disable_to_bam(struct tmc_drvdata *drvdata)
+{
+	if (!drvdata->enable_to_bam)
+		return;
+
+	TMC_UNLOCK(drvdata);
+
+	tmc_flush_and_stop(drvdata);
+	__tmc_disable(drvdata);
+
+	TMC_LOCK(drvdata);
+
+	/* Disable CSR registers */
+	msm_qdss_csr_disable_bam_to_usb();
+	drvdata->enable_to_bam = false;
+}
+
+static void tmc_etr_bam_disable(struct tmc_drvdata *drvdata)
+{
+	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
+
+	if (!bamdata->enable)
+		return;
+
+	sps_disconnect(bamdata->pipe);
+	sps_free_endpoint(bamdata->pipe);
+	bamdata->enable = false;
+}
+
+static void usb_notifier(void *priv, unsigned int event,
+			struct qdss_request *d_req, struct usb_qdss_ch *ch)
+{
+	struct tmc_drvdata *drvdata = priv;
+	unsigned long flags;
+	int ret = 0;
+
+	mutex_lock(&drvdata->usb_lock);
+	if (event == USB_QDSS_CONNECT) {
+		tmc_etr_fill_usb_bam_data(drvdata);
+		ret = tmc_etr_bam_enable(drvdata);
+		if (ret)
+			dev_err(drvdata->dev, "ETR BAM enable failed\n");
+
+		spin_lock_irqsave(&drvdata->spinlock, flags);
+		__tmc_etr_enable_to_bam(drvdata);
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	} else if (event == USB_QDSS_DISCONNECT) {
+		spin_lock_irqsave(&drvdata->spinlock, flags);
+		__tmc_etr_disable_to_bam(drvdata);
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		tmc_etr_bam_disable(drvdata);
+	}
+	mutex_unlock(&drvdata->usb_lock);
+}
+
 static void __tmc_etb_enable(struct tmc_drvdata *drvdata)
 {
 	/* Zero out the memory to help with debug */
@@ -169,7 +344,7 @@
 	TMC_LOCK(drvdata);
 }
 
-static void __tmc_etr_enable(struct tmc_drvdata *drvdata)
+static void __tmc_etr_enable_to_mem(struct tmc_drvdata *drvdata)
 {
 	uint32_t axictl;
 
@@ -192,6 +367,7 @@
 	tmc_writel(drvdata, drvdata->paddr, TMC_DBALO);
 	tmc_writel(drvdata, 0x0, TMC_DBAHI);
 	tmc_writel(drvdata, 0x133, TMC_FFCR);
+	tmc_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
 	__tmc_enable(drvdata);
 
 	TMC_LOCK(drvdata);
@@ -218,17 +394,30 @@
 	if (ret)
 		return ret;
 
+	mutex_lock(&drvdata->usb_lock);
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
+			drvdata->usbch = usb_qdss_open("qdss", drvdata,
+						       usb_notifier);
+			if (IS_ERR(drvdata->usbch)) {
+				dev_err(drvdata->dev, "usb_qdss_open failed\n");
+				ret = PTR_ERR(drvdata->usbch);
+				goto err0;
+			}
+		}
+	}
+
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 	if (drvdata->reading) {
-		spin_unlock_irqrestore(&drvdata->spinlock, flags);
-		clk_disable_unprepare(drvdata->clk);
-		return -EBUSY;
+		ret = -EBUSY;
+		goto err1;
 	}
 
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
 		__tmc_etb_enable(drvdata);
 	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		__tmc_etr_enable(drvdata);
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+			__tmc_etr_enable_to_mem(drvdata);
 	} else {
 		if (mode == TMC_MODE_CIRCULAR_BUFFER)
 			__tmc_etb_enable(drvdata);
@@ -237,9 +426,19 @@
 	}
 	drvdata->enable = true;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	mutex_unlock(&drvdata->usb_lock);
 
 	dev_info(drvdata->dev, "TMC enabled\n");
 	return 0;
+err1:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
+			usb_qdss_close(drvdata->usbch);
+err0:
+	mutex_unlock(&drvdata->usb_lock);
+	clk_disable_unprepare(drvdata->clk);
+	return ret;
 }
 
 static int tmc_enable_sink(struct coresight_device *csdev)
@@ -306,12 +505,12 @@
 	rwphi = tmc_readl(drvdata, TMC_RWPHI);
 
 	if (BVAL(tmc_readl(drvdata, TMC_STS), 0))
-		drvdata->buf = drvdata->vaddr + rwp;
+		drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
 	else
 		drvdata->buf = drvdata->vaddr;
 }
 
-static void __tmc_etr_disable(struct tmc_drvdata *drvdata)
+static void __tmc_etr_disable_to_mem(struct tmc_drvdata *drvdata)
 {
 	TMC_UNLOCK(drvdata);
 
@@ -335,7 +534,9 @@
 static void tmc_disable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
 {
 	unsigned long flags;
+	bool etr_bam_disable = false;
 
+	mutex_lock(&drvdata->usb_lock);
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 	if (drvdata->reading)
 		goto out;
@@ -343,7 +544,10 @@
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
 		__tmc_etb_disable(drvdata);
 	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		__tmc_etr_disable(drvdata);
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+			__tmc_etr_disable_to_mem(drvdata);
+		else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
+			etr_bam_disable = true;
 	} else {
 		if (mode == TMC_MODE_CIRCULAR_BUFFER)
 			__tmc_etb_disable(drvdata);
@@ -354,6 +558,20 @@
 	drvdata->enable = false;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	if (etr_bam_disable) {
+		if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+			if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
+				spin_lock_irqsave(&drvdata->spinlock, flags);
+				__tmc_etr_disable_to_bam(drvdata);
+				spin_unlock_irqrestore(&drvdata->spinlock,
+						       flags);
+				tmc_etr_bam_disable(drvdata);
+				usb_qdss_close(drvdata->usbch);
+			}
+		}
+	}
+	mutex_unlock(&drvdata->usb_lock);
+
 	clk_disable_unprepare(drvdata->clk);
 
 	dev_info(drvdata->dev, "TMC disabled\n");
@@ -387,7 +605,8 @@
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
 		__tmc_etb_disable(drvdata);
 	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		__tmc_etr_disable(drvdata);
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+			__tmc_etr_disable_to_mem(drvdata);
 	} else {
 		mode = tmc_readl(drvdata, TMC_MODE);
 		if (mode == TMC_MODE_CIRCULAR_BUFFER)
@@ -442,7 +661,12 @@
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
 		__tmc_etb_disable(drvdata);
 	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		__tmc_etr_disable(drvdata);
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
+			__tmc_etr_disable_to_mem(drvdata);
+		} else {
+			ret = -ENODEV;
+			goto err;
+		}
 	} else {
 		mode = tmc_readl(drvdata, TMC_MODE);
 		if (mode == TMC_MODE_CIRCULAR_BUFFER) {
@@ -475,7 +699,8 @@
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
 		__tmc_etb_enable(drvdata);
 	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		__tmc_etr_enable(drvdata);
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+			__tmc_etr_enable_to_mem(drvdata);
 	} else {
 		mode = tmc_readl(drvdata, TMC_MODE);
 		if (mode == TMC_MODE_CIRCULAR_BUFFER)
@@ -494,17 +719,23 @@
 						   struct tmc_drvdata, miscdev);
 	int ret = 0;
 
+	mutex_lock(&drvdata->read_lock);
 	if (drvdata->read_count++)
 		goto out;
 
 	ret = tmc_read_prepare(drvdata);
 	if (ret)
-		return ret;
+		goto err;
 out:
+	mutex_unlock(&drvdata->read_lock);
 	nonseekable_open(inode, file);
 
 	dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
 	return 0;
+err:
+	drvdata->read_count--;
+	mutex_unlock(&drvdata->read_lock);
+	return ret;
 }
 
 static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
@@ -520,6 +751,8 @@
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
 		if (bufp == (char *)(drvdata->vaddr + drvdata->size))
 			bufp = drvdata->vaddr;
+		else if (bufp > (char *)(drvdata->vaddr + drvdata->size))
+			bufp -= drvdata->size;
 		if ((bufp + len) > (char *)(drvdata->vaddr + drvdata->size))
 			len = (char *)(drvdata->vaddr + drvdata->size) - bufp;
 	}
@@ -541,6 +774,7 @@
 	struct tmc_drvdata *drvdata = container_of(file->private_data,
 						   struct tmc_drvdata, miscdev);
 
+	mutex_lock(&drvdata->read_lock);
 	if (--drvdata->read_count) {
 		if (drvdata->read_count < 0) {
 			WARN_ONCE(1, "mismatched close\n");
@@ -551,6 +785,7 @@
 
 	tmc_read_unprepare(drvdata);
 out:
+	mutex_unlock(&drvdata->read_lock);
 	dev_dbg(drvdata->dev, "%s: released\n", __func__);
 	return 0;
 }
@@ -588,6 +823,87 @@
 static DEVICE_ATTR(trigger_cntr, S_IRUGO | S_IWUSR, tmc_show_trigger_cntr,
 		   tmc_store_trigger_cntr);
 
+static ssize_t tmc_etr_show_out_mode(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n",
+			 drvdata->out_mode == TMC_ETR_OUT_MODE_MEM ?
+			 "mem" : "usb");
+}
+
+static ssize_t tmc_etr_store_out_mode(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t size)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	char str[10] = "";
+	unsigned long flags;
+	bool etr_bam_flag = false;
+	int ret;
+
+	if (strlen(buf) >= 10)
+		return -EINVAL;
+	if (sscanf(buf, "%s", str) != 1)
+		return -EINVAL;
+
+	mutex_lock(&drvdata->usb_lock);
+	if (!strcmp(str, "mem")) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+			goto out;
+
+		spin_lock_irqsave(&drvdata->spinlock, flags);
+		if (drvdata->enable) {
+			__tmc_etr_disable_to_bam(drvdata);
+			__tmc_etr_enable_to_mem(drvdata);
+			etr_bam_flag = true;
+		}
+		drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+		if (etr_bam_flag) {
+			tmc_etr_bam_disable(drvdata);
+			usb_qdss_close(drvdata->usbch);
+		}
+	} else if (!strcmp(str, "usb")) {
+		if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
+			goto out;
+
+		spin_lock_irqsave(&drvdata->spinlock, flags);
+		if (drvdata->enable) {
+			if (drvdata->reading) {
+				ret = -EBUSY;
+				goto err1;
+			}
+			__tmc_etr_disable_to_mem(drvdata);
+			etr_bam_flag = true;
+		}
+		drvdata->out_mode = TMC_ETR_OUT_MODE_USB;
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+		if (etr_bam_flag) {
+			drvdata->usbch = usb_qdss_open("qdss", drvdata,
+						       usb_notifier);
+			if (IS_ERR(drvdata->usbch)) {
+				dev_err(drvdata->dev, "usb_qdss_open failed\n");
+				ret = PTR_ERR(drvdata->usbch);
+				goto err0;
+			}
+		}
+	}
+out:
+	mutex_unlock(&drvdata->usb_lock);
+	return size;
+err1:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+err0:
+	mutex_unlock(&drvdata->usb_lock);
+	return ret;
+}
+static DEVICE_ATTR(out_mode, S_IRUGO | S_IWUSR, tmc_etr_show_out_mode,
+		   tmc_etr_store_out_mode);
+
 static struct attribute *tmc_attrs[] = {
 	&dev_attr_trigger_cntr.attr,
 	NULL,
@@ -597,6 +913,15 @@
 	.attrs = tmc_attrs,
 };
 
+static struct attribute *tmc_etr_attrs[] = {
+	&dev_attr_out_mode.attr,
+	NULL,
+};
+
+static struct attribute_group tmc_etr_attr_grp = {
+	.attrs = tmc_etr_attrs,
+};
+
 static const struct attribute_group *tmc_etb_attr_grps[] = {
 	&tmc_attr_grp,
 	NULL,
@@ -604,6 +929,7 @@
 
 static const struct attribute_group *tmc_etr_attr_grps[] = {
 	&tmc_attr_grp,
+	&tmc_etr_attr_grp,
 	NULL,
 };
 
@@ -612,6 +938,46 @@
 	NULL,
 };
 
+static int __devinit tmc_etr_bam_init(struct platform_device *pdev,
+				      struct tmc_drvdata *drvdata)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct tmc_etr_bam_data *bamdata;
+
+	bamdata = devm_kzalloc(dev, sizeof(*bamdata), GFP_KERNEL);
+	if (!bamdata)
+		return -ENOMEM;
+	drvdata->bamdata = bamdata;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -ENODEV;
+
+	bamdata->props.phys_addr = res->start;
+	bamdata->props.virt_addr = devm_ioremap(dev, res->start,
+						resource_size(res));
+	if (!bamdata->props.virt_addr)
+		return -ENOMEM;
+	bamdata->props.virt_size = resource_size(res);
+
+	bamdata->props.event_threshold = 0x4; /* Pipe event threshold */
+	bamdata->props.summing_threshold = 0x10; /* BAM event threshold */
+	bamdata->props.irq = 0;
+	bamdata->props.num_pipes = TMC_ETR_BAM_NR_PIPES;
+
+	return sps_register_bam_device(&bamdata->props, &bamdata->handle);
+}
+
+static void tmc_etr_bam_exit(struct tmc_drvdata *drvdata)
+{
+	struct tmc_etr_bam_data *bamdata = drvdata->bamdata;
+
+	if (!bamdata->handle)
+		return;
+	sps_deregister_bam_device(bamdata->handle);
+}
+
 static int __devinit tmc_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -644,6 +1010,8 @@
 		return -ENOMEM;
 
 	spin_lock_init(&drvdata->spinlock);
+	mutex_init(&drvdata->read_lock);
+	mutex_init(&drvdata->usb_lock);
 
 	drvdata->clk = devm_clk_get(dev, "core_clk");
 	if (IS_ERR(drvdata->clk))
@@ -679,6 +1047,11 @@
 			goto err0;
 		}
 		memset(drvdata->vaddr, 0, drvdata->size);
+		drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
+
+		ret = tmc_etr_bam_init(pdev, drvdata);
+		if (ret)
+			goto err0;
 	} else {
 		drvdata->buf = devm_kzalloc(dev, drvdata->size, GFP_KERNEL);
 		if (!drvdata->buf)
@@ -688,7 +1061,7 @@
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc) {
 		ret = -ENOMEM;
-		goto err0;
+		goto err1;
 	}
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
 		desc->type = CORESIGHT_DEV_TYPE_SINK;
@@ -701,7 +1074,7 @@
 		drvdata->csdev = coresight_register(desc);
 		if (IS_ERR(drvdata->csdev)) {
 			ret = PTR_ERR(drvdata->csdev);
-			goto err0;
+			goto err1;
 		}
 	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
 		desc->type = CORESIGHT_DEV_TYPE_SINK;
@@ -714,7 +1087,7 @@
 		drvdata->csdev = coresight_register(desc);
 		if (IS_ERR(drvdata->csdev)) {
 			ret = PTR_ERR(drvdata->csdev);
-			goto err0;
+			goto err1;
 		}
 	} else {
 		desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
@@ -728,7 +1101,7 @@
 		drvdata->csdev = coresight_register(desc);
 		if (IS_ERR(drvdata->csdev)) {
 			ret = PTR_ERR(drvdata->csdev);
-			goto err0;
+			goto err1;
 		}
 	}
 
@@ -738,12 +1111,14 @@
 	drvdata->miscdev.fops = &tmc_fops;
 	ret = misc_register(&drvdata->miscdev);
 	if (ret)
-		goto err1;
+		goto err2;
 
 	dev_info(dev, "TMC initialized\n");
 	return 0;
-err1:
+err2:
 	coresight_unregister(drvdata->csdev);
+err1:
+	tmc_etr_bam_exit(drvdata);
 err0:
 	free_contiguous_memory_by_paddr(drvdata->paddr);
 	return ret;
@@ -755,6 +1130,7 @@
 
 	misc_deregister(&drvdata->miscdev);
 	coresight_unregister(drvdata->csdev);
+	tmc_etr_bam_exit(drvdata);
 	free_contiguous_memory_by_paddr(drvdata->paddr);
 	return 0;
 }
@@ -763,6 +1139,7 @@
 	{.compatible = "arm,coresight-tmc"},
 	{}
 };
+EXPORT_COMPAT("arm,coresight-tmc");
 
 static struct platform_driver tmc_driver = {
 	.probe          = tmc_probe,
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
index f76d303..cccb5a7 100644
--- a/drivers/coresight/coresight.c
+++ b/drivers/coresight/coresight.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -496,6 +496,9 @@
 
 static struct device_type coresight_dev_type[] = {
 	{
+		.name = "none",
+	},
+	{
 		.name = "sink",
 		.groups = coresight_attr_grps_sink,
 	},
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 497ec49..f022a2c 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1097,6 +1097,7 @@
 	/* SPS driver wll handle the crypto BAM IRQ */
 	bam.irq = (u32)pce_dev->ce_sps.bam_irq;
 	bam.manage = SPS_BAM_MGR_LOCAL;
+	bam.ee = 1;
 
 	pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
 	pr_debug("bam virtual base=0x%x\n", (u32)bam.virt_addr);
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index ab15945..3969319 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -67,6 +67,40 @@
 #define GPIO_EPM_GLOBAL_ENABLE		86
 #define EPM_ADC_CONVERSION_TIME_MIN	50000
 #define EPM_ADC_CONVERSION_TIME_MAX	51000
+/* PSoc Commands */
+#define EPM_PSOC_INIT_CMD				0x1
+#define EPM_PSOC_INIT_RESPONSE_CMD			0x2
+#define EPM_PSOC_CHANNEL_ENABLE_DISABLE_CMD		0x5
+#define EPM_PSOC_CHANNEL_ENABLE_DISABLE_RESPONSE_CMD	0x6
+#define EPM_PSOC_SET_AVERAGING_CMD			0x7
+#define EPM_PSOC_SET_AVERAGING_RESPONSE_CMD		0x8
+#define EPM_PSOC_GET_LAST_MEASUREMENT_CMD		0x9
+#define EPM_PSOC_GET_LAST_MEASUREMENT_RESPONSE_CMD	0xa
+#define EPM_PSOC_GET_BUFFERED_DATA_CMD			0xb
+#define EPM_PSOC_GET_BUFFERED_RESPONSE_CMD		0xc
+#define EPM_PSOC_GET_SYSTEM_TIMESTAMP_CMD		0x11
+#define EPM_PSOC_GET_SYSTEM_TIMESTAMP_RESPONSE_CMD	0x12
+#define EPM_PSOC_SET_SYSTEM_TIMESTAMP_CMD		0x13
+#define EPM_PSOC_SET_SYSTEM_TIMESTAMP_RESPONSE_CMD	0x14
+#define EPM_PSOC_SET_CHANNEL_TYPE_CMD			0x15
+#define EPM_PSOC_SET_CHANNEL_TYPE_RESPONSE_CMD		0x16
+#define EPM_PSOC_GET_AVERAGED_DATA_CMD			0x19
+#define EPM_PSOC_GET_AVERAGED_DATA_RESPONSE_CMD		0x1a
+#define EPM_PSOC_SET_CHANNEL_SWITCH_DELAY_CMD		0x1b
+#define EPM_PSOC_SET_CHANNEL_SWITCH_DELAY_RESPONSE_CMD	0x1c
+#define EPM_PSOC_CLEAR_BUFFER_CMD			0x1d
+#define EPM_PSOC_CLEAR_BUFFER_RESPONSE_CMD		0x1e
+#define EPM_PSOC_SET_VADC_REFERENCE_CMD			0x1f
+#define EPM_PSOC_SET_VADC_REFERENCE_RESPONSE_CMD	0x20
+
+#define EPM_PSOC_GLOBAL_ENABLE				81
+#define EPM_PSOC_VREF_VOLTAGE				2048
+#define EPM_PSOC_MAX_ADC_CODE_16_BIT			32767
+#define EPM_GLOBAL_ENABLE_MIN_DELAY			5000
+#define EPM_GLOBAL_ENABLE_MAX_DELAY			5100
+
+#define EPM_PSOC_BUFFERED_DATA_LENGTH			48
+#define EPM_PSOC_BUFFERED_DATA_LENGTH2			54
 
 #define EPM_SPI_NOR_CS_N_GPIO		53
 
@@ -77,6 +111,7 @@
 	struct mutex			conv_lock;
 	uint32_t			bus_id;
 	struct miscdevice		misc;
+	struct epm_chan_properties	epm_psoc_ch_prop[0];
 };
 
 static struct epm_adc_drv *epm_adc_drv;
@@ -220,13 +255,11 @@
 	if (!rc) {
 		rc = gpio_direction_output(GPIO_EPM_SPI_ADC2_CS_N, 1);
 		if (rc) {
-			pr_err("%s: Set GPIO_EPM_SPI_ADC2_CS_N "
-					"failed\n", __func__);
+			pr_err("Set GPIO_EPM_SPI_ADC2_CS_N failed\n");
 			return rc;
 		}
 	} else {
-		pr_err("%s: gpio_request GPIO_EPM_SPI_ADC2_CS_N "
-				"failed\n", __func__);
+		pr_err("gpio_request GPIO_EPM_SPI_ADC2_CS_N failed\n");
 		return rc;
 	}
 
@@ -471,8 +504,7 @@
 	mutex_lock(&epm_adc->conv_lock);
 	rc = epm_adc_gpio_configure_expander_disable();
 	if (rc != 0) {
-		pr_err("epm gpio configure expander disable failed,"
-			" rc = %d\n", rc);
+		pr_err("gpio expander disable failed with %d\n", rc);
 		goto epm_adc_hw_deinit_err;
 	}
 
@@ -518,7 +550,7 @@
 		channel_num -= EPM_ADC_CHANNEL_AIN_OFFSET;
 		/*
 		 * Conversion for the adc channels.
-		 * mvVRef is in milli-volts and resistorValue is in micro-ohms.
+		 * mvVRef is in milli-volts and resistorvalue is in micro-ohms.
 		 * Hence, I = V/R gives us current in kilo-amps.
 		 */
 		if (*adc_scaled_data & EPM_ADC_MAX_NEGATIVE_SCALE_CODE) {
@@ -540,7 +572,7 @@
 			*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
 			 /* Data is now in micro-amps.*/
 			do_div(*adc_scaled_data,
-				pdata->channel[chan_idx].resistorValue);
+				pdata->channel[chan_idx].resistorvalue);
 			 /* Set the sign bit for lekage current. */
 			*adc_scaled_data *= sign_bit;
 		}
@@ -550,6 +582,18 @@
 	return 0;
 }
 
+static int epm_psoc_scale_result(uint16_t *adc_raw_data, uint32_t index)
+{
+	struct epm_adc_drv *epm_adc = epm_adc_drv;
+	/* result = 2.048V/(32767 * gain * rsense) */
+	*adc_raw_data = (EPM_PSOC_VREF_VOLTAGE/EPM_PSOC_MAX_ADC_CODE_16_BIT)
+				* (*adc_raw_data);
+	*adc_raw_data = *adc_raw_data/
+		(epm_adc->epm_psoc_ch_prop[index].gain *
+			epm_adc->epm_psoc_ch_prop[index].resistorvalue);
+	return 0;
+}
+
 static int epm_adc_blocking_conversion(struct epm_adc_drv *epm_adc,
 					struct epm_chan_request *conv)
 {
@@ -620,6 +664,465 @@
 	return rc;
 }
 
+static int epm_adc_psoc_gpio_init(bool enable)
+{
+	int rc = 0;
+
+	if (enable) {
+		rc = gpio_request(EPM_PSOC_GLOBAL_ENABLE, "EPM_PSOC_GLOBAL_EN");
+		if (!rc) {
+			gpio_direction_output(EPM_PSOC_GLOBAL_ENABLE, 1);
+		} else {
+			pr_err("%s: Configure EPM_GLOBAL_EN Failed\n",
+								__func__);
+			return rc;
+		}
+	} else {
+		gpio_direction_output(EPM_PSOC_GLOBAL_ENABLE, 0);
+		gpio_free(EPM_PSOC_GLOBAL_ENABLE);
+	}
+
+	return 0;
+}
+
+static int epm_psoc_init(struct epm_adc_drv *epm_adc,
+					struct epm_psoc_init_resp *init_resp)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[17], rx_buf[17];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = init_resp->cmd;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	init_resp->cmd			= rx_buf[0];
+	init_resp->version		= rx_buf[1];
+	init_resp->compatible_ver	= rx_buf[2];
+	init_resp->firm_ver[0]		= rx_buf[3];
+	init_resp->firm_ver[1]		= rx_buf[4];
+	init_resp->firm_ver[2]		= rx_buf[5];
+	init_resp->num_dev		= rx_buf[6];
+	init_resp->num_channel		= rx_buf[7];
+
+	return rc;
+}
+
+static int epm_psoc_channel_configure(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_channel_configure *psoc_chan_configure)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[9], rx_buf[9];
+	int32_t rc = 0, chan_num;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	chan_num = psoc_chan_configure->channel_num;
+
+	tx_buf[0] = psoc_chan_configure->cmd;
+	tx_buf[1] = 0;
+	tx_buf[2] = (chan_num & 0xff000000) >> 24;
+	tx_buf[3] = (chan_num & 0xff0000) >> 16;
+	tx_buf[4] = (chan_num & 0xff00) >> 8;
+	tx_buf[5] = (chan_num & 0xff);
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_chan_configure->cmd		= rx_buf[0];
+	psoc_chan_configure->device_num		= rx_buf[1];
+	chan_num = rx_buf[2] << 24 | (rx_buf[3] << 16) | (rx_buf[4] << 8) |
+						rx_buf[5];
+	psoc_chan_configure->channel_num	= chan_num;
+	pr_debug("dev_num:%d, chan_num:%d\n", rx_buf[1], chan_num);
+
+	return rc;
+}
+
+static int epm_psoc_set_averaging(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_set_avg *psoc_set_avg)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[4], rx_buf[4];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_set_avg->cmd;
+	tx_buf[1] = psoc_set_avg->avg_period;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_set_avg->cmd		= rx_buf[0];
+	psoc_set_avg->return_code	= rx_buf[1];
+
+	return rc;
+}
+
+static int epm_psoc_get_data(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_get_data *psoc_get_meas)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[10], rx_buf[10];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_get_meas->cmd;
+	tx_buf[1] = psoc_get_meas->dev_num;
+	tx_buf[2] = psoc_get_meas->chan_num;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_get_meas->cmd		= rx_buf[0];
+	psoc_get_meas->dev_num		= rx_buf[1];
+	psoc_get_meas->chan_num		= rx_buf[2];
+	psoc_get_meas->timestamp_resp_value = (rx_buf[3] << 24) |
+			(rx_buf[4] << 16) | (rx_buf[5] << 8) |
+			rx_buf[6];
+	psoc_get_meas->reading_value = (rx_buf[7] << 8) | rx_buf[8];
+
+	pr_debug("dev_num:%d, chan_num:%d\n", rx_buf[1], rx_buf[2]);
+	pr_debug("data %d\n", psoc_get_meas->reading_value);
+	return rc;
+}
+
+static int epm_psoc_get_buffered_data(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_get_buffered_data *psoc_get_meas)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[64], rx_buf[64];
+	int rc = 0, i;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_get_meas->cmd;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_get_meas->cmd		= rx_buf[0];
+	psoc_get_meas->dev_num		= rx_buf[1];
+	psoc_get_meas->status_mask	= rx_buf[2];
+	psoc_get_meas->chan_idx		= rx_buf[3];
+	psoc_get_meas->chan_mask	= (rx_buf[4] << 24 |
+		rx_buf[5] << 16 | rx_buf[6] << 8
+			| rx_buf[7]);
+	psoc_get_meas->timestamp_start	= (rx_buf[8] << 24 |
+			rx_buf[9] << 16 | rx_buf[10] << 8
+			| rx_buf[11]);
+	psoc_get_meas->timestamp_end	= (rx_buf[12] << 24 |
+			rx_buf[13] << 16 | rx_buf[14] << 8
+			| rx_buf[15]);
+
+	for (i = 0; i < EPM_PSOC_BUFFERED_DATA_LENGTH; i++)
+		psoc_get_meas->buff_data[i] = rx_buf[16 + i];
+
+	return rc;
+}
+
+static int epm_psoc_timestamp(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_system_time_stamp *psoc_timestamp)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[10], rx_buf[10];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	if (psoc_timestamp->cmd == EPM_PSOC_SET_SYSTEM_TIMESTAMP_CMD) {
+		tx_buf[0] = psoc_timestamp->cmd;
+		tx_buf[1] = (psoc_timestamp->timestamp & 0xff000000) >> 24;
+		tx_buf[2] = (psoc_timestamp->timestamp & 0xff0000) >> 16;
+		tx_buf[3] = (psoc_timestamp->timestamp & 0xff00) >> 8;
+		tx_buf[4] = (psoc_timestamp->timestamp & 0xff);
+	} else if (psoc_timestamp->cmd == EPM_PSOC_GET_SYSTEM_TIMESTAMP_CMD) {
+		tx_buf[0] = psoc_timestamp->cmd;
+	}
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_timestamp->cmd		= rx_buf[0];
+	psoc_timestamp->timestamp = rx_buf[1] << 24 | rx_buf[2] << 16 |
+					rx_buf[3] << 8 | rx_buf[4];
+
+	return rc;
+}
+
+static int epm_psoc_get_avg_buffered_switch_data(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_get_avg_buffered_switch_data *psoc_get_meas)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[64], rx_buf[64];
+	int rc = 0, i;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_get_meas->cmd;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_get_meas->cmd		= rx_buf[0];
+	psoc_get_meas->status		= rx_buf[1];
+	psoc_get_meas->timestamp_start	= (rx_buf[2] << 24 |
+			rx_buf[3] << 16 | rx_buf[4] << 8
+			| rx_buf[5]);
+	psoc_get_meas->channel_mask	= (rx_buf[6] << 24 |
+		rx_buf[7] << 16 | rx_buf[8] << 8
+			| rx_buf[9]);
+
+	for (i = 0; i < EPM_PSOC_BUFFERED_DATA_LENGTH2; i++)
+		psoc_get_meas->avg_data[i] = rx_buf[10 + i];
+
+	return rc;
+}
+
+static int epm_psoc_set_vadc(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_set_vadc *psoc_set_vadc)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[10], rx_buf[10];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_set_vadc->cmd;
+	tx_buf[1] = psoc_set_vadc->vadc_dev;
+	tx_buf[2] = (psoc_set_vadc->vadc_voltage & 0xff000000) >> 24;
+	tx_buf[3] = (psoc_set_vadc->vadc_voltage & 0xff0000) >> 16;
+	tx_buf[4] = (psoc_set_vadc->vadc_voltage & 0xff00) >> 8;
+	tx_buf[5] = psoc_set_vadc->vadc_voltage & 0xff;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_set_vadc->cmd		= rx_buf[0];
+	psoc_set_vadc->vadc_dev		= rx_buf[1];
+	psoc_set_vadc->vadc_voltage = (rx_buf[2] << 24) | (rx_buf[3] << 16) |
+					(rx_buf[4] << 8) | (rx_buf[5]);
+
+	return rc;
+}
+
+static int epm_psoc_set_channel_switch(struct epm_adc_drv *epm_adc,
+		struct epm_psoc_set_channel_switch *psoc_channel_switch)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[10], rx_buf[10];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = psoc_channel_switch->cmd;
+	tx_buf[1] = psoc_channel_switch->dev;
+	tx_buf[2] = (psoc_channel_switch->delay & 0xff000000) >> 24;
+	tx_buf[3] = (psoc_channel_switch->delay & 0xff0000) >> 16;
+	tx_buf[4] = (psoc_channel_switch->delay & 0xff00) >> 8;
+	tx_buf[5] = psoc_channel_switch->delay & 0xff;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	psoc_channel_switch->cmd		= rx_buf[0];
+	psoc_channel_switch->dev		= rx_buf[1];
+	psoc_channel_switch->delay		= rx_buf[2] << 24 |
+					rx_buf[3] << 16 |
+					rx_buf[4] << 8 | rx_buf[5];
+
+	return rc;
+}
+
+static int epm_psoc_clear_buffer(struct epm_adc_drv *epm_adc)
+{
+	struct spi_message m;
+	struct spi_transfer t;
+	char tx_buf[3], rx_buf[3];
+	int rc = 0;
+
+	spi_setup(epm_adc->epm_spi_client);
+
+	memset(&t, 0, sizeof t);
+	memset(tx_buf, 0, sizeof tx_buf);
+	memset(rx_buf, 0, sizeof tx_buf);
+	t.tx_buf = tx_buf;
+	t.rx_buf = rx_buf;
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	tx_buf[0] = EPM_PSOC_CLEAR_BUFFER_CMD;
+
+	t.len = sizeof(tx_buf);
+	t.bits_per_word = EPM_ADC_ADS_SPI_BITS_PER_WORD;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = spi_sync(epm_adc->epm_spi_client, &m);
+	if (rc)
+		return rc;
+
+	rc = rx_buf[2];
+
+	return rc;
+}
+
 static long epm_adc_ioctl(struct file *file, unsigned int cmd,
 						unsigned long arg)
 {
@@ -659,7 +1162,7 @@
 				epm_adc_expander_register = true;
 			}
 
-			result = epm_adc_hw_init(epm_adc_drv);
+			result = epm_adc_hw_init(epm_adc);
 
 			if (copy_to_user((void __user *)arg, &result,
 						sizeof(uint32_t)))
@@ -669,13 +1172,232 @@
 	case EPM_ADC_DEINIT:
 		{
 			uint32_t result;
-			result = epm_adc_hw_deinit(epm_adc_drv);
+			result = epm_adc_hw_deinit(epm_adc);
 
 			if (copy_to_user((void __user *)arg, &result,
 						sizeof(uint32_t)))
 				return -EFAULT;
 			break;
 		}
+	case EPM_PSOC_ADC_INIT:
+		{
+			struct epm_psoc_init_resp psoc_init;
+			int rc;
+
+			if (copy_from_user(&psoc_init, (void __user *)arg,
+					sizeof(struct epm_psoc_init_resp)))
+				return -EFAULT;
+
+			psoc_init.cmd = EPM_PSOC_INIT_CMD;
+			rc = epm_psoc_init(epm_adc, &psoc_init);
+			if (rc) {
+				pr_err("PSOC initialization failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_init,
+				sizeof(struct epm_psoc_init_resp)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_CHANNEL_ENABLE:
+	case EPM_PSOC_ADC_CHANNEL_DISABLE:
+		{
+			struct epm_psoc_channel_configure psoc_chan_configure;
+			int rc;
+
+			if (copy_from_user(&psoc_chan_configure,
+				(void __user *)arg,
+				sizeof(struct epm_psoc_channel_configure)))
+				return -EFAULT;
+
+			psoc_chan_configure.cmd =
+					EPM_PSOC_CHANNEL_ENABLE_DISABLE_CMD;
+			rc = epm_psoc_channel_configure(epm_adc,
+							&psoc_chan_configure);
+			if (rc) {
+				pr_err("PSOC channel configure failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg,
+				&psoc_chan_configure,
+				sizeof(struct epm_psoc_channel_configure)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_SET_AVERAGING:
+		{
+			struct epm_psoc_set_avg psoc_set_avg;
+			int rc;
+
+			if (copy_from_user(&psoc_set_avg, (void __user *)arg,
+					sizeof(struct epm_psoc_set_avg)))
+				return -EFAULT;
+
+			psoc_set_avg.cmd = EPM_PSOC_SET_AVERAGING_CMD;
+			rc = epm_psoc_set_averaging(epm_adc, &psoc_set_avg);
+			if (rc) {
+				pr_err("PSOC averaging failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_set_avg,
+					sizeof(struct epm_psoc_set_avg)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_GET_LAST_MEASUREMENT:
+		{
+			struct epm_psoc_get_data psoc_get_data;
+			int rc;
+
+			if (copy_from_user(&psoc_get_data,
+					(void __user *)arg,
+					sizeof(struct epm_psoc_get_data)))
+				return -EFAULT;
+
+			psoc_get_data.cmd = EPM_PSOC_GET_LAST_MEASUREMENT_CMD;
+			rc = epm_psoc_get_data(epm_adc, &psoc_get_data);
+			if (rc) {
+				pr_err("PSOC last measured data failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_get_data,
+				sizeof(struct epm_psoc_get_data)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_GET_BUFFERED_DATA:
+		{
+			struct epm_psoc_get_buffered_data psoc_get_data;
+			int rc;
+
+			if (copy_from_user(&psoc_get_data,
+				(void __user *)arg,
+				sizeof(struct epm_psoc_get_buffered_data)))
+				return -EFAULT;
+
+			psoc_get_data.cmd = EPM_PSOC_GET_BUFFERED_DATA_CMD;
+			rc = epm_psoc_get_buffered_data(epm_adc,
+								&psoc_get_data);
+			if (rc) {
+				pr_err("PSOC buffered measurement failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_get_data,
+				sizeof(struct epm_psoc_get_buffered_data)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_GET_SYSTEM_TIMESTAMP:
+	case EPM_PSOC_ADC_SET_SYSTEM_TIMESTAMP:
+		{
+			struct epm_psoc_system_time_stamp psoc_timestamp;
+			int rc;
+
+			if (copy_from_user(&psoc_timestamp,
+				(void __user *)arg,
+				sizeof(struct epm_psoc_system_time_stamp)))
+				return -EFAULT;
+
+			rc = epm_psoc_timestamp(epm_adc, &psoc_timestamp);
+			if (rc) {
+				pr_err("PSOC buffered measurement failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_timestamp,
+				sizeof(struct epm_psoc_system_time_stamp)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_GET_AVERAGE_DATA:
+		{
+			struct epm_psoc_get_avg_buffered_switch_data
+								psoc_get_data;
+			int rc;
+
+			if (copy_from_user(&psoc_get_data,
+				(void __user *)arg,
+				sizeof(struct
+				epm_psoc_get_avg_buffered_switch_data)))
+				return -EFAULT;
+
+			psoc_get_data.cmd = EPM_PSOC_GET_AVERAGED_DATA_CMD;
+			rc = epm_psoc_get_avg_buffered_switch_data(epm_adc,
+								&psoc_get_data);
+			if (rc) {
+				pr_err("Get averaged buffered data failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_get_data,
+				sizeof(struct
+				epm_psoc_get_avg_buffered_switch_data)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_SET_CHANNEL_SWITCH:
+		{
+			struct epm_psoc_set_channel_switch psoc_channel_switch;
+			int rc;
+
+			if (copy_from_user(&psoc_channel_switch,
+				(void __user *)arg,
+				sizeof(struct epm_psoc_set_channel_switch)))
+				return -EFAULT;
+
+			rc = epm_psoc_set_channel_switch(epm_adc,
+						&psoc_channel_switch);
+			if (rc) {
+				pr_err("PSOC channel switch failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg,
+				&psoc_channel_switch,
+				sizeof(struct epm_psoc_set_channel_switch)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_CLEAR_BUFFER:
+		{
+			int rc;
+			rc = epm_psoc_clear_buffer(epm_adc);
+			if (rc) {
+				pr_err("PSOC clear buffer failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &rc,
+						sizeof(uint32_t)))
+				return -EFAULT;
+			break;
+		}
+	case EPM_PSOC_ADC_SET_VADC_REFERENCE:
+		{
+			struct epm_psoc_set_vadc psoc_set_vadc;
+			int rc;
+
+			if (copy_from_user(&psoc_set_vadc,
+					(void __user *)arg,
+					sizeof(struct epm_psoc_set_vadc)))
+				return -EFAULT;
+
+			rc = epm_psoc_set_vadc(epm_adc, &psoc_set_vadc);
+			if (rc) {
+				pr_err("PSOC set VADC failed\n");
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void __user *)arg, &psoc_set_vadc,
+				sizeof(struct epm_psoc_set_vadc)))
+				return -EFAULT;
+			break;
+		}
 	default:
 		return -EINVAL;
 	}
@@ -687,6 +1409,252 @@
 	.unlocked_ioctl = epm_adc_ioctl,
 };
 
+static ssize_t epm_adc_psoc_show_in(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct epm_adc_drv *epm_adc = epm_adc_drv;
+	struct epm_psoc_init_resp init_resp;
+	struct epm_psoc_channel_configure psoc_chan_configure;
+	struct epm_psoc_get_data psoc_get_meas;
+	int16_t *adc_code = 0;
+	int rc = 0;
+
+	rc = epm_adc_psoc_gpio_init(true);
+	if (rc) {
+		pr_err("GPIO init failed\n");
+		return 0;
+	}
+	usleep_range(EPM_GLOBAL_ENABLE_MIN_DELAY,
+				EPM_GLOBAL_ENABLE_MAX_DELAY);
+
+	init_resp.cmd = EPM_PSOC_INIT_CMD;
+	rc = epm_psoc_init(epm_adc, &init_resp);
+	if (rc) {
+		pr_info("PSOC init failed %d\n", rc);
+		return 0;
+	}
+
+	psoc_chan_configure.channel_num = (1 << attr->index);
+	psoc_chan_configure.cmd = EPM_PSOC_CHANNEL_ENABLE_DISABLE_CMD;
+	rc = epm_psoc_channel_configure(epm_adc, &psoc_chan_configure);
+	if (rc) {
+		pr_info("PSOC channel configure failed\n");
+		return 0;
+	}
+
+	usleep_range(EPM_GLOBAL_ENABLE_MIN_DELAY,
+				EPM_GLOBAL_ENABLE_MAX_DELAY);
+
+	psoc_get_meas.cmd = EPM_PSOC_GET_LAST_MEASUREMENT_CMD;
+	psoc_get_meas.dev_num = 0;
+	psoc_get_meas.chan_num = attr->index;
+	rc = epm_psoc_get_data(epm_adc, &psoc_get_meas);
+	if (rc) {
+		pr_info("PSOC get data failed\n");
+		return 0;
+	}
+
+	*adc_code = psoc_get_meas.reading_value;
+
+	rc = epm_psoc_scale_result(adc_code,
+			psoc_chan_configure.channel_num);
+	if (rc) {
+		pr_info("Scale result failed\n");
+		return 0;
+	}
+
+	psoc_get_meas.reading_value = *adc_code;
+
+	rc = epm_adc_psoc_gpio_init(false);
+	if (rc) {
+		pr_err("GPIO de-init failed\n");
+		return 0;
+	}
+
+	return snprintf(buf, 16, "Result: %d\n", psoc_get_meas.reading_value);
+}
+
+static struct sensor_device_attribute epm_adc_psoc_in_attrs[] = {
+	SENSOR_ATTR(ads0_chan0,  S_IRUGO, epm_adc_psoc_show_in, NULL, 0),
+	SENSOR_ATTR(ads0_chan1,  S_IRUGO, epm_adc_psoc_show_in, NULL, 1),
+	SENSOR_ATTR(ads0_chan2,  S_IRUGO, epm_adc_psoc_show_in, NULL, 2),
+	SENSOR_ATTR(ads0_chan3,  S_IRUGO, epm_adc_psoc_show_in, NULL, 3),
+	SENSOR_ATTR(ads0_chan4,  S_IRUGO, epm_adc_psoc_show_in, NULL, 4),
+	SENSOR_ATTR(ads0_chan5,  S_IRUGO, epm_adc_psoc_show_in, NULL, 5),
+	SENSOR_ATTR(ads0_chan6,  S_IRUGO, epm_adc_psoc_show_in, NULL, 6),
+	SENSOR_ATTR(ads0_chan7,  S_IRUGO, epm_adc_psoc_show_in, NULL, 7),
+	SENSOR_ATTR(ads0_chan8,  S_IRUGO, epm_adc_psoc_show_in, NULL, 8),
+	SENSOR_ATTR(ads0_chan9,  S_IRUGO, epm_adc_psoc_show_in, NULL, 9),
+	SENSOR_ATTR(ads0_chan10, S_IRUGO, epm_adc_psoc_show_in, NULL, 10),
+	SENSOR_ATTR(ads0_chan11, S_IRUGO, epm_adc_psoc_show_in, NULL, 11),
+	SENSOR_ATTR(ads0_chan12, S_IRUGO, epm_adc_psoc_show_in, NULL, 12),
+	SENSOR_ATTR(ads0_chan13, S_IRUGO, epm_adc_psoc_show_in, NULL, 13),
+	SENSOR_ATTR(ads0_chan14, S_IRUGO, epm_adc_psoc_show_in, NULL, 14),
+	SENSOR_ATTR(ads0_chan15, S_IRUGO, epm_adc_psoc_show_in, NULL, 15),
+	SENSOR_ATTR(ads1_chan0,  S_IRUGO, epm_adc_psoc_show_in, NULL, 16),
+	SENSOR_ATTR(ads1_chan1,  S_IRUGO, epm_adc_psoc_show_in, NULL, 17),
+	SENSOR_ATTR(ads1_chan2,  S_IRUGO, epm_adc_psoc_show_in, NULL, 18),
+	SENSOR_ATTR(ads1_chan3,  S_IRUGO, epm_adc_psoc_show_in, NULL, 19),
+	SENSOR_ATTR(ads1_chan4,  S_IRUGO, epm_adc_psoc_show_in, NULL, 20),
+	SENSOR_ATTR(ads1_chan5,  S_IRUGO, epm_adc_psoc_show_in, NULL, 21),
+	SENSOR_ATTR(ads1_chan6,  S_IRUGO, epm_adc_psoc_show_in, NULL, 22),
+	SENSOR_ATTR(ads1_chan7,  S_IRUGO, epm_adc_psoc_show_in, NULL, 23),
+	SENSOR_ATTR(ads1_chan8,  S_IRUGO, epm_adc_psoc_show_in, NULL, 24),
+	SENSOR_ATTR(ads1_chan9,  S_IRUGO, epm_adc_psoc_show_in, NULL, 25),
+	SENSOR_ATTR(ads1_chan10, S_IRUGO, epm_adc_psoc_show_in, NULL, 26),
+	SENSOR_ATTR(ads1_chan11, S_IRUGO, epm_adc_psoc_show_in, NULL, 27),
+	SENSOR_ATTR(ads1_chan12, S_IRUGO, epm_adc_psoc_show_in, NULL, 28),
+	SENSOR_ATTR(ads1_chan13, S_IRUGO, epm_adc_psoc_show_in, NULL, 29),
+	SENSOR_ATTR(ads1_chan14, S_IRUGO, epm_adc_psoc_show_in, NULL, 30),
+	SENSOR_ATTR(ads1_chan15, S_IRUGO, epm_adc_psoc_show_in, NULL, 31),
+};
+
+static int __devinit epm_adc_psoc_init_hwmon(struct spi_device *spi,
+						struct epm_adc_drv *epm_adc)
+{
+	int i, rc, num_chans = 15;
+
+	for (i = 0; i < num_chans; i++) {
+		rc = device_create_file(&spi->dev,
+				&epm_adc_psoc_in_attrs[i].dev_attr);
+		if (rc) {
+			dev_err(&spi->dev, "device_create_file failed\n");
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int get_device_tree_data(struct spi_device *spi)
+{
+	const struct device_node *node = spi->dev.of_node;
+	struct epm_adc_drv *epm_adc;
+	int32_t *epm_ch_gain, *epm_ch_rsense;
+	u32 rc = 0, epm_num_channels, i;
+
+	if (!node)
+		return -EINVAL;
+
+	rc = of_property_read_u32(node,
+			"qcom,channels", &epm_num_channels);
+	if (rc) {
+		dev_err(&spi->dev, "missing channel numbers\n");
+		return -ENODEV;
+	}
+
+	epm_ch_gain = devm_kzalloc(&spi->dev,
+				epm_num_channels, GFP_KERNEL);
+	if (!epm_ch_gain) {
+		dev_err(&spi->dev, "cannot allocate gain\n");
+		return -ENOMEM;
+	}
+
+	epm_ch_rsense = devm_kzalloc(&spi->dev,
+				epm_num_channels, GFP_KERNEL);
+	if (!epm_ch_rsense) {
+		dev_err(&spi->dev, "cannot allocate rsense\n");
+		return -ENOMEM;
+	}
+
+	rc = of_property_read_u32_array(node,
+			"qcom,gain", epm_ch_gain, epm_num_channels);
+	if (rc) {
+		dev_err(&spi->dev, "invalid gain property:%d\n", rc);
+		return rc;
+	}
+
+	rc = of_property_read_u32_array(node,
+			"qcom,rsense", epm_ch_rsense, epm_num_channels);
+	if (rc) {
+		dev_err(&spi->dev, "invalid rsense property:%d\n", rc);
+		return rc;
+	}
+
+	epm_adc = devm_kzalloc(&spi->dev,
+			sizeof(struct epm_adc_drv) +
+			(epm_num_channels *
+			sizeof(struct epm_chan_properties)),
+			GFP_KERNEL);
+	if (!epm_adc) {
+		dev_err(&spi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < epm_num_channels; i++) {
+		epm_adc->epm_psoc_ch_prop[i].resistorvalue =
+							epm_ch_rsense[i];
+		epm_adc->epm_psoc_ch_prop[i].gain =
+							epm_ch_gain[i];
+	}
+
+	epm_adc_drv = epm_adc;
+
+	return 0;
+}
+
+static int __devinit epm_adc_psoc_spi_probe(struct spi_device *spi)
+{
+	struct epm_adc_drv *epm_adc;
+	struct device_node *node = spi->dev.of_node;
+	int rc = 0;
+
+	if (!node) {
+		dev_err(&spi->dev, "no platform data?\n");
+		pr_info("Error in the probe\n");
+		return -EINVAL;
+	}
+
+	if (node)
+		rc = get_device_tree_data(spi);
+	else
+		return -ENODEV;
+
+	epm_adc = epm_adc_drv;
+	epm_adc->misc.name = EPM_ADC_DRIVER_NAME;
+	epm_adc->misc.minor = MISC_DYNAMIC_MINOR;
+	epm_adc_drv->epm_spi_client = spi;
+	epm_adc_drv->epm_spi_client->bits_per_word =
+				EPM_ADC_ADS_SPI_BITS_PER_WORD;
+	rc = epm_adc_psoc_init_hwmon(spi, epm_adc);
+	if (rc) {
+		dev_err(&spi->dev, "msm_adc_dev_init failed\n");
+		return rc;
+	}
+
+	epm_adc->hwmon = hwmon_device_register(&spi->dev);
+	if (IS_ERR(epm_adc->hwmon)) {
+		dev_err(&spi->dev, "hwmon_device_register failed\n");
+		return rc;
+	}
+
+	mutex_init(&epm_adc->conv_lock);
+
+	return rc;
+}
+
+static int __devexit epm_adc_psoc_spi_remove(struct spi_device *spi)
+{
+	epm_adc_drv->epm_spi_client = NULL;
+	return 0;
+}
+
+static const struct of_device_id epm_adc_psoc_match_table[] = {
+	{	.compatible = "qcom,epm-adc",
+	},
+	{}
+};
+
+static struct spi_driver epm_spi_driver = {
+	.probe = epm_adc_psoc_spi_probe,
+	.remove = __devexit_p(epm_adc_psoc_spi_remove),
+	.driver = {
+		.name = EPM_ADC_DRIVER_NAME,
+		.of_match_table = epm_adc_psoc_match_table,
+	},
+};
+
 static ssize_t epm_adc_show_in(struct device *dev,
 				 struct device_attribute *devattr, char *buf)
 {
@@ -786,33 +1754,6 @@
 	return 0;
 }
 
-static int __devinit epm_adc_spi_probe(struct spi_device *spi)
-
-{
-	if (!epm_adc_drv)
-		return -ENODEV;
-	epm_adc_drv->epm_spi_client = spi;
-	epm_adc_drv->epm_spi_client->bits_per_word =
-				EPM_ADC_ADS_SPI_BITS_PER_WORD;
-
-	return 0;
-}
-
-static int __devexit epm_adc_spi_remove(struct spi_device *spi)
-{
-	epm_adc_drv->epm_spi_client = NULL;
-	return 0;
-}
-
-static struct spi_driver epm_spi_driver = {
-	.probe = epm_adc_spi_probe,
-	.remove = __devexit_p(epm_adc_spi_remove),
-	.driver = {
-		.name = EPM_ADC_DRIVER_NAME,
-		.owner = THIS_MODULE,
-	},
-};
-
 static int __devinit epm_adc_probe(struct platform_device *pdev)
 {
 	struct epm_adc_drv *epm_adc;
@@ -863,6 +1804,7 @@
 	epm_adc->bus_id = pdata->bus_id;
 	epm_gpio_expander_base_addr = pdata->gpio_expander_base_addr;
 	epm_adc_expander_register = false;
+
 	return rc;
 }
 
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index c122270..f908181 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -26,6 +26,7 @@
 #include <linux/spmi.h>
 #include <linux/of_irq.h>
 #include <linux/interrupt.h>
+#include <linux/completion.h>
 #include <linux/qpnp/qpnp-adc.h>
 #include <linux/platform_device.h>
 
@@ -33,6 +34,491 @@
 #define QPNP_VADC_MIN_ADC_CODE			0x6000
 /* Max ADC code represents full-scale range of 1.8V */
 #define QPNP_VADC_MAX_ADC_CODE			0xA800
+#define KELVINMIL_DEGMIL	273160
+
+/* Units for temperature below (on x axis) is in 0.1DegC as
+   required by the battery driver. Note the resolution used
+   here to compute the table was done for DegC to milli-volts.
+   In consideration to limit the size of the table for the given
+   temperature range below, the result is linearly interpolated
+   and provided to the battery driver in the units desired for
+   their framework which is 0.1DegC. True resolution of 0.1DegC
+   will result in the below table size to increase by 10 times */
+static const struct qpnp_vadc_map_pt adcmap_btm_threshold[] = {
+	{-300,	1642},
+	{-200,	1544},
+	{-100,	1414},
+	{0,	1260},
+	{10,	1244},
+	{20,	1228},
+	{30,	1212},
+	{40,	1195},
+	{50,	1179},
+	{60,	1162},
+	{70,	1146},
+	{80,	1129},
+	{90,	1113},
+	{100,	1097},
+	{110,	1080},
+	{120,	1064},
+	{130,	1048},
+	{140,	1032},
+	{150,	1016},
+	{160,	1000},
+	{170,	985},
+	{180,	969},
+	{190,	954},
+	{200,	939},
+	{210,	924},
+	{220,	909},
+	{230,	894},
+	{240,	880},
+	{250,	866},
+	{260,	852},
+	{270,	838},
+	{280,	824},
+	{290,	811},
+	{300,	798},
+	{310,	785},
+	{320,	773},
+	{330,	760},
+	{340,	748},
+	{350,	736},
+	{360,	725},
+	{370,	713},
+	{380,	702},
+	{390,	691},
+	{400,	681},
+	{410,	670},
+	{420,	660},
+	{430,	650},
+	{440,	640},
+	{450,	631},
+	{460,	622},
+	{470,	613},
+	{480,	604},
+	{490,	595},
+	{500,	587},
+	{510,	579},
+	{520,	571},
+	{530,	563},
+	{540,	556},
+	{550,	548},
+	{560,	541},
+	{570,	534},
+	{580,	527},
+	{590,	521},
+	{600,	514},
+	{610,	508},
+	{620,	502},
+	{630,	496},
+	{640,	490},
+	{650,	485},
+	{660,	281},
+	{670,	274},
+	{680,	267},
+	{690,	260},
+	{700,	254},
+	{710,	247},
+	{720,	241},
+	{730,	235},
+	{740,	229},
+	{750,	224},
+	{760,	218},
+	{770,	213},
+	{780,	208},
+	{790,	203}
+};
+
+static const struct qpnp_vadc_map_pt adcmap_ntcg_104ef_104fb[] = {
+	{696483,	-40960},
+	{649148,	-39936},
+	{605368,	-38912},
+	{564809,	-37888},
+	{527215,	-36864},
+	{492322,	-35840},
+	{460007,	-34816},
+	{429982,	-33792},
+	{402099,	-32768},
+	{376192,	-31744},
+	{352075,	-30720},
+	{329714,	-29696},
+	{308876,	-28672},
+	{289480,	-27648},
+	{271417,	-26624},
+	{254574,	-25600},
+	{238903,	-24576},
+	{224276,	-23552},
+	{210631,	-22528},
+	{197896,	-21504},
+	{186007,	-20480},
+	{174899,	-19456},
+	{164521,	-18432},
+	{154818,	-17408},
+	{145744,	-16384},
+	{137265,	-15360},
+	{129307,	-14336},
+	{121866,	-13312},
+	{114896,	-12288},
+	{108365,	-11264},
+	{102252,	-10240},
+	{96499,		-9216},
+	{91111,		-8192},
+	{86055,		-7168},
+	{81308,		-6144},
+	{76857,		-5120},
+	{72660,		-4096},
+	{68722,		-3072},
+	{65020,		-2048},
+	{61538,		-1024},
+	{58261,		0},
+	{55177,		1024},
+	{52274,		2048},
+	{49538,		3072},
+	{46962,		4096},
+	{44531,		5120},
+	{42243,		6144},
+	{40083,		7168},
+	{38045,		8192},
+	{36122,		9216},
+	{34308,		10240},
+	{32592,		11264},
+	{30972,		12288},
+	{29442,		13312},
+	{27995,		14336},
+	{26624,		15360},
+	{25333,		16384},
+	{24109,		17408},
+	{22951,		18432},
+	{21854,		19456},
+	{20807,		20480},
+	{19831,		21504},
+	{18899,		22528},
+	{18016,		23552},
+	{17178,		24576},
+	{16384,		25600},
+	{15631,		26624},
+	{14916,		27648},
+	{14237,		28672},
+	{13593,		29696},
+	{12976,		30720},
+	{12400,		31744},
+	{11848,		32768},
+	{11324,		33792},
+	{10825,		34816},
+	{10354,		35840},
+	{9900,		36864},
+	{9471,		37888},
+	{9062,		38912},
+	{8674,		39936},
+	{8306,		40960},
+	{7951,		41984},
+	{7616,		43008},
+	{7296,		44032},
+	{6991,		45056},
+	{6701,		46080},
+	{6424,		47104},
+	{6160,		48128},
+	{5908,		49152},
+	{5667,		50176},
+	{5439,		51200},
+	{5219,		52224},
+	{5010,		53248},
+	{4810,		54272},
+	{4619,		55296},
+	{4440,		56320},
+	{4263,		57344},
+	{4097,		58368},
+	{3938,		59392},
+	{3785,		60416},
+	{3637,		61440},
+	{3501,		62464},
+	{3368,		63488},
+	{3240,		64512},
+	{3118,		65536},
+	{2998,		66560},
+	{2889,		67584},
+	{2782,		68608},
+	{2680,		69632},
+	{2581,		70656},
+	{2490,		71680},
+	{2397,		72704},
+	{2310,		73728},
+	{2227,		74752},
+	{2147,		75776},
+	{2064,		76800},
+	{1998,		77824},
+	{1927,		78848},
+	{1860,		79872},
+	{1795,		80896},
+	{1736,		81920},
+	{1673,		82944},
+	{1615,		83968},
+	{1560,		84992},
+	{1507,		86016},
+	{1456,		87040},
+	{1407,		88064},
+	{1360,		89088},
+	{1314,		90112},
+	{1271,		91136},
+	{1228,		92160},
+	{1189,		93184},
+	{1150,		94208},
+	{1112,		95232},
+	{1076,		96256},
+	{1042,		97280},
+	{1008,		98304},
+	{976,		99328},
+	{945,		100352},
+	{915,		101376},
+	{886,		102400},
+	{859,		103424},
+	{832,		104448},
+	{807,		105472},
+	{782,		106496},
+	{756,		107520},
+	{735,		108544},
+	{712,		109568},
+	{691,		110592},
+	{670,		111616},
+	{650,		112640},
+	{631,		113664},
+	{612,		114688},
+	{594,		115712},
+	{577,		116736},
+	{560,		117760},
+	{544,		118784},
+	{528,		119808},
+	{513,		120832},
+	{498,		121856},
+	{483,		122880},
+	{470,		123904},
+	{457,		124928},
+	{444,		125952},
+	{431,		126976},
+	{419,		128000}
+};
+
+static int32_t qpnp_adc_map_linear(const struct qpnp_vadc_map_pt *pts,
+		uint32_t tablesize, int32_t input, int64_t *output)
+{
+	bool descending = 1;
+	uint32_t i = 0;
+
+	if ((pts == NULL) || (output == NULL))
+		return -EINVAL;
+
+	/* Check if table is descending or ascending */
+	if (tablesize > 1) {
+		if (pts[0].x < pts[1].x)
+			descending = 0;
+	}
+
+	while (i < tablesize) {
+		if ((descending == 1) && (pts[i].x < input)) {
+			/* table entry is less than measured
+				value and table is descending, stop */
+			break;
+		} else if ((descending == 0) &&
+				(pts[i].x > input)) {
+			/* table entry is greater than measured
+				value and table is ascending, stop */
+			break;
+		} else {
+			i++;
+		}
+	}
+
+	if (i == 0)
+		*output = pts[0].y;
+	else if (i == tablesize)
+		*output = pts[tablesize-1].y;
+	else {
+		/* result is between search_index and search_index-1 */
+		/* interpolate linearly */
+		*output = (((int32_t) ((pts[i].y - pts[i-1].y)*
+			(input - pts[i-1].x))/
+			(pts[i].x - pts[i-1].x))+
+			pts[i-1].y);
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_adc_map_batt_therm(const struct qpnp_vadc_map_pt *pts,
+		uint32_t tablesize, int32_t input, int64_t *output)
+{
+	bool descending = 1;
+	uint32_t i = 0;
+
+	if ((pts == NULL) || (output == NULL))
+		return -EINVAL;
+
+	/* Check if table is descending or ascending */
+	if (tablesize > 1) {
+		if (pts[0].y < pts[1].y)
+			descending = 0;
+	}
+
+	while (i < tablesize) {
+		if ((descending == 1) && (pts[i].y < input)) {
+			/* table entry is less than measured
+				value and table is descending, stop */
+			break;
+		} else if ((descending == 0) && (pts[i].y > input)) {
+			/* table entry is greater than measured
+				value and table is ascending, stop */
+			break;
+		} else {
+			i++;
+		}
+	}
+
+	if (i == 0) {
+		*output = pts[0].x;
+	} else if (i == tablesize) {
+		*output = pts[tablesize-1].x;
+	} else {
+		/* result is between search_index and search_index-1 */
+		/* interpolate linearly */
+		*output = (((int32_t) ((pts[i].x - pts[i-1].x)*
+			(input - pts[i-1].y))/
+			(pts[i].y - pts[i-1].y))+
+			pts[i-1].x);
+	}
+
+	return 0;
+}
+
+static int64_t qpnp_adc_scale_ratiometric_calib(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties)
+{
+	int64_t adc_voltage = 0;
+	bool negative_offset = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties)
+		return -EINVAL;
+
+	adc_voltage = (adc_code -
+		chan_properties->adc_graph[CALIB_RATIOMETRIC].adc_gnd)
+		* adc_properties->adc_vdd_reference;
+	if (adc_voltage < 0) {
+		negative_offset = 1;
+		adc_voltage = -adc_voltage;
+	}
+	do_div(adc_voltage,
+		chan_properties->adc_graph[CALIB_RATIOMETRIC].dy);
+	if (negative_offset)
+		adc_voltage = -adc_voltage;
+
+	return adc_voltage;
+}
+
+int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t pmic_voltage = 0;
+	bool negative_offset = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	pmic_voltage = (adc_code -
+		chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
+		* chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+	if (pmic_voltage < 0) {
+		negative_offset = 1;
+		pmic_voltage = -pmic_voltage;
+	}
+	do_div(pmic_voltage,
+		chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
+	if (negative_offset)
+		pmic_voltage = -pmic_voltage;
+	pmic_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+
+	if (pmic_voltage > 0) {
+		/* 2mV/K */
+		adc_chan_result->measurement = pmic_voltage*
+			chan_properties->offset_gain_denominator;
+
+		do_div(adc_chan_result->measurement,
+			chan_properties->offset_gain_numerator * 2);
+	} else {
+		adc_chan_result->measurement = 0;
+	}
+	/* Change to .001 deg C */
+	adc_chan_result->measurement -= KELVINMIL_DEGMIL;
+	adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_pmic_therm);
+
+/* Scales the ADC code to 0.001 degrees C using the map
+ * table for the XO thermistor.
+ */
+int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t xo_thm = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	xo_thm = qpnp_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+	xo_thm <<= 4;
+	qpnp_adc_map_linear(adcmap_ntcg_104ef_104fb,
+		ARRAY_SIZE(adcmap_ntcg_104ef_104fb),
+		xo_thm, &adc_chan_result->physical);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_tdkntcg_therm);
+
+int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t bat_voltage = 0;
+
+	bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+
+	return qpnp_adc_map_batt_therm(
+			adcmap_btm_threshold,
+			ARRAY_SIZE(adcmap_btm_threshold),
+			bat_voltage,
+			&adc_chan_result->physical);
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_therm);
+
+int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t batt_id_voltage = 0;
+
+	batt_id_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+			adc_properties, chan_properties);
+	adc_chan_result->physical = batt_id_voltage;
+	adc_chan_result->physical = adc_chan_result->measurement;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_id);
 
 int32_t qpnp_adc_scale_default(int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -203,7 +689,7 @@
 				"qcom,calibration-type", NULL);
 		if (!strncmp(calibration_param, "absolute", 8))
 			calib_type = CALIB_ABSOLUTE;
-		else if (!strncmp(calibration_param, "historical", 9))
+		else if (!strncmp(calibration_param, "ratiometric", 11))
 			calib_type = CALIB_RATIOMETRIC;
 		else {
 			pr_err("%s: Invalid calibration property\n", __func__);
@@ -252,6 +738,8 @@
 		return -ENXIO;
 	}
 
+	init_completion(&adc_qpnp->adc_rslt_completion);
+
 	mutex_init(&adc_qpnp->adc_lock);
 
 	return 0;
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index b689255..aa375d7 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -33,6 +33,15 @@
 #include <linux/platform_device.h>
 
 /* QPNP IADC register definition */
+#define QPNP_IADC_REVISION1				0x0
+#define QPNP_IADC_REVISION2				0x1
+#define QPNP_IADC_REVISION3				0x2
+#define QPNP_IADC_REVISION4				0x3
+#define QPNP_IADC_PERPH_TYPE				0x4
+#define QPNP_IADC_PERH_SUBTYPE				0x5
+
+#define QPNP_IADC_SUPPORTED_REVISION2			1
+
 #define QPNP_STATUS1					0x8
 #define QPNP_STATUS1_OP_MODE				4
 #define QPNP_STATUS1_MULTI_MEAS_EN			BIT(3)
@@ -67,13 +76,14 @@
 #define QPNP_INT_CLR_FIFO_NOT_EMPTY_INT_EN		BIT(1)
 #define QPNP_INT_CLR_EOC_INT_EN_CLR			BIT(0)
 #define QPNP_INT_CLR_MASK				0x1f
-#define QPNP_MODE_CTL					0x40
+#define QPNP_IADC_MODE_CTL				0x40
 #define QPNP_OP_MODE_SHIFT				4
 #define QPNP_USE_BMS_DATA				BIT(4)
 #define QPNP_VADC_SYNCH_EN				BIT(2)
 #define QPNP_OFFSET_RMV_EN				BIT(1)
 #define QPNP_ADC_TRIM_EN				BIT(0)
-#define QPNP_EN_CTL1					0x46
+#define QPNP_IADC_EN_CTL1				0x46
+#define QPNP_IADC_ADC_EN				BIT(7)
 #define QPNP_ADC_CH_SEL_CTL				0x48
 #define QPNP_ADC_DIG_PARAM				0x50
 #define QPNP_ADC_CLK_SEL_MASK				0x3
@@ -101,13 +111,6 @@
 #define QPNP_DATA1					0x61
 #define QPNP_CONV_TIMEOUT_ERR				2
 
-#define QPNP_IADC_MODE_CTL				0x40
-#define QPNP_IADC_USE_BMS_DATA				BIT(4)
-#define QPNP_IADC_RESERVED_BIT3				BIT(3)
-#define QPNP_IADC_VADC_SYNC_EN				BIT(2)
-#define QPNP_IADC_OFFSET_RMV_EN				BIT(1)
-#define QPNP_IADC_ADC_TRIM_EN				BIT(0)
-
 #define QPNP_IADC_ADC_CH_SEL_CTL			0x48
 #define QPNP_IADC_ADC_CHX_SEL_SHIFT			3
 
@@ -121,16 +124,18 @@
 #define QPNP_IADC_DATA0					0x60
 #define QPNP_IADC_DATA1					0x61
 
-#define QPNP_ADC_CONV_TIME_MIN				2000
-#define QPNP_ADC_CONV_TIME_MAX				2200
+#define QPNP_ADC_CONV_TIME_MIN				8000
+#define QPNP_ADC_CONV_TIME_MAX				8200
 
-#define QPNP_ADC_GAIN_CALCULATION			2500
+#define QPNP_ADC_GAIN_CALCULATION_UV			17857
+#define QPNP_IADC_RSENSE_MILLI_FACTOR			1000
 
 struct qpnp_iadc_drv {
 	struct qpnp_adc_drv		*adc;
 	int32_t				rsense;
 	struct device			*iadc_hwmon;
 	bool				iadc_init_calib;
+	bool				iadc_initialized;
 	struct sensor_device_attribute		sens_attr[0];
 };
 
@@ -223,6 +228,31 @@
 	return IRQ_HANDLED;
 }
 
+static int32_t qpnp_iadc_enable(bool state)
+{
+	int rc = 0;
+	u8 data = 0;
+
+	data = QPNP_IADC_ADC_EN;
+	if (state) {
+		rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
+					data);
+		if (rc < 0) {
+			pr_err("IADC enable failed\n");
+			return rc;
+		}
+	} else {
+		rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
+					(~data & QPNP_IADC_ADC_EN));
+		if (rc < 0) {
+			pr_err("IADC disable failed\n");
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
 static int32_t qpnp_iadc_read_conversion_result(int32_t *data)
 {
 	uint8_t rslt_lsb, rslt_msb;
@@ -242,12 +272,9 @@
 
 	*data = (rslt_msb << 8) | rslt_lsb;
 
-	rc = qpnp_vadc_check_result(data);
-	if (rc < 0) {
-		pr_err("VADC data check failed\n");
+	rc = qpnp_iadc_enable(false);
+	if (rc)
 		return rc;
-	}
-
 	return 0;
 }
 
@@ -259,10 +286,7 @@
 	u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
 	int32_t rc = 0;
 
-	qpnp_iadc_mode_reg |= (QPNP_IADC_USE_BMS_DATA | QPNP_IADC_USE_BMS_DATA
-			| QPNP_IADC_OFFSET_RMV_EN | QPNP_IADC_ADC_TRIM_EN);
-
-	qpnp_iadc_ch_sel_reg = channel << QPNP_IADC_ADC_CHX_SEL_SHIFT;
+	qpnp_iadc_ch_sel_reg = channel;
 
 	qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
 					QPNP_IADC_DEC_RATIO_SEL;
@@ -310,6 +334,10 @@
 		return rc;
 	}
 
+	rc = qpnp_iadc_enable(true);
+	if (rc)
+		return rc;
+
 	rc = qpnp_iadc_write_reg(QPNP_CONV_REQ, qpnp_iadc_conv_req);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
@@ -353,17 +381,53 @@
 	return rc;
 }
 
+static int32_t qpnp_iadc_version_check(void)
+{
+	uint8_t revision;
+	int rc;
+
+	rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &revision);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed with %d\n", rc);
+		return rc;
+	}
+
+	if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
+		pr_err("IADC Version not supported\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int32_t qpnp_iadc_is_ready(void)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+
+	if (!iadc || !iadc->iadc_initialized)
+		return -EPROBE_DEFER;
+	else
+		return 0;
+}
+EXPORT_SYMBOL(qpnp_iadc_is_ready);
+
 int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
 						int32_t *result)
 {
 	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	int32_t vsense_mv = 0, rc;
 
+	if (!iadc || !iadc->iadc_initialized)
+		return -EPROBE_DEFER;
+
 	mutex_lock(&iadc->adc->adc_lock);
 
 	if (!iadc->iadc_init_calib) {
+		rc = qpnp_iadc_version_check();
+		if (rc)
+			goto fail;
 		rc = qpnp_iadc_init_calib();
-		if (!rc) {
+		if (rc) {
 			pr_err("Calibration failed\n");
 			goto fail;
 		} else
@@ -376,12 +440,11 @@
 		goto fail;
 	}
 
-	vsense_mv = ((*result - iadc->adc->calib.offset)/
-			(iadc->adc->calib.gain - iadc->adc->calib.offset))
-			* QPNP_ADC_GAIN_CALCULATION;
+	*result = ((vsense_mv - iadc->adc->calib.offset) *
+				QPNP_ADC_GAIN_CALCULATION_UV)/
+			(iadc->adc->calib.gain - iadc->adc->calib.offset);
 
-	*result = (vsense_mv/qpnp_iadc->rsense);
-
+	*result = (*result / (qpnp_iadc->rsense));
 fail:
 	mutex_unlock(&iadc->adc->adc_lock);
 
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 9e8a2e2..a0e7ab9 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -32,6 +32,15 @@
 #include <linux/platform_device.h>
 
 /* QPNP VADC register definition */
+#define QPNP_VADC_REVISION1				0x0
+#define QPNP_VADC_REVISION2				0x1
+#define QPNP_VADC_REVISION3				0x2
+#define QPNP_VADC_REVISION4				0x3
+#define QPNP_VADC_PERPH_TYPE				0x4
+#define QPNP_VADC_PERH_SUBTYPE				0x5
+
+#define QPNP_VADC_SUPPORTED_REVISION2			1
+
 #define QPNP_VADC_STATUS1					0x8
 #define QPNP_VADC_STATUS1_OP_MODE				4
 #define QPNP_VADC_STATUS1_MEAS_INTERVAL_EN_STS			BIT(2)
@@ -98,6 +107,8 @@
 	struct dentry			*dent;
 	struct device			*vadc_hwmon;
 	bool				vadc_init_calib;
+	bool				vadc_initialized;
+	int				max_channels_available;
 	struct sensor_device_attribute		sens_attr[0];
 };
 
@@ -105,6 +116,9 @@
 
 static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
 	[SCALE_DEFAULT] = {qpnp_adc_scale_default},
+	[SCALE_BATT_THERM] = {qpnp_adc_scale_batt_therm},
+	[SCALE_PMIC_THERM] = {qpnp_adc_scale_pmic_therm},
+	[SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
 };
 
 static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
@@ -206,32 +220,21 @@
 	u8 mode_ctrl = 0;
 	int rc = 0;
 
-	if (vadc->vadc_init_calib) {
-		/* Configure interrupt if calibration is complete */
-		rc = qpnp_vadc_write_reg(QPNP_VADC_INT_EN_SET,
-				QPNP_VADC_INT_EOC_BIT);
-		if (rc < 0) {
-			pr_err("Configure error for interrupt setup\n");
-			return rc;
-		}
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_EN_SET,
+			QPNP_VADC_INT_EOC_BIT);
+	if (rc < 0) {
+		pr_err("Configure error for interrupt setup\n");
+		return rc;
 	}
 
 	/* Mode selection */
-	rc = qpnp_vadc_read_reg(QPNP_VADC_MODE_CTL, &mode_ctrl);
-	if (rc < 0) {
-		pr_err("Mode configure read error\n");
-		return rc;
-	}
-	mode_ctrl |= chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT;
+	mode_ctrl = chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT;
 	rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
 	if (rc < 0) {
 		pr_err("Mode configure write error\n");
 		return rc;
 	}
 
-	rc = qpnp_vadc_enable(true);
-	if (rc)
-		return rc;
 
 	/* Channel selection */
 	rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
@@ -242,12 +245,7 @@
 	}
 
 	/* Digital parameter setup */
-	rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_DIG_PARAM, &decimation);
-	if (rc < 0) {
-		pr_err("Digital parameter configure read error\n");
-		return rc;
-	}
-	decimation |= chan_prop->decimation <<
+	decimation = chan_prop->decimation <<
 				QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
 	rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
 	if (rc < 0) {
@@ -296,6 +294,12 @@
 		}
 	}
 
+	INIT_COMPLETION(vadc->adc->adc_rslt_completion);
+
+	rc = qpnp_vadc_enable(true);
+	if (rc)
+		return rc;
+
 	/* Request conversion */
 	rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ, QPNP_VADC_CONV_REQ_SET);
 	if (rc < 0) {
@@ -402,6 +406,25 @@
 	return IRQ_HANDLED;
 }
 
+static int32_t qpnp_vadc_version_check(void)
+{
+	uint8_t revision;
+	int rc;
+
+	rc = qpnp_vadc_read_reg(QPNP_VADC_REVISION2, &revision);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed with %d\n", rc);
+		return rc;
+	}
+
+	if (revision < QPNP_VADC_SUPPORTED_REVISION2) {
+		pr_err("VADC Version not supported\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static uint32_t qpnp_vadc_calib_device(void)
 {
 	struct qpnp_vadc_drv *vadc = qpnp_vadc;
@@ -421,8 +444,7 @@
 		goto calib_fail;
 	}
 
-	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
-					QPNP_VADC_STATUS1_EOC)) {
+	while (status1 != QPNP_VADC_STATUS1_EOC) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
@@ -449,8 +471,7 @@
 	}
 
 	status1 = 0;
-	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
-					QPNP_VADC_STATUS1_EOC)) {
+	while (status1 != QPNP_VADC_STATUS1_EOC) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
@@ -459,7 +480,7 @@
 					QPNP_VADC_CONV_TIME_MAX);
 	}
 
-	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	rc = qpnp_vadc_read_conversion_result(&calib_read_2);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
 		goto calib_fail;
@@ -467,6 +488,7 @@
 
 	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
 					(calib_read_1 - calib_read_2);
+
 	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
 						= QPNP_ADC_625_UV;
 	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
@@ -486,8 +508,7 @@
 	}
 
 	status1 = 0;
-	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
-					QPNP_VADC_STATUS1_EOC)) {
+	while (status1 != QPNP_VADC_STATUS1_EOC) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
@@ -502,7 +523,7 @@
 		goto calib_fail;
 	}
 
-	conv.amux_channel = VDD_VADC;
+	conv.amux_channel = GND_REF;
 	conv.decimation = DECIMATION_TYPE2;
 	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
 	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
@@ -514,8 +535,7 @@
 	}
 
 	status1 = 0;
-	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
-					QPNP_VADC_STATUS1_EOC)) {
+	while (status1 != QPNP_VADC_STATUS1_EOC) {
 		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
 		if (rc < 0)
 			return rc;
@@ -524,7 +544,7 @@
 					QPNP_VADC_CONV_TIME_MAX);
 	}
 
-	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	rc = qpnp_vadc_read_conversion_result(&calib_read_2);
 	if (rc) {
 		pr_err("qpnp adc read adc failed with %d\n", rc);
 		goto calib_fail;
@@ -543,14 +563,31 @@
 	return rc;
 }
 
+int32_t qpnp_vadc_is_ready(void)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+
+	if (!vadc || !vadc->vadc_initialized)
+		return -EPROBE_DEFER;
+	else
+		return 0;
+}
+EXPORT_SYMBOL(qpnp_vadc_is_ready);
+
 int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
 					enum qpnp_vadc_channels channel,
 					struct qpnp_vadc_result *result)
 {
 	struct qpnp_vadc_drv *vadc = qpnp_vadc;
-	int rc = 0, scale_type, amux_prescaling;
+	int rc = 0, scale_type, amux_prescaling, dt_index = 0;
+
+	if (!vadc || !vadc->vadc_initialized)
+		return -EPROBE_DEFER;
 
 	if (!vadc->vadc_init_calib) {
+		rc = qpnp_vadc_version_check();
+		if (rc)
+			return rc;
 		rc = qpnp_vadc_calib_device();
 		if (rc) {
 			pr_err("Calibration failed\n");
@@ -562,12 +599,20 @@
 	mutex_lock(&vadc->adc->adc_lock);
 
 	vadc->adc->amux_prop->amux_channel = channel;
+
+	while (vadc->adc->adc_channels[dt_index].channel_num
+			!= channel || dt_index > vadc->max_channels_available)
+		dt_index++;
+
+	if (dt_index > vadc->max_channels_available)
+		goto fail_unlock;
+
 	vadc->adc->amux_prop->decimation =
-			vadc->adc->adc_channels[channel].adc_decimation;
+			vadc->adc->adc_channels[dt_index].adc_decimation;
 	vadc->adc->amux_prop->hw_settle_time =
-			vadc->adc->adc_channels[channel].hw_settle_time;
+			vadc->adc->adc_channels[dt_index].hw_settle_time;
 	vadc->adc->amux_prop->fast_avg_setup =
-			vadc->adc->adc_channels[channel].fast_avg_setup;
+			vadc->adc->adc_channels[dt_index].fast_avg_setup;
 
 	if (trigger_channel < ADC_SEQ_NONE)
 		vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
@@ -602,14 +647,15 @@
 		goto fail_unlock;
 	}
 
-	amux_prescaling = vadc->adc->adc_channels[channel].chan_path_prescaling;
+	amux_prescaling =
+		vadc->adc->adc_channels[dt_index].chan_path_prescaling;
 
 	vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
 		qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
 	vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
 		 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
 
-	scale_type = vadc->adc->adc_channels[channel].adc_scale_fn;
+	scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
 	if (scale_type >= SCALE_NONE) {
 		rc = -EBADF;
 		goto fail_unlock;
@@ -642,8 +688,10 @@
 
 	rc = qpnp_vadc_read(attr->index, &result);
 
-	if (rc)
+	if (rc) {
+		pr_err("VADC read error with %d\n", rc);
 		return 0;
+	}
 
 	return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
 		"Result:%lld Raw:%d\n", result.physical, result.adc_code);
@@ -738,6 +786,8 @@
 		dev_err(&spmi->dev,
 			"failed to request adc irq with error %d\n", rc);
 		return rc;
+	} else {
+		enable_irq_wake(vadc->adc->adc_irq);
 	}
 
 	qpnp_vadc = vadc;
@@ -749,6 +799,8 @@
 	}
 	vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
 	vadc->vadc_init_calib = false;
+	vadc->vadc_initialized = true;
+	vadc->max_channels_available = count_adc_channel_list;
 
 	rc = qpnp_vadc_configure_interrupt();
 	if (rc) {
@@ -777,6 +829,7 @@
 		i++;
 	}
 	free_irq(vadc->adc->adc_irq, vadc);
+	vadc->vadc_initialized = false;
 	dev_set_drvdata(&spmi->dev, NULL);
 
 	return 0;
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
index 68cfcd1..893273d 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -13,7 +13,7 @@
 #ifndef _MPQ_DMX_PLUGIN_COMMON_H
 #define _MPQ_DMX_PLUGIN_COMMON_H
 
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
 
 #include "dvbdev.h"
 #include "dmxdev.h"
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video.c b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
index cd0f605..68653ba 100644
--- a/drivers/media/dvb/mpq/video/mpq_dvb_video.c
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
@@ -63,7 +63,6 @@
 {
 	int i;
 
-	mutex_lock(&mpq_dvb_video_device->lock);
 	for (i = 0; i < DVB_MPQ_NUM_VIDEO_DEVICES; i++) {
 		if (mpq_dvb_video_device->dev_inst[i].client_ctx ==
 						client_ctx) {
@@ -71,7 +70,6 @@
 			break;
 		}
 	}
-	mutex_unlock(&mpq_dvb_video_device->lock);
 
 	if (i == DVB_MPQ_NUM_VIDEO_DEVICES)
 		return -ENODEV;
@@ -423,26 +421,26 @@
 		mutex_unlock(&client_ctx->msg_queue_lock);
 		wake_up(&client_ctx->msg_wait);
 	} else {
-		bcast_msg = kzalloc(sizeof(struct mpq_bcast_msg),
-					GFP_KERNEL);
-		if (!bcast_msg) {
-			DBG("mpq_int_vid_dec_input_frame_done(): "\
-				"cannot allocate mpq_bcast_msg buffer\n");
-			return;
-		}
-
 		if (event == VCD_EVT_RESP_INPUT_DONE) {
+			bcast_msg = kzalloc(sizeof(struct mpq_bcast_msg),
+						GFP_KERNEL);
+			if (!bcast_msg) {
+				DBG("mpq_int_vid_dec_input_frame_done(): "\
+				"cannot allocate mpq_bcast_msg buffer\n");
+				return;
+			}
+
 			bcast_msg->info.code = MPQ_BCAST_MSG_IBD;
 			bcast_msg->info.data =
 				(unsigned int)vcd_frame_data->frm_clnt_data;
+
+			dmx_data = dev_inst->dmx_src_data;
+
+			mutex_lock(&dmx_data->msg_queue_lock);
+			list_add_tail(&bcast_msg->list, &dmx_data->msg_queue);
+			mutex_unlock(&dmx_data->msg_queue_lock);
+			wake_up(&dmx_data->msg_wait);
 		}
-
-		dmx_data = dev_inst->dmx_src_data;
-
-		mutex_lock(&dmx_data->msg_queue_lock);
-		list_add_tail(&bcast_msg->list, &dmx_data->msg_queue);
-		mutex_unlock(&dmx_data->msg_queue_lock);
-		wake_up(&dmx_data->msg_wait);
 	}
 }
 
diff --git a/drivers/media/video/msm/csi/msm_csid.h b/drivers/media/video/msm/csi/msm_csid.h
index 0e53753..46e8117 100644
--- a/drivers/media/video/msm/csi/msm_csid.h
+++ b/drivers/media/video/msm/csi/msm_csid.h
@@ -36,8 +36,8 @@
 	uint32_t hw_version;
 	enum msm_csid_state_t csid_state;
 
-	struct clk *csid0_clk[5];
-	struct clk *csid_clk[5];
+	struct clk *csid0_clk[6];
+	struct clk *csid_clk[6];
 };
 
 #define VIDIOC_MSM_CSID_CFG \
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
index b0782a3..6ac4a5e 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
@@ -477,9 +477,11 @@
 
 	buf_p->y_buffer_addr    = msm_jpeg_platform_v2p(buf_cmd.fd,
 		buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
-		&buf_p->handle, pgmn_dev->domain_num) + buf_cmd.offset;
+		&buf_p->handle, pgmn_dev->domain_num) + buf_cmd.offset
+		+ buf_cmd.y_off;
 	buf_p->y_len          = buf_cmd.y_len;
-	buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
+	buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len
+						+ buf_cmd.cbcr_off;
 	buf_p->cbcr_len       = buf_cmd.cbcr_len;
 	buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
 	JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%x, fd =%d\n",
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 0711ca5..60f08ce 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -1163,7 +1163,7 @@
 static int msm_mctl_v4l2_dqbuf(struct file *f, void *pctx,
 					struct v4l2_buffer *pb)
 {
-	int rc = 0;
+	int rc = 0, i;
 	/* get the camera device */
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	pcam_inst = container_of(f->private_data,
@@ -1180,6 +1180,26 @@
 	rc = vb2_dqbuf(&pcam_inst->vid_bufq, pb,  f->f_flags & O_NONBLOCK);
 	D("%s, videobuf_dqbuf returns %d\n", __func__, rc);
 
+	if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		/* Reject the buffer if planes array was not allocated */
+		if (pb->m.planes == NULL) {
+			pr_err("%s Planes array is null\n", __func__);
+			mutex_unlock(&pcam_inst->inst_lock);
+			return -EINVAL;
+		}
+		for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
+			pb->m.planes[i].data_offset =
+				pcam_inst->buf_offset[pb->index][i].data_offset;
+			pb->m.planes[i].reserved[0] =
+				pcam_inst->buf_offset[pb->index][i].addr_offset;
+			D("%s update offsets for plane %d as A %d D %d\n",
+				__func__, i, pb->m.planes[i].reserved[0],
+				pb->m.planes[i].data_offset);
+		}
+	} else {
+		pb->reserved = pcam_inst->buf_offset[pb->index][0].addr_offset;
+		D("%s stored reserved info %d\n", __func__, pb->reserved);
+	}
 	mutex_unlock(&pcam_inst->inst_lock);
 	return rc;
 }
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index b2cddb0..a114b37 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -103,6 +103,10 @@
 		if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_T)
 			*pp_type = OUTPUT_TYPE_T;
 		break;
+	case MSM_V4L2_EXT_CAPTURE_MODE_RDI:
+		if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_R)
+			*pp_type = OUTPUT_TYPE_R;
+		break;
 	default:
 		break;
 	}
@@ -405,8 +409,8 @@
 			ERR_COPY_FROM_USER();
 			return -EFAULT;
 		}
-		D("%s: PP_PATH, path=%d",
-			__func__, divert_pp.path);
+		D("%s: Divert Image mode =%d Enable %d",
+			__func__, divert_pp.path, divert_pp.enable);
 		spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
 		if (divert_pp.enable)
 			p_mctl->pp_info.pp_ctrl.pp_msg_type |= divert_pp.path;
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 1423063..bc38f62 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -700,9 +700,15 @@
 	int_time[0] = line >> 12;
 	int_time[1] = line >> 4;
 	int_time[2] = line << 4;
-	msm_camera_i2c_write_seq(s_ctrl->sensor_i2c_client,
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr-1,
-		&int_time[0], 3);
+		int_time[0], MSM_CAMERA_I2C_BYTE_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+		int_time[1], MSM_CAMERA_I2C_BYTE_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr+1,
+		int_time[2], MSM_CAMERA_I2C_BYTE_DATA);
 	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
 		s_ctrl->sensor_exp_gain_info->global_gain_addr, gain,
 		MSM_CAMERA_I2C_WORD_DATA);
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 12347bd..20493be 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -1197,11 +1197,13 @@
 			HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
 		h264_db_control.slice_alpha_offset = control.value;
 		pdata = &h264_db_control;
+		break;
 	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
 		property_id =
 			HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
 		h264_db_control.slice_beta_offset = control.value;
 		pdata = &h264_db_control;
+		break;
 	default:
 		break;
 	}
@@ -1534,7 +1536,7 @@
 			"Failed to find buffer queue for type = %d\n", i);
 		return -EINVAL;
 	}
-	dprintk(VIDC_DBG, "Calling streamoff\n");
+	dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i);
 	rc = vb2_streamoff(q, i);
 	if (rc)
 		dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index d785f88..ffe8c98 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -585,9 +585,16 @@
 			vb->v4l2_buf.timestamp =
 				ns_to_timeval(time_usec * NSEC_PER_USEC);
 		}
+		vb->v4l2_buf.flags = 0;
 
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
 			vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
+			vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+
+		if (!inst->fbd_count)
+			vb->v4l2_buf.flags = V4L2_BUF_FLAG_KEYFRAME;
+		++inst->fbd_count;
 
 		switch (fill_buf_done->picture_type) {
 		case HAL_PICTURE_IDR:
@@ -605,6 +612,8 @@
 			/* Do we need to care about these? */
 		case HAL_FRAME_YUV:
 			break;
+		default:
+			break;
 		}
 
 		dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
@@ -641,6 +650,31 @@
 	}
 }
 
+static void  handle_seq_hdr_done(enum command_response cmd, void *data)
+{
+	struct msm_vidc_cb_data_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct vb2_buffer *vb;
+	struct vidc_hal_fbd *fill_buf_done;
+	if (!response) {
+		pr_err("Invalid response from vidc_hal\n");
+		return;
+	}
+	inst = (struct msm_vidc_inst *)response->session_id;
+	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+	vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+		(u32)fill_buf_done->packet_buffer1);
+	if (vb)
+		vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+
+	vb->v4l2_buf.flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+
+	dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
+				vb->v4l2_planes[0].bytesused,
+				vb->v4l2_buf.flags);
+	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+}
+
 void handle_cmd_response(enum command_response cmd, void *data)
 {
 	dprintk(VIDC_DBG, "Command response = %d\n", cmd);
@@ -684,6 +718,9 @@
 	case SESSION_FLUSH_DONE:
 		handle_session_flush(cmd, data);
 		break;
+	case SESSION_GET_SEQ_HDR_DONE:
+		handle_seq_hdr_done(cmd, data);
+		break;
 	default:
 		dprintk(VIDC_ERR, "response unhandled\n");
 		break;
@@ -1159,6 +1196,8 @@
 			inst->session_type, fourcc);
 		goto exit;
 	}
+	inst->ftb_count = 0;
+	inst->fbd_count = 0;
 	change_inst_state(inst, MSM_VIDC_OPEN);
 exit:
 	return rc;
@@ -1422,7 +1461,6 @@
 	} else {
 		int64_t time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp);
 		do_div(time_usec, NSEC_PER_USEC);
-
 		memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
 		frame_data.alloc_len = vb->v4l2_planes[0].length;
 		frame_data.filled_len = vb->v4l2_planes[0].bytesused;
@@ -1451,6 +1489,7 @@
 					&frame_data);
 			dprintk(VIDC_DBG, "Sent etb to HAL\n");
 		} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			struct vidc_seq_hdr seq_hdr;
 			frame_data.filled_len = 0;
 			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
 			if (inst->extradata_handle) {
@@ -1465,8 +1504,23 @@
 			dprintk(VIDC_DBG,
 				" extradata_addr: %d\n",
 				frame_data.extradata_addr);
-			rc = vidc_hal_session_ftb((void *) inst->session,
-					&frame_data);
+			if (!inst->ftb_count &&
+			   inst->session_type == MSM_VIDC_ENCODER) {
+				seq_hdr.seq_hdr = (u8 *) vb->v4l2_planes[0].
+					m.userptr;
+				seq_hdr.seq_hdr_len = vb->v4l2_planes[0].length;
+				rc = vidc_hal_session_get_seq_hdr((void *)
+						inst->session, &seq_hdr);
+				if (!rc) {
+					inst->vb2_seq_hdr = vb;
+					dprintk(VIDC_DBG, "Seq_hdr: %p\n",
+						inst->vb2_seq_hdr);
+				}
+			} else {
+				rc = vidc_hal_session_ftb((void *)
+					inst->session, &frame_data);
+			}
+			inst->ftb_count++;
 		} else {
 			dprintk(VIDC_ERR,
 				"This capability is not supported: %d\n",
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 613f8d9..55aec74 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -244,6 +244,9 @@
 	u32 reconfig_width;
 	u32 reconfig_height;
 	struct dentry *debugfs_root;
+	u32 ftb_count;
+	u32 fbd_count;
+	struct vb2_buffer *vb2_seq_hdr;
 };
 
 extern struct msm_vidc_drv *vidc_driver;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index fcc7722..2b01882 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -253,7 +253,6 @@
 	}
 
 	qinfo =	(struct vidc_iface_q_info *) info;
-	dprintk(VIDC_DBG, "In : ");
 	queue = (struct hfi_queue_header *) qinfo->q_hdr;
 
 	if (!queue) {
@@ -529,7 +528,7 @@
 					dev->hal_client,
 			VIDC_IFACEQ_TABLE_SIZE, 1, SMEM_UNCACHED, domain);
 	if (rc) {
-		dprintk(VIDC_ERR, ":iface_q_table_alloc_fail");
+		dprintk(VIDC_ERR, "iface_q_table_alloc_fail");
 		return -ENOMEM;
 	}
 	q_tbl_hdr = (struct hfi_queue_table_header *)
@@ -549,7 +548,7 @@
 				dev->hal_client, VIDC_IFACEQ_QUEUE_SIZE,
 				1, SMEM_UNCACHED, domain);
 		if (rc) {
-			dprintk(VIDC_ERR, ":iface_q_table_alloc[%d]_fail", i);
+			dprintk(VIDC_ERR, "iface_q_table_alloc[%d]_fail", i);
 			vidc_hal_interface_queues_release(dev);
 			return -ENOMEM;
 		} else {
@@ -637,7 +636,7 @@
 	if (device) {
 		dev = device;
 	} else {
-		dprintk(VIDC_ERR, ":invalid device");
+		dprintk(VIDC_ERR, "Invalid device");
 		return -ENODEV;
 	}
 	enable_irq(dev->hal_data->irq);
@@ -700,7 +699,7 @@
 	if (device) {
 		dev = device;
 	} else {
-		dprintk(VIDC_ERR, ":invalid device");
+		dprintk(VIDC_ERR, "invalid device");
 		return -ENODEV;
 	}
 	write_register(dev->hal_data->register_base_addr,
@@ -720,7 +719,7 @@
 	if (device) {
 		dev = device;
 	} else {
-		dprintk(VIDC_ERR, ":invalid device");
+		dprintk(VIDC_ERR, "invalid device");
 		return -ENODEV;
 	}
 	pkt.size = sizeof(struct hfi_cmd_sys_pc_prep_packet);
@@ -768,7 +767,7 @@
 	struct hal_device *dev;
 
 	if (!device || !resource_hdr || !resource_value) {
-		dprintk(VIDC_ERR, "Invalid Params in ");
+		dprintk(VIDC_ERR, "set_res: Invalid Params");
 		return -EINVAL;
 	} else {
 		dev = device;
@@ -798,7 +797,7 @@
 		break;
 	}
 	default:
-		dprintk(VIDC_INFO, "In  called for resource %d",
+		dprintk(VIDC_INFO, "Invalid res_id in set_res %d",
 						resource_hdr->resource_id);
 		break;
 	}
@@ -813,7 +812,7 @@
 	struct hal_device *dev;
 
 	if (!device || !resource_hdr) {
-		dprintk(VIDC_ERR, "Invalid Params in ");
+		dprintk(VIDC_ERR, "Inv-Params in rel_res");
 		return -EINVAL;
 	} else {
 		dev = device;
@@ -838,7 +837,7 @@
 	if (device) {
 		dev = device;
 	} else {
-		dprintk(VIDC_ERR, ":invalid device");
+		dprintk(VIDC_ERR, "invalid device");
 		return -ENODEV;
 	}
 	pkt.size = sizeof(struct hfi_cmd_sys_ping_packet);
@@ -877,7 +876,8 @@
 		buffer = HFI_BUFFER_INTERNAL_PERSIST;
 		break;
 	default:
-		dprintk(VIDC_ERR, "Invalid buffer type : 0x%x\n", hal_buffer);
+		dprintk(VIDC_ERR, "Invalid buffer :0x%x\n",
+				hal_buffer);
 		buffer = 0;
 		break;
 	}
@@ -892,13 +892,13 @@
 	struct hal_session *session;
 
 	if (!sess || !pdata) {
-		dprintk(VIDC_ERR, "Invalid Params in ");
+		dprintk(VIDC_ERR, "Invalid Params");
 		return -EINVAL;
 	} else {
 		session = sess;
 	}
 
-	dprintk(VIDC_INFO, "IN func: , with property id: %d", ptype);
+	dprintk(VIDC_INFO, "in set_prop,with prop id: 0x%x", ptype);
 	pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
 	pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
 	pkt->session_id = (u32) session;
@@ -1238,11 +1238,11 @@
 	}
 	case HAL_PARAM_VENC_RATE_CONTROL:
 	{
-		u32 *rc_mode;
+		u32 *rc;
 		pkt->rg_property_data[0] =
 			HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
-		rc_mode = (u32 *)pdata;
-		switch ((enum hal_rate_control) *rc_mode) {
+		rc = (u32 *)pdata;
+		switch ((enum hal_rate_control) *rc) {
 		case HAL_RATE_CONTROL_OFF:
 		pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF;
 			break;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 66c3f2f..795024d 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -577,6 +577,8 @@
 		data_done.output_done.packet_buffer1 = pkt->packet_buffer;
 		data_done.output_done.extra_data_buffer =
 			pkt->extra_data_buffer;
+		dprintk(VIDC_DBG, "FBD: Received buf: %p, of len: %d\n",
+				   pkt->packet_buffer, pkt->filled_len);
 	} else if (is_decoder == 1) {
 		struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt =
 		(struct	hfi_msg_session_fbd_uncompressed_plane0_packet *)
@@ -731,6 +733,29 @@
 	device->callback(SESSION_END_DONE, &cmd_done);
 }
 
+static void hal_process_session_get_seq_hdr_done(struct hal_device *device,
+	struct hfi_msg_session_get_sequence_header_done_packet *pkt)
+{
+	struct msm_vidc_cb_data_done data_done;
+	if (!pkt || pkt->size !=
+		sizeof(struct
+		hfi_msg_session_get_sequence_header_done_packet)) {
+		dprintk(VIDC_ERR, "bad packet/packet size: %d", pkt->size);
+		return;
+	}
+	memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
+	data_done.device_id = device->device_id;
+	data_done.size = sizeof(struct msm_vidc_cb_data_done);
+	data_done.session_id =
+		((struct hal_session *) pkt->session_id)->session_id;
+	data_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+	data_done.output_done.packet_buffer1 = pkt->sequence_header;
+	data_done.output_done.filled_len1 = pkt->header_len;
+	dprintk(VIDC_INFO, "seq_hdr: %p, Length: %d",
+		   pkt->sequence_header, pkt->header_len);
+	device->callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
+}
+
 static void hal_process_msg_packet(struct hal_device *device,
 	struct vidc_hal_msg_pkt_hdr *msg_hdr)
 {
@@ -805,6 +830,11 @@
 			(struct hfi_msg_sys_release_resource_done_packet *)
 			msg_hdr);
 		break;
+	case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+		hal_process_session_get_seq_hdr_done(device, (struct
+			hfi_msg_session_get_sequence_header_done_packet
+			 *) msg_hdr);
+		break;
 	default:
 		dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
 		break;
@@ -815,7 +845,7 @@
 {
 	u8 packet[VIDC_IFACEQ_MED_PKT_SIZE];
 
-	dprintk(VIDC_INFO, "############vidc_hal_response_handler\n");
+	dprintk(VIDC_INFO, "#####vidc_hal_response_handler#####\n");
 	if (device) {
 		while (!vidc_hal_iface_msgq_read(device, packet)) {
 			hal_process_msg_packet(device,
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index a86798d..fe18a90 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1160,7 +1160,7 @@
 		*c |= MCI_CSPM_DATCMD;
 
 	/* Check if AUTO CMD19 is required or not? */
-	if (host->tuning_needed &&
+	if (host->tuning_needed && host->en_auto_cmd19 &&
 		!(host->mmc->ios.timing == MMC_TIMING_MMC_HS200)) {
 
 		/*
@@ -1176,7 +1176,9 @@
 			(cmd->opcode == MMC_READ_SINGLE_BLOCK ||
 			cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
 			msmsdcc_enable_cdr_cm_sdc4_dll(host);
-			*c |= MCI_CSPM_AUTO_CMD19;
+			if (host->en_auto_cmd19 &&
+			    host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
+				*c |= MCI_CSPM_AUTO_CMD19;
 		}
 	}
 
@@ -4814,6 +4816,42 @@
 	return count;
 }
 
+static inline void set_auto_cmd_setting(struct device *dev,
+					 const char *buf,
+					 bool is_cmd19)
+{
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct msmsdcc_host *host = mmc_priv(mmc);
+	unsigned int long flags;
+	int temp;
+
+	if (!kstrtou32(buf, 0, &temp)) {
+		spin_lock_irqsave(&host->lock, flags);
+		if (is_cmd19)
+			host->en_auto_cmd19 = !!temp;
+		spin_unlock_irqrestore(&host->lock, flags);
+	}
+}
+
+static ssize_t
+show_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct msmsdcc_host *host = mmc_priv(mmc);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", host->en_auto_cmd19);
+}
+
+static ssize_t
+store_enable_auto_cmd19(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	set_auto_cmd_setting(dev, buf, true);
+
+	return count;
+}
+
 #ifdef CONFIG_HAS_EARLYSUSPEND
 static void msmsdcc_early_suspend(struct early_suspend *h)
 {
@@ -5958,8 +5996,25 @@
 	ret = device_create_file(&pdev->dev, &host->idle_timeout);
 	if (ret)
 		goto remove_polling_file;
+
+	if (!is_auto_cmd19(host))
+		goto exit;
+
+	/* Sysfs entry for AUTO CMD19 control */
+	host->auto_cmd19_attr.show = show_enable_auto_cmd19;
+	host->auto_cmd19_attr.store = store_enable_auto_cmd19;
+	sysfs_attr_init(&host->auto_cmd19_attr.attr);
+	host->auto_cmd19_attr.attr.name = "enable_auto_cmd19";
+	host->auto_cmd19_attr.attr.mode = S_IRUGO | S_IWUSR;
+	ret = device_create_file(&pdev->dev, &host->auto_cmd19_attr);
+	if (ret)
+		goto remove_idle_timeout_file;
+
+ exit:
 	return 0;
 
+ remove_idle_timeout_file:
+	device_remove_file(&pdev->dev, &host->idle_timeout);
  remove_polling_file:
 	if (!plat->status_irq)
 		device_remove_file(&pdev->dev, &host->polling);
@@ -6040,6 +6095,8 @@
 	DBG(host, "Removing SDCC device = %d\n", pdev->id);
 	plat = host->plat;
 
+	if (is_auto_cmd19(host))
+		device_remove_file(&pdev->dev, &host->auto_cmd19_attr);
 	device_remove_file(&pdev->dev, &host->max_bus_bw);
 	if (!plat->status_irq)
 		device_remove_file(&pdev->dev, &host->polling);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 236785d..30b1908 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -401,6 +401,7 @@
 	bool io_pad_pwr_switch;
 	bool tuning_in_progress;
 	bool tuning_needed;
+	bool en_auto_cmd19;
 	bool sdio_gpio_lpm;
 	bool irq_wake_enabled;
 	struct pm_qos_request pm_qos_req_dma;
@@ -417,6 +418,7 @@
 	struct device_attribute	max_bus_bw;
 	struct device_attribute	polling;
 	struct device_attribute idle_timeout;
+	struct device_attribute auto_cmd19_attr;
 };
 
 #define MSMSDCC_VERSION_MASK	0xFFFF
@@ -429,6 +431,7 @@
 #define MSMSDCC_SW_RST_CFG	(1 << 6)
 #define MSMSDCC_WAIT_FOR_TX_RX	(1 << 7)
 #define MSMSDCC_IO_PAD_PWR_SWITCH	(1 << 8)
+#define MSMSDCC_AUTO_CMD19	(1 << 9)
 
 #define set_hw_caps(h, val)		((h)->hw_caps |= val)
 #define is_sps_mode(h)			((h)->hw_caps & MSMSDCC_SPS_BAM_SUP)
@@ -440,6 +443,7 @@
 #define is_sw_reset_save_config(h)	((h)->hw_caps & MSMSDCC_SW_RST_CFG)
 #define is_wait_for_tx_rx_active(h)	((h)->hw_caps & MSMSDCC_WAIT_FOR_TX_RX)
 #define is_io_pad_pwr_switch(h)	((h)->hw_caps & MSMSDCC_IO_PAD_PWR_SWITCH)
+#define is_auto_cmd19(h)		((h)->hw_caps & MSMSDCC_AUTO_CMD19)
 
 /* Set controller capabilities based on version */
 static inline void set_default_hw_caps(struct msmsdcc_host *host)
@@ -459,7 +463,8 @@
 	if (version) /* SDCC v4 and greater */
 		host->hw_caps |= MSMSDCC_AUTO_PROG_DONE |
 			MSMSDCC_SOFT_RESET | MSMSDCC_REG_WR_ACTIVE
-			| MSMSDCC_WAIT_FOR_TX_RX | MSMSDCC_IO_PAD_PWR_SWITCH;
+			| MSMSDCC_WAIT_FOR_TX_RX | MSMSDCC_IO_PAD_PWR_SWITCH
+			| MSMSDCC_AUTO_CMD19;
 
 	if (version >= 0x2D) /* SDCC v4 2.1.0 and greater */
 		host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_SW_RST_CFG;
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 914f4fb..9b8ab39 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -295,7 +295,7 @@
 
 config WCNSS_CORE
 	tristate "Qualcomm WCNSS CORE driver"
-	depends on ARCH_MSM8960
+	depends on (ARCH_MSM8960 || ARCH_MSM8974)
 	select WIRELESS_EXT
 	select WEXT_PRIV
 	select WEXT_CORE
@@ -303,6 +303,12 @@
 	---help---
 	  Core driver for the Qualcomm WCNSS triple play connectivity subsystem
 
+config WCNSS_CORE_PRONTO
+	tristate "Qualcomm WCNSS Pronto Support"
+	depends on WCNSS_CORE
+	---help---
+	  Pronto Support for the Qualcomm WCNSS triple play connectivity subsystem
+
 source "drivers/net/wireless/ath/Kconfig"
 source "drivers/net/wireless/b43/Kconfig"
 source "drivers/net/wireless/b43legacy/Kconfig"
diff --git a/drivers/net/wireless/wcnss/Makefile b/drivers/net/wireless/wcnss/Makefile
index c077848..11fa673 100644
--- a/drivers/net/wireless/wcnss/Makefile
+++ b/drivers/net/wireless/wcnss/Makefile
@@ -1,6 +1,6 @@
 
 # Makefile for WCNSS triple-play driver
 
-wcnsscore-objs += wcnss_wlan.o wcnss_riva.o qcomwlan_secif.o
+wcnsscore-objs += wcnss_wlan.o qcomwlan_secif.o wcnss_vreg.o
 
 obj-$(CONFIG_WCNSS_CORE) += wcnsscore.o
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
deleted file mode 100644
index 2d9ad82..0000000
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- *
- * This 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/slab.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/regulator/consumer.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
-#include <linux/mfd/pm8xxx/gpio.h>
-#include <linux/wcnss_wlan.h>
-#include <linux/semaphore.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <mach/msm_xo.h>
-#include <mach/msm_iomap.h>
-
-
-static void __iomem *msm_riva_base;
-static struct msm_xo_voter *wlan_clock;
-static const char *id = "WLAN";
-static LIST_HEAD(power_on_lock_list);
-static DEFINE_MUTEX(list_lock);
-static DEFINE_SEMAPHORE(riva_power_on_lock);
-
-#define MSM_RIVA_PHYS                     0x03204000
-#define RIVA_PMU_CFG                      (msm_riva_base + 0x28)
-#define RIVA_PMU_CFG_IRIS_XO_CFG          BIT(3)
-#define RIVA_PMU_CFG_IRIS_XO_EN           BIT(4)
-#define RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP   BIT(5)
-#define RIVA_PMU_CFG_IRIS_XO_CFG_STS      BIT(6) /* 1: in progress, 0: done */
-
-#define RIVA_PMU_CFG_IRIS_XO_MODE         0x6
-#define RIVA_PMU_CFG_IRIS_XO_MODE_48      (3 << 1)
-
-#define VREG_NULL_CONFIG            0x0000
-#define VREG_GET_REGULATOR_MASK     0x0001
-#define VREG_SET_VOLTAGE_MASK       0x0002
-#define VREG_OPTIMUM_MODE_MASK      0x0004
-#define VREG_ENABLE_MASK            0x0008
-
-struct vregs_info {
-	const char * const name;
-	int state;
-	const int nominal_min;
-	const int low_power_min;
-	const int max_voltage;
-	const int uA_load;
-	struct regulator *regulator;
-};
-
-static struct vregs_info iris_vregs[] = {
-	{"iris_vddxo",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000,  NULL},
-	{"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
-	{"iris_vddpa",  VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
-	{"iris_vdddig", VREG_NULL_CONFIG, 1200000, 0, 1225000, 10000,  NULL},
-};
-
-static struct vregs_info riva_vregs[] = {
-	{"riva_vddmx",  VREG_NULL_CONFIG, 1050000, 0, 1150000, 0,      NULL},
-	{"riva_vddcx",  VREG_NULL_CONFIG, 1050000, 0, 1150000, 0,      NULL},
-	{"riva_vddpx",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 0,      NULL},
-};
-
-struct host_driver {
-	char name[20];
-	struct list_head list;
-};
-
-
-static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
-{
-	u32 reg = 0;
-	int rc = 0;
-	struct clk *cxo = clk_get(dev, "cxo");
-	if (IS_ERR(cxo)) {
-		pr_err("Couldn't get cxo clock\n");
-		return PTR_ERR(cxo);
-	}
-
-	if (on) {
-		msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
-		if (!msm_riva_base) {
-			pr_err("ioremap MSM_RIVA_PHYS failed\n");
-			goto fail;
-		}
-
-		/* Enable IRIS XO */
-		rc = clk_prepare_enable(cxo);
-		if (rc) {
-			pr_err("cxo enable failed\n");
-			goto fail;
-		}
-		writel_relaxed(0, RIVA_PMU_CFG);
-		reg = readl_relaxed(RIVA_PMU_CFG);
-		reg |= RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
-				RIVA_PMU_CFG_IRIS_XO_EN;
-		writel_relaxed(reg, RIVA_PMU_CFG);
-
-		/* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
-		reg &= ~(RIVA_PMU_CFG_IRIS_XO_MODE);
-
-		if (use_48mhz_xo)
-			reg |= RIVA_PMU_CFG_IRIS_XO_MODE_48;
-
-		writel_relaxed(reg, RIVA_PMU_CFG);
-
-		/* Start IRIS XO configuration */
-		reg |= RIVA_PMU_CFG_IRIS_XO_CFG;
-		writel_relaxed(reg, RIVA_PMU_CFG);
-
-		/* Wait for XO configuration to finish */
-		while (readl_relaxed(RIVA_PMU_CFG) &
-						RIVA_PMU_CFG_IRIS_XO_CFG_STS)
-			cpu_relax();
-
-		/* Stop IRIS XO configuration */
-		reg &= ~(RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
-				RIVA_PMU_CFG_IRIS_XO_CFG);
-		writel_relaxed(reg, RIVA_PMU_CFG);
-		clk_disable_unprepare(cxo);
-
-		if (!use_48mhz_xo) {
-			wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
-			if (IS_ERR(wlan_clock)) {
-				rc = PTR_ERR(wlan_clock);
-				pr_err("Failed to get MSM_XO_TCXO_A2 voter"
-							" (%d)\n", rc);
-				goto fail;
-			}
-
-			rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_ON);
-			if (rc < 0) {
-				pr_err("Configuring MSM_XO_MODE_ON failed"
-							" (%d)\n", rc);
-				goto msm_xo_vote_fail;
-			}
-		}
-	}  else {
-		if (wlan_clock != NULL && !use_48mhz_xo) {
-			rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF);
-			if (rc < 0)
-				pr_err("Configuring MSM_XO_MODE_OFF failed"
-							" (%d)\n", rc);
-		}
-	}
-
-	/* Add some delay for XO to settle */
-	msleep(20);
-
-	clk_put(cxo);
-	return rc;
-
-msm_xo_vote_fail:
-	msm_xo_put(wlan_clock);
-
-fail:
-	clk_put(cxo);
-	return rc;
-}
-
-/* Helper routine to turn off all WCNSS vregs e.g. IRIS, Riva */
-static void wcnss_vregs_off(struct vregs_info regulators[], uint size)
-{
-	int i, rc = 0;
-
-	/* Regulators need to be turned off in the reverse order */
-	for (i = (size-1); i >= 0; i--) {
-		if (regulators[i].state == VREG_NULL_CONFIG)
-			continue;
-
-		/* Remove PWM mode */
-		if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
-			rc = regulator_set_optimum_mode(
-					regulators[i].regulator, 0);
-			if (rc < 0)
-				pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
-						regulators[i].name, rc);
-		}
-
-		/* Set voltage to lowest level */
-		if (regulators[i].state & VREG_SET_VOLTAGE_MASK) {
-			rc = regulator_set_voltage(regulators[i].regulator,
-					regulators[i].low_power_min,
-					regulators[i].max_voltage);
-			if (rc)
-				pr_err("regulator_set_voltage(%s) failed (%d)\n",
-						regulators[i].name, rc);
-		}
-
-		/* Disable regulator */
-		if (regulators[i].state & VREG_ENABLE_MASK) {
-			rc = regulator_disable(regulators[i].regulator);
-			if (rc < 0)
-				pr_err("vreg %s disable failed (%d)\n",
-						regulators[i].name, rc);
-		}
-
-		/* Free the regulator source */
-		if (regulators[i].state & VREG_GET_REGULATOR_MASK)
-			regulator_put(regulators[i].regulator);
-
-		regulators[i].state = VREG_NULL_CONFIG;
-	}
-}
-
-/* Common helper routine to turn on all WCNSS vregs e.g. IRIS, Riva */
-static int wcnss_vregs_on(struct device *dev,
-		struct vregs_info regulators[], uint size)
-{
-	int i, rc = 0, reg_cnt;
-
-	for (i = 0; i < size; i++) {
-			/* Get regulator source */
-		regulators[i].regulator =
-			regulator_get(dev, regulators[i].name);
-		if (IS_ERR(regulators[i].regulator)) {
-			rc = PTR_ERR(regulators[i].regulator);
-				pr_err("regulator get of %s failed (%d)\n",
-					regulators[i].name, rc);
-				goto fail;
-		}
-		regulators[i].state |= VREG_GET_REGULATOR_MASK;
-		reg_cnt = regulator_count_voltages(regulators[i].regulator);
-		/* Set voltage to nominal. Exclude swtiches e.g. LVS */
-		if ((regulators[i].nominal_min || regulators[i].max_voltage)
-				&& (reg_cnt > 0)) {
-			rc = regulator_set_voltage(regulators[i].regulator,
-					regulators[i].nominal_min,
-					regulators[i].max_voltage);
-			if (rc) {
-				pr_err("regulator_set_voltage(%s) failed (%d)\n",
-						regulators[i].name, rc);
-				goto fail;
-			}
-			regulators[i].state |= VREG_SET_VOLTAGE_MASK;
-		}
-
-		/* Vote for PWM/PFM mode if needed */
-		if (regulators[i].uA_load && (reg_cnt > 0)) {
-			rc = regulator_set_optimum_mode(regulators[i].regulator,
-					regulators[i].uA_load);
-			if (rc < 0) {
-				pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
-						regulators[i].name, rc);
-				goto fail;
-			}
-			regulators[i].state |= VREG_OPTIMUM_MODE_MASK;
-		}
-
-		/* Enable the regulator */
-		rc = regulator_enable(regulators[i].regulator);
-		if (rc) {
-			pr_err("vreg %s enable failed (%d)\n",
-				regulators[i].name, rc);
-			goto fail;
-		}
-		regulators[i].state |= VREG_ENABLE_MASK;
-	}
-
-	return rc;
-
-fail:
-	wcnss_vregs_off(regulators, size);
-	return rc;
-
-}
-
-static void wcnss_iris_vregs_off(void)
-{
-	wcnss_vregs_off(iris_vregs, ARRAY_SIZE(iris_vregs));
-}
-
-static int wcnss_iris_vregs_on(struct device *dev)
-{
-	return wcnss_vregs_on(dev, iris_vregs, ARRAY_SIZE(iris_vregs));
-}
-
-static void wcnss_riva_vregs_off(void)
-{
-	wcnss_vregs_off(riva_vregs, ARRAY_SIZE(riva_vregs));
-}
-
-static int wcnss_riva_vregs_on(struct device *dev)
-{
-	return wcnss_vregs_on(dev, riva_vregs, ARRAY_SIZE(riva_vregs));
-}
-
-int wcnss_wlan_power(struct device *dev,
-		struct wcnss_wlan_config *cfg,
-		enum wcnss_opcode on)
-{
-	int rc = 0;
-
-	if (on) {
-		down(&riva_power_on_lock);
-		/* RIVA regulator settings */
-		rc = wcnss_riva_vregs_on(dev);
-		if (rc)
-			goto fail_riva_on;
-
-		/* IRIS regulator settings */
-		rc = wcnss_iris_vregs_on(dev);
-		if (rc)
-			goto fail_iris_on;
-
-		/* Configure IRIS XO */
-		rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
-				WCNSS_WLAN_SWITCH_ON);
-		if (rc)
-			goto fail_iris_xo;
-		up(&riva_power_on_lock);
-
-	} else {
-		configure_iris_xo(dev, cfg->use_48mhz_xo,
-				WCNSS_WLAN_SWITCH_OFF);
-		wcnss_iris_vregs_off();
-		wcnss_riva_vregs_off();
-	}
-
-	return rc;
-
-fail_iris_xo:
-	wcnss_iris_vregs_off();
-
-fail_iris_on:
-	wcnss_riva_vregs_off();
-
-fail_riva_on:
-	up(&riva_power_on_lock);
-	return rc;
-}
-EXPORT_SYMBOL(wcnss_wlan_power);
-
-/*
- * During SSR Riva should not be 'powered on' until all the host drivers
- * finish their shutdown routines.  Host drivers use below APIs to
- * synchronize power-on. Riva will not be 'powered on' until all the
- * requests(to lock power-on) are freed.
- */
-int req_riva_power_on_lock(char *driver_name)
-{
-	struct host_driver *node;
-
-	if (!driver_name)
-		goto err;
-
-	node = kmalloc(sizeof(struct host_driver), GFP_KERNEL);
-	if (!node)
-		goto err;
-	strncpy(node->name, driver_name, sizeof(node->name));
-
-	mutex_lock(&list_lock);
-	/* Lock when the first request is added */
-	if (list_empty(&power_on_lock_list))
-		down(&riva_power_on_lock);
-	list_add(&node->list, &power_on_lock_list);
-	mutex_unlock(&list_lock);
-
-	return 0;
-
-err:
-	return -EINVAL;
-}
-EXPORT_SYMBOL(req_riva_power_on_lock);
-
-int free_riva_power_on_lock(char *driver_name)
-{
-	int ret = -1;
-	struct host_driver *node;
-
-	mutex_lock(&list_lock);
-	list_for_each_entry(node, &power_on_lock_list, list) {
-		if (!strncmp(node->name, driver_name, sizeof(node->name))) {
-			list_del(&node->list);
-			kfree(node);
-			ret = 0;
-			break;
-		}
-	}
-	/* unlock when the last host driver frees the lock */
-	if (list_empty(&power_on_lock_list))
-		up(&riva_power_on_lock);
-	mutex_unlock(&list_lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(free_riva_power_on_lock);
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
new file mode 100644
index 0000000..01b27dd
--- /dev/null
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -0,0 +1,503 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/gpio.h>
+#include <linux/wcnss_wlan.h>
+#include <linux/semaphore.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <mach/msm_xo.h>
+#include <mach/msm_iomap.h>
+
+
+static void __iomem *msm_wcnss_base;
+static struct msm_xo_voter *wlan_clock;
+static const char *id = "WLAN";
+static LIST_HEAD(power_on_lock_list);
+static DEFINE_MUTEX(list_lock);
+static DEFINE_SEMAPHORE(wcnss_power_on_lock);
+
+#define MSM_RIVA_PHYS           0x03204000
+#define MSM_PRONTO_PHYS         0xfb21b000
+
+#define RIVA_PMU_OFFSET         0x28
+#define PRONTO_PMU_OFFSET       0x1004
+
+#define WCNSS_PMU_CFG_IRIS_XO_CFG          BIT(3)
+#define WCNSS_PMU_CFG_IRIS_XO_EN           BIT(4)
+#define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP   BIT(5)
+#define WCNSS_PMU_CFG_IRIS_XO_CFG_STS      BIT(6) /* 1: in progress, 0: done */
+
+#define WCNSS_PMU_CFG_IRIS_XO_MODE         0x6
+#define WCNSS_PMU_CFG_IRIS_XO_MODE_48      (3 << 1)
+
+#define VREG_NULL_CONFIG            0x0000
+#define VREG_GET_REGULATOR_MASK     0x0001
+#define VREG_SET_VOLTAGE_MASK       0x0002
+#define VREG_OPTIMUM_MODE_MASK      0x0004
+#define VREG_ENABLE_MASK            0x0008
+
+struct vregs_info {
+	const char * const name;
+	int state;
+	const int nominal_min;
+	const int low_power_min;
+	const int max_voltage;
+	const int uA_load;
+	struct regulator *regulator;
+};
+
+/* IRIS regulators for Riva hardware */
+static struct vregs_info iris_vregs_riva[] = {
+	{"iris_vddxo",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000,  NULL},
+	{"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
+	{"iris_vddpa",  VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
+	{"iris_vdddig", VREG_NULL_CONFIG, 1200000, 0, 1225000, 10000,  NULL},
+};
+
+/* WCNSS regulators for Riva hardware */
+static struct vregs_info riva_vregs[] = {
+	/* Riva */
+	{"riva_vddmx",  VREG_NULL_CONFIG, 1050000, 0, 1150000, 0,      NULL},
+	{"riva_vddcx",  VREG_NULL_CONFIG, 1050000, 0, 1150000, 0,      NULL},
+	{"riva_vddpx",  VREG_NULL_CONFIG, 1800000, 0, 1800000, 0,      NULL},
+};
+
+/* IRIS regulators for Pronto hardware */
+static struct vregs_info iris_vregs_pronto[] = {
+	{"qcom,iris-vddxo",  VREG_NULL_CONFIG, 1800000, 0,
+		1800000, 10000,  NULL},
+	{"qcom,iris-vddrfa", VREG_NULL_CONFIG, 1300000, 0,
+		1300000, 100000, NULL},
+	{"qcom,iris-vddpa",  VREG_NULL_CONFIG, 2900000, 0,
+		3000000, 515000, NULL},
+	{"qcom,iris-vdddig", VREG_NULL_CONFIG, 1225000, 0,
+		1225000, 10000,  NULL},
+};
+
+/* WCNSS regulators for Pronto hardware */
+static struct vregs_info pronto_vregs[] = {
+	{"qcom,pronto-vddmx",  VREG_NULL_CONFIG, 950000,  0,
+		1150000, 0,    NULL},
+	{"qcom,pronto-vddcx",  VREG_NULL_CONFIG, 900000,  0,
+		1150000, 0,    NULL},
+	{"qcom,pronto-vddpx",  VREG_NULL_CONFIG, 1800000, 0,
+		1800000, 0,    NULL},
+};
+
+
+struct host_driver {
+	char name[20];
+	struct list_head list;
+};
+
+
+static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
+{
+	u32 reg = 0;
+	int rc = 0;
+	int size = 0;
+	int pmu_offset = 0;
+	unsigned long wcnss_phys_addr;
+	void __iomem *pmu_conf_reg;
+	struct clk *clk;
+
+	if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
+		wcnss_phys_addr = MSM_PRONTO_PHYS;
+		pmu_offset = PRONTO_PMU_OFFSET;
+		size = 0x3000;
+
+		clk = clk_get(dev, "xo");
+		if (IS_ERR(clk)) {
+			pr_err("Couldn't get xo clock\n");
+			return PTR_ERR(clk);
+		}
+	} else {
+		wcnss_phys_addr = MSM_RIVA_PHYS;
+		pmu_offset = RIVA_PMU_OFFSET;
+		size = SZ_256;
+
+		clk = clk_get(dev, "cxo");
+		if (IS_ERR(clk)) {
+			pr_err("Couldn't get cxo clock\n");
+			return PTR_ERR(clk);
+		}
+	}
+
+	if (on) {
+		msm_wcnss_base = ioremap(wcnss_phys_addr, size);
+		if (!msm_wcnss_base) {
+			pr_err("ioremap wcnss physical failed\n");
+			goto fail;
+		}
+		pmu_conf_reg = msm_wcnss_base + pmu_offset;
+
+		/* Enable IRIS XO */
+		rc = clk_prepare_enable(clk);
+		if (rc) {
+			pr_err("clk enable failed\n");
+			goto fail;
+		}
+		writel_relaxed(0, pmu_conf_reg);
+		reg = readl_relaxed(pmu_conf_reg);
+		reg |= WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
+				WCNSS_PMU_CFG_IRIS_XO_EN;
+		writel_relaxed(reg, pmu_conf_reg);
+
+		/* Clear XO_MODE[b2:b1] bits. Clear implies 19.2 MHz TCXO */
+		reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
+
+		if (use_48mhz_xo)
+			reg |= WCNSS_PMU_CFG_IRIS_XO_MODE_48;
+
+		writel_relaxed(reg, pmu_conf_reg);
+
+		/* Start IRIS XO configuration */
+		reg |= WCNSS_PMU_CFG_IRIS_XO_CFG;
+		writel_relaxed(reg, pmu_conf_reg);
+
+		/* Wait for XO configuration to finish */
+		while (readl_relaxed(pmu_conf_reg) &
+						WCNSS_PMU_CFG_IRIS_XO_CFG_STS)
+			cpu_relax();
+
+		/* Stop IRIS XO configuration */
+		reg &= ~(WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
+				WCNSS_PMU_CFG_IRIS_XO_CFG);
+		writel_relaxed(reg, pmu_conf_reg);
+		clk_disable_unprepare(clk);
+
+		if (!use_48mhz_xo) {
+			wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
+			if (IS_ERR(wlan_clock)) {
+				rc = PTR_ERR(wlan_clock);
+				pr_err("Failed to get MSM_XO_TCXO_A2 voter (%d)\n",
+						rc);
+				goto fail;
+			}
+
+			rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_ON);
+			if (rc < 0) {
+				pr_err("Configuring MSM_XO_MODE_ON failed (%d)\n",
+						rc);
+				goto msm_xo_vote_fail;
+			}
+		}
+	}  else {
+		if (wlan_clock != NULL && !use_48mhz_xo) {
+			rc = msm_xo_mode_vote(wlan_clock, MSM_XO_MODE_OFF);
+			if (rc < 0)
+				pr_err("Configuring MSM_XO_MODE_OFF failed (%d)\n",
+						rc);
+		}
+	}
+
+	/* Add some delay for XO to settle */
+	msleep(20);
+
+	clk_put(clk);
+	return rc;
+
+msm_xo_vote_fail:
+	msm_xo_put(wlan_clock);
+
+fail:
+	clk_put(clk);
+	return rc;
+}
+
+/* Helper routine to turn off all WCNSS & IRIS vregs */
+static void wcnss_vregs_off(struct vregs_info regulators[], uint size)
+{
+	int i, rc = 0;
+
+	/* Regulators need to be turned off in the reverse order */
+	for (i = (size-1); i >= 0; i--) {
+		if (regulators[i].state == VREG_NULL_CONFIG)
+			continue;
+
+		/* Remove PWM mode */
+		if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
+			rc = regulator_set_optimum_mode(
+					regulators[i].regulator, 0);
+			if (rc < 0)
+				pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
+						regulators[i].name, rc);
+		}
+
+		/* Set voltage to lowest level */
+		if (regulators[i].state & VREG_SET_VOLTAGE_MASK) {
+			rc = regulator_set_voltage(regulators[i].regulator,
+					regulators[i].low_power_min,
+					regulators[i].max_voltage);
+			if (rc)
+				pr_err("regulator_set_voltage(%s) failed (%d)\n",
+						regulators[i].name, rc);
+		}
+
+		/* Disable regulator */
+		if (regulators[i].state & VREG_ENABLE_MASK) {
+			rc = regulator_disable(regulators[i].regulator);
+			if (rc < 0)
+				pr_err("vreg %s disable failed (%d)\n",
+						regulators[i].name, rc);
+		}
+
+		/* Free the regulator source */
+		if (regulators[i].state & VREG_GET_REGULATOR_MASK)
+			regulator_put(regulators[i].regulator);
+
+		regulators[i].state = VREG_NULL_CONFIG;
+	}
+}
+
+/* Common helper routine to turn on all WCNSS & IRIS vregs */
+static int wcnss_vregs_on(struct device *dev,
+		struct vregs_info regulators[], uint size)
+{
+	int i, rc = 0, reg_cnt;
+
+	for (i = 0; i < size; i++) {
+			/* Get regulator source */
+		regulators[i].regulator =
+			regulator_get(dev, regulators[i].name);
+		if (IS_ERR(regulators[i].regulator)) {
+			rc = PTR_ERR(regulators[i].regulator);
+				pr_err("regulator get of %s failed (%d)\n",
+					regulators[i].name, rc);
+				goto fail;
+		}
+		regulators[i].state |= VREG_GET_REGULATOR_MASK;
+		reg_cnt = regulator_count_voltages(regulators[i].regulator);
+		/* Set voltage to nominal. Exclude swtiches e.g. LVS */
+		if ((regulators[i].nominal_min || regulators[i].max_voltage)
+				&& (reg_cnt > 0)) {
+			rc = regulator_set_voltage(regulators[i].regulator,
+					regulators[i].nominal_min,
+					regulators[i].max_voltage);
+			if (rc) {
+				pr_err("regulator_set_voltage(%s) failed (%d)\n",
+						regulators[i].name, rc);
+				goto fail;
+			}
+			regulators[i].state |= VREG_SET_VOLTAGE_MASK;
+		}
+
+		/* Vote for PWM/PFM mode if needed */
+		if (regulators[i].uA_load && (reg_cnt > 0)) {
+			rc = regulator_set_optimum_mode(regulators[i].regulator,
+					regulators[i].uA_load);
+			if (rc < 0) {
+				pr_err("regulator_set_optimum_mode(%s) failed (%d)\n",
+						regulators[i].name, rc);
+				goto fail;
+			}
+			regulators[i].state |= VREG_OPTIMUM_MODE_MASK;
+		}
+
+		/* Enable the regulator */
+		rc = regulator_enable(regulators[i].regulator);
+		if (rc) {
+			pr_err("vreg %s enable failed (%d)\n",
+				regulators[i].name, rc);
+			goto fail;
+		}
+		regulators[i].state |= VREG_ENABLE_MASK;
+	}
+
+	return rc;
+
+fail:
+	wcnss_vregs_off(regulators, size);
+	return rc;
+
+}
+
+static void wcnss_iris_vregs_off(enum wcnss_hw_type hw_type)
+{
+	switch (hw_type) {
+	case WCNSS_RIVA_HW:
+		wcnss_vregs_off(iris_vregs_riva, ARRAY_SIZE(iris_vregs_riva));
+		break;
+	case WCNSS_PRONTO_HW:
+		wcnss_vregs_off(iris_vregs_pronto,
+				ARRAY_SIZE(iris_vregs_pronto));
+		break;
+	default:
+		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+
+	}
+}
+
+static int wcnss_iris_vregs_on(struct device *dev, enum wcnss_hw_type hw_type)
+{
+	int ret = -1;
+
+	switch (hw_type) {
+	case WCNSS_RIVA_HW:
+		ret = wcnss_vregs_on(dev, iris_vregs_riva,
+				ARRAY_SIZE(iris_vregs_riva));
+		break;
+	case WCNSS_PRONTO_HW:
+		ret = wcnss_vregs_on(dev, iris_vregs_pronto,
+				ARRAY_SIZE(iris_vregs_pronto));
+		break;
+	default:
+		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+	}
+	return ret;
+}
+
+static void wcnss_core_vregs_off(enum wcnss_hw_type hw_type)
+{
+	switch (hw_type) {
+	case WCNSS_RIVA_HW:
+		wcnss_vregs_off(riva_vregs, ARRAY_SIZE(riva_vregs));
+		break;
+	case WCNSS_PRONTO_HW:
+		wcnss_vregs_off(pronto_vregs, ARRAY_SIZE(pronto_vregs));
+		break;
+	default:
+		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+	}
+
+}
+
+static int wcnss_core_vregs_on(struct device *dev, enum wcnss_hw_type hw_type)
+{
+	int ret = -1;
+
+	switch (hw_type) {
+	case WCNSS_RIVA_HW:
+		ret = wcnss_vregs_on(dev, riva_vregs, ARRAY_SIZE(riva_vregs));
+		break;
+	case WCNSS_PRONTO_HW:
+		ret = wcnss_vregs_on(dev, pronto_vregs,
+				ARRAY_SIZE(pronto_vregs));
+		break;
+	default:
+		pr_err("%s invalid hardware %d\n", __func__, hw_type);
+	}
+
+	return ret;
+
+}
+
+int wcnss_wlan_power(struct device *dev,
+		struct wcnss_wlan_config *cfg,
+		enum wcnss_opcode on)
+{
+	int rc = 0;
+	enum wcnss_hw_type hw_type = wcnss_hardware_type();
+
+	if (on) {
+		down(&wcnss_power_on_lock);
+		/* RIVA regulator settings */
+		rc = wcnss_core_vregs_on(dev, hw_type);
+		if (rc)
+			goto fail_wcnss_on;
+
+		/* IRIS regulator settings */
+		rc = wcnss_iris_vregs_on(dev, hw_type);
+		if (rc)
+			goto fail_iris_on;
+
+		/* Configure IRIS XO */
+		rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
+				WCNSS_WLAN_SWITCH_ON);
+		if (rc)
+			goto fail_iris_xo;
+		up(&wcnss_power_on_lock);
+
+	} else {
+		configure_iris_xo(dev, cfg->use_48mhz_xo,
+				WCNSS_WLAN_SWITCH_OFF);
+		wcnss_iris_vregs_off(hw_type);
+		wcnss_core_vregs_off(hw_type);
+	}
+
+	return rc;
+
+fail_iris_xo:
+	wcnss_iris_vregs_off(hw_type);
+
+fail_iris_on:
+	wcnss_core_vregs_off(hw_type);
+
+fail_wcnss_on:
+	up(&wcnss_power_on_lock);
+	return rc;
+}
+EXPORT_SYMBOL(wcnss_wlan_power);
+
+/*
+ * During SSR WCNSS should not be 'powered on' until all the host drivers
+ * finish their shutdown routines.  Host drivers use below APIs to
+ * synchronize power-on. WCNSS will not be 'powered on' until all the
+ * requests(to lock power-on) are freed.
+ */
+int wcnss_req_power_on_lock(char *driver_name)
+{
+	struct host_driver *node;
+
+	if (!driver_name)
+		goto err;
+
+	node = kmalloc(sizeof(struct host_driver), GFP_KERNEL);
+	if (!node)
+		goto err;
+	strlcpy(node->name, driver_name, sizeof(node->name));
+
+	mutex_lock(&list_lock);
+	/* Lock when the first request is added */
+	if (list_empty(&power_on_lock_list))
+		down(&wcnss_power_on_lock);
+	list_add(&node->list, &power_on_lock_list);
+	mutex_unlock(&list_lock);
+
+	return 0;
+
+err:
+	return -EINVAL;
+}
+EXPORT_SYMBOL(wcnss_req_power_on_lock);
+
+int wcnss_free_power_on_lock(char *driver_name)
+{
+	int ret = -1;
+	struct host_driver *node;
+
+	mutex_lock(&list_lock);
+	list_for_each_entry(node, &power_on_lock_list, list) {
+		if (!strncmp(node->name, driver_name, sizeof(node->name))) {
+			list_del(&node->list);
+			kfree(node);
+			ret = 0;
+			break;
+		}
+	}
+	/* unlock when the last host driver frees the lock */
+	if (list_empty(&power_on_lock_list))
+		up(&wcnss_power_on_lock);
+	mutex_unlock(&list_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(wcnss_free_power_on_lock);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 633809a..e83b195 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -23,6 +23,8 @@
 #include <linux/gpio.h>
 #include <linux/wakelock.h>
 #include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <mach/peripheral-loader.h>
 #include <mach/msm_smd.h>
 
@@ -76,6 +78,7 @@
 	unsigned char	wcnss_version[WCNSS_VERSION_LEN];
 	unsigned int	serial_number;
 	int		thermal_mitigation;
+	enum wcnss_hw_type	wcnss_hw_type;
 	void		(*tm_notify)(struct device *, int);
 	struct wcnss_wlan_config wlan_config;
 	struct delayed_work wcnss_work;
@@ -225,11 +228,42 @@
 
 static void wcnss_post_bootup(struct work_struct *work)
 {
-	pr_info("%s: Cancel APPS vote for Iris & Riva\n", __func__);
+	pr_info("%s: Cancel APPS vote for Iris & WCNSS\n", __func__);
 
-	/* Since Riva is up, cancel any APPS vote for Iris & Riva VREGs  */
+	/* Since WCNSS is up, cancel any APPS vote for Iris & WCNSS VREGs  */
 	wcnss_wlan_power(&penv->pdev->dev, &penv->wlan_config,
 		WCNSS_WLAN_SWITCH_OFF);
+
+}
+
+static int
+wcnss_pronto_gpios_config(struct device *dev, bool enable)
+{
+	int rc = 0;
+	int i, j;
+	int WCNSS_WLAN_NUM_GPIOS = 5;
+
+	for (i = 0; i < WCNSS_WLAN_NUM_GPIOS; i++) {
+		int gpio = of_get_gpio(dev->of_node, i);
+		if (enable) {
+			rc = gpio_request(gpio, "wcnss_wlan");
+			if (rc) {
+				pr_err("WCNSS gpio_request %d err %d\n",
+					gpio, rc);
+				goto fail;
+			}
+		} else
+			gpio_free(gpio);
+	}
+
+	return rc;
+
+fail:
+	for (j = WCNSS_WLAN_NUM_GPIOS-1; j >= 0; j--) {
+		int gpio = of_get_gpio(dev->of_node, i);
+		gpio_free(gpio);
+	}
+	return rc;
 }
 
 static int
@@ -469,6 +503,15 @@
 }
 EXPORT_SYMBOL(wcnss_allow_suspend);
 
+int wcnss_hardware_type(void)
+{
+	if (penv)
+		return penv->wcnss_hw_type;
+	else
+		return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_hardware_type);
+
 static int wcnss_smd_tx(void *data, int len)
 {
 	int ret = 0;
@@ -551,6 +594,8 @@
 {
 	int ret;
 	struct qcom_wcnss_opts *pdata;
+	int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
+									"qcom,has_pronto_hw");
 
 	/* make sure we are only triggered once */
 	if (penv->triggered)
@@ -559,25 +604,36 @@
 
 	/* initialize the WCNSS device configuration */
 	pdata = pdev->dev.platform_data;
-	if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo)
-		has_48mhz_xo = pdata->has_48mhz_xo;
+	if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) {
+		if (has_pronto_hw) {
+			has_48mhz_xo = of_property_read_bool(pdev->dev.of_node,
+										"qcom,has_48mhz_xo");
+			penv->wcnss_hw_type = WCNSS_PRONTO_HW;
+		} else {
+			penv->wcnss_hw_type = WCNSS_RIVA_HW;
+			has_48mhz_xo = pdata->has_48mhz_xo;
+		}
+	}
 	penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
 
 	penv->thermal_mitigation = 0;
 	strlcpy(penv->wcnss_version, "INVALID", WCNSS_VERSION_LEN);
 
-	penv->gpios_5wire = platform_get_resource_byname(pdev, IORESOURCE_IO,
-							"wcnss_gpios_5wire");
-
-	/* allocate 5-wire GPIO resources */
-	if (!penv->gpios_5wire) {
-		dev_err(&pdev->dev, "insufficient IO resources\n");
-		ret = -ENOENT;
-		goto fail_gpio_res;
-	}
-
 	/* Configure 5 wire GPIOs */
-	ret = wcnss_gpios_config(penv->gpios_5wire, true);
+	if (!has_pronto_hw) {
+		penv->gpios_5wire = platform_get_resource_byname(pdev,
+					IORESOURCE_IO, "wcnss_gpios_5wire");
+
+		/* allocate 5-wire GPIO resources */
+		if (!penv->gpios_5wire) {
+			dev_err(&pdev->dev, "insufficient IO resources\n");
+			ret = -ENOENT;
+			goto fail_gpio_res;
+		}
+		ret = wcnss_gpios_config(penv->gpios_5wire, true);
+	} else
+		ret = wcnss_pronto_gpios_config(&pdev->dev, true);
+
 	if (ret) {
 		dev_err(&pdev->dev, "WCNSS gpios config failed.\n");
 		goto fail_gpio_res;
@@ -627,7 +683,10 @@
 	wcnss_wlan_power(&pdev->dev, &penv->wlan_config,
 				WCNSS_WLAN_SWITCH_OFF);
 fail_power:
-	wcnss_gpios_config(penv->gpios_5wire, false);
+	if (has_pronto_hw)
+		ret = wcnss_pronto_gpios_config(&pdev->dev, false);
+	else
+		wcnss_gpios_config(penv->gpios_5wire, false);
 fail_gpio_res:
 	kfree(penv);
 	penv = NULL;
@@ -724,11 +783,21 @@
 	.resume		= wcnss_wlan_resume,
 };
 
+#ifdef CONFIG_WCNSS_CORE_PRONTO
+static struct of_device_id msm_wcnss_pronto_match[] = {
+	{.compatible = "qcom,wcnss_wlan"},
+	{}
+};
+#endif
+
 static struct platform_driver wcnss_wlan_driver = {
 	.driver = {
 		.name	= DEVICE,
 		.owner	= THIS_MODULE,
 		.pm	= &wcnss_wlan_pm_ops,
+#ifdef CONFIG_WCNSS_CORE_PRONTO
+		.of_match_table = msm_wcnss_pronto_match,
+#endif
 	},
 	.probe	= wcnss_wlan_probe,
 	.remove	= __devexit_p(wcnss_wlan_remove),
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index f87a06a..556e3ea 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -88,6 +88,8 @@
 #define QC_DEVID_SAT2	0x4
 #define QC_DEVID_PGD	0x5
 #define QC_MSM_DEVS	5
+#define INIT_MX_RETRIES 10
+#define DEF_RETRY_MS	10
 
 #define PGD_THIS_EE(r, v) ((v) ? PGD_THIS_EE_V2(r) : PGD_THIS_EE_V1(r))
 #define PGD_PORT(r, p, v) ((v) ? PGD_PORT_V2(r, p) : PGD_PORT_V1(r, p))
@@ -175,6 +177,7 @@
 	MGR_INT_CLR	= 0x218,
 	MGR_TX_MSG	= 0x230,
 	MGR_RX_MSG	= 0x270,
+	MGR_IE_STAT	= 0x2F0,
 	MGR_VE_STAT	= 0x300,
 };
 
@@ -449,8 +452,34 @@
 			writel_relaxed(MGR_INT_TX_MSG_SENT,
 					dev->base + MGR_INT_CLR);
 		else {
+			u32 mgr_stat = readl_relaxed(dev->base + MGR_STATUS);
+			u32 mgr_ie_stat = readl_relaxed(dev->base +
+						MGR_IE_STAT);
+			u32 frm_stat = readl_relaxed(dev->base + FRM_STAT);
+			u32 frm_cfg = readl_relaxed(dev->base + FRM_CFG);
+			u32 frm_intr_stat = readl_relaxed(dev->base +
+						FRM_INT_STAT);
+			u32 frm_ie_stat = readl_relaxed(dev->base +
+						FRM_IE_STAT);
+			u32 intf_stat = readl_relaxed(dev->base + INTF_STAT);
+			u32 intf_intr_stat = readl_relaxed(dev->base +
+						INTF_INT_STAT);
+			u32 intf_ie_stat = readl_relaxed(dev->base +
+						INTF_IE_STAT);
+
 			writel_relaxed(MGR_INT_TX_NACKED_2,
 					dev->base + MGR_INT_CLR);
+			pr_err("TX Nack MGR dump:int_stat:0x%x, mgr_stat:0x%x",
+					stat, mgr_stat);
+			pr_err("TX Nack MGR dump:ie_stat:0x%x", mgr_ie_stat);
+			pr_err("TX Nack FRM dump:int_stat:0x%x, frm_stat:0x%x",
+					frm_intr_stat, frm_stat);
+			pr_err("TX Nack FRM dump:frm_cfg:0x%x, ie_stat:0x%x",
+					frm_cfg, frm_ie_stat);
+			pr_err("TX Nack INTF dump:intr_st:0x%x, intf_stat:0x%x",
+					intf_intr_stat, intf_stat);
+			pr_err("TX Nack INTF dump:ie_stat:0x%x", intf_ie_stat);
+
 			dev->err = -EIO;
 		}
 		/*
@@ -863,7 +892,8 @@
 	dev->wr_comp = &done;
 	msm_send_msg_buf(ctrl, pbuf, txn->rl);
 	timeout = wait_for_completion_timeout(&done, HZ);
-
+	if (!timeout)
+		dev->wr_comp = NULL;
 	if (mc == SLIM_MSG_MC_RECONFIGURE_NOW) {
 		if ((txn->mc == (SLIM_MSG_MC_RECONFIGURE_NOW |
 					SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
@@ -903,13 +933,28 @@
 	return timeout ? dev->err : -ETIMEDOUT;
 }
 
+static void msm_slim_wait_retry(struct msm_slim_ctrl *dev)
+{
+	int msec_per_frm = 0;
+	int sfr_per_sec;
+	/* Wait for 1 superframe, or default time and then retry */
+	sfr_per_sec = dev->framer.superfreq /
+			(1 << (SLIM_MAX_CLK_GEAR - dev->ctrl.clkgear));
+	if (sfr_per_sec)
+		msec_per_frm = MSEC_PER_SEC / sfr_per_sec;
+	if (msec_per_frm < DEF_RETRY_MS)
+		msec_per_frm = DEF_RETRY_MS;
+	msleep(msec_per_frm);
+}
 static int msm_set_laddr(struct slim_controller *ctrl, const u8 *ea,
 				u8 elen, u8 laddr)
 {
 	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
-	DECLARE_COMPLETION_ONSTACK(done);
-	int timeout;
+	struct completion done;
+	int timeout, ret, retries = 0;
 	u32 *buf;
+retry_laddr:
+	init_completion(&done);
 	mutex_lock(&dev->tx_lock);
 	buf = msm_get_msg_buf(ctrl, 9);
 	buf[0] = SLIM_MSG_ASM_FIRST_WORD(9, SLIM_MSG_MT_CORE,
@@ -920,10 +965,27 @@
 	buf[2] = laddr;
 
 	dev->wr_comp = &done;
-	msm_send_msg_buf(ctrl, buf, 9);
+	ret = msm_send_msg_buf(ctrl, buf, 9);
 	timeout = wait_for_completion_timeout(&done, HZ);
+	if (!timeout)
+		dev->err = -ETIMEDOUT;
+	if (dev->err) {
+		ret = dev->err;
+		dev->err = 0;
+		dev->wr_comp = NULL;
+	}
 	mutex_unlock(&dev->tx_lock);
-	return timeout ? dev->err : -ETIMEDOUT;
+	if (ret) {
+		pr_err("set LADDR:0x%x failed:ret:%d, retrying", laddr, ret);
+		if (retries < INIT_MX_RETRIES) {
+			msm_slim_wait_retry(dev);
+			retries++;
+			goto retry_laddr;
+		} else {
+			pr_err("set LADDR failed after retrying:ret:%d", ret);
+		}
+	}
+	return ret;
 }
 
 static int msm_clk_pause_wakeup(struct slim_controller *ctrl)
@@ -1154,6 +1216,8 @@
 				msm_sat_enqueue(sat, (u32 *)buf, len);
 				queue_work(sat->wq, &sat->wd);
 			}
+			if (ret)
+				pr_err("assign laddr failed, error:%d", ret);
 		} else if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
 				mc == SLIM_MSG_MC_REPLY_VALUE) {
 			u8 tid = buf[3];
@@ -1196,7 +1260,7 @@
 		bool gen_ack = false;
 		u8 tid;
 		u8 wbuf[8];
-		int i;
+		int i, retries = 0;
 		txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
 		txn.dt = SLIM_MSG_DEST_LOGICALADDR;
 		txn.ec = 0;
@@ -1209,7 +1273,6 @@
 
 		if (mt == SLIM_MSG_MT_CORE &&
 			mc == SLIM_MSG_MC_REPORT_PRESENT) {
-			u8 laddr;
 			u8 e_addr[6];
 			for (i = 0; i < 6; i++)
 				e_addr[i] = buf[7-i];
@@ -1219,8 +1282,6 @@
 				if (satv >= 0)
 					sat->pending_capability = true;
 			}
-			slim_assign_laddr(&dev->ctrl, e_addr, 6, &laddr);
-			sat->satcl.laddr = laddr;
 			/*
 			 * Since capability message is already sent, present
 			 * message will indicate subsystem hosting this
@@ -1232,7 +1293,7 @@
 				for (i = 0; i < sat->nsatch; i++) {
 					if (sat->satch[i].reconf) {
 						pr_err("SSR, sat:%d, rm ch:%d",
-							laddr,
+							sat->satcl.laddr,
 							sat->satch[i].chan);
 						slim_control_ch(&sat->satcl,
 							sat->satch[i].chanh,
@@ -1284,8 +1345,21 @@
 			wbuf[3] = SAT_MSG_PROT;
 			txn.wbuf = wbuf;
 			txn.len = 4;
-			sat->sent_capability = true;
-			msm_xfer_msg(&dev->ctrl, &txn);
+			ret = msm_xfer_msg(&dev->ctrl, &txn);
+			if (ret) {
+				pr_err("capability for:0x%x fail:%d, retry:%d",
+						sat->satcl.laddr, ret, retries);
+				if (retries < INIT_MX_RETRIES) {
+					msm_slim_wait_retry(dev);
+					retries++;
+					goto send_capability;
+				} else {
+					pr_err("failed after all retries:%d",
+							ret);
+				}
+			} else {
+				sat->sent_capability = true;
+			}
 			break;
 		case SLIM_USR_MC_ADDR_QUERY:
 			memcpy(&wbuf[1], &buf[4], 6);
@@ -1326,7 +1400,7 @@
 			ret = slim_reconfigure_now(&sat->satcl);
 			for (i = 0; i < sat->nsatch; i++) {
 				struct msm_sat_chan *sch = &sat->satch[i];
-				if (sch->req_rem) {
+				if (sch->req_rem && sch->reconf) {
 					if (!ret) {
 						slim_dealloc_ch(&sat->satcl,
 								sch->chanh);
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index daf0564..0c49a89 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -682,20 +682,6 @@
 	return IRQ_HANDLED;
 }
 
-static void tsens8960_sensor_mode_init(void)
-{
-	unsigned int reg_cntl = 0;
-
-	reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
-	if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
-			tmdev->hw_type == APQ_8064) {
-		writel_relaxed(reg_cntl &
-				~((((1 << tmdev->tsens_num_sensor) - 1) >> 1)
-				<< (TSENS_SENSOR0_SHIFT + 1)), TSENS_CNTL_ADDR);
-		tmdev->sensor[TSENS_MAIN_SENSOR].mode = THERMAL_DEVICE_ENABLED;
-	}
-}
-
 #ifdef CONFIG_PM
 static int tsens_suspend(struct device *dev)
 {
@@ -1018,11 +1004,8 @@
 			rc = -ENODEV;
 			goto fail;
 		}
-		tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
 	}
 
-	tsens8960_sensor_mode_init();
-
 	rc = request_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
 		IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
 	if (rc < 0) {
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index dcf307d..a740d95 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -882,6 +882,11 @@
 
 	rndis_set_max_pkt_xfer(rndis->config, rndis->max_pkt_per_xfer);
 
+	/* In case of aggregated packets QC device will request
+	 * aliment to 4 (2^2).
+	 */
+	rndis_set_pkt_alignment_factor(rndis->config, 2);
+
 	/* NOTE:  all that is done without knowing or caring about
 	 * the network link ... which is unavailable to this code
 	 * until we're activated via set_alt().
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 087c928..801d24d 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -586,12 +586,13 @@
 	resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
 	resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
 	resp->MaxPacketsPerTransfer = cpu_to_le32(params->max_pkt_per_xfer);
-	resp->MaxTransferSize = cpu_to_le32(
-		  params->dev->mtu
+	resp->MaxTransferSize = cpu_to_le32(params->max_pkt_per_xfer *
+		(params->dev->mtu
 		+ sizeof(struct ethhdr)
 		+ sizeof(struct rndis_packet_msg_type)
-		+ 22);
-	resp->PacketAlignmentFactor = cpu_to_le32(0);
+
+		+ 22));
+	resp->PacketAlignmentFactor = cpu_to_le32(params->pkt_alignment_factor);
 	resp->AFListOffset = cpu_to_le32(0);
 	resp->AFListSize = cpu_to_le32(0);
 
@@ -903,6 +904,7 @@
 			rndis_per_dev_params[i].resp_avail = resp_avail;
 			rndis_per_dev_params[i].v = v;
 			rndis_per_dev_params[i].max_pkt_per_xfer = 1;
+			rndis_per_dev_params[i].pkt_alignment_factor = 0;
 			pr_debug("%s: configNr = %d\n", __func__, i);
 			return i;
 		}
@@ -963,6 +965,14 @@
 	rndis_per_dev_params[configNr].max_pkt_per_xfer = max_pkt_per_xfer;
 }
 
+void rndis_set_pkt_alignment_factor(u8 configNr, u8 pkt_alignment_factor)
+{
+	pr_debug("%s:\n", __func__);
+
+	rndis_per_dev_params[configNr].pkt_alignment_factor =
+					pkt_alignment_factor;
+}
+
 void rndis_add_hdr(struct sk_buff *skb)
 {
 	struct rndis_packet_msg_type *header;
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 1f06c42..8a6a630 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -236,6 +236,7 @@
 
 	u32			vendorID;
 	u8			max_pkt_per_xfer;
+	u8			pkt_alignment_factor;
 	const char		*vendorDescr;
 	void			(*resp_avail)(void *v);
 	void			*v;
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index be8b58b..aa7a33c 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -441,8 +441,13 @@
 
 	pr_debug("status:%d actual:%d", urb->status, urb->actual_length);
 
+	/*non zero len of data received while unlinking urb*/
+	if (urb->status == -ENOENT && urb->actual_length > 0)
+		goto add_to_list;
+
 	if (urb->status < 0) {
-		if (urb->status != -ESHUTDOWN && urb->status != -ENOENT)
+		if (urb->status != -ESHUTDOWN && urb->status != -ENOENT
+				&& urb->status != -EPROTO)
 			pr_err_ratelimited("urb failed with err:%d",
 					urb->status);
 		ksb_free_data_pkt(pkt);
@@ -456,6 +461,7 @@
 		goto resubmit_urb;
 	}
 
+add_to_list:
 	spin_lock(&ksb->lock);
 	pkt->len = urb->actual_length;
 	list_add_tail(&pkt->list, &ksb->to_ks_list);
@@ -601,7 +607,7 @@
 
 	dbg_log_event(ksb, "SUSPEND", 0, 0);
 
-	pr_info("read cnt: %d", ksb->alloced_read_pkts);
+	pr_debug("read cnt: %d", ksb->alloced_read_pkts);
 
 	usb_kill_anchored_urbs(&ksb->submitted);
 
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index c845053..70e78f4 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -925,6 +925,9 @@
 int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *plist);
 void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, int flag);
+int mdp4_update_base_blend(struct msm_fb_data_type *mfd,
+				struct mdp_blend_cfg *mdp_blend_cfg);
+u32 mdp4_get_mixer_num(u32 panel_type);
 
 #ifndef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
 static inline void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index ce287c6..2b27562 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1926,7 +1926,7 @@
 	int i, off, ptype, alpha_drop = 0;
 	int d_alpha, s_alpha;
 	unsigned char *overlay_base;
-	uint32 c0, c1, c2;
+	uint32 c0, c1, c2, base_premulti;
 
 
 	d_pipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
@@ -1936,6 +1936,8 @@
 	}
 
 	blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE0];
+	base_premulti = ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE].op &
+		MDP4_BLEND_FG_ALPHA_BG_CONST;
 	for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
 		blend->solidfill = 0;
 		blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
@@ -1976,9 +1978,13 @@
 		} else if (s_alpha) {
 			if (!alpha_drop) {
 				blend->op = MDP4_BLEND_BG_ALPHA_FG_PIXEL;
-				if (!(s_pipe->flags & MDP_BLEND_FG_PREMULT))
+				if ((!(s_pipe->flags & MDP_BLEND_FG_PREMULT)) &&
+						((i != MDP4_MIXER_STAGE0) ||
+							(!base_premulti)))
 					blend->op |=
 						MDP4_BLEND_FG_ALPHA_FG_PIXEL;
+				else
+					blend->fg_alpha = 0xff;
 			} else
 				blend->op = MDP4_BLEND_BG_ALPHA_FG_CONST;
 
@@ -1988,9 +1994,14 @@
 			if (ptype == OVERLAY_TYPE_VIDEO) {
 				blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL |
 					MDP4_BLEND_FG_INV_ALPHA);
-				if (!(s_pipe->flags & MDP_BLEND_FG_PREMULT))
+				if ((!(s_pipe->flags & MDP_BLEND_FG_PREMULT)) &&
+						((i != MDP4_MIXER_STAGE0) ||
+							(!base_premulti)))
 					blend->op |=
 						MDP4_BLEND_BG_ALPHA_BG_PIXEL;
+				else
+					blend->fg_alpha = 0xff;
+
 				blend->co3_sel = 0; /* use bg alpha */
 			} else {
 				/* s_pipe is rgb without alpha */
@@ -2463,6 +2474,11 @@
 		mfd->panel_info.type == MIPI_CMD_PANEL) ?
 		mfd->panel_info.mipi.dsi_pclk_rate :
 		mfd->panel_info.clk_rate;
+
+	if (mfd->panel_info.type == LVDS_PANEL &&
+		mfd->panel_info.lvds.channel_mode == LVDS_DUAL_CHANNEL_MODE)
+		pclk = pclk << 1;
+
 	if (!pclk) {
 		pipe->req_clk = mdp_max_clk;
 		pr_err("%s panel pixel clk is zero!\n", __func__);
@@ -3680,3 +3696,22 @@
 	mutex_unlock(&mfd->dma->ov_mutex);
 	return err;
 }
+int mdp4_update_base_blend(struct msm_fb_data_type *mfd,
+			struct mdp_blend_cfg *mdp_blend_cfg)
+{
+	int ret = 0;
+	u32 mixer_num;
+	struct blend_cfg *blend;
+	mixer_num = mdp4_get_mixer_num(mfd->panel_info.type);
+	if (!ctrl)
+		return -EPERM;
+	blend = &ctrl->blend[mixer_num][MDP4_MIXER_STAGE_BASE];
+	if (mdp_blend_cfg->is_premultiplied) {
+		blend->bg_alpha = 0xFF;
+		blend->op = MDP4_BLEND_FG_ALPHA_BG_CONST;
+	} else {
+		blend->op = MDP4_BLEND_FG_ALPHA_FG_PIXEL;
+		blend->bg_alpha = 0;
+	}
+	return ret;
+}
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 940aea8..2a44dda 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -276,6 +276,9 @@
 
 	writeback_pipe->ov_blt_addr = (ulong) (node ? node->addr : NULL);
 
+	/* free previous iommu at freelist back to pool */
+	mdp4_overlay_iommu_unmap_freelist(writeback_pipe->mixer_num);
+
 	if (!writeback_pipe->ov_blt_addr) {
 		pr_err("%s: no writeback buffer 0x%x, %p\n", __func__,
 			(unsigned int)writeback_pipe->ov_blt_addr, node);
@@ -292,6 +295,9 @@
 
 	mdp4_writeback_overlay_kickoff(mfd, pipe);
 
+	/* move current committed iommu to freelist */
+	mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
+
 	mutex_lock(&mfd->writeback_mutex);
 	list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
 	mutex_unlock(&mfd->writeback_mutex);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 34ae716..359f37e 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -3091,3 +3091,16 @@
 error:
 	return ret;
 }
+u32 mdp4_get_mixer_num(u32 panel_type)
+{
+	u32 mixer_num;
+	if ((panel_type == TV_PANEL) ||
+			(panel_type == DTV_PANEL))
+		mixer_num = MDP4_MIXER1;
+	else if (panel_type == WRITEBACK_PANEL) {
+		mixer_num = MDP4_MIXER2;
+	} else {
+		mixer_num = MDP4_MIXER0;
+	}
+	return mixer_num;
+}
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 6bc21bc..ddb6dd9 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -16,4 +16,5 @@
 
 obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_tx.o
 obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_util.o
+obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_edid.o
 obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 3017200..5613398 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -15,6 +15,7 @@
 #define MDSS_H
 
 #include <linux/ion.h>
+#include <linux/msm_mdp.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
@@ -71,6 +72,8 @@
 	u32 *mixer_type_map;
 
 	struct ion_client *iclient;
+	int iommu_domain;
+	int iommu_attached;
 };
 extern struct mdss_data_type *mdss_res;
 
@@ -92,10 +95,29 @@
 void mdss_enable_irq(struct mdss_hw *hw);
 void mdss_disable_irq(struct mdss_hw *hw);
 void mdss_disable_irq_nosync(struct mdss_hw *hw);
+
 static inline struct ion_client *mdss_get_ionclient(void)
 {
 	if (!mdss_res)
 		return NULL;
 	return mdss_res->iclient;
 }
+
+static inline int is_mdss_iommu_attached(void)
+{
+	if (!mdss_res)
+		return false;
+	return mdss_res->iommu_attached;
+}
+
+static inline int mdss_get_iommu_domain(void)
+{
+	if (!mdss_res)
+		return -ENODEV;
+
+	return mdss_res->iommu_domain;
+}
+
+int mdss_iommu_attach(void);
+int mdss_iommu_dettach(void);
 #endif /* MDSS_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index a9cf61e..c10306d 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -21,6 +21,8 @@
 #include <linux/slab.h>
 #include <linux/iopoll.h>
 
+#include <mach/iommu_domains.h>
+
 #include "mdss.h"
 #include "mdss_dsi.h"
 
@@ -1093,6 +1095,7 @@
 	int len;
 	int i;
 	char *bp;
+	unsigned long size, addr;
 
 	bp = tp->data;
 
@@ -1102,17 +1105,30 @@
 
 	pr_debug("\n");
 
-	len = tp->len;
-	len += 3;
-	len &= ~0x03;	/* multipled by 4 */
+	len = ALIGN(tp->len, 4);
+	size = ALIGN(tp->len, SZ_4K);
 
-	tp->dmap = dma_map_single(&dsi_dev, tp->data, len, DMA_TO_DEVICE);
-	if (dma_mapping_error(&dsi_dev, tp->dmap))
+	tp->dmap = dma_map_single(&dsi_dev, tp->data, size, DMA_TO_DEVICE);
+	if (dma_mapping_error(&dsi_dev, tp->dmap)) {
 		pr_err("%s: dmap mapp failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	if (is_mdss_iommu_attached()) {
+		int ret = msm_iommu_map_contig_buffer(tp->dmap,
+					mdss_get_iommu_domain(), 0,
+					size, SZ_4K, 0, &(addr));
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("unable to map dma memory to iommu(%d)\n", ret);
+			return -ENOMEM;
+		}
+	} else {
+		addr = tp->dmap;
+	}
 
 	INIT_COMPLETION(dsi_dma_comp);
 
-	MIPI_OUTP((pdata->dsi_base) + 0x048, tp->dmap);
+	MIPI_OUTP((pdata->dsi_base) + 0x048, addr);
 	MIPI_OUTP((pdata->dsi_base) + 0x04c, len);
 	wmb();
 
@@ -1121,7 +1137,11 @@
 
 	wait_for_completion(&dsi_dma_comp);
 
-	dma_unmap_single(&dsi_dev, tp->dmap, len, DMA_TO_DEVICE);
+	if (is_mdss_iommu_attached())
+		msm_iommu_unmap_contig_buffer(addr, mdss_get_iommu_domain(),
+					      0, size);
+
+	dma_unmap_single(&dsi_dev, tp->dmap, size, DMA_TO_DEVICE);
 	tp->dmap = 0;
 	return tp->len;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index e4b1867..b909966 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -528,8 +528,8 @@
 
 static int __init mdss_dsi_panel_init(void)
 {
-	mdss_dsi_buf_alloc(&dsi_panel_tx_buf, DSI_BUF_SIZE);
-	mdss_dsi_buf_alloc(&dsi_panel_rx_buf, DSI_BUF_SIZE);
+	mdss_dsi_buf_alloc(&dsi_panel_tx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
+	mdss_dsi_buf_alloc(&dsi_panel_rx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
 
 	return platform_driver_register(&this_driver);
 }
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 5ea52e7..18b4d87 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -144,9 +144,9 @@
 	return ret;
 }
 
-static DEVICE_ATTR(mdss_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
+static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
 static struct attribute *mdss_fb_attrs[] = {
-	&dev_attr_mdss_fb_type.attr,
+	&dev_attr_msm_fb_type.attr,
 	NULL,
 };
 
@@ -217,6 +217,14 @@
 	if (rc)
 		return rc;
 
+	/*
+	 * todo: Currently mfd keeps a full copy of panel data rather than
+	 *       pointer to it.
+	 *       Following line shares the fbi with panel drivers for their
+	 *       sysfs or any external communications with the panel driver.
+	 */
+	pdata->panel_info.fbi = fbi;
+
 	rc = pm_runtime_set_active(mfd->fbi->dev);
 	if (rc < 0)
 		pr_err("pm_runtime: fail to set active.\n");
@@ -603,6 +611,14 @@
 
 			virt = ion_map_kernel(iclient, mfd->ihdl, 0);
 			ion_phys(iclient, mfd->ihdl, &phys, &size);
+
+			if (is_mdss_iommu_attached()) {
+				ion_map_iommu(iclient, mfd->ihdl,
+					      mdss_get_iommu_domain(),
+					      0, SZ_4K, 0, &mfd->iova,
+					      (unsigned long *) &size,
+					      0, 0);
+			}
 		} else {
 			virt = dma_alloc_coherent(NULL, size,
 					(dma_addr_t *) &phys, GFP_KERNEL);
@@ -786,6 +802,20 @@
 	mfd->var_yres = var->yres;
 	mfd->var_pixclock = var->pixclock;
 
+	if (panel_info->type == MIPI_VIDEO_PANEL) {
+		var->reserved[4] = panel_info->mipi.frame_rate;
+	} else {
+		var->reserved[4] = panel_info->clk_rate /
+			((panel_info->lcdc.h_back_porch +
+			  panel_info->lcdc.h_front_porch +
+			  panel_info->lcdc.h_pulse_width +
+			  panel_info->xres) *
+			 (panel_info->lcdc.v_back_porch +
+			  panel_info->lcdc.v_front_porch +
+			  panel_info->lcdc.v_pulse_width +
+			  panel_info->yres));
+	}
+
 	/* id field for fb app  */
 
 	id = (int *)&mfd->panel;
@@ -1205,6 +1235,7 @@
 int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
 {
 	struct fb_info *info;
+	struct msm_fb_data_type *mfd;
 
 	if (fb_num > MAX_FBI_LIST)
 		return -EINVAL;
@@ -1213,8 +1244,16 @@
 	if (!info)
 		return -ENOENT;
 
-	*start = info->fix.smem_start;
+	mfd = (struct msm_fb_data_type *)info->par;
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->iova)
+		*start = mfd->iova;
+	else
+		*start = info->fix.smem_start;
 	*len = info->fix.smem_len;
+
 	return 0;
 }
 EXPORT_SYMBOL(mdss_fb_get_phys_info);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index dd84ce5..342ebb8 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -76,8 +76,10 @@
 			     struct mdp_histogram *hist);
 
 	struct ion_handle *ihdl;
+	unsigned long iova;
 	void *cursor_buf;
-	void *cursor_buf_phys;
+	unsigned long cursor_buf_phys;
+	unsigned long cursor_buf_iova;
 
 	u32 bl_level;
 	struct mutex lock;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
new file mode 100644
index 0000000..f720a2f
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -0,0 +1,1420 @@
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This 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/io.h>
+#include <linux/types.h>
+#include <mach/board.h>
+#include "mdss_hdmi_edid.h"
+
+#define DBC_START_OFFSET 4
+#define HDMI_VSDB_3D_DATA_OFFSET(vsd) \
+	(!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
+
+struct hdmi_edid_sink_data {
+	u32 disp_mode_list[HDMI_VFRMT_MAX];
+	u32 disp_3d_mode_list[HDMI_VFRMT_MAX];
+	u32 disp_multi_3d_mode_list[16];
+	u32 disp_multi_3d_mode_list_cnt;
+	u32 num_of_elements;
+	u32 preferred_video_format;
+};
+
+struct hdmi_edid_ctrl {
+	u8 pt_scan_info;
+	u8 it_scan_info;
+	u8 ce_scan_info;
+	u16 physical_address;
+	u32 video_resolution; /* selected by user */
+	u32 sink_mode; /* HDMI or DVI */
+	u8 speaker_allocation_block;
+	u8 audio_data_block_cnt;
+	u16 audio_latency;
+	u16 video_latency;
+	u32 present_3d;
+
+	struct hdmi_edid_sink_data sink_data;
+	struct hdmi_edid_init_data init_data;
+};
+
+/* The Logic ID for HDMI TX Core. Currently only support 1 HDMI TX Core. */
+struct hdmi_edid_video_mode_property_type {
+	u32	video_code;
+	u32	active_h;
+	u32	active_v;
+	u32	interlaced;
+	u32	total_h;
+	u32	total_blank_h;
+	u32	total_v;
+	u32	total_blank_v;
+	/* Must divide by 1000 to get the frequency */
+	u32	freq_h;
+	/* Must divide by 1000 to get the frequency */
+	u32	freq_v;
+	/* Must divide by 1000 to get the frequency */
+	u32	pixel_freq;
+	/* Must divide by 1000 to get the frequency */
+	u32	refresh_rate;
+	u32	aspect_ratio_4_3;
+};
+
+/* LUT is sorted from lowest Active H to highest Active H - ease searching */
+static struct hdmi_edid_video_mode_property_type
+	hdmi_edid_disp_mode_lut[] = {
+
+	/* All 640 H Active */
+	{HDMI_VFRMT_640x480p60_4_3, 640, 480, false, 800, 160, 525, 45,
+	 31465, 59940, 25175, 59940, true},
+	{HDMI_VFRMT_640x480p60_4_3, 640, 480, false, 800, 160, 525, 45,
+	 31500, 60000, 25200, 60000, true},
+
+	/* All 720 H Active */
+	{HDMI_VFRMT_720x576p50_4_3,  720, 576, false, 864, 144, 625, 49,
+	 31250, 50000, 27000, 50000, true},
+	{HDMI_VFRMT_720x480p60_4_3,  720, 480, false, 858, 138, 525, 45,
+	 31465, 59940, 27000, 59940, true},
+	{HDMI_VFRMT_720x480p60_4_3,  720, 480, false, 858, 138, 525, 45,
+	 31500, 60000, 27030, 60000, true},
+	{HDMI_VFRMT_720x576p100_4_3, 720, 576, false, 864, 144, 625, 49,
+	 62500, 100000, 54000, 100000, true},
+	{HDMI_VFRMT_720x480p120_4_3, 720, 480, false, 858, 138, 525, 45,
+	 62937, 119880, 54000, 119880, true},
+	{HDMI_VFRMT_720x480p120_4_3, 720, 480, false, 858, 138, 525, 45,
+	 63000, 120000, 54054, 120000, true},
+	{HDMI_VFRMT_720x576p200_4_3, 720, 576, false, 864, 144, 625, 49,
+	 125000, 200000, 108000, 200000, true},
+	{HDMI_VFRMT_720x480p240_4_3, 720, 480, false, 858, 138, 525, 45,
+	 125874, 239760, 108000, 239000, true},
+	{HDMI_VFRMT_720x480p240_4_3, 720, 480, false, 858, 138, 525, 45,
+	 126000, 240000, 108108, 240000, true},
+
+	/* All 1280 H Active */
+	{HDMI_VFRMT_1280x720p50_16_9,  1280, 720, false, 1980, 700, 750, 30,
+	 37500, 50000, 74250, 50000, false},
+	{HDMI_VFRMT_1280x720p60_16_9,  1280, 720, false, 1650, 370, 750, 30,
+	 44955, 59940, 74176, 59940, false},
+	{HDMI_VFRMT_1280x720p60_16_9,  1280, 720, false, 1650, 370, 750, 30,
+	 45000, 60000, 74250, 60000, false},
+	{HDMI_VFRMT_1280x720p100_16_9, 1280, 720, false, 1980, 700, 750, 30,
+	 75000, 100000, 148500, 100000, false},
+	{HDMI_VFRMT_1280x720p120_16_9, 1280, 720, false, 1650, 370, 750, 30,
+	 89909, 119880, 148352, 119880, false},
+	{HDMI_VFRMT_1280x720p120_16_9, 1280, 720, false, 1650, 370, 750, 30,
+	 90000, 120000, 148500, 120000, false},
+
+	/* All 1440 H Active */
+	{HDMI_VFRMT_1440x576i50_4_3, 1440, 576, true,  1728, 288, 625, 24,
+	 15625, 50000, 27000, 50000, true},
+	{HDMI_VFRMT_720x288p50_4_3,  1440, 288, false, 1728, 288, 312, 24,
+	 15625, 50080, 27000, 50000, true},
+	{HDMI_VFRMT_720x288p50_4_3,  1440, 288, false, 1728, 288, 313, 25,
+	 15625, 49920, 27000, 50000, true},
+	{HDMI_VFRMT_720x288p50_4_3,  1440, 288, false, 1728, 288, 314, 26,
+	 15625, 49761, 27000, 50000, true},
+	{HDMI_VFRMT_1440x576p50_4_3, 1440, 576, false, 1728, 288, 625, 49,
+	 31250, 50000, 54000, 50000, true},
+	{HDMI_VFRMT_1440x480i60_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 15734, 59940, 27000, 59940, true},
+	{HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 262, 22,
+	 15734, 60054, 27000, 59940, true},
+	{HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 263, 23,
+	 15734, 59826, 27000, 59940, true},
+	{HDMI_VFRMT_1440x480p60_4_3, 1440, 480, false, 1716, 276, 525, 45,
+	 31469, 59940, 54000, 59940, true},
+	{HDMI_VFRMT_1440x480i60_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 15750, 60000, 27027, 60000, true},
+	{HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 262, 22,
+	 15750, 60115, 27027, 60000, true},
+	{HDMI_VFRMT_1440x240p60_4_3, 1440, 240, false, 1716, 276, 263, 23,
+	 15750, 59886, 27027, 60000, true},
+	{HDMI_VFRMT_1440x480p60_4_3, 1440, 480, false, 1716, 276, 525, 45,
+	 31500, 60000, 54054, 60000, true},
+	{HDMI_VFRMT_1440x576i100_4_3, 1440, 576, true,  1728, 288, 625, 24,
+	 31250, 100000, 54000, 100000, true},
+	{HDMI_VFRMT_1440x480i120_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 31469, 119880, 54000, 119880, true},
+	{HDMI_VFRMT_1440x480i120_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 31500, 120000, 54054, 120000, true},
+	{HDMI_VFRMT_1440x576i200_4_3, 1440, 576, true,  1728, 288, 625, 24,
+	 62500, 200000, 108000, 200000, true},
+	{HDMI_VFRMT_1440x480i240_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 62937, 239760, 108000, 239000, true},
+	{HDMI_VFRMT_1440x480i240_4_3, 1440, 480, true,  1716, 276, 525, 22,
+	 63000, 240000, 108108, 240000, true},
+
+	/* All 1920 H Active */
+	{HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, false, 2200, 280, 1125,
+	 45, 67433, 59940, 148352, 59940, false},
+	{HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, true,  2200, 280, 1125,
+	 45, 67500, 60000, 148500, 60000, false},
+	{HDMI_VFRMT_1920x1080p50_16_9, 1920, 1080, false, 2640, 720, 1125,
+	 45, 56250, 50000, 148500, 50000, false},
+	{HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, false, 2750, 830, 1125,
+	 45, 26973, 23976, 74176, 24000, false},
+	{HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, false, 2750, 830, 1125,
+	 45, 27000, 24000, 74250, 24000, false},
+	{HDMI_VFRMT_1920x1080p25_16_9, 1920, 1080, false, 2640, 720, 1125,
+	 45, 28125, 25000, 74250, 25000, false},
+	{HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, false, 2200, 280, 1125,
+	 45, 33716, 29970, 74176, 30000, false},
+	{HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, false, 2200, 280, 1125,
+	 45, 33750, 30000, 74250, 30000, false},
+	{HDMI_VFRMT_1920x1080i50_16_9, 1920, 1080, true,  2304, 384, 1250,
+	 85, 31250, 50000, 72000, 50000, false},
+	{HDMI_VFRMT_1920x1080i60_16_9, 1920, 1080, true,  2200, 280, 1125,
+	 22, 33716, 59940, 74176, 59940, false},
+	{HDMI_VFRMT_1920x1080i60_16_9, 1920, 1080, true,  2200, 280, 1125,
+	 22, 33750, 60000, 74250, 60000, false},
+	{HDMI_VFRMT_1920x1080i100_16_9, 1920, 1080, true,  2640, 720, 1125,
+	 22, 56250, 100000, 148500, 100000, false},
+	{HDMI_VFRMT_1920x1080i120_16_9, 1920, 1080, true,  2200, 280, 1125,
+	 22, 67432, 119880, 148352, 119980, false},
+	{HDMI_VFRMT_1920x1080i120_16_9, 1920, 1080, true,  2200, 280, 1125,
+	 22, 67500, 120000, 148500, 120000, false},
+
+	/* All 2880 H Active */
+	{HDMI_VFRMT_2880x576i50_4_3, 2880, 576, true,  3456, 576, 625, 24,
+	 15625, 50000, 54000, 50000, true},
+	{HDMI_VFRMT_2880x288p50_4_3, 2880, 576, false, 3456, 576, 312, 24,
+	 15625, 50080, 54000, 50000, true},
+	{HDMI_VFRMT_2880x288p50_4_3, 2880, 576, false, 3456, 576, 313, 25,
+	 15625, 49920, 54000, 50000, true},
+	{HDMI_VFRMT_2880x288p50_4_3, 2880, 576, false, 3456, 576, 314, 26,
+	 15625, 49761, 54000, 50000, true},
+	{HDMI_VFRMT_2880x576p50_4_3, 2880, 576, false, 3456, 576, 625, 49,
+	 31250, 50000, 108000, 50000, true},
+	{HDMI_VFRMT_2880x480i60_4_3, 2880, 480, true,  3432, 552, 525, 22,
+	 15734, 59940, 54000, 59940, true},
+	{HDMI_VFRMT_2880x240p60_4_3, 2880, 480, false, 3432, 552, 262, 22,
+	 15734, 60054, 54000, 59940, true},
+	{HDMI_VFRMT_2880x240p60_4_3, 2880, 480, false, 3432, 552, 263, 23,
+	 15734, 59940, 54000, 59940, true},
+	{HDMI_VFRMT_2880x480p60_4_3, 2880, 480, false, 3432, 552, 525, 45,
+	 31469, 59940, 108000, 59940, true},
+	{HDMI_VFRMT_2880x480i60_4_3, 2880, 480, true,  3432, 552, 525, 22,
+	 15750, 60000, 54054, 60000, true},
+	{HDMI_VFRMT_2880x240p60_4_3, 2880, 240, false, 3432, 552, 262, 22,
+	 15750, 60115, 54054, 60000, true},
+	{HDMI_VFRMT_2880x240p60_4_3, 2880, 240, false, 3432, 552, 262, 23,
+	 15750, 59886, 54054, 60000, true},
+	{HDMI_VFRMT_2880x480p60_4_3, 2880, 480, false, 3432, 552, 525, 45,
+	 31500, 60000, 108108, 60000, true},
+};
+
+static ssize_t hdmi_edid_sysfs_rda_modes(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+	int i;
+	struct hdmi_edid_ctrl *edid_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	buf[0] = 0;
+	if (edid_ctrl->sink_data.num_of_elements) {
+		u32 *video_mode = edid_ctrl->sink_data.disp_mode_list;
+		for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
+			if (ret > 0)
+				ret += snprintf(buf+ret, PAGE_SIZE-ret, ",%d",
+					*video_mode++ + 1);
+			else
+				ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+					*video_mode++ + 1);
+		}
+	} else {
+		ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+			edid_ctrl->video_resolution+1);
+	}
+
+	DEV_DBG("%s: '%s'\n", __func__, buf);
+	ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+
+	return ret;
+} /* hdmi_edid_sysfs_rda_modes */
+static DEVICE_ATTR(edid_modes, S_IRUGO, hdmi_edid_sysfs_rda_modes, NULL);
+
+static ssize_t hdmi_edid_sysfs_rda_physical_address(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct hdmi_edid_ctrl *edid_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", edid_ctrl->physical_address);
+	DEV_DBG("%s: '%d'\n", __func__, edid_ctrl->physical_address);
+
+	return ret;
+} /* hdmi_edid_sysfs_rda_physical_address */
+static DEVICE_ATTR(pa, S_IRUGO, hdmi_edid_sysfs_rda_physical_address, NULL);
+
+static ssize_t hdmi_edid_sysfs_rda_scan_info(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct hdmi_edid_ctrl *edid_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = snprintf(buf, PAGE_SIZE, "%d, %d, %d\n", edid_ctrl->pt_scan_info,
+		edid_ctrl->it_scan_info, edid_ctrl->ce_scan_info);
+	DEV_DBG("%s: '%s'\n", __func__, buf);
+
+	return ret;
+} /* hdmi_edid_sysfs_rda_scan_info */
+static DEVICE_ATTR(scan_info, S_IRUGO, hdmi_edid_sysfs_rda_scan_info, NULL);
+
+static ssize_t hdmi_edid_sysfs_rda_3d_modes(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+	int i;
+	char buff_3d[128];
+	struct hdmi_edid_ctrl *edid_ctrl =
+		hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	buf[0] = 0;
+	if (edid_ctrl->sink_data.num_of_elements) {
+		u32 *video_mode = edid_ctrl->sink_data.disp_mode_list;
+		u32 *video_3d_mode = edid_ctrl->sink_data.disp_3d_mode_list;
+
+		for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
+			ret = hdmi_get_video_3d_fmt_2string(*video_3d_mode++,
+				buff_3d);
+			if (ret > 0)
+				ret += snprintf(buf+ret, PAGE_SIZE-ret,
+					",%d=%s", *video_mode++ + 1,
+					buff_3d);
+			else
+				ret += snprintf(buf+ret, PAGE_SIZE-ret,
+					"%d=%s", *video_mode++ + 1,
+					buff_3d);
+		}
+	} else {
+		ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d",
+			edid_ctrl->video_resolution+1);
+	}
+
+	DEV_DBG("%s: '%s'\n", __func__, buf);
+	ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+
+	return ret;
+} /* hdmi_edid_sysfs_rda_3d_modes */
+static DEVICE_ATTR(edid_3d_modes, S_IRUGO, hdmi_edid_sysfs_rda_3d_modes, NULL);
+
+static struct attribute *hdmi_edid_fs_attrs[] = {
+	&dev_attr_edid_modes.attr,
+	&dev_attr_pa.attr,
+	&dev_attr_scan_info.attr,
+	&dev_attr_edid_3d_modes.attr,
+	NULL,
+};
+
+static struct attribute_group hdmi_edid_fs_attrs_group = {
+	.attrs = hdmi_edid_fs_attrs,
+};
+
+static int hdmi_edid_read_block(struct hdmi_edid_ctrl *edid_ctrl, int block,
+	u8 *edid_buf)
+{
+	const u8 *b = NULL;
+	u32 ndx, check_sum, print_len;
+	int block_size = 0x80;
+	int i, status;
+	struct hdmi_tx_ddc_data ddc_data;
+	b = edid_buf;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	do {
+		DEV_DBG("EDID: reading block(%d) with block-size=%d\n",
+			block, block_size);
+		for (i = 0; i < 0x80; i += block_size) {
+			/*Read EDID twice with 32bit alighnment too */
+			if (block < 2) {
+				memset(&ddc_data, 0, sizeof(ddc_data));
+				ddc_data.dev_addr = 0xA0;
+				ddc_data.offset   = block*0x80 + i;
+				ddc_data.data_buf = edid_buf+i;
+				ddc_data.data_len = block_size;
+				ddc_data.retry    = 1;
+				ddc_data.what     = "EDID";
+				ddc_data.no_align = false;
+
+				status = hdmi_ddc_read(
+					edid_ctrl->init_data.ddc_ctrl,
+					&ddc_data);
+			} else {
+				memset(&ddc_data, 0, sizeof(ddc_data));
+				ddc_data.dev_addr    = 0xA0;
+				ddc_data.offset      = block*0x80 + i;
+				ddc_data.data_buf    = edid_buf+i;
+				ddc_data.data_len    = block_size;
+				ddc_data.request_len = block_size;
+				ddc_data.retry       = 1;
+				ddc_data.what        = "EDID";
+
+				status = hdmi_ddc_read_seg(
+					edid_ctrl->init_data.ddc_ctrl,
+					&ddc_data);
+			}
+			if (status)
+				break;
+		}
+
+		block_size /= 2;
+	} while (status && (block_size >= 16));
+
+	if (status)
+		goto error;
+
+	/* Calculate checksum */
+	check_sum = 0;
+	for (ndx = 0; ndx < 0x80; ++ndx)
+		check_sum += edid_buf[ndx];
+
+	if (check_sum & 0xFF) {
+		DEV_ERR("%s: failed CHECKSUM (read:%x, expected:%x)\n",
+			__func__, (u8)edid_buf[0x7F], (u8)check_sum);
+		for (ndx = 0; ndx < 0x100; ndx += 4)
+			DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x\n",
+				ndx, ndx+3,
+				b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3]);
+		status = -EPROTO;
+		goto error;
+	}
+
+	print_len = 0x80;
+	for (ndx = 0; ndx < print_len; ndx += 16)
+		DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x\n",
+			ndx, ndx+3,
+			b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3]);
+
+error:
+	return status;
+} /* hdmi_edid_read_block */
+
+static const u8 *hdmi_edid_find_block(const u8 *in_buf, u32 start_offset,
+	u8 type, u8 *len)
+{
+	/* the start of data block collection, start of Video Data Block */
+	u32 offset = start_offset;
+	u32 end_dbc_offset = in_buf[2];
+
+	*len = 0;
+
+	/*
+	 * * edid buffer 1, byte 2 being 4 means no non-DTD/Data block
+	 *   collection present.
+	 * * edid buffer 1, byte 2 being 0 menas no non-DTD/DATA block
+	 *   collection present and no DTD data present.
+	 */
+	if ((end_dbc_offset == 0) || (end_dbc_offset == 4)) {
+		DEV_WARN("EDID: no DTD or non-DTD data present\n");
+		return NULL;
+	}
+
+	while (offset < end_dbc_offset) {
+		u8 block_len = in_buf[offset] & 0x1F;
+		if ((in_buf[offset] >> 5) == type) {
+			*len = block_len;
+			DEV_DBG("%s: EDID: block=%d found @ %d w/ length=%d\n",
+				__func__, type, offset, block_len);
+
+			return in_buf + offset;
+		}
+		offset += 1 + block_len;
+	}
+	DEV_WARN("%s: EDID: type=%d block not found in EDID block\n",
+		__func__, type);
+
+	return NULL;
+} /* hdmi_edid_find_block */
+
+static void hdmi_edid_extract_extended_data_blocks(
+	struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+	u8 len = 0;
+	u32 start_offset = DBC_START_OFFSET;
+	u8 const *etag = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	/* A Tage code of 7 identifies extended data blocks */
+	etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+
+	while (etag != NULL) {
+		/* The extended data block should at least be 2 bytes long */
+		if (len < 2) {
+			DEV_DBG("%s: data block of len < 2 bytes. Ignor...\n",
+				__func__);
+		} else {
+			/*
+			 * The second byte of the extended data block has the
+			 * extended tag code
+			 */
+			switch (etag[1]) {
+			case 0:
+				/* Video Capability Data Block */
+				DEV_DBG("%s: EDID: VCDB=%02X %02X\n", __func__,
+					etag[1], etag[2]);
+
+				/*
+				 * Check if the sink specifies underscan
+				 * support for:
+				 * BIT 5: preferred video format
+				 * BIT 3: IT video format
+				 * BIT 1: CE video format
+				 */
+				edid_ctrl->pt_scan_info =
+					(etag[2] & (BIT(4) | BIT(5))) >> 4;
+				edid_ctrl->it_scan_info =
+					(etag[2] & (BIT(3) | BIT(2))) >> 2;
+				edid_ctrl->ce_scan_info =
+					etag[2] & (BIT(1) | BIT(0));
+				DEV_DBG("%s: Scan Info (pt|it|ce): (%d|%d|%d)",
+					__func__,
+					edid_ctrl->pt_scan_info,
+					edid_ctrl->it_scan_info,
+					edid_ctrl->ce_scan_info);
+				break;
+			default:
+				DEV_DBG("%s: Tag Code %d not supported\n",
+					__func__, etag[1]);
+				break;
+			}
+		}
+
+		/* There could be more that one extended data block */
+		start_offset = etag - in_buf + len + 1;
+		etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+	}
+} /* hdmi_edid_extract_extended_data_blocks */
+
+static void hdmi_edid_extract_3d_present(struct hdmi_edid_ctrl *edid_ctrl,
+	const u8 *in_buf)
+{
+	u8 len, offset;
+	const u8 *vsd = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+
+	edid_ctrl->present_3d = 0;
+	if (vsd == NULL || len < 9) {
+		DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+			__func__);
+		return;
+	}
+
+	offset = HDMI_VSDB_3D_DATA_OFFSET(vsd);
+	DEV_DBG("%s: EDID: 3D present @ %d = %02x\n", __func__,
+		offset, vsd[offset]);
+
+	if (vsd[offset] >> 7) { /* 3D format indication present */
+		DEV_INFO("%s: EDID: 3D present, 3D-len=%d\n", __func__,
+			vsd[offset+1] & 0x1F);
+		edid_ctrl->present_3d = 1;
+	}
+} /* hdmi_edid_extract_3d_present */
+
+static void hdmi_edid_extract_audio_data_blocks(
+	struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+	u8 len;
+	const u8 *sad = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, &len);
+	if (sad == NULL)
+		return;
+
+	edid_ctrl->audio_data_block_cnt = 0;
+	while (len >= 3 && edid_ctrl->audio_data_block_cnt < 16) {
+		DEV_DBG("%s: ch=%d fmt=%d sampling=0x%02x bitdepth=0x%02x\n",
+			__func__, (sad[1]&0x7)+1, sad[1]>>3, sad[2], sad[3]);
+
+		++edid_ctrl->audio_data_block_cnt;
+		len -= 3;
+		sad += 3;
+	}
+} /* hdmi_edid_extract_audio_data_blocks */
+
+static void hdmi_edid_extract_speaker_allocation_data(
+	struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+	u8 len;
+	const u8 *sad = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, &len);
+	if (sad == NULL)
+		return;
+
+	edid_ctrl->speaker_allocation_block = sad[1];
+	DEV_DBG("%s: EDID: speaker alloc data SP byte = %08x %s%s%s%s%s%s%s\n",
+		__func__, sad[1],
+		(sad[1] & BIT(0)) ? "FL/FR," : "",
+		(sad[1] & BIT(1)) ? "LFE," : "",
+		(sad[1] & BIT(2)) ? "FC," : "",
+		(sad[1] & BIT(3)) ? "RL/RR," : "",
+		(sad[1] & BIT(4)) ? "RC," : "",
+		(sad[1] & BIT(5)) ? "FLC/FRC," : "",
+		(sad[1] & BIT(6)) ? "RLC/RRC," : "");
+} /* hdmi_edid_extract_speaker_allocation_data */
+
+static void hdmi_edid_extract_latency_fields(struct hdmi_edid_ctrl *edid_ctrl,
+	const u8 *in_buf)
+{
+	u8 len;
+	const u8 *vsd = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+
+	if (vsd == NULL || len < 12 || !(vsd[8] & BIT(7))) {
+		edid_ctrl->video_latency = (u16)-1;
+		edid_ctrl->audio_latency = (u16)-1;
+		DEV_DBG("%s: EDID: No audio/video latency present\n", __func__);
+	} else {
+		edid_ctrl->video_latency = vsd[9];
+		edid_ctrl->audio_latency = vsd[10];
+		DEV_DBG("%s: EDID: video-latency=%04x, audio-latency=%04x\n",
+			__func__, edid_ctrl->video_latency,
+			edid_ctrl->audio_latency);
+	}
+} /* hdmi_edid_extract_latency_fields */
+
+static u32 hdmi_edid_extract_ieee_reg_id(struct hdmi_edid_ctrl *edid_ctrl,
+	const u8 *in_buf)
+{
+	u8 len;
+	const u8 *vsd = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return 0;
+	}
+
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+	if (vsd == NULL)
+		return 0;
+
+	DEV_DBG("%s: EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n", __func__,
+		((u32)vsd[4] << 8) + (u32)vsd[5], (u32)vsd[7] * 5);
+
+	edid_ctrl->physical_address = ((u16)vsd[4] << 8) + (u16)vsd[5];
+
+	return ((u32)vsd[3] << 16) + ((u32)vsd[2] << 8) + (u32)vsd[1];
+} /* hdmi_edid_extract_ieee_reg_id */
+
+static void hdmi_edid_extract_vendor_id(const u8 *in_buf,
+	char *vendor_id)
+{
+	u32 id_codes = ((u32)in_buf[8] << 8) + in_buf[9];
+
+	vendor_id[0] = 'A' - 1 + ((id_codes >> 10) & 0x1F);
+	vendor_id[1] = 'A' - 1 + ((id_codes >> 5) & 0x1F);
+	vendor_id[2] = 'A' - 1 + (id_codes & 0x1F);
+	vendor_id[3] = 0;
+} /* hdmi_edid_extract_vendor_id */
+
+static u32 hdmi_edid_check_header(const u8 *edid_buf)
+{
+	return (edid_buf[0] == 0x00) && (edid_buf[1] == 0xff)
+		&& (edid_buf[2] == 0xff) && (edid_buf[3] == 0xff)
+		&& (edid_buf[4] == 0xff) && (edid_buf[5] == 0xff)
+		&& (edid_buf[6] == 0xff) && (edid_buf[7] == 0x00);
+} /* hdmi_edid_check_header */
+
+static void hdmi_edid_detail_desc(const u8 *data_buf, u32 *disp_mode)
+{
+	u32	aspect_ratio_4_3    = false;
+	u32	interlaced          = false;
+	u32	active_h            = 0;
+	u32	active_v            = 0;
+	u32	blank_h             = 0;
+	u32	blank_v             = 0;
+	u32	ndx                 = 0;
+	u32	max_num_of_elements = 0;
+	u32	img_size_h          = 0;
+	u32	img_size_v          = 0;
+
+	/*
+	 * * See VESA Spec
+	 * * EDID_TIMING_DESC_UPPER_H_NIBBLE[0x4]: Relative Offset to the
+	 *   EDID detailed timing descriptors - Upper 4 bit for each H
+	 *   active/blank field
+	 * * EDID_TIMING_DESC_H_ACTIVE[0x2]: Relative Offset to the EDID
+	 *   detailed timing descriptors - H active
+	 */
+	active_h = ((((u32)data_buf[0x4] >> 0x4) & 0xF) << 8)
+		| data_buf[0x2];
+
+	/*
+	 * EDID_TIMING_DESC_H_BLANK[0x3]: Relative Offset to the EDID detailed
+	 *   timing descriptors - H blank
+	 */
+	blank_h = (((u32)data_buf[0x4] & 0xF) << 8)
+		| data_buf[0x3];
+
+	/*
+	 * * EDID_TIMING_DESC_UPPER_V_NIBBLE[0x7]: Relative Offset to the
+	 *   EDID detailed timing descriptors - Upper 4 bit for each V
+	 *   active/blank field
+	 * * EDID_TIMING_DESC_V_ACTIVE[0x5]: Relative Offset to the EDID
+	 *   detailed timing descriptors - V active
+	 */
+	active_v = ((((u32)data_buf[0x7] >> 0x4) & 0xF) << 8)
+		| data_buf[0x5];
+
+	/*
+	 * EDID_TIMING_DESC_V_BLANK[0x6]: Relative Offset to the EDID
+	 * detailed timing descriptors - V blank
+	 */
+	blank_v = (((u32)data_buf[0x7] & 0xF) << 8)
+		| data_buf[0x6];
+
+	/*
+	 * * EDID_TIMING_DESC_IMAGE_SIZE_UPPER_NIBBLE[0xE]: Relative Offset
+	 *   to the EDID detailed timing descriptors - Image Size upper
+	 *   nibble V and H
+	 * * EDID_TIMING_DESC_H_IMAGE_SIZE[0xC]: Relative Offset to the EDID
+	 *   detailed timing descriptors - H image size
+	 * * EDID_TIMING_DESC_V_IMAGE_SIZE[0xD]: Relative Offset to the EDID
+	 *   detailed timing descriptors - V image size
+	 */
+	img_size_h = ((((u32)data_buf[0xE] >> 0x4) & 0xF) << 8)
+		| data_buf[0xC];
+	img_size_v = (((u32)data_buf[0xE] & 0xF) << 8)
+		| data_buf[0xD];
+
+	/*
+	 * aspect ratio as 4:3 if within specificed range , rathaer than being
+	 * absolute value
+	 */
+	aspect_ratio_4_3 = (abs(img_size_h * 3 - img_size_v * 4) < 5) ? 1 : 0;
+
+	max_num_of_elements = sizeof(hdmi_edid_disp_mode_lut)
+		/ sizeof(*hdmi_edid_disp_mode_lut);
+
+	/*
+	 * EDID_TIMING_DESC_INTERLACE[0x11:7]: Relative Offset to the EDID
+	 * detailed timing descriptors - Interlace flag
+	 */
+	DEV_DBG("%s: Interlaced mode byte data_buf[0x11]=[%x]\n", __func__,
+		data_buf[0x11]);
+
+	/*
+	 * CEA 861-D: interlaced bit is bit[7] of byte[0x11]
+	 */
+	interlaced = (data_buf[0x11] & 0x80) >> 7;
+
+	DEV_DBG("%s: A[%ux%u] B[%ux%u] V[%ux%u] %s\n", __func__,
+		active_h, active_v, blank_h, blank_v, img_size_h, img_size_v,
+		interlaced ? "i" : "p");
+
+	*disp_mode = HDMI_VFRMT_FORCE_32BIT;
+	while (ndx < max_num_of_elements) {
+		const struct hdmi_edid_video_mode_property_type *edid =
+			hdmi_edid_disp_mode_lut + ndx;
+
+		if ((interlaced    == edid->interlaced)    &&
+			(active_h  == edid->active_h)      &&
+			(blank_h   == edid->total_blank_h) &&
+			(blank_v   == edid->total_blank_v) &&
+			((active_v == edid->active_v) ||
+			(active_v  == (edid->active_v + 1)))) {
+			if (edid->aspect_ratio_4_3 && !aspect_ratio_4_3)
+				/* Aspect ratio 16:9 */
+				*disp_mode = edid->video_code + 1;
+			else
+				/* Aspect ratio 4:3 */
+				*disp_mode = edid->video_code;
+
+			DEV_DBG("%s: mode found:%d\n", __func__, *disp_mode);
+			break;
+		}
+		++ndx;
+	}
+	if (ndx == max_num_of_elements)
+		DEV_INFO("%s: *no mode* found\n", __func__);
+} /* hdmi_edid_detail_desc */
+
+static void hdmi_edid_add_sink_3d_format(struct hdmi_edid_sink_data *sink_data,
+	u32 video_format, u32 video_3d_format)
+{
+	char string[128];
+	u32 added = false;
+	int i;
+
+	for (i = 0; i < sink_data->num_of_elements; ++i) {
+		if (sink_data->disp_mode_list[i] == video_format) {
+			sink_data->disp_3d_mode_list[i] |= video_3d_format;
+			added = true;
+			break;
+		}
+	}
+
+	hdmi_get_video_3d_fmt_2string(video_3d_format, string);
+
+	DEV_DBG("%s: EDID[3D]: format: %d [%s], %s %s\n", __func__,
+		video_format, hdmi_get_video_fmt_2string(video_format),
+		string, added ? "added" : "NOT added");
+} /* hdmi_edid_add_sink_3d_format */
+
+static void hdmi_edid_add_sink_video_format(
+	struct hdmi_edid_sink_data *sink_data, u32 video_format)
+{
+	const struct hdmi_disp_mode_timing_type *timing =
+		hdmi_get_supported_mode(video_format);
+	u32 supported = timing != NULL;
+
+	if (video_format >= HDMI_VFRMT_MAX) {
+		DEV_ERR("%s: video format: %s is not supported\n", __func__,
+			hdmi_get_video_fmt_2string(video_format));
+		return;
+	}
+
+	DEV_DBG("%s: EDID: format: %d [%s], %s\n", __func__,
+		video_format, hdmi_get_video_fmt_2string(video_format),
+		supported ? "Supported" : "Not-Supported");
+
+	if (supported) {
+		/* todo: MHL */
+		sink_data->disp_mode_list[sink_data->num_of_elements++] =
+			video_format;
+	}
+} /* hdmi_edid_add_sink_video_format */
+
+static void hdmi_edid_get_display_vsd_3d_mode(const u8 *data_buf,
+	struct hdmi_edid_sink_data *sink_data, u32 num_of_cea_blocks)
+{
+	u8 len, offset, present_multi_3d, hdmi_vic_len, hdmi_3d_len;
+	u16 structure_all, structure_mask;
+	const u8 *vsd = num_of_cea_blocks ?
+		hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
+				3, &len) : NULL;
+	int i;
+
+	offset = HDMI_VSDB_3D_DATA_OFFSET(vsd);
+	present_multi_3d = (vsd[offset] & 0x60) >> 5;
+
+	offset += 1;
+	hdmi_vic_len = (vsd[offset] >> 5) & 0x7;
+	hdmi_3d_len = vsd[offset] & 0x1F;
+	DEV_DBG("%s: EDID[3D]: HDMI_VIC_LEN = %d, HDMI_3D_LEN = %d\n", __func__,
+		hdmi_vic_len, hdmi_3d_len);
+
+	offset += (hdmi_vic_len + 1);
+	if (present_multi_3d == 1 || present_multi_3d == 2) {
+		DEV_DBG("%s: EDID[3D]: multi 3D present (%d)\n", __func__,
+			present_multi_3d);
+		/* 3d_structure_all */
+		structure_all = (vsd[offset] << 8) | vsd[offset + 1];
+		offset += 2;
+		hdmi_3d_len -= 2;
+		if (present_multi_3d == 2) {
+			/* 3d_structure_mask */
+			structure_mask = (vsd[offset] << 8) | vsd[offset + 1];
+			offset += 2;
+			hdmi_3d_len -= 2;
+		} else
+			structure_mask = 0xffff;
+
+		i = 0;
+		while (i < 16) {
+			if (i >= sink_data->disp_multi_3d_mode_list_cnt)
+				break;
+
+			if (!(structure_mask & BIT(i))) {
+				++i;
+				continue;
+			}
+
+			/* BIT0: FRAME PACKING */
+			if (structure_all & BIT(0))
+				hdmi_edid_add_sink_3d_format(sink_data,
+					sink_data->
+					disp_multi_3d_mode_list[i],
+					FRAME_PACKING);
+
+			/* BIT6: TOP AND BOTTOM */
+			if (structure_all & BIT(6))
+				hdmi_edid_add_sink_3d_format(sink_data,
+					sink_data->
+					disp_multi_3d_mode_list[i],
+					TOP_AND_BOTTOM);
+
+			/* BIT8: SIDE BY SIDE HALF */
+			if (structure_all & BIT(8))
+				hdmi_edid_add_sink_3d_format(sink_data,
+					sink_data->
+					disp_multi_3d_mode_list[i],
+					SIDE_BY_SIDE_HALF);
+
+			++i;
+		}
+	}
+
+	i = 0;
+	while (hdmi_3d_len > 0) {
+		DEV_DBG("%s: EDID[3D]: 3D_Structure_%d @ %d: %02x\n", __func__,
+			i + 1, offset, vsd[offset]);
+
+		if ((vsd[offset] >> 4) >=
+			sink_data->disp_multi_3d_mode_list_cnt) {
+			if ((vsd[offset] & 0x0F) >= 8) {
+				offset += 1;
+				hdmi_3d_len -= 1;
+				DEV_DBG("%s:EDID[3D]:3D_Detail_%d @ %d: %02x\n",
+					__func__, i + 1, offset,
+					vsd[offset]);
+			}
+			i += 1;
+			offset += 1;
+			hdmi_3d_len -= 1;
+			continue;
+		}
+
+		switch (vsd[offset] & 0x0F) {
+		case 0:
+			/* 0000b: FRAME PACKING */
+			hdmi_edid_add_sink_3d_format(sink_data,
+				sink_data->
+				disp_multi_3d_mode_list[vsd[offset] >> 4],
+				FRAME_PACKING);
+			break;
+		case 6:
+			/* 0110b: TOP AND BOTTOM */
+			hdmi_edid_add_sink_3d_format(sink_data,
+				sink_data->
+				disp_multi_3d_mode_list[vsd[offset] >> 4],
+				TOP_AND_BOTTOM);
+			break;
+		case 8:
+			/* 1000b: SIDE BY SIDE HALF */
+			hdmi_edid_add_sink_3d_format(sink_data,
+				sink_data->
+				disp_multi_3d_mode_list[vsd[offset] >> 4],
+				SIDE_BY_SIDE_HALF);
+			break;
+		}
+		if ((vsd[offset] & 0x0F) >= 8) {
+			offset += 1;
+			hdmi_3d_len -= 1;
+			DEV_DBG("%s: EDID[3D]: 3D_Detail_%d @ %d: %02x\n",
+				__func__, i + 1, offset,
+				vsd[offset]);
+		}
+		i += 1;
+		offset += 1;
+		hdmi_3d_len -= 1;
+	}
+} /* hdmi_edid_get_display_vsd_3d_mode */
+
+static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl,
+	const u8 *data_buf, u32 num_of_cea_blocks)
+{
+	u8 i = 0;
+	u32 video_format = HDMI_VFRMT_640x480p60_4_3;
+	u32 has480p = false;
+	u8 len;
+	const u8 *edid_blk0 = NULL;
+	const u8 *edid_blk1 = NULL;
+	const u8 *svd = NULL;
+	u32 has60hz_mode = false;
+	u32 has50hz_mode = false;
+	struct hdmi_edid_sink_data *sink_data = NULL;
+
+	if (!edid_ctrl || !data_buf) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	edid_blk0 = &data_buf[0x0];
+	edid_blk1 = &data_buf[0x80];
+	svd = num_of_cea_blocks ?
+		hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, 2,
+			&len) : NULL;
+
+	sink_data = &edid_ctrl->sink_data;
+
+	sink_data->num_of_elements = 0;
+	sink_data->disp_multi_3d_mode_list_cnt = 0;
+	if (svd != NULL) {
+		++svd;
+		for (i = 0; i < len; ++i, ++svd) {
+			/*
+			 * Subtract 1 because it is zero based in the driver,
+			 * while the Video identification code is 1 based in the
+			 * CEA_861D spec
+			 */
+			video_format = (*svd & 0x7F) - 1;
+			hdmi_edid_add_sink_video_format(sink_data,
+				video_format);
+			/* Make a note of the preferred video format */
+			if (i == 0)
+				sink_data->preferred_video_format =
+					video_format;
+
+			if (i < 16) {
+				sink_data->disp_multi_3d_mode_list[i]
+					= video_format;
+				sink_data->disp_multi_3d_mode_list_cnt++;
+			}
+
+			if (video_format <= HDMI_VFRMT_1920x1080p60_16_9 ||
+				video_format == HDMI_VFRMT_2880x480p60_4_3 ||
+				video_format == HDMI_VFRMT_2880x480p60_16_9)
+				has60hz_mode = true;
+
+			if ((video_format >= HDMI_VFRMT_720x576p50_4_3 &&
+				video_format <= HDMI_VFRMT_1920x1080p50_16_9) ||
+				video_format == HDMI_VFRMT_2880x576p50_4_3 ||
+				video_format == HDMI_VFRMT_2880x576p50_16_9 ||
+				video_format == HDMI_VFRMT_1920x1250i50_16_9)
+				has50hz_mode = true;
+
+			if (video_format == HDMI_VFRMT_640x480p60_4_3)
+				has480p = true;
+		}
+	} else if (!num_of_cea_blocks) {
+		/* Detailed timing descriptors */
+		u32 desc_offset = 0;
+		/*
+		 * * Maximum 4 timing descriptor in block 0 - No CEA
+		 *   extension in this case
+		 * * EDID_FIRST_TIMING_DESC[0x36] - 1st detailed timing
+		 *   descriptor
+		 * * EDID_DETAIL_TIMING_DESC_BLCK_SZ[0x12] - Each detailed
+		 *   timing descriptor has block size of 18
+		 */
+		while (4 > i && 0 != edid_blk0[0x36+desc_offset]) {
+			hdmi_edid_detail_desc(edid_blk0+0x36+desc_offset,
+				&video_format);
+
+			DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
+				__func__, __LINE__,
+				hdmi_get_video_fmt_2string(video_format));
+
+			hdmi_edid_add_sink_video_format(sink_data,
+				video_format);
+
+			if (video_format == HDMI_VFRMT_640x480p60_4_3)
+				has480p = true;
+
+			/* Make a note of the preferred video format */
+			if (i == 0) {
+				sink_data->preferred_video_format =
+					video_format;
+			}
+			desc_offset += 0x12;
+			++i;
+		}
+	} else if (1 == num_of_cea_blocks) {
+		u32 desc_offset = 0;
+
+		/*
+		 * Read from both block 0 and block 1
+		 * Read EDID block[0] as above
+		 */
+		while (4 > i && 0 != edid_blk0[0x36+desc_offset]) {
+			hdmi_edid_detail_desc(edid_blk0+0x36+desc_offset,
+				&video_format);
+
+			DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
+				__func__, __LINE__,
+				hdmi_get_video_fmt_2string(video_format));
+
+			hdmi_edid_add_sink_video_format(sink_data,
+				video_format);
+
+			if (video_format == HDMI_VFRMT_640x480p60_4_3)
+				has480p = true;
+
+			/* Make a note of the preferred video format */
+			if (i == 0) {
+				sink_data->preferred_video_format =
+					video_format;
+			}
+			desc_offset += 0x12;
+			++i;
+		}
+
+		/*
+		 * * Parse block 1 - CEA extension byte offset of first
+		 *   detailed timing generation - offset is relevant to
+		 *   the offset of block 1
+		 * * EDID_CEA_EXTENSION_FIRST_DESC[0x82]: Offset to CEA
+		 *   extension first timing desc - indicate the offset of
+		 *   the first detailed timing descriptor
+		 * * EDID_BLOCK_SIZE = 0x80  Each page size in the EDID ROM
+		 */
+		desc_offset = edid_blk1[0x02];
+		while (0 != edid_blk1[desc_offset]) {
+			hdmi_edid_detail_desc(edid_blk1+desc_offset,
+				&video_format);
+
+			DEV_DBG("[%s:%d] Block-1 Adding vid fmt = [%s]\n",
+				__func__, __LINE__,
+				hdmi_get_video_fmt_2string(video_format));
+
+			hdmi_edid_add_sink_video_format(sink_data,
+				video_format);
+			if (video_format == HDMI_VFRMT_640x480p60_4_3)
+				has480p = true;
+
+			/* Make a note of the preferred video format */
+			if (i == 0) {
+				sink_data->preferred_video_format =
+					video_format;
+			}
+			desc_offset += 0x12;
+			++i;
+		}
+	}
+
+	/* mandaroty 3d format */
+	if (edid_ctrl->present_3d) {
+		if (has60hz_mode) {
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1920x1080p24_16_9,
+				FRAME_PACKING | TOP_AND_BOTTOM);
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1280x720p60_16_9,
+				FRAME_PACKING | TOP_AND_BOTTOM);
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1920x1080i60_16_9,
+				SIDE_BY_SIDE_HALF);
+		}
+
+		if (has50hz_mode) {
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1920x1080p24_16_9,
+				FRAME_PACKING | TOP_AND_BOTTOM);
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1280x720p50_16_9,
+				FRAME_PACKING | TOP_AND_BOTTOM);
+			hdmi_edid_add_sink_3d_format(sink_data,
+				HDMI_VFRMT_1920x1080i50_16_9,
+				SIDE_BY_SIDE_HALF);
+		}
+
+		/* 3d format described in Vendor Specific Data */
+		hdmi_edid_get_display_vsd_3d_mode(data_buf, sink_data,
+			num_of_cea_blocks);
+	}
+
+	/*
+	 * Need to add default 640 by 480 timings, in case not described
+	 * in the EDID structure.
+	 * All DTV sink devices should support this mode
+	 */
+	if (!has480p)
+		hdmi_edid_add_sink_video_format(sink_data,
+			HDMI_VFRMT_640x480p60_4_3);
+} /* hdmi_edid_get_display_mode */
+
+int hdmi_edid_read(void *input)
+{
+	/* EDID_BLOCK_SIZE[0x80] Each page size in the EDID ROM */
+	u8 edid_buf[0x80 * 4];
+	u32 cea_extension_ver = 0;
+	u32 num_of_cea_blocks = 0;
+	u32 ieee_reg_id = 0;
+	u32 i = 1;
+	int status = 0;
+	char vendor_id[5];
+	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	edid_ctrl->pt_scan_info = 0;
+	edid_ctrl->it_scan_info = 0;
+	edid_ctrl->ce_scan_info = 0;
+	edid_ctrl->present_3d = 0;
+	memset(&edid_ctrl->sink_data, 0, sizeof(edid_ctrl->sink_data));
+	memset(edid_buf, 0, sizeof(edid_buf));
+
+	status = hdmi_edid_read_block(edid_ctrl, 0, edid_buf);
+	if (status || !hdmi_edid_check_header(edid_buf)) {
+		if (!status)
+			status = -EPROTO;
+		DEV_ERR("%s: blk0 fail:%d[%02x%02x%02x%02x%02x%02x%02x%02x]\n",
+			__func__, status,
+			edid_buf[0], edid_buf[1], edid_buf[2], edid_buf[3],
+			edid_buf[4], edid_buf[5], edid_buf[6], edid_buf[7]);
+		goto error;
+	}
+	hdmi_edid_extract_vendor_id(edid_buf, vendor_id);
+
+	/* EDID_CEA_EXTENSION_FLAG[0x7E] - CEC extension byte */
+	num_of_cea_blocks = edid_buf[0x7E];
+	DEV_DBG("%s: No. of CEA blocks is  [%u]\n", __func__,
+		num_of_cea_blocks);
+	/* Find out any CEA extension blocks following block 0 */
+	switch (num_of_cea_blocks) {
+	case 0: /* No CEA extension */
+		edid_ctrl->sink_mode = false;
+		DEV_DBG("HDMI DVI mode: %s\n",
+			edid_ctrl->sink_mode ? "no" : "yes");
+		break;
+	case 1: /* Read block 1 */
+		status = hdmi_edid_read_block(edid_ctrl, 1, &edid_buf[0x80]);
+		if (status) {
+			DEV_ERR("%s: ddc read block(1) failed: %d\n", __func__,
+				status);
+			goto error;
+		}
+		if (edid_buf[0x80] != 2)
+			num_of_cea_blocks = 0;
+		if (num_of_cea_blocks) {
+			ieee_reg_id =
+				hdmi_edid_extract_ieee_reg_id(edid_ctrl,
+					edid_buf+0x80);
+			if (ieee_reg_id == 0x0c03)
+				edid_ctrl->sink_mode = true;
+			else
+				edid_ctrl->sink_mode = false;
+
+			hdmi_edid_extract_latency_fields(edid_ctrl,
+				edid_buf+0x80);
+			hdmi_edid_extract_speaker_allocation_data(
+				edid_ctrl, edid_buf+0x80);
+			hdmi_edid_extract_audio_data_blocks(edid_ctrl,
+				edid_buf+0x80);
+			hdmi_edid_extract_3d_present(edid_ctrl,
+				edid_buf+0x80);
+			hdmi_edid_extract_extended_data_blocks(edid_ctrl,
+				edid_buf+0x80);
+		}
+		break;
+	case 2:
+	case 3:
+	case 4:
+		for (i = 1; i <= num_of_cea_blocks; i++) {
+			if (!(i % 2)) {
+				status = hdmi_edid_read_block(
+					edid_ctrl, i, edid_buf+0x00);
+				if (status) {
+					DEV_ERR("%s: read blk(%d) failed:%d\n",
+						__func__, i, status);
+					goto error;
+				}
+			} else {
+				status = hdmi_edid_read_block(
+					edid_ctrl, i, edid_buf+0x80);
+				if (status) {
+					DEV_ERR("%s: read blk(%d) failed:%d\n",
+						__func__, i, status);
+					goto error;
+				}
+			}
+		}
+		break;
+	default:
+		DEV_ERR("%s: ddc read failed, not supported multi-blocks: %d\n",
+			__func__, num_of_cea_blocks);
+		status = -EPROTO;
+		goto error;
+	}
+
+	if (num_of_cea_blocks) {
+		/* EDID_CEA_EXTENSION_VERSION[0x81]: Offset to CEA extension
+		 * version number - v1,v2,v3 (v1 is seldom, v2 is obsolete,
+		 * v3 most common) */
+		cea_extension_ver = edid_buf[0x81];
+	}
+
+	/* EDID_VERSION[0x12] - EDID Version */
+	/* EDID_REVISION[0x13] - EDID Revision */
+	DEV_INFO("%s: V=%d.%d #CEABlks=%d[V%d] ID=%s IEEE=%04x Ext=0x%02x\n",
+		__func__, edid_buf[0x12], edid_buf[0x13],
+		num_of_cea_blocks, cea_extension_ver, vendor_id, ieee_reg_id,
+		edid_buf[0x80]);
+
+	hdmi_edid_get_display_mode(edid_ctrl, edid_buf, num_of_cea_blocks);
+
+	return 0;
+
+error:
+	edid_ctrl->sink_data.num_of_elements = 1;
+	edid_ctrl->sink_data.disp_mode_list[0] = edid_ctrl->video_resolution;
+
+	return status;
+} /* hdmi_edid_read */
+
+/*
+ * If the sink specified support for both underscan/overscan then, by default,
+ * set the underscan bit. Only checking underscan support for preferred
+ * format and cea formats.
+ */
+u8 hdmi_edid_get_sink_scaninfo(void *input, u32 resolution)
+{
+	u8 scaninfo = 0;
+	int use_ce_scan_info = true;
+	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		goto end;
+	}
+
+	if (resolution == edid_ctrl->sink_data.preferred_video_format) {
+		use_ce_scan_info = false;
+		switch (edid_ctrl->pt_scan_info) {
+		case 0:
+			/*
+			 * Need to use the info specified for the corresponding
+			 * IT or CE format
+			 */
+			DEV_DBG("%s: No underscan info for preferred V fmt\n",
+				__func__);
+			use_ce_scan_info = true;
+			break;
+		case 3:
+			DEV_DBG("%s: Set underscan bit for preferred V fmt\n",
+				__func__);
+			scaninfo = BIT(1);
+			break;
+		default:
+			DEV_DBG("%s: Underscan not set for preferred V fmt\n",
+				__func__);
+			break;
+		}
+	}
+
+	if (use_ce_scan_info) {
+		if (3 == edid_ctrl->ce_scan_info) {
+			DEV_DBG("%s: Setting underscan bit for CE video fmt\n",
+				__func__);
+			scaninfo |= BIT(1);
+		} else {
+			DEV_DBG("%s: Not setting underscan bit for CE V fmt\n",
+				__func__);
+		}
+	}
+
+end:
+	return scaninfo;
+} /* hdmi_edid_get_sink_scaninfo */
+
+u32 hdmi_edid_get_sink_mode(void *input)
+{
+	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return 0;
+	}
+
+	return edid_ctrl->sink_mode;
+} /* hdmi_edid_get_sink_mode */
+
+void hdmi_edid_set_video_resolution(void *input, u32 resolution)
+{
+	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	edid_ctrl->video_resolution = resolution;
+
+	if (1 == edid_ctrl->sink_data.num_of_elements)
+		edid_ctrl->sink_data.disp_mode_list[0] = resolution;
+} /* hdmi_edid_set_video_resolution */
+
+void hdmi_edid_deinit(void *input)
+{
+	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+	if (edid_ctrl) {
+		sysfs_remove_group(edid_ctrl->init_data.sysfs_kobj,
+			&hdmi_edid_fs_attrs_group);
+		kfree(edid_ctrl);
+	}
+} /* hdmi_edid_deinit */
+
+void *hdmi_edid_init(struct hdmi_edid_init_data *init_data)
+{
+	struct hdmi_edid_ctrl *edid_ctrl = NULL;
+
+	if (!init_data || !init_data->base ||
+		!init_data->mutex || !init_data->sysfs_kobj ||
+		!init_data->ddc_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		goto error;
+	}
+
+	edid_ctrl = kzalloc(sizeof(*edid_ctrl), GFP_KERNEL);
+	if (!edid_ctrl) {
+		DEV_ERR("%s: Out of memory\n", __func__);
+		goto error;
+	}
+
+	edid_ctrl->init_data = *init_data;
+	edid_ctrl->sink_mode = false;
+
+	if (sysfs_create_group(init_data->sysfs_kobj,
+		&hdmi_edid_fs_attrs_group)) {
+		DEV_ERR("%s: EDID sysfs create failed\n", __func__);
+		kfree(edid_ctrl);
+		edid_ctrl = NULL;
+	}
+
+error:
+	return (void *)edid_ctrl;
+} /* hdmi_edid_deinit */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.h b/drivers/video/msm/mdss/mdss_hdmi_edid.h
new file mode 100644
index 0000000..d10ae49
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __HDMI_EDID_H__
+#define __HDMI_EDID_H__
+
+#include "mdss_hdmi_util.h"
+
+struct hdmi_edid_init_data {
+	void __iomem *base;
+	struct mutex *mutex;
+	struct kobject *sysfs_kobj;
+
+	struct hdmi_tx_ddc_ctrl *ddc_ctrl;
+};
+
+int hdmi_edid_read(void *edid_ctrl);
+u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution);
+u32 hdmi_edid_get_sink_mode(void *edid_ctrl);
+void hdmi_edid_set_video_resolution(void *edid_ctrl, u32 resolution);
+void hdmi_edid_deinit(void *edid_ctrl);
+void *hdmi_edid_init(struct hdmi_edid_init_data *init_data);
+
+#endif /* __HDMI_EDID_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 6317069..b88ff72 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -24,12 +24,24 @@
 
 #include "mdss_fb.h"
 #include "mdss_hdmi_tx.h"
+#include "mdss_hdmi_edid.h"
 #include "mdss.h"
 #include "mdss_panel.h"
 
 #define DRV_NAME "hdmi-tx"
 #define COMPATIBLE_NAME "qcom,hdmi-tx"
 
+#define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9;
+
+/* HDMI PHY/PLL bit field macros */
+#define SW_RESET BIT(2)
+#define SW_RESET_PLL BIT(0)
+
+#define IFRAME_CHECKSUM_32(d)			\
+	((d & 0xff) + ((d >> 8) & 0xff) +	\
+	((d >> 16) & 0xff) + ((d >> 24) & 0xff))
+
+static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on);
 static irqreturn_t hdmi_tx_isr(int irq, void *data);
 
 struct mdss_hw hdmi_tx_hw = {
@@ -48,6 +60,37 @@
 	}
 } /* hdmi_pm_name */
 
+static u8 hdmi_tx_avi_iframe_lut[][16] = {
+/*	480p60	480i60	576p50	576i50	720p60	 720p50	1080p60	1080i60	1080p50
+	1080i50	1080p24	1080p30	1080p25	640x480p 480p60_16_9 576p50_4_3 */
+	{0x10,	0x10,	0x10,	0x10,	0x10,	 0x10,	0x10,	0x10,	0x10,
+	 0x10,	0x10,	0x10,	0x10,	0x10, 0x10, 0x10}, /*00*/
+	{0x18,	0x18,	0x28,	0x28,	0x28,	 0x28,	0x28,	0x28,	0x28,
+	 0x28,	0x28,	0x28,	0x28,	0x18, 0x28, 0x18}, /*01*/
+	{0x00,	0x04,	0x04,	0x04,	0x04,	 0x04,	0x04,	0x04,	0x04,
+	 0x04,	0x04,	0x04,	0x04,	0x88, 0x00, 0x04}, /*02*/
+	{0x02,	0x06,	0x11,	0x15,	0x04,	 0x13,	0x10,	0x05,	0x1F,
+	 0x14,	0x20,	0x22,	0x21,	0x01, 0x03, 0x11}, /*03*/
+	{0x00,	0x01,	0x00,	0x01,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*04*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*05*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*06*/
+	{0xE1,	0xE1,	0x41,	0x41,	0xD1,	 0xd1,	0x39,	0x39,	0x39,
+	 0x39,	0x39,	0x39,	0x39,	0xe1, 0xE1, 0x41}, /*07*/
+	{0x01,	0x01,	0x02,	0x02,	0x02,	 0x02,	0x04,	0x04,	0x04,
+	 0x04,	0x04,	0x04,	0x04,	0x01, 0x01, 0x02}, /*08*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*09*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*10*/
+	{0xD1,	0xD1,	0xD1,	0xD1,	0x01,	 0x01,	0x81,	0x81,	0x81,
+	 0x81,	0x81,	0x81,	0x81,	0x81, 0xD1, 0xD1}, /*11*/
+	{0x02,	0x02,	0x02,	0x02,	0x05,	 0x05,	0x07,	0x07,	0x07,
+	 0x07,	0x07,	0x07,	0x07,	0x02, 0x02, 0x02}  /*12*/
+};
+
 static const char *hdmi_tx_clk_name(u32 clk)
 {
 	switch (clk) {
@@ -68,6 +111,298 @@
 	}
 } /* hdmi_tx_io_name */
 
+static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_panel_data(
+	struct mdss_panel_data *mpd)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	if (mpd) {
+		hdmi_ctrl = container_of(mpd, struct hdmi_tx_ctrl, panel_data);
+		if (hdmi_ctrl) {
+			hdmi_ctrl->pixel_clk =
+				mpd->panel_info.fbi->var.pixclock;
+			hdmi_ctrl->xres = mpd->panel_info.fbi->var.xres;
+			hdmi_ctrl->yres = mpd->panel_info.fbi->var.yres;
+		} else {
+			DEV_ERR("%s: hdmi_ctrl = NULL\n", __func__);
+		}
+	} else {
+		DEV_ERR("%s: mdss_panel_data = NULL\n", __func__);
+	}
+	return hdmi_ctrl;
+} /* hdmi_tx_get_drvdata_from_panel_data */
+
+static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_sysfs_dev(
+	struct device *device)
+{
+	struct msm_fb_data_type *mfd = NULL;
+	struct mdss_panel_data *panel_data = NULL;
+	struct fb_info *fbi = dev_get_drvdata(device);
+
+	if (fbi) {
+		mfd = (struct msm_fb_data_type *)fbi->par;
+		panel_data = dev_get_platdata(&mfd->pdev->dev);
+
+		return hdmi_tx_get_drvdata_from_panel_data(panel_data);
+	} else {
+		DEV_ERR("%s: fbi = NULL\n", __func__);
+		return NULL;
+	}
+} /* hdmi_tx_get_drvdata_from_sysfs_dev */
+
+/* todo: Fix this. Right now this is declared in hdmi_util.h */
+void *hdmi_get_featuredata_from_sysfs_dev(struct device *device,
+	u32 feature_type)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	if (!device || feature_type > HDMI_TX_FEAT_MAX) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return NULL;
+	}
+
+	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(device);
+	if (hdmi_ctrl)
+		return hdmi_ctrl->feature_data[feature_type];
+	else
+		return NULL;
+
+} /* hdmi_tx_get_featuredata_from_sysfs_dev */
+EXPORT_SYMBOL(hdmi_get_featuredata_from_sysfs_dev);
+
+static ssize_t hdmi_tx_sysfs_rda_connected(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct hdmi_tx_ctrl *hdmi_ctrl =
+		hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_state);
+	DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_state);
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	return ret;
+} /* hdmi_tx_sysfs_rda_connected */
+
+static ssize_t hdmi_tx_sysfs_rda_fake_hpd(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct hdmi_tx_ctrl *hdmi_ctrl =
+		hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_state);
+	DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_state);
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	return ret;
+} /* hdmi_tx_sysfs_rda_fake_hpd */
+
+static ssize_t hdmi_tx_sysfs_wta_fake_hpd(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int fake_hpd, rc = 0;
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	DEV_DBG("%s:\n", __func__);
+	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = kstrtoint(buf, 10, &fake_hpd);
+	if (rc) {
+		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		return rc;
+	}
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	DEV_INFO("%s: fake_hpd=%d\n", __func__, fake_hpd);
+	if (fake_hpd) {
+		hdmi_ctrl->hpd_state = true;
+
+		/* todo: Remove this once HPD line is available in HW */
+		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
+		if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE))
+			DEV_ERR("%s: failed sending online event\n", __func__);
+		switch_set_state(&hdmi_ctrl->sdev, 1);
+		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
+	} else {
+		hdmi_ctrl->hpd_state = false;
+
+		/* todo: Remove this once HPD line is available in HW */
+		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
+		if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE))
+			DEV_ERR("%s: failed sending online event\n", __func__);
+		switch_set_state(&hdmi_ctrl->sdev, 0);
+		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
+	}
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	return ret;
+} /* hdmi_tx_sysfs_wta_fake_hpd */
+
+static ssize_t hdmi_tx_sysfs_rda_hpd(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct hdmi_tx_ctrl *hdmi_ctrl =
+		hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_feature_on);
+	DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
+
+	return ret;
+} /* hdmi_tx_sysfs_rda_hpd */
+
+static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int hpd, rc = 0;
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	DEV_DBG("%s:\n", __func__);
+	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = kstrtoint(buf, 10, &hpd);
+	if (rc) {
+		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		return rc;
+	}
+
+	/* todo: Remove this once HPD line is available in HW */
+	if (0) {
+		if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
+			rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+		} else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
+			rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+		} else {
+			rc = -EPERM;
+			ret = rc;
+		}
+	}
+
+	if (!rc) {
+		hdmi_ctrl->hpd_feature_on =
+			(~hdmi_ctrl->hpd_feature_on) & BIT(0);
+		DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
+	} else {
+		DEV_DBG("%s: '%d' (unchanged)\n", __func__,
+			hdmi_ctrl->hpd_feature_on);
+	}
+
+	return ret;
+} /* hdmi_tx_sysfs_wta_hpd */
+
+static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
+static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
+	hdmi_tx_sysfs_wta_hpd);
+static DEVICE_ATTR(fake_hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_fake_hpd,
+	hdmi_tx_sysfs_wta_fake_hpd);
+
+static struct attribute *hdmi_tx_fs_attrs[] = {
+	&dev_attr_connected.attr,
+	&dev_attr_hpd.attr,
+	&dev_attr_fake_hpd.attr,
+	NULL,
+};
+static struct attribute_group hdmi_tx_fs_attrs_group = {
+	.attrs = hdmi_tx_fs_attrs,
+};
+
+static int hdmi_tx_sysfs_create(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc;
+	struct mdss_panel_info *pinfo = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -ENODEV;
+	}
+	pinfo = &hdmi_ctrl->panel_data.panel_info;
+
+	rc = sysfs_create_group(&pinfo->fbi->dev->kobj,
+		&hdmi_tx_fs_attrs_group);
+	if (rc) {
+		DEV_ERR("%s: failed, rc=%d\n", __func__, rc);
+		return rc;
+	}
+	hdmi_ctrl->kobj = &pinfo->fbi->dev->kobj;
+	DEV_DBG("%s: sysfs group %p\n", __func__, hdmi_ctrl->kobj);
+
+	kobject_uevent(hdmi_ctrl->kobj, KOBJ_ADD);
+	DEV_DBG("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+
+	return 0;
+} /* hdmi_tx_sysfs_create */
+
+static void hdmi_tx_sysfs_remove(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+	if (hdmi_ctrl->kobj)
+		sysfs_remove_group(hdmi_ctrl->kobj, &hdmi_tx_fs_attrs_group);
+	hdmi_ctrl->kobj = NULL;
+} /* hdmi_tx_sysfs_remove */
+
+/* Enable HDMI features */
+static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	struct hdmi_edid_init_data edid_init_data;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	edid_init_data.base = hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base;
+	edid_init_data.mutex = &hdmi_ctrl->mutex;
+	edid_init_data.sysfs_kobj = hdmi_ctrl->kobj;
+	edid_init_data.ddc_ctrl = &hdmi_ctrl->ddc_ctrl;
+
+	hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] =
+		hdmi_edid_init(&edid_init_data);
+	if (!hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) {
+		DEV_ERR("%s: hdmi_edid_init failed\n", __func__);
+		return -EPERM;
+	}
+	hdmi_edid_set_video_resolution(
+		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
+		hdmi_ctrl->video_resolution);
+
+	return 0;
+} /* hdmi_tx_init_features */
+
 static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
 	return HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
@@ -138,11 +473,76 @@
 	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p60_16_9);
 } /* hdmi_tx_setup_video_mode_lut */
 
+static inline struct clk *hdmi_tx_get_clk(struct hdmi_tx_platform_data *pdata,
+	u32 clk_idx)
+{
+	if (!pdata || clk_idx > HDMI_TX_MAX_CLK) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return NULL;
+	}
+
+	return pdata->clk[clk_idx];
+} /* hdmi_tx_get_clk */
+
+static int hdmi_tx_clk_set_rate(struct hdmi_tx_platform_data *pdata,
+	u32 clk_idx, unsigned long clk_rate)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	if (!pdata) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	clk = hdmi_tx_get_clk(pdata, clk_idx);
+	if (clk) {
+		rc = clk_set_rate(clk, clk_rate);
+		if (IS_ERR_VALUE(rc))
+			DEV_ERR("%s: failed rc=%d\n", __func__, rc);
+		else
+			DEV_DBG("%s: name='%s' rate=%lu\n", __func__,
+				hdmi_tx_clk_name(clk_idx), clk_rate);
+	} else {
+		DEV_ERR("%s: FAILED: invalid clk_idx=%d\n", __func__, clk_idx);
+		rc = -EINVAL;
+	}
+
+	return rc;
+} /* hdmi_tx_clk_set_rate */
+
+static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int status;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!hdmi_tx_is_controller_on(hdmi_ctrl)) {
+		DEV_ERR("%s: failed: HDMI controller is off", __func__);
+		status = -ENXIO;
+		goto error;
+	}
+
+	hdmi_ddc_config(&hdmi_ctrl->ddc_ctrl);
+
+	status = hdmi_edid_read(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
+	if (!status)
+		DEV_DBG("%s: hdmi_edid_read success\n", __func__);
+	else
+		DEV_ERR("%s: hdmi_edid_read failed\n", __func__);
+
+error:
+	return status;
+} /* hdmi_tx_read_sink_info */
+
 static void hdmi_tx_hpd_state_work(struct work_struct *work)
 {
 	u32 hpd_state = false;
 	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-	struct hdmi_tx_io_data *io = NULL;
+	struct dss_io_data *io = NULL;
 
 	hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_state_work);
 	if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
@@ -181,7 +581,6 @@
 	}
 
 	hdmi_ctrl->hpd_stable = 1;
-	DEV_INFO("HDMI HPD: event detected\n");
 
 	/*
 	 *todo: Revisit cable chg detected condition when HPD support is ready
@@ -190,6 +589,8 @@
 	mutex_unlock(&hdmi_ctrl->mutex);
 
 	if (hpd_state) {
+		/* todo: what if EDID read fails? */
+		hdmi_tx_read_sink_info(hdmi_ctrl);
 		DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
 		kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE);
 		switch_set_state(&hdmi_ctrl->sdev, 1);
@@ -235,7 +636,432 @@
 	return 0;
 } /* hdmi_tx_check_capability */
 
-/* todo: revisit when new HPD debouncing logic is available */
+static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+	const struct hdmi_disp_mode_timing_type *timing = NULL;
+	struct hdmi_tx_platform_data *pdata = NULL;
+	u32 format = DEFAULT_VIDEO_RESOLUTION;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	pdata = &hdmi_ctrl->pdata;
+
+	DEV_DBG("%s: Resolution wanted=%dx%d\n", __func__, hdmi_ctrl->xres,
+		hdmi_ctrl->yres);
+	switch (hdmi_ctrl->xres) {
+	default:
+	case 640:
+		format = HDMI_VFRMT_640x480p60_4_3;
+		break;
+	case 720:
+		format = (hdmi_ctrl->yres == 480)
+			? HDMI_VFRMT_720x480p60_16_9
+			: HDMI_VFRMT_720x576p50_16_9;
+		break;
+	case 1280:
+		if (hdmi_ctrl->frame_rate == 50000)
+			format = HDMI_VFRMT_1280x720p50_16_9;
+		else
+			format = HDMI_VFRMT_1280x720p60_16_9;
+		break;
+	case 1440:
+		/* interlaced has half of y res. */
+		format = (hdmi_ctrl->yres == 240)
+			? HDMI_VFRMT_1440x480i60_16_9
+			: HDMI_VFRMT_1440x576i50_16_9;
+		break;
+	case 1920:
+		if (hdmi_ctrl->yres == 540) {/* interlaced */
+			format = HDMI_VFRMT_1920x1080i60_16_9;
+		} else if (hdmi_ctrl->yres == 1080) {
+			if (hdmi_ctrl->frame_rate == 50000)
+				format = HDMI_VFRMT_1920x1080p50_16_9;
+			else if (hdmi_ctrl->frame_rate == 24000)
+				format = HDMI_VFRMT_1920x1080p24_16_9;
+			else if (hdmi_ctrl->frame_rate == 25000)
+				format = HDMI_VFRMT_1920x1080p25_16_9;
+			else if (hdmi_ctrl->frame_rate == 30000)
+				format = HDMI_VFRMT_1920x1080p30_16_9;
+			else
+				format = HDMI_VFRMT_1920x1080p60_16_9;
+		}
+		break;
+	}
+
+	if (hdmi_ctrl->video_resolution != format)
+		DEV_DBG("%s: switching %s => %s", __func__,
+			hdmi_get_video_fmt_2string(
+			hdmi_ctrl->video_resolution),
+			hdmi_get_video_fmt_2string(format));
+	else
+		DEV_DBG("resolution %s", hdmi_get_video_fmt_2string(
+			hdmi_ctrl->video_resolution));
+
+	timing = hdmi_get_supported_mode(format);
+	if (!timing) {
+		DEV_ERR("%s: invalid video fmt=%d\n", __func__,
+			hdmi_ctrl->video_resolution);
+		rc = -EPERM;
+		goto end;
+	}
+
+	/*
+	 * extpclk is driven by hdmi phy pll. This phy pll programming requires
+	 * hdmi_ahb_clk. So enable it and then disable.
+	 */
+	rc = clk_prepare_enable(pdata->clk[HDMI_TX_AHB_CLK]);
+	if (rc) {
+		DEV_ERR("%s: failed to enable '%s' clk\n", __func__,
+			hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
+		goto end;
+	}
+	rc = hdmi_tx_clk_set_rate(pdata, HDMI_TX_EXTP_CLK,
+		timing->pixel_freq * 1000);
+	if (rc) {
+		DEV_ERR("%s: FAILED: '%s' clk set rate\n", __func__,
+			hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
+		clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
+		goto end;
+	}
+	clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
+
+	hdmi_ctrl->video_resolution = format;
+	hdmi_edid_set_video_resolution(
+		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], format);
+
+end:
+	return rc;
+} /* hdmi_tx_set_video_fmt */
+
+static void hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
+	int video_format)
+{
+	u32 total_v   = 0;
+	u32 total_h   = 0;
+	u32 start_h   = 0;
+	u32 end_h     = 0;
+	u32 start_v   = 0;
+	u32 end_v     = 0;
+	struct dss_io_data *io = NULL;
+
+	const struct hdmi_disp_mode_timing_type *timing =
+		hdmi_get_supported_mode(video_format);
+	if (timing == NULL) {
+		DEV_ERR("%s: video format not supported: %d\n", __func__,
+			video_format);
+		return;
+	}
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	total_h = timing->active_h + timing->front_porch_h +
+		timing->back_porch_h + timing->pulse_width_h - 1;
+	total_v = timing->active_v + timing->front_porch_v +
+		timing->back_porch_v + timing->pulse_width_v - 1;
+	HDMI_REG_W(io->base, HDMI_TOTAL,
+		((total_v << 16) & 0x0FFF0000) |
+		((total_h << 0) & 0x00000FFF));
+
+	start_h = timing->back_porch_h + timing->pulse_width_h;
+	end_h   = (total_h + 1) - timing->front_porch_h;
+	HDMI_REG_W(io->base, HDMI_ACTIVE_H,
+		((end_h << 16) & 0x0FFF0000) |
+		((start_h << 0) & 0x00000FFF));
+
+	start_v = timing->back_porch_v + timing->pulse_width_v - 1;
+	end_v   = total_v - timing->front_porch_v;
+	HDMI_REG_W(io->base, HDMI_ACTIVE_V,
+		((end_v << 16) & 0x0FFF0000) |
+		((start_v << 0) & 0x00000FFF));
+
+	if (timing->interlaced) {
+		HDMI_REG_W(io->base, HDMI_V_TOTAL_F2,
+			((total_v + 1) << 0) & 0x00000FFF);
+
+		HDMI_REG_W(io->base, HDMI_ACTIVE_V_F2,
+			(((start_v + 1) << 0) & 0x00000FFF) |
+			(((end_v + 1) << 16) & 0x0FFF0000));
+	} else {
+		HDMI_REG_W(io->base, HDMI_V_TOTAL_F2, 0);
+		HDMI_REG_W(io->base, HDMI_ACTIVE_V_F2, 0);
+	}
+
+	HDMI_REG_W(io->base, HDMI_FRAME_CTRL,
+		((timing->interlaced << 31) & 0x80000000) |
+		((timing->active_low_h << 29) & 0x20000000) |
+		((timing->active_low_v << 28) & 0x10000000));
+} /* hdmi_tx_video_setup */
+
+static void hdmi_tx_set_avi_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int i, mode = 0;
+	u8 avi_iframe[16]; /* two header + length + 13 data */
+	u8 checksum;
+	u32 sum, regVal;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	switch (hdmi_ctrl->video_resolution) {
+	case HDMI_VFRMT_720x480p60_4_3:
+		mode = 0;
+		break;
+	case HDMI_VFRMT_720x480i60_16_9:
+		mode = 1;
+		break;
+	case HDMI_VFRMT_720x576p50_16_9:
+		mode = 2;
+		break;
+	case HDMI_VFRMT_720x576i50_16_9:
+		mode = 3;
+		break;
+	case HDMI_VFRMT_1280x720p60_16_9:
+		mode = 4;
+		break;
+	case HDMI_VFRMT_1280x720p50_16_9:
+		mode = 5;
+		break;
+	case HDMI_VFRMT_1920x1080p60_16_9:
+		mode = 6;
+		break;
+	case HDMI_VFRMT_1920x1080i60_16_9:
+		mode = 7;
+		break;
+	case HDMI_VFRMT_1920x1080p50_16_9:
+		mode = 8;
+		break;
+	case HDMI_VFRMT_1920x1080i50_16_9:
+		mode = 9;
+		break;
+	case HDMI_VFRMT_1920x1080p24_16_9:
+		mode = 10;
+		break;
+	case HDMI_VFRMT_1920x1080p30_16_9:
+		mode = 11;
+		break;
+	case HDMI_VFRMT_1920x1080p25_16_9:
+		mode = 12;
+		break;
+	case HDMI_VFRMT_640x480p60_4_3:
+		mode = 13;
+		break;
+	case HDMI_VFRMT_720x480p60_16_9:
+		mode = 14;
+		break;
+	case HDMI_VFRMT_720x576p50_4_3:
+		mode = 15;
+		break;
+	default:
+		DEV_INFO("%s: mode %d not supported\n", __func__,
+			hdmi_ctrl->video_resolution);
+		return;
+	}
+
+	/* InfoFrame Type = 82 */
+	avi_iframe[0]  = 0x82;
+	/* Version = 2 */
+	avi_iframe[1]  = 2;
+	/* Length of AVI InfoFrame = 13 */
+	avi_iframe[2]  = 13;
+
+	/* Data Byte 01: 0 Y1 Y0 A0 B1 B0 S1 S0 */
+	avi_iframe[3]  = hdmi_tx_avi_iframe_lut[0][mode];
+	avi_iframe[3] |= hdmi_edid_get_sink_scaninfo(
+		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
+		hdmi_ctrl->video_resolution);
+
+	/* Data Byte 02: C1 C0 M1 M0 R3 R2 R1 R0 */
+	avi_iframe[4]  = hdmi_tx_avi_iframe_lut[1][mode];
+	/* Data Byte 03: ITC EC2 EC1 EC0 Q1 Q0 SC1 SC0 */
+	avi_iframe[5]  = hdmi_tx_avi_iframe_lut[2][mode];
+	/* Data Byte 04: 0 VIC6 VIC5 VIC4 VIC3 VIC2 VIC1 VIC0 */
+	avi_iframe[6]  = hdmi_tx_avi_iframe_lut[3][mode];
+	/* Data Byte 05: 0 0 0 0 PR3 PR2 PR1 PR0 */
+	avi_iframe[7]  = hdmi_tx_avi_iframe_lut[4][mode];
+	/* Data Byte 06: LSB Line No of End of Top Bar */
+	avi_iframe[8]  = hdmi_tx_avi_iframe_lut[5][mode];
+	/* Data Byte 07: MSB Line No of End of Top Bar */
+	avi_iframe[9]  = hdmi_tx_avi_iframe_lut[6][mode];
+	/* Data Byte 08: LSB Line No of Start of Bottom Bar */
+	avi_iframe[10] = hdmi_tx_avi_iframe_lut[7][mode];
+	/* Data Byte 09: MSB Line No of Start of Bottom Bar */
+	avi_iframe[11] = hdmi_tx_avi_iframe_lut[8][mode];
+	/* Data Byte 10: LSB Pixel Number of End of Left Bar */
+	avi_iframe[12] = hdmi_tx_avi_iframe_lut[9][mode];
+	/* Data Byte 11: MSB Pixel Number of End of Left Bar */
+	avi_iframe[13] = hdmi_tx_avi_iframe_lut[10][mode];
+	/* Data Byte 12: LSB Pixel Number of Start of Right Bar */
+	avi_iframe[14] = hdmi_tx_avi_iframe_lut[11][mode];
+	/* Data Byte 13: MSB Pixel Number of Start of Right Bar */
+	avi_iframe[15] = hdmi_tx_avi_iframe_lut[12][mode];
+
+	sum = 0;
+	for (i = 0; i < 16; i++)
+		sum += avi_iframe[i];
+	sum &= 0xFF;
+	sum = 256 - sum;
+	checksum = (u8) sum;
+
+	regVal = avi_iframe[5];
+	regVal = regVal << 8 | avi_iframe[4];
+	regVal = regVal << 8 | avi_iframe[3];
+	regVal = regVal << 8 | checksum;
+	HDMI_REG_W(io->base, HDMI_AVI_INFO0, regVal);
+
+	regVal = avi_iframe[9];
+	regVal = regVal << 8 | avi_iframe[8];
+	regVal = regVal << 8 | avi_iframe[7];
+	regVal = regVal << 8 | avi_iframe[6];
+	HDMI_REG_W(io->base, HDMI_AVI_INFO1, regVal);
+
+	regVal = avi_iframe[13];
+	regVal = regVal << 8 | avi_iframe[12];
+	regVal = regVal << 8 | avi_iframe[11];
+	regVal = regVal << 8 | avi_iframe[10];
+	HDMI_REG_W(io->base, HDMI_AVI_INFO2, regVal);
+
+	regVal = avi_iframe[1];
+	regVal = regVal << 16 | avi_iframe[15];
+	regVal = regVal << 8 | avi_iframe[14];
+	HDMI_REG_W(io->base, HDMI_AVI_INFO3, regVal);
+
+	/* 0x3 for AVI InfFrame enable (every frame) */
+	HDMI_REG_W(io->base, HDMI_INFOFRAME_CTRL0,
+		HDMI_REG_R(io->base, HDMI_INFOFRAME_CTRL0) |
+		0x00000003L);
+} /* hdmi_tx_set_avi_infoframe */
+
+static void hdmi_tx_set_spd_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	u32 packet_header  = 0;
+	u32 check_sum      = 0;
+	u32 packet_payload = 0;
+	u32 packet_control = 0;
+
+	u8 *vendor_name = NULL;
+	u8 *product_description = NULL;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	vendor_name = hdmi_ctrl->spd_vendor_name;
+	product_description = hdmi_ctrl->spd_product_description;
+
+	/* Setup Packet header and payload */
+	/*
+	 * 0x83 InfoFrame Type Code
+	 * 0x01 InfoFrame Version Number
+	 * 0x19 Length of Source Product Description InfoFrame
+	 */
+	packet_header  = 0x83 | (0x01 << 8) | (0x19 << 16);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_HDR, packet_header);
+	check_sum += IFRAME_CHECKSUM_32(packet_header);
+
+	packet_payload = (vendor_name[3] & 0x7f)
+		| ((vendor_name[4] & 0x7f) << 8)
+		| ((vendor_name[5] & 0x7f) << 16)
+		| ((vendor_name[6] & 0x7f) << 24);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_1, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	/* Product Description (7-bit ASCII code) */
+	packet_payload = (vendor_name[7] & 0x7f)
+		| ((product_description[0] & 0x7f) << 8)
+		| ((product_description[1] & 0x7f) << 16)
+		| ((product_description[2] & 0x7f) << 24);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_2, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	packet_payload = (product_description[3] & 0x7f)
+		| ((product_description[4] & 0x7f) << 8)
+		| ((product_description[5] & 0x7f) << 16)
+		| ((product_description[6] & 0x7f) << 24);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_3, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	packet_payload = (product_description[7] & 0x7f)
+		| ((product_description[8] & 0x7f) << 8)
+		| ((product_description[9] & 0x7f) << 16)
+		| ((product_description[10] & 0x7f) << 24);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_4, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	packet_payload = (product_description[11] & 0x7f)
+		| ((product_description[12] & 0x7f) << 8)
+		| ((product_description[13] & 0x7f) << 16)
+		| ((product_description[14] & 0x7f) << 24);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_5, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	/*
+	 * Source Device Information
+	 * 00h unknown
+	 * 01h Digital STB
+	 * 02h DVD
+	 * 03h D-VHS
+	 * 04h HDD Video
+	 * 05h DVC
+	 * 06h DSC
+	 * 07h Video CD
+	 * 08h Game
+	 * 09h PC general
+	 */
+	packet_payload = (product_description[15] & 0x7f) | 0x00 << 8;
+	HDMI_REG_W(io->base, HDMI_GENERIC1_6, packet_payload);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+	/* Vendor Name (7bit ASCII code) */
+	packet_payload = ((vendor_name[0] & 0x7f) << 8)
+		| ((vendor_name[1] & 0x7f) << 16)
+		| ((vendor_name[2] & 0x7f) << 24);
+	check_sum += IFRAME_CHECKSUM_32(packet_payload);
+	packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff);
+	HDMI_REG_W(io->base, HDMI_GENERIC1_0, packet_payload);
+
+	/*
+	 * GENERIC1_LINE | GENERIC1_CONT | GENERIC1_SEND
+	 * Setup HDMI TX generic packet control
+	 * Enable this packet to transmit every frame
+	 * Enable HDMI TX engine to transmit Generic packet 1
+	 */
+	packet_control = HDMI_REG_R_ND(io->base, HDMI_GEN_PKT_CTRL);
+	packet_control |= ((0x1 << 24) | (1 << 5) | (1 << 4));
+	HDMI_REG_W(io->base, HDMI_GEN_PKT_CTRL, packet_control);
+} /* hdmi_tx_set_spd_infoframe */
+
+/* todo: revisit when new HPD debouncing logic is avialble */
 static void hdmi_tx_hpd_state_timer(unsigned long data)
 {
 	struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
@@ -246,59 +1072,551 @@
 		DEV_ERR("%s: invalid input\n", __func__);
 } /* hdmi_tx_hpd_state_timer */
 
-static inline struct clk *hdmi_tx_get_clk(struct hdmi_tx_platform_data *pdata,
-	u32 clk_idx)
+static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
 {
-	if (!pdata || clk_idx > HDMI_TX_MAX_CLK) {
+	u32 reg_val = 0;
+
+	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
-		return NULL;
+		return;
 	}
 
-	return pdata->clk[clk_idx];
-} /* hdmi_tx_get_clk */
+	if (power_on) {
+		/* ENABLE */
+		reg_val |= BIT(0); /* Enable the block */
+		if (hdmi_edid_get_sink_mode(
+			hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) == 0) {
+			if (hdmi_ctrl->present_hdcp)
+				/* HDMI Encryption */
+				reg_val |= BIT(2);
+			reg_val |= BIT(1);
+		} else {
+			if (hdmi_ctrl->present_hdcp)
+				/* HDMI_Encryption_ON */
+				reg_val |= BIT(1) | BIT(2);
+			else
+				reg_val |= BIT(1);
+		}
+	} else {
+		reg_val = BIT(1);
+	}
 
-static int hdmi_tx_clk_set_rate(struct hdmi_tx_platform_data *pdata,
-	u32 clk_idx, unsigned long clk_rate)
+	HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base, HDMI_CTRL,
+		reg_val);
+
+	DEV_DBG("HDMI Core: %s, HDMI_CTRL=0x%08x\n",
+		power_on ? "Enable" : "Disable", reg_val);
+} /* hdmi_tx_set_mode */
+
+static int hdmi_tx_clk_update(struct hdmi_tx_platform_data *pdata, u32 clk_idx,
+	u32 enable)
 {
 	int rc = 0;
-	struct clk *clk = NULL;
+	struct clk *clk = hdmi_tx_get_clk(pdata, clk_idx);
 
-	if (!pdata) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return -EINVAL;
-	}
-
-	clk = hdmi_tx_get_clk(pdata, clk_idx);
 	if (clk) {
-		rc = clk_set_rate(clk, clk_rate);
-		if (IS_ERR_VALUE(rc))
-			DEV_ERR("%s: failed rc=%d\n", __func__, rc);
-		else
-			DEV_DBG("%s: clk=%d rate=%lu\n", __func__,
-				clk_idx, clk_rate);
+		DEV_DBG("%s: clk=%d en=%d\n", __func__, clk_idx, enable);
+		if (enable) {
+			rc = clk_prepare_enable(clk);
+			if (rc)
+				DEV_ERR("%s: clk=%d enable failed\n",
+				__func__, clk_idx);
+		} else {
+			clk_disable_unprepare(clk);
+		}
 	} else {
-		DEV_ERR("%s: FAILED: invalid clk_idx=%d\n", __func__, clk_idx);
+		DEV_ERR("%s: FAILED: invalid input for clk='%s'\n", __func__,
+			hdmi_tx_clk_name(clk_idx));
 		rc = -EINVAL;
 	}
 
 	return rc;
-} /* hdmi_tx_clk_set_rate */
+} /* hdmi_tx_clk_update */
 
-static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
+/* Note: Before accessing extpclk, always make sure that hdmi_ahb_clk is on */
+static int hdmi_tx_clk_ctrl_update(struct hdmi_tx_platform_data *pdata, int on)
 {
-	return 0;
-} /* hdmi_tx_power_on */
+	int  rc = 0;
+	DEV_DBG("%s: HDMI Clk: %s\n", __func__, on ? "Enable" : "Disable");
+
+	rc = hdmi_tx_clk_update(pdata, HDMI_TX_APP_CLK, on);
+	if (on && rc) {
+		DEV_ERR("%s: '%s' on failed\n", __func__,
+			hdmi_tx_clk_name(HDMI_TX_APP_CLK));
+		goto fail_hdmi_app_clk;
+	}
+	if (on) {
+		rc = hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, on);
+		if (rc) {
+			DEV_ERR("%s: '%s' on failed\n", __func__,
+				hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
+			goto fail_hdmi_ahb_clk;
+		}
+		rc = hdmi_tx_clk_update(pdata, HDMI_TX_EXTP_CLK, on);
+		if (rc) {
+			DEV_ERR("%s: '%s' on failed\n", __func__,
+				hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
+			goto fail_hdmi_extp_clk;
+		}
+	} else {
+		hdmi_tx_clk_update(pdata, HDMI_TX_EXTP_CLK, on);
+		hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, on);
+	}
+	return rc;
+
+fail_hdmi_extp_clk:
+	hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, 0);
+fail_hdmi_ahb_clk:
+	hdmi_tx_clk_update(pdata, HDMI_TX_APP_CLK, 0);
+fail_hdmi_app_clk:
+	return rc;
+} /* hdmi_tx_clk_ctrl_update */
+
+static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl,
+	enum hdmi_tx_power_module_type module, int enable)
+{
+	int rc = 0;
+	struct dss_module_power *power_data = NULL;
+
+	if (!hdmi_ctrl || module >= HDMI_TX_MAX_PM) {
+		DEV_ERR("%s: Error: invalid input\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	power_data = &hdmi_ctrl->pdata.power_data[module];
+	if (!power_data) {
+		DEV_ERR("%s: Error: invalid power data\n", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (enable) {
+		rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+			power_data->vreg_config, power_data->num_vreg, 1);
+		if (rc) {
+			DEV_ERR("%s: Failed to config %s vreg. Error=%d\n",
+				__func__, hdmi_pm_name(module), rc);
+			return rc;
+		}
+
+		rc = msm_dss_enable_vreg(power_data->vreg_config,
+			power_data->num_vreg, 1);
+		if (rc) {
+			DEV_ERR("%s: Failed to enable %s vreg. Error=%d\n",
+				__func__, hdmi_pm_name(module), rc);
+			goto deconfig_vreg;
+		}
+
+		rc = msm_dss_enable_gpio(power_data->gpio_config,
+			power_data->num_gpio, enable);
+		if (rc) {
+			DEV_ERR("%s: Failed to enable %s gpio. Error=%d\n",
+				__func__, hdmi_pm_name(module), rc);
+			goto disable_vreg;
+		}
+	} else {
+		msm_dss_enable_gpio(power_data->gpio_config,
+			power_data->num_gpio, 0);
+	}
+
+	return rc;
+
+disable_vreg:
+	msm_dss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 0);
+deconfig_vreg:
+	msm_dss_config_vreg(&hdmi_ctrl->pdev->dev, power_data->vreg_config,
+		power_data->num_vreg, 0);
+error:
+	return rc;
+} /* hdmi_tx_enable_power */
+
+static void hdmi_tx_core_off(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 0);
+	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
+} /* hdmi_tx_core_off */
+
+static int hdmi_tx_core_on(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 1);
+	if (rc) {
+		DEV_ERR("%s: core hdmi_msm_enable_power failed rc = %d\n",
+			__func__, rc);
+		goto error;
+	}
+	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 1);
+	if (rc) {
+		DEV_ERR("%s: cec hdmi_msm_enable_power failed rc = %d\n",
+			__func__, rc);
+		goto disable_core_power;
+	}
+
+	return rc;
+disable_core_power:
+	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
+error:
+	return rc;
+} /* hdmi_tx_core_on */
+
+static void hdmi_tx_phy_reset(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	unsigned int phy_reset_polarity = 0x0;
+	unsigned int pll_reset_polarity = 0x0;
+	unsigned int val;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: io not inititalized\n", __func__);
+		return;
+	}
+
+	val = HDMI_REG_R_ND(io->base, HDMI_PHY_CTRL);
+
+	phy_reset_polarity = val >> 3 & 0x1;
+	pll_reset_polarity = val >> 1 & 0x1;
+
+	if (phy_reset_polarity == 0)
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET);
+	else
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val & (~SW_RESET));
+
+	if (pll_reset_polarity == 0)
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET_PLL);
+	else
+		HDMI_REG_W_ND(io->base,
+			HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
+
+	if (phy_reset_polarity == 0)
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val & (~SW_RESET));
+	else
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET);
+
+	if (pll_reset_polarity == 0)
+		HDMI_REG_W_ND(io->base,
+			HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
+	else
+		HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET_PLL);
+} /* hdmi_tx_phy_reset */
+
+static void hdmi_tx_init_phy(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	HDMI_REG_W_ND(io->base, HDMI_PHY_ANA_CFG0, 0x1B);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_ANA_CFG1, 0xF2);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_CFG0, 0x0);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN0, 0x0);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN1, 0x0);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN2, 0x0);
+	HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN3, 0x0);
+
+	HDMI_REG_W_ND(io->base, HDMI_PHY_PD_CTRL1, 0x20);
+} /* hdmi_tx_init_phy */
+
+static void hdmi_tx_powerdown_phy(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	HDMI_REG_W_ND(hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO].base,
+		HDMI_PHY_PD_CTRL0, 0x7F);
+} /* hdmi_tx_powerdown_phy */
+
+static int hdmi_tx_start(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+	/* todo: Audio */
+
+	hdmi_tx_set_mode(hdmi_ctrl, false);
+	mutex_lock(&hdmi_ctrl->mutex);
+	rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 1);
+	if (rc) {
+		DEV_ERR("%s: hdmi_tx_clk_enable failed.\n", __func__);
+		mutex_unlock(&hdmi_ctrl->mutex);
+		return rc;
+	}
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	hdmi_tx_init_phy(hdmi_ctrl);
+	HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+		HDMI_USEC_REFTIMER, 0x0001001B);
+
+	hdmi_tx_set_mode(hdmi_ctrl, true);
+
+	hdmi_tx_video_setup(hdmi_ctrl, hdmi_ctrl->video_resolution);
+	/* todo: Audio */
+	hdmi_tx_set_avi_infoframe(hdmi_ctrl);
+	/* todo: CONFIG_FB_MSM_HDMI_3D */
+	hdmi_tx_set_spd_infoframe(hdmi_ctrl);
+
+	/* Set IRQ for HPD */
+	HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+		HDMI_HPD_INT_CTRL, 4 | (hdmi_ctrl->hpd_state ? 0 : 2));
+
+	/* todo: HDCP/CEC */
+
+	DEV_INFO("%s: HDMI Core: Initialized\n", __func__);
+
+	return rc;
+} /* hdmi_tx_start */
 
 static int hdmi_tx_power_off(struct mdss_panel_data *panel_data)
 {
+	struct hdmi_tx_ctrl *hdmi_ctrl =
+		hdmi_tx_get_drvdata_from_panel_data(panel_data);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	DEV_INFO("%s: power: OFF (audio off, Reset Core)\n", __func__);
+	/* todo: Audio */
+	hdmi_tx_powerdown_phy(hdmi_ctrl);
+	hdmi_ctrl->panel_power_on = false;
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	if (hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 0))
+		DEV_ERR("%s: hdmi_tx_clk_disable failed.\n", __func__);
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	hdmi_tx_core_off(hdmi_ctrl);
+
 	return 0;
 } /* hdmi_tx_power_off */
 
+static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
+{
+	int rc = 0;
+	struct hdmi_tx_ctrl *hdmi_ctrl =
+		hdmi_tx_get_drvdata_from_panel_data(panel_data);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = hdmi_tx_core_on(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: hdmi_msm_core_on failed\n", __func__);
+		return rc;
+	}
+
+	DEV_INFO("power: ON (%dx%d %ld)\n", hdmi_ctrl->xres, hdmi_ctrl->yres,
+		hdmi_ctrl->pixel_clk);
+
+	rc = hdmi_tx_set_video_fmt(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc);
+		hdmi_tx_core_off(hdmi_ctrl);
+		return rc;
+	}
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	hdmi_ctrl->panel_power_on = true;
+
+	/* todo: check hdmi_tx_is_controller_on when hpd is on */
+	if (hdmi_ctrl->hpd_state) {
+		DEV_DBG("%s: Turning HDMI on\n", __func__);
+		mutex_unlock(&hdmi_ctrl->mutex);
+		rc = hdmi_tx_start(hdmi_ctrl);
+		if (rc) {
+			DEV_ERR("%s: hdmi_tx_start failed. rc=%d\n",
+				__func__, rc);
+			hdmi_tx_power_off(panel_data);
+			return rc;
+		}
+		/* todo: HDCP */
+	} else {
+		mutex_unlock(&hdmi_ctrl->mutex);
+	}
+
+	hdmi_reg_dump(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+		hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].len, "HDMI-ON: ");
+
+	DEV_INFO("%s: HDMI=%s DVI= %s\n", __func__,
+		hdmi_tx_is_controller_on(hdmi_ctrl) ? "ON" : "OFF" ,
+		hdmi_tx_is_dvi_mode(hdmi_ctrl) ? "ON" : "OFF");
+
+	return 0;
+} /* hdmi_tx_power_on */
+
+static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int rc = 0;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	if (!hdmi_ctrl->hpd_initialized) {
+		DEV_DBG("%s: HPD is already OFF, returning\n", __func__);
+		return;
+	}
+
+	DEV_DBG("%s: (timer, 5V, IRQ off)\n", __func__);
+	del_timer_sync(&hdmi_ctrl->hpd_state_timer);
+	mdss_disable_irq(&hdmi_tx_hw);
+
+	hdmi_tx_set_mode(hdmi_ctrl, false);
+
+	mutex_lock(&hdmi_ctrl->mutex);
+	rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 0);
+	if (rc)
+		DEV_INFO("%s: Failed to disable clock. Error=%d\n",
+			__func__, rc);
+	mutex_unlock(&hdmi_ctrl->mutex);
+
+	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
+	if (rc)
+		DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
+			__func__, rc);
+
+	hdmi_ctrl->hpd_initialized = false;
+} /* hdmi_tx_hpd_off */
+
+static int hdmi_tx_hpd_on(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	u32 reg_val;
+	int rc = 0;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: io not inititalized\n", __func__);
+		return -EINVAL;
+	}
+
+	if (hdmi_ctrl->hpd_initialized) {
+		DEV_DBG("%s: HPD is already ON\n", __func__);
+	} else {
+		rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, true);
+		if (rc) {
+			DEV_ERR("%s: Failed to enable hpd power. rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		mutex_lock(&hdmi_ctrl->mutex);
+		rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, true);
+		if (rc) {
+			DEV_ERR("%s: Failed to enable clocks. rc=%d\n",
+				__func__, rc);
+			mutex_unlock(&hdmi_ctrl->mutex);
+			goto disable_hpd_power;
+		}
+		mutex_unlock(&hdmi_ctrl->mutex);
+
+		hdmi_reg_dump(io->base, io->len, "HDMI-INIT: ");
+
+		hdmi_tx_set_mode(hdmi_ctrl, false);
+		hdmi_tx_phy_reset(hdmi_ctrl);
+		hdmi_tx_set_mode(hdmi_ctrl, true);
+
+		HDMI_REG_W(io->base, HDMI_USEC_REFTIMER, 0x0001001B);
+
+		/* set timeout to 4.1ms (max) for hardware debounce */
+		reg_val = HDMI_REG_R(io->base, HDMI_HPD_CTRL) | 0x1FFF;
+
+		/* Toggle HPD circuit to trigger HPD sense */
+		HDMI_REG_W(io->base, HDMI_HPD_CTRL,
+			~(1 << 28) & reg_val);
+		HDMI_REG_W(io->base, HDMI_HPD_CTRL, (1 << 28) | reg_val);
+
+		hdmi_ctrl->hpd_initialized = true;
+
+		/* Check HPD State */
+		mdss_enable_irq(&hdmi_tx_hw);
+	}
+
+	/* Set HPD state machine: ensure at least 2 readouts */
+	mutex_lock(&hdmi_ctrl->mutex);
+	hdmi_ctrl->hpd_stable = 0;
+	hdmi_ctrl->hpd_prev_state = true;
+	hdmi_ctrl->hpd_state = false;
+	hdmi_ctrl->hpd_cable_chg_detected = true;
+	mutex_unlock(&hdmi_ctrl->mutex);
+	mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+
+	return 0;
+
+disable_hpd_power:
+	hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, false);
+
+	return rc;
+} /* hdmi_tx_hpd_on */
+
+static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on)
+{
+	int rc = 0;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	DEV_INFO("%s: %d\n", __func__, on);
+	if (on) {
+		rc = hdmi_tx_hpd_on(hdmi_ctrl);
+	} else {
+		hdmi_tx_hpd_off(hdmi_ctrl);
+		/* Set HDMI switch node to 0 on HPD feature disable */
+		switch_set_state(&hdmi_ctrl->sdev, 0);
+		DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+			hdmi_ctrl->sdev.state);
+	}
+
+	return rc;
+} /* hdmi_tx_sysfs_enable_hpd */
+
 static irqreturn_t hdmi_tx_isr(int irq, void *data)
 {
 	u32 hpd_int_status;
 	u32 hpd_int_ctrl;
-	struct hdmi_tx_io_data *io = NULL;
+	struct dss_io_data *io = NULL;
 	struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
 
 	if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
@@ -339,6 +1657,9 @@
 		return IRQ_HANDLED;
 	}
 
+	if (!hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl))
+		return IRQ_HANDLED;
+
 	DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
 		hpd_int_status);
 
@@ -400,26 +1721,6 @@
 	}
 	pdata->clk[HDMI_TX_EXTP_CLK] = clk;
 
-	/*
-	 * extpclk src is hdmi phy pll. This phy pll programming requires
-	 * hdmi_ahb_clk. So enable it and then disable.
-	 */
-	rc = clk_prepare_enable(pdata->clk[HDMI_TX_AHB_CLK]);
-	if (rc) {
-		DEV_ERR("%s: failed to enable '%s' clk\n", __func__,
-			hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
-		goto error;
-	}
-	rc = hdmi_tx_clk_set_rate(pdata, HDMI_TX_EXTP_CLK,
-		HDMI_TX_EXTP_CLK_DEFAULT);
-	if (rc) {
-		DEV_ERR("%s: FAILED: '%s' clk set rate\n", __func__,
-			hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
-		clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
-		goto error;
-	}
-	clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
-
 	return rc;
 
 error:
@@ -434,8 +1735,11 @@
 		return;
 	}
 
+	if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID])
+		hdmi_edid_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
+
 	switch_dev_unregister(&hdmi_ctrl->sdev);
-	del_timer(&hdmi_ctrl->hpd_state_timer);
+	del_timer_sync(&hdmi_ctrl->hpd_state_timer);
 	if (hdmi_ctrl->workq)
 		destroy_workqueue(hdmi_ctrl->workq);
 	mutex_destroy(&hdmi_ctrl->mutex);
@@ -472,6 +1776,10 @@
 		goto fail_create_workq;
 	}
 
+	/* todo: May be move this ? */
+	hdmi_ctrl->ddc_ctrl.base = pdata->io[HDMI_TX_CORE_IO].base;
+	init_completion(&hdmi_ctrl->ddc_ctrl.ddc_sw_done);
+
 	INIT_WORK(&hdmi_ctrl->hpd_state_work, hdmi_tx_hpd_state_work);
 	init_timer(&hdmi_ctrl->hpd_state_timer);
 	hdmi_ctrl->hpd_state_timer.function = hdmi_tx_hpd_state_timer;
@@ -487,7 +1795,7 @@
 	return 0;
 
 fail_switch_dev:
-	del_timer(&hdmi_ctrl->hpd_state_timer);
+	del_timer_sync(&hdmi_ctrl->hpd_state_timer);
 fail_create_workq:
 	if (hdmi_ctrl->workq)
 		destroy_workqueue(hdmi_ctrl->workq);
@@ -508,7 +1816,7 @@
 	hdmi_ctrl->panel_data.on = hdmi_tx_power_on;
 	hdmi_ctrl->panel_data.off = hdmi_tx_power_off;
 
-	hdmi_ctrl->video_resolution = HDMI_VFRMT_1920x1080p60_16_9;
+	hdmi_ctrl->video_resolution = DEFAULT_VIDEO_RESOLUTION;
 	rc = hdmi_tx_init_panel_info(hdmi_ctrl->video_resolution,
 		&hdmi_ctrl->panel_data.panel_info);
 	if (rc) {
@@ -806,7 +2114,6 @@
 		if (strnstr(st, mod_name, strlen(st))) {
 			ndx_mask |= BIT(i);
 			mod_gpio_total++;
-			continue;
 		}
 	}
 
@@ -863,47 +2170,6 @@
 	return rc;
 } /* hdmi_tx_get_dt_gpio_data */
 
-static struct resource *hdmi_tx_get_res_byname(struct platform_device *pdev,
-	unsigned int type, const char *name)
-{
-	struct resource *res = NULL;
-
-	res = platform_get_resource_byname(pdev, type, name);
-	if (!res)
-		DEV_ERR("%s: '%s' resource not found\n", __func__, name);
-
-	return res;
-} /* hdmi_tx_get_res_byname */
-
-static int hdmi_tx_ioremap_byname(struct platform_device *pdev,
-	struct hdmi_tx_io_data *io_data, u32 io_type)
-{
-	struct resource *res = NULL;
-
-	if (!pdev) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return -EINVAL;
-	}
-
-	res = hdmi_tx_get_res_byname(pdev, IORESOURCE_MEM,
-		hdmi_tx_io_name(io_type));
-	if (!res) {
-		DEV_ERR("%s: '%s' hdmi_tx_get_res_byname failed\n", __func__,
-			hdmi_tx_io_name(io_type));
-		return -ENODEV;
-	}
-
-	io_data->len = resource_size(res);
-	io_data->base = ioremap(res->start, io_data->len);
-	if (!io_data->base) {
-		DEV_ERR("%s: '%s' ioremap failed\n", __func__,
-			hdmi_tx_io_name(io_type));
-		return -EIO;
-	}
-
-	return 0;
-} /* hdmi_tx_ioremap_byname */
-
 static void hdmi_tx_put_dt_data(struct device *dev,
 	struct hdmi_tx_platform_data *pdata)
 {
@@ -952,7 +2218,8 @@
 
 	/* IO */
 	for (i = 0; i < HDMI_TX_MAX_IO; i++) {
-		rc = hdmi_tx_ioremap_byname(pdev, &pdata->io[i], i);
+		rc = msm_dss_ioremap_byname(pdev, &pdata->io[i],
+			hdmi_tx_io_name(i));
 		if (rc) {
 			DEV_ERR("%s: '%s' remap failed\n", __func__,
 				hdmi_tx_io_name(i));
@@ -1040,8 +2307,23 @@
 		goto failed_reg_panel;
 	}
 
+	rc = hdmi_tx_sysfs_create(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: hdmi_tx_sysfs_create failed.rc=%d\n",
+			__func__, rc);
+		goto failed_reg_panel;
+	}
+
+	rc = hdmi_tx_init_features(hdmi_ctrl);
+	if (rc) {
+		DEV_ERR("%s: init_features failed.rc=%d\n", __func__, rc);
+		goto failed_init_features;
+	}
+
 	return rc;
 
+failed_init_features:
+	hdmi_tx_sysfs_remove(hdmi_ctrl);
 failed_reg_panel:
 	hdmi_tx_dev_deinit(hdmi_ctrl);
 failed_dev_init:
@@ -1060,6 +2342,7 @@
 		return -ENODEV;
 	}
 
+	hdmi_tx_sysfs_remove(hdmi_ctrl);
 	hdmi_tx_dev_deinit(hdmi_ctrl);
 	hdmi_tx_put_dt_data(&pdev->dev, &hdmi_ctrl->pdata);
 	devm_kfree(&hdmi_ctrl->pdev->dev, hdmi_ctrl);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 2e175ee..7e37d28 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -17,11 +17,6 @@
 #include "mdss_hdmi_util.h"
 #include "mdss_io_util.h"
 
-#define HDMI_TX_EXTP_CLK_DEFAULT 148500000
-#define HDMI_TX_EXTP_CLK_LOW     148500000
-#define HDMI_TX_EXTP_CLK_NOMINAL 297000000
-#define HDMI_TX_EXTP_CLK_TURBO   297000000 /* ToDo: Find correct value */
-
 enum hdmi_tx_clk_type {
 	HDMI_TX_AHB_CLK,
 	HDMI_TX_APP_CLK,
@@ -43,14 +38,9 @@
 	HDMI_TX_MAX_PM
 };
 
-struct hdmi_tx_io_data {
-	u32 len;
-	void __iomem *base;
-};
-
 struct hdmi_tx_platform_data {
 	/* Data filled from device tree nodes */
-	struct hdmi_tx_io_data io[HDMI_TX_MAX_IO];
+	struct dss_io_data io[HDMI_TX_MAX_IO];
 	struct dss_module_power power_data[HDMI_TX_MAX_PM];
 
 	/* clk and regulator handles */
@@ -88,6 +78,10 @@
 
 	u8 spd_vendor_name[8];
 	u8 spd_product_description[16];
+
+	struct hdmi_tx_ddc_ctrl ddc_ctrl;
+
+	void *feature_data[HDMI_TX_FEAT_MAX];
 };
 
 #endif /* __MDSS_HDMI_TX_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index e86f32b..3ba9f89 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -446,8 +446,8 @@
 const char *hdmi_get_single_video_3d_fmt_2string(u32 format)
 {
 	switch (format) {
-	case TOP_AND_BOTTOM: return "TAB";
-	case FRAME_PACKING: return "FP";
+	case TOP_AND_BOTTOM:	return "TAB";
+	case FRAME_PACKING:	return "FP";
 	case SIDE_BY_SIDE_HALF: return "SSH";
 	}
 	return "";
@@ -483,3 +483,625 @@
 
 	return len;
 } /* hdmi_get_video_3d_fmt_2string */
+
+static void hdmi_ddc_print_data(struct hdmi_tx_ddc_data *ddc_data,
+	const char *caller)
+{
+	if (!ddc_data) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	DEV_DBG("%s: buf=%p, d_len=0x%x, d_addr=0x%x, no_align=%d\n",
+		caller, ddc_data->data_buf, ddc_data->data_len,
+		ddc_data->dev_addr, ddc_data->no_align);
+	DEV_DBG("%s: offset=0x%x, req_len=0x%x, retry=%d, what=%s\n",
+		caller, ddc_data->offset, ddc_data->request_len,
+		ddc_data->retry, ddc_data->what);
+} /* hdmi_ddc_print_data */
+
+static int hdmi_ddc_clear_irq(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+	char *what)
+{
+	u32 reg_val, time_out_count;
+
+	if (!ddc_ctrl || !ddc_ctrl->base) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	/* clear pending and enable interrupt */
+	time_out_count = 0xFFFF;
+	do {
+		--time_out_count;
+		/* Clear and Enable DDC interrupt */
+		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL,
+			BIT(2) | BIT(1));
+		reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+	} while ((reg_val & BIT(0)) && time_out_count);
+
+	if (!time_out_count) {
+		DEV_ERR("%s[%s]: timedout\n", __func__, what);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+} /*hdmi_ddc_clear_irq */
+
+static int hdmi_ddc_read_retry(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+	struct hdmi_tx_ddc_data *ddc_data)
+{
+	u32 reg_val, ndx, time_out_count;
+	int status = 0;
+	int log_retry_fail;
+
+	if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!ddc_data->data_buf) {
+		status = -EINVAL;
+		DEV_ERR("%s[%s]: invalid buf\n", __func__, ddc_data->what);
+		goto error;
+	}
+
+	hdmi_ddc_print_data(ddc_data, __func__);
+
+	log_retry_fail = ddc_data->retry != 1;
+again:
+	status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what);
+	if (status)
+		goto error;
+
+	/* Ensure Device Address has LSB set to 0 to indicate Slave addr read */
+	ddc_data->dev_addr &= 0xFE;
+
+	/*
+	 * 1. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #1
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = linkAddress (primary link address and writing)
+	 *    INDEX = 0x0 (initial offset into buffer)
+	 *    INDEX_WRITE = 0x1 (setting initial offset)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		BIT(31) | (ddc_data->dev_addr << 8));
+
+	/*
+	 * 2. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #2
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = offsetAddress
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+
+	/*
+	 * 3. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #3
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = linkAddress + 1 (primary link address 0x74 and reading)
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		(ddc_data->dev_addr | BIT(0)) << 8);
+
+	/* Data setup is complete, now setup the transaction characteristics */
+
+	/*
+	 * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in
+	 *    order to handle characteristics of portion #1 and portion #2
+	 *    RW0 = 0x0 (write)
+	 *    START0 = 0x1 (insert START bit)
+	 *    STOP0 = 0x0 (do NOT insert STOP bit)
+	 *    CNT0 = 0x1 (single byte transaction excluding address)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+
+	/*
+	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+	 *    order to handle characteristics of portion #3
+	 *    RW1 = 0x1 (read)
+	 *    START1 = 0x1 (insert START bit)
+	 *    STOP1 = 0x1 (insert STOP bit)
+	 *    CNT1 = data_len   (it's 128 (0x80) for a blk read)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1,
+		BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16));
+
+	/* Trigger the I2C transfer */
+
+	/*
+	 * 6. Write to HDMI_I2C_CONTROL to kick off the hardware.
+	 *    Note that NOTHING has been transmitted on the DDC lines up to this
+	 *    point.
+	 *    TRANSACTION_CNT = 0x1 (execute transaction0 followed by
+	 *    transaction1)
+	 *    SEND_RESET = Set to 1 to send reset sequence
+	 *    GO = 0x1 (kicks off hardware)
+	 */
+	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(20));
+
+	time_out_count = wait_for_completion_interruptible_timeout(
+		&ddc_ctrl->ddc_sw_done, HZ/2);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, BIT(1));
+	if (!time_out_count) {
+		if (ddc_data->retry-- > 0) {
+			DEV_INFO("%s: failed timout, retry=%d\n", __func__,
+				ddc_data->retry);
+			goto again;
+		}
+		status = -ETIMEDOUT;
+		DEV_ERR("%s: timedout(7), Int Ctrl=%08x\n", __func__,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+		DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
+			__func__,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+		goto error;
+	}
+
+	/* Read DDC status */
+	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+	reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
+
+	/* Check if any NACK occurred */
+	if (reg_val) {
+		/* SW_STATUS_RESET */
+		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+
+		if (ddc_data->retry == 1)
+			/* SOFT_RESET */
+			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+
+		if (ddc_data->retry-- > 0) {
+			DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d\n",
+				__func__, ddc_data->what, reg_val,
+				ddc_data->retry);
+			DEV_DBG("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+				__func__, ddc_data->dev_addr,
+				ddc_data->offset, ddc_data->data_len);
+			goto again;
+		}
+		status = -EIO;
+		if (log_retry_fail) {
+			DEV_ERR("%s(%s): failed NACK=0x%08x\n",
+				__func__, ddc_data->what, reg_val);
+			DEV_ERR("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+				__func__, ddc_data->dev_addr,
+				ddc_data->offset, ddc_data->data_len);
+		}
+		goto error;
+	}
+
+	/*
+	 * 8. ALL data is now available and waiting in the DDC buffer.
+	 *    Read HDMI_I2C_DATA with the following fields set
+	 *    RW = 0x1 (read)
+	 *    DATA = BCAPS (this is field where data is pulled from)
+	 *    INDEX = 0x3 (where the data has been placed in buffer by hardware)
+	 *    INDEX_WRITE = 0x1 (explicitly define offset)
+	 */
+	/* Write this data to DDC buffer */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		BIT(0) | (3 << 16) | BIT(31));
+
+	/* Discard first byte */
+	HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+	for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
+		reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+		ddc_data->data_buf[ndx] = (u8)((reg_val & 0x0000FF00) >> 8);
+	}
+
+	DEV_DBG("%s[%s] success\n", __func__, ddc_data->what);
+
+error:
+	return status;
+} /* hdmi_ddc_read_retry */
+
+void hdmi_ddc_config(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
+{
+	if (!ddc_ctrl || !ddc_ctrl->base) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	/* Configure Pre-Scale multiplier & Threshold */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_SPEED, (10 << 16) | (2 << 0));
+
+	/*
+	 * Setting 31:24 bits : Time units to wait before timeout
+	 * when clock is being stalled by external sink device
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_SETUP, 0xFF000000);
+
+	/* Enable reference timer to 27 micro-seconds */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_REF, (1 << 16) | (27 << 0));
+} /* hdmi_ddc_config */
+
+int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
+{
+	int rc = -1;
+	u32 ddc_int_ctrl;
+
+	if (!ddc_ctrl || !ddc_ctrl->base) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	ddc_int_ctrl = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+	if ((ddc_int_ctrl & BIT(2)) && (ddc_int_ctrl & BIT(0))) {
+		/* SW_DONE INT occured, clr it */
+		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL,
+			ddc_int_ctrl | BIT(1));
+		complete(&ddc_ctrl->ddc_sw_done);
+		return 0;
+	}
+
+	DEV_DBG("%s: ddc_int_ctrl=%04x\n", __func__, ddc_int_ctrl);
+
+	return rc;
+} /* hdmi_ddc_isr */
+
+int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+	struct hdmi_tx_ddc_data *ddc_data)
+{
+	int rc = 0;
+
+	if (!ddc_ctrl || !ddc_data) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = hdmi_ddc_read_retry(ddc_ctrl, ddc_data);
+	if (!rc)
+		return rc;
+
+	if (ddc_data->no_align) {
+		rc = hdmi_ddc_read_retry(ddc_ctrl, ddc_data);
+	} else {
+		ddc_data->request_len = 32 * ((ddc_data->data_len + 31) / 32);
+		rc = hdmi_ddc_read_retry(ddc_ctrl, ddc_data);
+	}
+
+	return rc;
+} /* hdmi_ddc_read */
+
+int hdmi_ddc_read_seg(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+	struct hdmi_tx_ddc_data *ddc_data)
+{
+	int status = 0;
+	u32 reg_val, ndx, time_out_count;
+	int log_retry_fail;
+	int seg_addr = 0x60, seg_num = 0x01;
+
+	if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!ddc_data->data_buf) {
+		status = -EINVAL;
+		DEV_ERR("%s[%s]: invalid buf\n", __func__, ddc_data->what);
+		goto error;
+	}
+
+	log_retry_fail = ddc_data->retry != 1;
+
+again:
+	status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what);
+	if (status)
+		goto error;
+
+	/* Ensure Device Address has LSB set to 0 to indicate Slave addr read */
+	ddc_data->dev_addr &= 0xFE;
+
+	/*
+	 * 1. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #1
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = linkAddress (primary link address and writing)
+	 *    INDEX = 0x0 (initial offset into buffer)
+	 *    INDEX_WRITE = 0x1 (setting initial offset)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, BIT(31) | (seg_addr << 8));
+
+	/*
+	 * 2. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #2
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = offsetAddress
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, seg_num << 8);
+
+	/*
+	 * 3. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #3
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = linkAddress + 1 (primary link address 0x74 and reading)
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->dev_addr << 8);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		(ddc_data->dev_addr | BIT(0)) << 8);
+
+	/* Data setup is complete, now setup the transaction characteristics */
+
+	/*
+	 * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in
+	 *    order to handle characteristics of portion #1 and portion #2
+	 *    RW0 = 0x0 (write)
+	 *    START0 = 0x1 (insert START bit)
+	 *    STOP0 = 0x0 (do NOT insert STOP bit)
+	 *    CNT0 = 0x1 (single byte transaction excluding address)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+
+	/*
+	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+	 *    order to handle characteristics of portion #3
+	 *    RW1 = 0x1 (read)
+	 *    START1 = 0x1 (insert START bit)
+	 *    STOP1 = 0x1 (insert STOP bit)
+	 *    CNT1 = data_len   (it's 128 (0x80) for a blk read)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1, BIT(12) | BIT(16));
+
+	/*
+	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+	 *    order to handle characteristics of portion #3
+	 *    RW1 = 0x1 (read)
+	 *    START1 = 0x1 (insert START bit)
+	 *    STOP1 = 0x1 (insert STOP bit)
+	 *    CNT1 = data_len   (it's 128 (0x80) for a blk read)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS2,
+		BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16));
+
+	/* Trigger the I2C transfer */
+
+	/*
+	 * 6. Write to HDMI_I2C_CONTROL to kick off the hardware.
+	 *    Note that NOTHING has been transmitted on the DDC lines up to this
+	 *    point.
+	 *    TRANSACTION_CNT = 0x2 (execute transaction0 followed by
+	 *    transaction1)
+	 *    GO = 0x1 (kicks off hardware)
+	 */
+	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(21));
+
+	time_out_count = wait_for_completion_interruptible_timeout(
+		&ddc_ctrl->ddc_sw_done, HZ/2);
+
+	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
+	if (!time_out_count) {
+		if (ddc_data->retry-- > 0) {
+			DEV_INFO("%s: failed timout, retry=%d\n", __func__,
+				ddc_data->retry);
+			goto again;
+		}
+		status = -ETIMEDOUT;
+		DEV_ERR("%s: timedout(7), Int Ctrl=%08x\n", __func__,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+		DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
+			__func__,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+		goto error;
+	}
+
+	/* Read DDC status */
+	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+	reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
+
+	/* Check if any NACK occurred */
+	if (reg_val) {
+		/* SW_STATUS_RESET */
+		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+		if (ddc_data->retry == 1)
+			/* SOFT_RESET */
+			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+		if (ddc_data->retry-- > 0) {
+			DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d\n",
+				__func__, ddc_data->what, reg_val,
+				ddc_data->retry);
+			DEV_DBG("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+				__func__, ddc_data->dev_addr,
+				ddc_data->offset, ddc_data->data_len);
+			goto again;
+		}
+		status = -EIO;
+		if (log_retry_fail) {
+			DEV_ERR("%s(%s): failed NACK=0x%08x\n",
+				__func__, ddc_data->what, reg_val);
+			DEV_ERR("%s: daddr=0x%02x,off=0x%02x,len=%d\n",
+				__func__, ddc_data->dev_addr,
+				ddc_data->offset, ddc_data->data_len);
+		}
+		goto error;
+	}
+
+	/*
+	 * 8. ALL data is now available and waiting in the DDC buffer.
+	 *    Read HDMI_I2C_DATA with the following fields set
+	 *    RW = 0x1 (read)
+	 *    DATA = BCAPS (this is field where data is pulled from)
+	 *    INDEX = 0x5 (where the data has been placed in buffer by hardware)
+	 *    INDEX_WRITE = 0x1 (explicitly define offset)
+	 */
+	/* Write this data to DDC buffer */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		BIT(0) | (5 << 16) | BIT(31));
+
+	/* Discard first byte */
+	HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+
+	for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
+		reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+		ddc_data->data_buf[ndx] = (u8) ((reg_val & 0x0000FF00) >> 8);
+	}
+
+	DEV_DBG("%s[%s] success\n", __func__, ddc_data->what);
+
+error:
+	return status;
+} /* hdmi_ddc_read_seg */
+
+int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
+	struct hdmi_tx_ddc_data *ddc_data)
+{
+	u32 reg_val, ndx;
+	int status = 0, retry = 10;
+	u32 time_out_count;
+
+	if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!ddc_data->data_buf) {
+		status = -EINVAL;
+		DEV_ERR("%s[%s]: invalid buf\n", __func__, ddc_data->what);
+		goto error;
+	}
+
+again:
+	status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what);
+	if (status)
+		goto error;
+
+	/* Ensure Device Address has LSB set to 0 to indicate Slave addr read */
+	ddc_data->dev_addr &= 0xFE;
+
+	/*
+	 * 1. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #1
+	 *    DATA_RW = 0x1 (write)
+	 *    DATA = linkAddress (primary link address and writing)
+	 *    INDEX = 0x0 (initial offset into buffer)
+	 *    INDEX_WRITE = 0x1 (setting initial offset)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+		BIT(31) | (ddc_data->dev_addr << 8));
+
+	/*
+	 * 2. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #2
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = offsetAddress
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+
+	/*
+	 * 3. Write to HDMI_I2C_DATA with the following fields set in order to
+	 *    handle portion #3
+	 *    DATA_RW = 0x0 (write)
+	 *    DATA = data_buf[ndx]
+	 *    INDEX = 0x0
+	 *    INDEX_WRITE = 0x0 (auto-increment by hardware)
+	 */
+	for (ndx = 0; ndx < ddc_data->data_len; ++ndx)
+		HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+			((u32)ddc_data->data_buf[ndx]) << 8);
+
+	/* Data setup is complete, now setup the transaction characteristics */
+
+	/*
+	 * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in
+	 *    order to handle characteristics of portion #1 and portion #2
+	 *    RW0 = 0x0 (write)
+	 *    START0 = 0x1 (insert START bit)
+	 *    STOP0 = 0x0 (do NOT insert STOP bit)
+	 *    CNT0 = 0x1 (single byte transaction excluding address)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+
+	/*
+	 * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
+	 *    order to handle characteristics of portion #3
+	 *    RW1 = 0x1 (read)
+	 *    START1 = 0x1 (insert START bit)
+	 *    STOP1 = 0x1 (insert STOP bit)
+	 *    CNT1 = data_len   (0xN (write N bytes of data))
+	 *    Byte count for second transition (excluding the first
+	 *    Byte which is usually the address)
+	 */
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1,
+		BIT(13) | ((ddc_data->data_len-1) << 16));
+
+	/* Trigger the I2C transfer */
+	/*
+	 * 6. Write to HDMI_I2C_CONTROL to kick off the hardware.
+	 *    Note that NOTHING has been transmitted on the DDC lines up to this
+	 *    point.
+	 *    TRANSACTION_CNT = 0x1 (execute transaction0 followed by
+	 *    transaction1)
+	 *    GO = 0x1 (kicks off hardware)
+	 */
+	INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(20));
+
+	time_out_count = wait_for_completion_interruptible_timeout(
+		&ddc_ctrl->ddc_sw_done, HZ/2);
+
+	reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+	HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
+	if (!time_out_count) {
+		if (retry-- > 0) {
+			DEV_INFO("%s[%s]: failed timout, retry=%d\n", __func__,
+				ddc_data->what, retry);
+			goto again;
+		}
+		status = -ETIMEDOUT;
+		DEV_ERR("%s[%s]: timedout, Int Ctrl=%08x\n",
+			__func__, ddc_data->what,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+		DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
+			__func__,
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
+			HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+		goto error;
+	}
+
+	/* Read DDC status */
+	reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+	reg_val &= 0x00001000 | 0x00002000 | 0x00004000 | 0x00008000;
+
+	/* Check if any NACK occurred */
+	if (reg_val) {
+		if (retry > 1)
+			/* SW_STATUS_RESET */
+			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+		else
+			/* SOFT_RESET */
+			HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+
+		if (retry-- > 0) {
+			DEV_DBG("%s[%s]: failed NACK=%08x, retry=%d\n",
+				__func__, ddc_data->what, reg_val, retry);
+			msleep(100);
+			goto again;
+		}
+		status = -EIO;
+		DEV_ERR("%s[%s]: failed NACK: %08x\n", __func__,
+			ddc_data->what, reg_val);
+		goto error;
+	}
+
+	DEV_DBG("%s[%s] success\n", __func__, ddc_data->what);
+
+error:
+	return status;
+} /* hdmi_ddc_write */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
index ae6f16a..47515ba 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -369,6 +369,13 @@
 #define FRAME_PACKING		0x20
 #define SIDE_BY_SIDE_HALF	0x40
 
+enum hdmi_tx_feature_type {
+	HDMI_TX_FEAT_EDID,
+	HDMI_TX_FEAT_HDCP,
+	HDMI_TX_FEAT_CEC,
+	HDMI_TX_FEAT_MAX,
+};
+
 struct hdmi_disp_mode_timing_type {
 	u32	video_format;
 	u32	active_h;
@@ -389,6 +396,22 @@
 	u32	supported;
 };
 
+struct hdmi_tx_ddc_ctrl {
+	void __iomem *base;
+	struct completion ddc_sw_done;
+};
+
+struct hdmi_tx_ddc_data {
+	char *what;
+	u8 *data_buf;
+	u32 data_len;
+	u32 dev_addr;
+	u32 offset;
+	u32 request_len;
+	u32 no_align;
+	int retry;
+};
+
 void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix);
 const char *hdmi_reg_name(u32 offset);
 
@@ -397,4 +420,14 @@
 const char *hdmi_get_video_fmt_2string(u32 format);
 ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf);
 
+/* todo: Fix this. Right now this is defined in mdss_hdmi_tx.c */
+void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, u32 type);
+
+/* DDC */
+void hdmi_ddc_config(struct hdmi_tx_ddc_ctrl *);
+int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *);
+int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *, struct hdmi_tx_ddc_data *);
+int hdmi_ddc_read_seg(struct hdmi_tx_ddc_ctrl *, struct hdmi_tx_ddc_data *);
+int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *, struct hdmi_tx_ddc_data *);
+
 #endif /* __HDMI_UTIL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index 84f5909..c121772 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -14,6 +14,46 @@
 #include <linux/io.h>
 #include "mdss_io_util.h"
 
+static struct resource *msm_dss_get_res_byname(struct platform_device *pdev,
+	unsigned int type, const char *name)
+{
+	struct resource *res = NULL;
+
+	res = platform_get_resource_byname(pdev, type, name);
+	if (!res)
+		pr_err("%s: '%s' resource not found\n", __func__, name);
+
+	return res;
+}
+
+
+int msm_dss_ioremap_byname(struct platform_device *pdev,
+	struct dss_io_data *io_data, const char *name)
+{
+	struct resource *res = NULL;
+
+	if (!pdev) {
+		pr_err("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name);
+	if (!res) {
+		pr_err("%s: '%s' msm_dss_get_res_byname failed\n",
+			__func__, name);
+		return -ENODEV;
+	}
+
+	io_data->len = resource_size(res);
+	io_data->base = ioremap(res->start, io_data->len);
+	if (!io_data->base) {
+		pr_err("%s: '%s' ioremap failed\n", __func__, name);
+		return -EIO;
+	}
+
+	return 0;
+}
+
 int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
 	int num_vreg, int config)
 {
diff --git a/drivers/video/msm/mdss/mdss_io_util.h b/drivers/video/msm/mdss/mdss_io_util.h
index 791e44a..9671414 100644
--- a/drivers/video/msm/mdss/mdss_io_util.h
+++ b/drivers/video/msm/mdss/mdss_io_util.h
@@ -14,8 +14,14 @@
 #define __MDSS_IO_UTIL_H__
 
 #include <linux/gpio.h>
+#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
+struct dss_io_data {
+	u32 len;
+	void __iomem *base;
+};
+
 enum dss_vreg_type {
 	DSS_REG_LDO,
 	DSS_REG_VS,
@@ -42,7 +48,10 @@
 	struct dss_gpio *gpio_config;
 };
 
+int msm_dss_ioremap_byname(struct platform_device *pdev,
+	struct dss_io_data *io_data, const char *name);
 int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable);
+int msm_dss_gpio_enable(struct dss_gpio *in_gpio, int num_gpio, int enable);
 int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
 	int num_vreg, int config);
 int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg,	int enable);
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 4604d4a..80e056f 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/iommu.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/pm_runtime.h>
@@ -42,6 +43,8 @@
 #include <mach/hardware.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
 
 #include "mdss.h"
 #include "mdss_fb.h"
@@ -92,6 +95,30 @@
 	.name = "mdss_mdp",
 };
 
+struct msm_iova_partition mdp_iommu_partitions[] = {
+	{
+		.start = SZ_128K,
+		.size = SZ_2G - SZ_128K,
+	},
+};
+struct msm_iova_layout mdp_iommu_layout = {
+	.client_name = "mdss_mdp",
+	.partitions = mdp_iommu_partitions,
+	.npartitions = ARRAY_SIZE(mdp_iommu_partitions),
+};
+
+struct {
+	char *name;
+	struct device *ctx;
+} mdp_iommu_ctx[] = {
+	{
+		.name = "mdp_0",
+	},
+	{
+		.name = "mdp_1",
+	}
+};
+
 struct mdss_hw mdss_mdp_hw = {
 	.hw_ndx = MDSS_HW_MDP,
 	.ptr = NULL,
@@ -584,6 +611,96 @@
 	return 0;
 }
 
+static int mdss_iommu_fault_handler(struct iommu_domain *domain,
+		struct device *dev, unsigned long iova, int flags)
+{
+	pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
+	return 0;
+}
+
+int mdss_iommu_attach(void)
+{
+	struct iommu_domain *domain;
+	int i, domain_idx;
+
+	if (mdss_res->iommu_attached) {
+		pr_warn("mdp iommu already attached\n");
+		return 0;
+	}
+
+	domain_idx = mdss_get_iommu_domain();
+	domain = msm_get_iommu_domain(domain_idx);
+	if (!domain) {
+		pr_err("unable to get iommu domain(%d)\n", domain_idx);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mdp_iommu_ctx); i++) {
+		if (iommu_attach_device(domain, mdp_iommu_ctx[i].ctx)) {
+			WARN(1, "could not attach iommu domain %d to ctx %s\n",
+				domain_idx, mdp_iommu_ctx[i].name);
+			return -EINVAL;
+		}
+	}
+	mdss_res->iommu_attached = true;
+
+	return 0;
+}
+
+int mdss_iommu_dettach(void)
+{
+	struct iommu_domain *domain;
+	int i, domain_idx;
+
+	if (!mdss_res->iommu_attached) {
+		pr_warn("mdp iommu already dettached\n");
+		return 0;
+	}
+
+	domain_idx = mdss_get_iommu_domain();
+	domain = msm_get_iommu_domain(domain_idx);
+	if (!domain) {
+		pr_err("unable to get iommu domain(%d)\n", domain_idx);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mdp_iommu_ctx); i++)
+		iommu_detach_device(domain, mdp_iommu_ctx[i].ctx);
+	mdss_res->iommu_attached = false;
+
+	return 0;
+}
+
+int mdss_iommu_init(void)
+{
+	struct iommu_domain *domain;
+	int domain_idx, i;
+
+	domain_idx = msm_register_domain(&mdp_iommu_layout);
+	if (IS_ERR_VALUE(domain_idx))
+		return -EINVAL;
+
+	domain = msm_get_iommu_domain(domain_idx);
+	if (!domain) {
+		pr_err("unable to get iommu domain(%d)\n", domain_idx);
+		return -EINVAL;
+	}
+
+	iommu_set_fault_handler(domain, mdss_iommu_fault_handler);
+
+	for (i = 0; i < ARRAY_SIZE(mdp_iommu_ctx); i++) {
+		mdp_iommu_ctx[i].ctx = msm_iommu_get_ctx(mdp_iommu_ctx[i].name);
+		if (!mdp_iommu_ctx[i].ctx) {
+			pr_warn("unable to get iommu ctx(%s)\n",
+					mdp_iommu_ctx[i].name);
+			return -EINVAL;
+		}
+	}
+	mdss_res->iommu_domain = domain_idx;
+
+	return 0;
+}
+
 static int mdss_hw_init(struct mdss_data_type *mdata)
 {
 	char *base = mdata->vbif_base;
@@ -646,6 +763,10 @@
 		mdata->iclient = NULL;
 	}
 
+	rc = mdss_iommu_init();
+	if (!IS_ERR_VALUE(rc))
+		mdss_iommu_attach();
+
 	rc = mdss_hw_init(mdata);
 
 	return rc;
@@ -744,9 +865,11 @@
 	if (on && !mdss_res->fs_ena) {
 		pr_debug("Enable MDP FS\n");
 		regulator_enable(mdss_res->fs);
+		mdss_iommu_attach();
 		mdss_res->fs_ena = true;
 	} else if (!on && mdss_res->fs_ena) {
 		pr_debug("Disable MDP FS\n");
+		mdss_iommu_dettach();
 		regulator_disable(mdss_res->fs);
 		mdss_res->fs_ena = false;
 	}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 6719d9e..e8e8163 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -20,6 +20,8 @@
 #include <linux/module.h>
 #include <linux/uaccess.h>
 
+#include <mach/iommu_domains.h>
+
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_mdp_rotator.h"
@@ -699,7 +701,12 @@
 		return;
 	}
 
-	data.p[0].addr = fbi->fix.smem_start + offset;
+	if (is_mdss_iommu_attached())
+		data.p[0].addr = mfd->iova;
+	else
+		data.p[0].addr = fbi->fix.smem_start;
+
+	data.p[0].addr += offset;
 	data.p[0].len = fbi->fix.smem_len - offset;
 	data.num_planes = 1;
 
@@ -788,7 +795,7 @@
 	u32 blendcfg;
 	int off, ret = 0;
 
-	if (!mfd->cursor_buf) {
+	if (!mfd->cursor_buf && (cursor->set & FB_CUR_SETIMAGE)) {
 		mfd->cursor_buf = dma_alloc_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
 					(dma_addr_t *) &mfd->cursor_buf_phys,
 					GFP_KERNEL);
@@ -796,6 +803,19 @@
 			pr_err("can't allocate cursor buffer\n");
 			return -ENOMEM;
 		}
+
+		ret = msm_iommu_map_contig_buffer(mfd->cursor_buf_phys,
+						mdss_get_iommu_domain(), 0,
+						MDSS_MDP_CURSOR_SIZE, SZ_4K,
+						0, &(mfd->cursor_buf_iova));
+		if (IS_ERR_VALUE(ret)) {
+			dma_free_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+					  mfd->cursor_buf,
+					  (dma_addr_t) mfd->cursor_buf_phys);
+			pr_err("unable to map cursor buffer to iommu(%d)\n",
+			       ret);
+			return -ENOMEM;
+		}
 	}
 
 	mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
@@ -817,12 +837,17 @@
 				   (img->dy << 16) | img->dx);
 
 	if (cursor->set & FB_CUR_SETIMAGE) {
-		int calpha_en, transp_en, alpha, size;
+		int calpha_en, transp_en, alpha, size, cursor_addr;
 		ret = copy_from_user(mfd->cursor_buf, img->data,
 				     img->width * img->height * 4);
 		if (ret)
 			return ret;
 
+		if (is_mdss_iommu_attached())
+			cursor_addr = mfd->cursor_buf_iova;
+		else
+			cursor_addr = mfd->cursor_buf_phys;
+
 		if (img->bg_color == 0xffffffff)
 			transp_en = 0;
 		else
@@ -841,7 +866,7 @@
 		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_STRIDE,
 				   img->width * 4);
 		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BASE_ADDR,
-				   mfd->cursor_buf_phys);
+				   cursor_addr);
 
 		wmb();
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 6fd8463..50cc025 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -17,10 +17,13 @@
 #include <linux/errno.h>
 #include <linux/file.h>
 #include <linux/ion.h>
+#include <linux/iommu.h>
 #include <linux/msm_kgsl.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
+#include <mach/iommu_domains.h>
+
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_mdp_formats.h"
@@ -295,6 +298,11 @@
 		data->srcp_file = NULL;
 	} else if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
 		pr_debug("ion hdl=%p buf=0x%x\n", data->srcp_ihdl, data->addr);
+
+		if (is_mdss_iommu_attached())
+			ion_unmap_iommu(iclient, data->srcp_ihdl,
+					mdss_get_iommu_domain(), 0);
+
 		ion_free(iclient, data->srcp_ihdl);
 		data->srcp_ihdl = NULL;
 	} else {
@@ -347,7 +355,17 @@
 			data->srcp_ihdl = NULL;
 			return ret;
 		}
-		ret = ion_phys(iclient, data->srcp_ihdl, start, (size_t *) len);
+
+		if (is_mdss_iommu_attached()) {
+			ret = ion_map_iommu(iclient, data->srcp_ihdl,
+					    mdss_get_iommu_domain(),
+					    0, SZ_4K, 0, start, len, 0,
+					    ION_IOMMU_UNMAP_DELAYED);
+		} else {
+			ret = ion_phys(iclient, data->srcp_ihdl, start,
+				       (size_t *) len);
+		}
+
 		if (IS_ERR_VALUE(ret)) {
 			ion_free(iclient, data->srcp_ihdl);
 			pr_err("failed to map ion handle (%d)\n", ret);
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 8c4b1b9..bd5f464 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -18,6 +18,10 @@
 #include <linux/major.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
+#include <linux/iommu.h>
+
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
 
 #include "mdss_mdp.h"
 #include "mdss_fb.h"
@@ -68,6 +72,7 @@
 	static void *videomemory;
 	static ion_phys_addr_t mdss_wb_mem;
 	static struct mdss_mdp_data mdss_wb_buffer = { .num_planes = 1, };
+	int rc;
 
 	if (IS_ERR_OR_NULL(ihdl)) {
 		struct fb_info *fbi;
@@ -79,6 +84,7 @@
 		img_size = fbi->var.xres * fbi->var.yres *
 			fbi->var.bits_per_pixel / 8;
 
+
 		ihdl = ion_alloc(iclient, img_size, SZ_4K,
 				 ION_HEAP(ION_SF_HEAP_ID));
 		if (IS_ERR_OR_NULL(ihdl)) {
@@ -89,8 +95,18 @@
 		videomemory = ion_map_kernel(iclient, ihdl, 0);
 		ion_phys(iclient, ihdl, &mdss_wb_mem, &img_size);
 
-		img->addr = mdss_wb_mem;
-		img->len = img_size;
+		if (is_mdss_iommu_attached()) {
+			rc = ion_map_iommu(iclient, ihdl,
+					   mdss_get_iommu_domain(),
+					   0, SZ_4K, 0,
+					   (unsigned long *) &img->addr,
+					   (unsigned long *) &img->len,
+					   0, 0);
+		} else {
+			img->addr = mdss_wb_mem;
+			img->len = img_size;
+		}
+
 		pr_debug("ihdl=%p virt=%p phys=0x%lx iova=0x%x size=%u\n",
 			 ihdl, videomemory, mdss_wb_mem, img->addr, img_size);
 	}
@@ -550,3 +566,9 @@
 	return mdss_mdp_wb_terminate(mfd);
 }
 EXPORT_SYMBOL(msm_fb_writeback_terminate);
+
+int msm_fb_get_iommu_domain(void)
+{
+	return mdss_get_iommu_domain();
+}
+EXPORT_SYMBOL(msm_fb_get_iommu_domain);
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index 94c24ee..0c6ff79 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -592,6 +592,7 @@
 static int __devinit mipi_nt35510_lcd_probe(struct platform_device *pdev)
 {
 	struct platform_device *pthisdev = NULL;
+	struct msm_fb_panel_data *pdata;
 	pr_debug("%s\n", __func__);
 
 	if (pdev->id == 0) {
@@ -601,6 +602,11 @@
 		return 0;
 	}
 
+	pdata = pdev->dev.platform_data;
+	if (mipi_nt35510_pdata && mipi_nt35510_pdata->rotate_panel()
+			&& pdata->panel_info.type == MIPI_CMD_PANEL)
+		pdata->panel_info.lcd.refx100 = 6200;
+
 	pthisdev = msm_fb_add_device(pdev);
 	mipi_nt35510_create_sysfs(pthisdev);
 
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index d7992a7..2b75193 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -1519,7 +1519,7 @@
 {
 	u32 status;
 	unsigned long flags;
-	int need_wait;
+	int need_wait = 0;
 
 	spin_lock_irqsave(&dsi_mdp_lock, flags);
 	status = MIPI_INP(MIPI_DSI_BASE + 0x0004);/* DSI_STATUS */
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 827a951..0e4e2cf 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -3243,12 +3243,14 @@
 
 	if (notify == NOTIFY_UPDATE_START) {
 		INIT_COMPLETION(mfd->msmfb_update_notify);
-		wait_for_completion_interruptible(&mfd->msmfb_update_notify);
+		ret = wait_for_completion_interruptible_timeout(
+		&mfd->msmfb_update_notify, 4*HZ);
 	} else {
 		INIT_COMPLETION(mfd->msmfb_no_update_notify);
-		wait_for_completion_interruptible(&mfd->msmfb_no_update_notify);
+		ret = wait_for_completion_interruptible_timeout(
+		&mfd->msmfb_no_update_notify, 4*HZ);
 	}
-	return 0;
+	return (ret > 0) ? 0 : -1;
 }
 
 static int msmfb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
@@ -3321,7 +3323,24 @@
 
 	return ret;
 }
-
+static int msmfb_handle_metadata_ioctl(struct msm_fb_data_type *mfd,
+				struct msmfb_metadata *metadata_ptr)
+{
+	int ret;
+	switch (metadata_ptr->op) {
+#ifdef CONFIG_FB_MSM_MDP40
+	case metadata_op_base_blend:
+		ret = mdp4_update_base_blend(mfd,
+						&metadata_ptr->data.blend_cfg);
+		break;
+#endif
+	default:
+		pr_warn("Unsupported request to MDP META IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
 static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
@@ -3339,6 +3358,7 @@
 #endif
 	struct mdp_page_protection fb_page_protection;
 	struct msmfb_mdp_pp mdp_pp;
+	struct msmfb_metadata mdp_metadata;
 	int ret = 0;
 
 	switch (cmd) {
@@ -3638,6 +3658,13 @@
 		ret = msmfb_handle_pp_ioctl(mfd, &mdp_pp);
 		break;
 
+	case MSMFB_METADATA_SET:
+		ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata));
+		if (ret)
+			return ret;
+		ret = msmfb_handle_metadata_ioctl(mfd, &mdp_metadata);
+		break;
+
 	default:
 		MSM_FB_INFO("MDP: unknown ioctl (cmd=%x) received!\n", cmd);
 		ret = -EINVAL;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 2d3bee3..596c86f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1879,7 +1879,6 @@
 		output_buf_req = &decoder->actual_output_buf_req;
 		input_buf_req = &decoder->actual_input_buf_req;
 		min_dpb = decoder->min_dpb_num;
-		y_cb_cr_size = decoder->y_cb_cr_size;
 		if ((decoder->buf_format.buffer_format ==
 			VCD_BUFFER_FORMAT_TILE_4x2) &&
 			(frame_size->height < MDP_MIN_TILE_HEIGHT)) {
@@ -1891,6 +1890,7 @@
 				&decoder->buf_format,
 				(!decoder->progressive_only),
 				decoder->hdr.decoding, NULL);
+			decoder->y_cb_cr_size = y_cb_cr_size;
 		} else
 			y_cb_cr_size = decoder->y_cb_cr_size;
 	}
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 972160a..2064e01 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -956,27 +956,54 @@
 
 int res_trk_open_secure_session()
 {
-	int rc;
-
-	if (res_trk_check_for_sec_session() == 1) {
-		mutex_lock(&resource_context.secure_lock);
+	int rc, memtype;
+	if (!res_trk_check_for_sec_session()) {
+		pr_err("Secure sessions are not active\n");
+		return -EINVAL;
+	}
+	mutex_lock(&resource_context.secure_lock);
+	if (!resource_context.sec_clk_heap) {
 		pr_err("Securing...\n");
 		rc = res_trk_enable_iommu_clocks();
 		if (rc) {
 			pr_err("IOMMU clock enabled failed while open");
 			goto error_open;
 		}
-		msm_ion_secure_heap(ION_HEAP(resource_context.memtype));
-		msm_ion_secure_heap(ION_HEAP(resource_context.cmd_mem_type));
-
-		if (resource_context.vidc_platform_data->secure_wb_heap)
-			msm_ion_secure_heap(ION_HEAP(ION_CP_WB_HEAP_ID));
-
+		memtype = ION_HEAP(resource_context.memtype);
+		rc = msm_ion_secure_heap(memtype);
+		if (rc) {
+			pr_err("ION heap secure failed heap id %d rc %d\n",
+				   resource_context.memtype, rc);
+			goto disable_iommu_clks;
+		}
+		memtype = ION_HEAP(resource_context.cmd_mem_type);
+		rc = msm_ion_secure_heap(memtype);
+		if (rc) {
+			pr_err("ION heap secure failed heap id %d rc %d\n",
+				   resource_context.cmd_mem_type, rc);
+			goto unsecure_memtype_heap;
+		}
+		if (resource_context.vidc_platform_data->secure_wb_heap) {
+			memtype = ION_HEAP(ION_CP_WB_HEAP_ID);
+			rc = msm_ion_secure_heap(memtype);
+			if (rc) {
+				pr_err("WB_HEAP_ID secure failed rc %d\n", rc);
+				goto unsecure_cmd_heap;
+			}
+		}
+		resource_context.sec_clk_heap = 1;
 		res_trk_disable_iommu_clocks();
-		mutex_unlock(&resource_context.secure_lock);
 	}
+	mutex_unlock(&resource_context.secure_lock);
 	return 0;
+unsecure_cmd_heap:
+	msm_ion_unsecure_heap(ION_HEAP(resource_context.memtype));
+unsecure_memtype_heap:
+	msm_ion_unsecure_heap(ION_HEAP(resource_context.cmd_mem_type));
+disable_iommu_clks:
+	res_trk_disable_iommu_clocks();
 error_open:
+	resource_context.sec_clk_heap = 0;
 	mutex_unlock(&resource_context.secure_lock);
 	return rc;
 }
@@ -984,12 +1011,13 @@
 int res_trk_close_secure_session()
 {
 	int rc;
-	if (res_trk_check_for_sec_session() == 1) {
+	if (res_trk_check_for_sec_session() == 1 &&
+		resource_context.sec_clk_heap) {
 		pr_err("Unsecuring....\n");
 		mutex_lock(&resource_context.secure_lock);
 		rc = res_trk_enable_iommu_clocks();
 		if (rc) {
-			pr_err("IOMMU clock enabled failed while close");
+			pr_err("IOMMU clock enabled failed while close\n");
 			goto error_close;
 		}
 		msm_ion_unsecure_heap(ION_HEAP(resource_context.cmd_mem_type));
@@ -999,6 +1027,7 @@
 			msm_ion_unsecure_heap(ION_HEAP(ION_CP_WB_HEAP_ID));
 
 		res_trk_disable_iommu_clocks();
+		resource_context.sec_clk_heap = 0;
 		mutex_unlock(&resource_context.secure_lock);
 	}
 	return 0;
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
index 01999a4..298930e 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
@@ -57,6 +57,7 @@
 	u32 mmu_clks_on;
 	u32 secure_session;
 	struct mutex secure_lock;
+	u32 sec_clk_heap;
 };
 
 #if DEBUG
diff --git a/include/linux/coresight-stm.h b/include/linux/coresight-stm.h
index 56a6cdf..754f2f3 100644
--- a/include/linux/coresight-stm.h
+++ b/include/linux/coresight-stm.h
@@ -19,7 +19,6 @@
 	OST_ENTITY_TRACE_PRINTK		= 0x02,
 	OST_ENTITY_TRACE_MARKER		= 0x04,
 	OST_ENTITY_DEV_NODE		= 0x08,
-	OST_ENTITY_PRINTK		= 0x10,
 	OST_ENTITY_ALL			= 0x1F,
 };
 
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 04fcd88..3bba69c 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -45,6 +45,7 @@
 };
 
 enum coresight_dev_type {
+	CORESIGHT_DEV_TYPE_NONE,
 	CORESIGHT_DEV_TYPE_SINK,
 	CORESIGHT_DEV_TYPE_LINK,
 	CORESIGHT_DEV_TYPE_LINKSINK,
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index 9cf2acf..076302b 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -13,9 +13,80 @@
 	int32_t physical;
 };
 
+struct epm_psoc_init_resp {
+	u8	cmd;
+	u8	version;
+	u8	compatible_ver;
+	u8	firm_ver[3];
+	u8	num_dev;
+	u8	num_channel;
+};
+
+struct epm_psoc_channel_configure {
+	u8		cmd;
+	u8		device_num;
+	uint32_t	channel_num;
+};
+
+struct epm_psoc_set_avg {
+	u8	cmd;
+	u8	avg_period;
+	u8	return_code;
+};
+
+struct epm_psoc_get_data {
+	u8		cmd;
+	u8		dev_num;
+	u8		chan_num;
+	uint32_t	timestamp_resp_value;
+	uint32_t	reading_value;
+};
+
+struct epm_psoc_get_buffered_data {
+	u8		cmd;
+	u8		dev_num;
+	u8		status_mask;
+	u8		chan_idx;
+	uint32_t	chan_mask;
+	uint32_t	timestamp_start;
+	uint32_t	timestamp_end;
+	u8		buff_data[48];
+};
+
+struct epm_psoc_system_time_stamp {
+	u8		cmd;
+	uint32_t	timestamp;
+};
+
+struct epm_psoc_set_channel {
+	u8		cmd;
+	u8		dev_num;
+	uint32_t	channel_mask;
+};
+
+struct epm_psoc_get_avg_buffered_switch_data {
+	u8		cmd;
+	u8		status;
+	uint32_t	timestamp_start;
+	uint32_t	channel_mask;
+	u8		avg_data[54];
+};
+
+struct epm_psoc_set_channel_switch {
+	u8		cmd;
+	u8		dev;
+	uint32_t	delay;
+};
+
+struct epm_psoc_set_vadc {
+	u8		cmd;
+	u8		vadc_dev;
+	uint32_t	vadc_voltage;
+};
+
 #ifdef __KERNEL__
 struct epm_chan_properties {
-	uint32_t resistorValue;
+	uint32_t resistorvalue;
 	uint32_t gain;
 };
 
@@ -41,4 +112,41 @@
 
 #define EPM_ADC_DEINIT		_IOR(EPM_ADC_IOCTL_CODE, 3,	\
 					     uint32_t)
+
+#define EPM_PSOC_ADC_INIT		_IOR(EPM_ADC_IOCTL_CODE, 4, \
+					struct epm_psoc_init_resp)
+
+#define EPM_PSOC_ADC_CHANNEL_ENABLE	_IOWR(EPM_ADC_IOCTL_CODE, 5, \
+					struct epm_psoc_channel_configure)
+
+#define EPM_PSOC_ADC_CHANNEL_DISABLE	_IOWR(EPM_ADC_IOCTL_CODE, 6, \
+					struct epm_psoc_channel_configure)
+
+#define EPM_PSOC_ADC_SET_AVERAGING	_IOWR(EPM_ADC_IOCTL_CODE, 7, \
+					struct epm_psoc_set_avg)
+
+#define EPM_PSOC_ADC_GET_LAST_MEASUREMENT	_IOWR(EPM_ADC_IOCTL_CODE, 8, \
+						struct epm_psoc_get_data)
+
+#define EPM_PSOC_ADC_GET_BUFFERED_DATA		_IOWR(EPM_ADC_IOCTL_CODE, 9, \
+					struct epm_psoc_get_buffered_data)
+
+#define EPM_PSOC_ADC_GET_SYSTEM_TIMESTAMP	_IOWR(EPM_ADC_IOCTL_CODE, 10, \
+					struct epm_psoc_system_time_stamp)
+
+#define EPM_PSOC_ADC_SET_SYSTEM_TIMESTAMP	_IOWR(EPM_ADC_IOCTL_CODE, 11, \
+					struct epm_psoc_system_time_stamp)
+
+#define EPM_PSOC_ADC_GET_AVERAGE_DATA		_IOWR(EPM_ADC_IOCTL_CODE, 12, \
+				struct epm_psoc_get_avg_buffered_switch_data)
+
+#define EPM_PSOC_SET_CHANNEL_SWITCH		_IOWR(EPM_ADC_IOCTL_CODE, 13, \
+					struct epm_psoc_set_channel_switch)
+
+#define EPM_PSOC_CLEAR_BUFFER			_IOWR(EPM_ADC_IOCTL_CODE, 14, \
+						uint32_t)
+
+#define EPM_PSOC_ADC_SET_VADC_REFERENCE		_IOWR(EPM_ADC_IOCTL_CODE, 15, \
+						struct epm_psoc_set_vadc)
+
 #endif /* __EPM_ADC_H */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index f6229b5..c9f9d74 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -70,6 +70,7 @@
 #define MSMFB_MDP_PP _IOWR(MSMFB_IOCTL_MAGIC, 156, struct msmfb_mdp_pp)
 #define MSMFB_OVERLAY_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int)
 #define MSMFB_VSYNC_CTRL  _IOW(MSMFB_IOCTL_MAGIC, 161, unsigned int)
+#define MSMFB_METADATA_SET  _IOW(MSMFB_IOCTL_MAGIC, 162, struct msmfb_metadata)
 #define FB_TYPE_3D_PANEL 0x10101010
 #define MDP_IMGTYPE2_START 0x10000
 #define MSMFB_DRIVER_VERSION	0xF9E8D701
@@ -492,7 +493,23 @@
 	} data;
 };
 
+enum {
+	metadata_op_none,
+	metadata_op_base_blend,
+	metadata_op_max
+};
 
+struct mdp_blend_cfg {
+	uint32_t is_premultiplied;
+};
+
+struct msmfb_metadata {
+	uint32_t op;
+	uint32_t flags;
+	union {
+		struct mdp_blend_cfg blend_cfg;
+	} data;
+};
 struct mdp_page_protection {
 	uint32_t page_protection;
 };
@@ -520,7 +537,7 @@
 };
 
 #ifdef __KERNEL__
-
+int msm_fb_get_iommu_domain(void);
 /* get the framebuffer physical address information */
 int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num,
 	int subsys_id);
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index cb56293..647a7ef 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -140,6 +140,7 @@
 	POWER_SUPPLY_TYPE_USB_DCP,	/* Dedicated Charging Port */
 	POWER_SUPPLY_TYPE_USB_CDP,	/* Charging Downstream Port */
 	POWER_SUPPLY_TYPE_USB_ACA,	/* Accessory Charger Adapters */
+	POWER_SUPPLY_TYPE_BMS,		/* Battery Monitor System */
 };
 
 union power_supply_propval {
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 8468aa5..19a1d97 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -175,17 +175,19 @@
 
 /**
  * enum qpnp_adc_channel_scaling_param - pre-scaling AMUX ratio.
- * %CHAN_PATH_SCALING1: ratio of {1, 1}
- * %CHAN_PATH_SCALING2: ratio of {1, 3}
- * %CHAN_PATH_SCALING3: ratio of {1, 4}
- * %CHAN_PATH_SCALING4: ratio of {1, 6}
+ * %CHAN_PATH_SCALING0: ratio of {1, 1}
+ * %CHAN_PATH_SCALING1: ratio of {1, 3}
+ * %CHAN_PATH_SCALING2: ratio of {1, 4}
+ * %CHAN_PATH_SCALING3: ratio of {1, 6}
+ * %CHAN_PATH_SCALING4: ratio of {1, 20}
  * %CHAN_PATH_NONE: Do not use this pre-scaling ratio type.
  *
  * The pre-scaling is applied for signals to be within the voltage range
  * of the ADC.
  */
 enum qpnp_adc_channel_scaling_param {
-	PATH_SCALING1 = 0,
+	PATH_SCALING0 = 0,
+	PATH_SCALING1,
 	PATH_SCALING2,
 	PATH_SCALING3,
 	PATH_SCALING4,
@@ -197,8 +199,8 @@
  *				   digital data relative to ADC reference.
  * %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage.
  * %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters.
+ * %ADC_SCALE_PA_THERM: Returns temperature in degC.
  * %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
- * %ADC_SCALE_XTERN_CHGR_CUR: Returns current across 0.1 ohm resistor.
  * %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
  * %ADC_SCALE_NONE: Do not use this scaling type.
  */
@@ -701,6 +703,75 @@
 			const struct qpnp_adc_properties *adc_prop,
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_pmic_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Performs the AMUX out as 2mV/K and returns
+ *		the temperature in milli degC.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the qpnp adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	Individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Returns the temperature in degC.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_tdkntcg_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Returns the temperature of the xo therm in mili
+		degC.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_vadc_is_ready() - Clients can use this API to check if the
+ *			  device is ready to use.
+ * @result:	0 on success and -EPROBE_DEFER when probe for the device
+ *		has not occured.
+ */
+int32_t qpnp_vadc_is_ready(void);
 #else
 static inline int32_t qpnp_vadc_read(uint32_t channel,
 				struct qpnp_vadc_result *result)
@@ -712,8 +783,30 @@
 { return -ENXIO; }
 static inline int32_t qpnp_adc_scale_default(int32_t adc_code,
 			const struct qpnp_adc_properties *adc_prop,
-			const struct qpnp_adc_chan_properties *chan_prop,
-			struct qpnp_adc_chan_result *chan_rslt)
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_vadc_is_read(void)
 { return -ENXIO; }
 #endif
 
@@ -742,6 +835,13 @@
  */
 int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
 						int32_t *result);
+/**
+ * qpnp_iadc_is_ready() - Clients can use this API to check if the
+ *			  device is ready to use.
+ * @result:	0 on success and -EPROBE_DEFER when probe for the device
+ *		has not occured.
+ */
+int32_t qpnp_iadc_is_ready(void);
 #else
 static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
 							int *result)
@@ -751,6 +851,8 @@
 static inline int32_t qpnp_iadc_get_offset(enum qpnp_iadc_channels channel,
 						int32_t *result)
 { return -ENXIO; }
+static inline int32_t qpnp_iadc_is_read(void)
+{ return -ENXIO; }
 #endif
 
 #endif
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 295be8f..cf7b555 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -21,6 +21,11 @@
 	WCNSS_WLAN_SWITCH_ON,
 };
 
+enum wcnss_hw_type {
+	WCNSS_RIVA_HW = 0,
+	WCNSS_PRONTO_HW,
+};
+
 struct wcnss_wlan_config {
 	int		use_48mhz_xo;
 };
@@ -44,13 +49,17 @@
 int wcnss_wlan_power(struct device *dev,
 				struct wcnss_wlan_config *cfg,
 				enum wcnss_opcode opcode);
-int req_riva_power_on_lock(char *driver_name);
-int free_riva_power_on_lock(char *driver_name);
+int wcnss_req_power_on_lock(char *driver_name);
+int wcnss_free_power_on_lock(char *driver_name);
 unsigned int wcnss_get_serial_number(void);
 void wcnss_flush_delayed_boot_votes(void);
 void wcnss_allow_suspend(void);
 void wcnss_prevent_suspend(void);
+int wcnss_hardware_type(void);
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
+/* WLAN driver uses these names */
+#define req_riva_power_on_lock(name) wcnss_req_power_on_lock(name)
+#define free_riva_power_on_lock(name) wcnss_free_power_on_lock(name)
 
 #endif /* _WCNSS_WLAN_H_ */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e8c0bf3..544f3bf 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -355,6 +355,7 @@
 	__u8		auth;
 	void		*smp_conn;
 	struct timer_list smp_timer;
+	__u8		conn_valid;
 
 
 	void (*connect_cfm_cb)	(struct hci_conn *conn, u8 status);
diff --git a/kernel/printk.c b/kernel/printk.c
index 90dfdde..4cf4670 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -41,7 +41,6 @@
 #include <linux/cpu.h>
 #include <linux/notifier.h>
 #include <linux/rculist.h>
-#include <linux/coresight-stm.h>
 
 #include <asm/uaccess.h>
 
@@ -960,8 +959,6 @@
 		}
 	}
 
-	stm_log(OST_ENTITY_PRINTK, printk_buf, printed_len);
-
 	/*
 	 * Copy the output into log_buf. If the caller didn't provide
 	 * the appropriate log prefix, we insert them here
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 0ade089..0704394 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -486,9 +486,7 @@
 
 	BT_DBG("conn %p mode %d", conn, conn->mode);
 
-	hci_dev_lock(conn->hdev);
 	hci_conn_enter_sniff_mode(conn);
-	hci_dev_unlock(conn->hdev);
 }
 
 static void hci_conn_rssi_update(struct work_struct *work)
@@ -543,6 +541,8 @@
 
 	conn->power_save = 1;
 	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+	conn->conn_valid = true;
+	spin_lock_init(&conn->lock);
 	wake_lock_init(&conn->idle_lock, WAKE_LOCK_SUSPEND, "bt_idle");
 
 	switch (type) {
@@ -615,6 +615,10 @@
 
 	BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
 
+	spin_lock_bh(&conn->lock);
+	conn->conn_valid = false; /* conn data is being released */
+	spin_unlock_bh(&conn->lock);
+
 	/* Make sure no timers are running */
 	del_timer(&conn->idle_timer);
 	wake_lock_destroy(&conn->idle_lock);
@@ -852,7 +856,18 @@
 	if (type == ACL_LINK)
 		return acl;
 
+	/* type of connection already existing can be ESCO or SCO
+	 * so check for both types before creating new */
+
 	sco = hci_conn_hash_lookup_ba(hdev, type, dst);
+
+	if (!sco && type == ESCO_LINK) {
+		sco = hci_conn_hash_lookup_ba(hdev, SCO_LINK, dst);
+	} else if (!sco && type == SCO_LINK) {
+		/* this case can be practically not possible */
+		sco = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, dst);
+	}
+
 	if (!sco) {
 		sco = hci_conn_add(hdev, type, pkt_type, dst);
 		if (!sco) {
@@ -1063,9 +1078,13 @@
 
 timer:
 	if (hdev->idle_timeout > 0) {
-		mod_timer(&conn->idle_timer,
-			jiffies + msecs_to_jiffies(hdev->idle_timeout));
-		wake_lock(&conn->idle_lock);
+		spin_lock_bh(&conn->lock);
+		if (conn->conn_valid) {
+			mod_timer(&conn->idle_timer,
+				jiffies + msecs_to_jiffies(hdev->idle_timeout));
+			wake_lock(&conn->idle_lock);
+		}
+		spin_unlock_bh(&conn->lock);
 	}
 }
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0cd3c3f..345b70f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2291,7 +2291,6 @@
 			if (count > hdev->acl_cnt)
 				return;
 
-			hci_dev_lock(hdev);
 			hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
 
 			hci_send_frame(skb);
@@ -2301,7 +2300,6 @@
 			quote -= count;
 
 			conn->sent += count;
-			hci_dev_unlock(hdev);
 		}
 	}
 }
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index d80c0e3..2c4ab78 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -93,40 +93,15 @@
 	return NULL;
 }
 
-static struct device *hidp_get_device(struct hidp_session *session)
-{
-	bdaddr_t *dst = &session->bdaddr;
-
-	struct device *device = NULL;
-	struct hci_dev *hdev;
-
-	hdev = hci_get_route(dst, BDADDR_ANY);
-	if (!hdev)
-		return NULL;
-
-	session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
-	if (session->conn)
-		device = &session->conn->dev;
-
-	hci_dev_put(hdev);
-
-	return device;
-}
-
 static void __hidp_link_session(struct hidp_session *session)
 {
 	__module_get(THIS_MODULE);
 	list_add(&session->list, &hidp_session_list);
-
-	hci_conn_hold_device(session->conn);
 }
 
 static void __hidp_unlink_session(struct hidp_session *session)
 {
-	struct device *dev;
-
-	dev = hidp_get_device(session);
-	if (dev)
+	if (session->conn)
 		hci_conn_put_device(session->conn);
 
 	list_del(&session->list);
@@ -660,6 +635,28 @@
 	return 0;
 }
 
+static struct hci_conn *hidp_get_connection(struct hidp_session *session)
+{
+	bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
+	bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
+	struct hci_conn *conn;
+	struct hci_dev *hdev;
+
+	hdev = hci_get_route(dst, src);
+	if (!hdev)
+		return NULL;
+
+	hci_dev_lock_bh(hdev);
+	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
+	if (conn)
+		hci_conn_hold_device(conn);
+	hci_dev_unlock_bh(hdev);
+
+	hci_dev_put(hdev);
+
+	return conn;
+}
+
 static int hidp_setup_input(struct hidp_session *session,
 				struct hidp_connadd_req *req)
 {
@@ -707,7 +704,7 @@
 		input->relbit[0] |= BIT_MASK(REL_WHEEL);
 	}
 
-	input->dev.parent = hidp_get_device(session);
+	input->dev.parent = &session->conn->dev;
 
 	input->event = hidp_input_event;
 
@@ -808,7 +805,7 @@
 	strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
 	strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
 
-	hid->dev.parent = hidp_get_device(session);
+	hid->dev.parent = &session->conn->dev;
 	hid->ll_driver = &hidp_hid_driver;
 
 	hid->hid_output_raw_report = hidp_output_raw_report;
@@ -866,6 +863,12 @@
 	session->intr_sock = intr_sock;
 	session->state     = BT_CONNECTED;
 
+	session->conn = hidp_get_connection(session);
+	if (!session->conn) {
+		err = -ENOTCONN;
+		goto failed;
+	}
+
 	setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
 
 	skb_queue_head_init(&session->ctrl_transmit);
@@ -874,6 +877,8 @@
 	session->flags   = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
 	session->idle_to = req->idle_to;
 
+	__hidp_link_session(session);
+
 	if (req->rd_size > 0) {
 		err = hidp_setup_hid(session, req);
 		if (err && err != -ENODEV)
@@ -886,8 +891,6 @@
 			goto purge;
 	}
 
-	__hidp_link_session(session);
-
 	hidp_set_timer(session);
 
 	err = kernel_thread(hidp_session, session, CLONE_KERNEL);
@@ -909,8 +912,6 @@
 unlink:
 	hidp_del_timer(session);
 
-	__hidp_unlink_session(session);
-
 	if (session->input) {
 		input_unregister_device(session->input);
 		session->input = NULL;
@@ -925,6 +926,8 @@
 	session->rd_data = NULL;
 
 purge:
+	__hidp_unlink_session(session);
+
 	skb_queue_purge(&session->ctrl_transmit);
 	skb_queue_purge(&session->intr_transmit);
 
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 374269d..38b1da8 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -5391,6 +5391,7 @@
 	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
 
 	if (insertion) {
+		pr_debug("%s: setup for insertion\n", __func__);
 		tabla_codec_switch_micbias(codec, 0);
 
 		/* DAPM can manipulate PA/DAC bits concurrently */
@@ -6778,7 +6779,6 @@
 		pr_debug("%s: Headphone Detected\n", __func__);
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
 		tabla_codec_cleanup_hs_polling(codec);
-		tabla_codec_enable_hs_detect(codec, 0, 0, false);
 		tabla_schedule_hs_detect_plug(tabla,
 					&tabla->hs_correct_plug_work_nogpio);
 	} else if (plug_type == PLUG_TYPE_HEADSET) {
@@ -7281,6 +7281,8 @@
 	 */
 	tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
 	if (!is_headset) {
+		pr_debug("%s: Inserted headphone is not a headset\n",
+			__func__);
 		tabla_turn_onoff_override(codec, false);
 		tabla_codec_cleanup_hs_polling(codec);
 		tabla_codec_enable_hs_detect(codec, 0, 0, false);
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 05e6e9e..5ccf8ed 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -337,7 +337,7 @@
 		pr_debug("SND_AUDIOCODEC_WMA\n");
 		memset(&wma_cfg, 0x0, sizeof(struct asm_wma_cfg));
 		wma_cfg.format_tag = compr->info.codec_param.codec.format;
-		wma_cfg.ch_cfg = runtime->channels;
+		wma_cfg.ch_cfg = compr->info.codec_param.codec.ch_in;
 		wma_cfg.sample_rate = compr->info.codec_param.codec.sample_rate;
 		wma_cfg.avg_bytes_per_sec =
 			compr->info.codec_param.codec.bit_rate/8;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 65a8824..54f379f 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -57,11 +57,11 @@
 	.rate_max =             48000,
 	.channels_min =         1,
 	.channels_max =         2,
-	.buffer_bytes_max =     2 * 1024 * 1024,
+	.buffer_bytes_max =     1024 * 1024,
 	.period_bytes_min =	128 * 1024,
-	.period_bytes_max =     512 * 1024,
+	.period_bytes_max =     256 * 1024,
 	.periods_min =          4,
-	.periods_max =          16,
+	.periods_max =          8,
 	.fifo_size =            0,
 };
 
@@ -109,12 +109,16 @@
 			break;
 		} else
 			atomic_set(&prtd->pending_buffer, 0);
-		if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
-			break;
+
+		buf = prtd->audio_client->port[IN].buf;
+		if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
+			memset((void *)buf[0].data +
+				(prtd->out_head * prtd->pcm_count),
+				0, prtd->pcm_count);
+		}
 		pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
 				__func__, prtd->pcm_count);
 
-		buf = prtd->audio_client->port[IN].buf;
 		param.paddr = (unsigned long)buf[0].phys
 				+ (prtd->out_head * prtd->pcm_count);
 		param.len = prtd->pcm_count;