Merge "msm: dma: Moving queue_work() function within spinlock"
diff --git a/Documentation/block/row-iosched.txt b/Documentation/block/row-iosched.txt
index 987bd88..fe8b88b 100644
--- a/Documentation/block/row-iosched.txt
+++ b/Documentation/block/row-iosched.txt
@@ -8,16 +8,28 @@
 The ROW IO scheduler was developed with the mobile devices needs in
 mind. In mobile devices we favor user experience upon everything else,
 thus we want to give READ IO requests as much priority as possible.
-The main idea of the ROW scheduling policy is:
-If there are READ requests in pipe - dispatch them but don't starve
-the WRITE requests too much.
+The main idea of the ROW scheduling policy is just that:
+- If there are READ requests in pipe - dispatch them, while write
+starvation is considered.
 
 Software description
 ====================
+The elevator defines a registering mechanism for different IO scheduler
+to implement. This makes implementing a new algorithm quite straight
+forward and requires almost no changes to block/elevator framework. A
+new IO scheduler just has to implement a set of callback functions
+defined by the elevator.
+These callbacks cover all the required IO operations such as
+adding/removing request to/from the scheduler, merging two requests,
+dispatching a request etc.
+
+Design
+======
+
 The requests are kept in queues according to their priority. The
 dispatching of requests is done in a Round Robin manner with a
 different slice for each queue. The dispatch quantum for a specific
-queue is defined according to the queues priority. READ queues are
+queue is set according to the queues priority. READ queues are
 given bigger dispatch quantum than the WRITE queues, within a dispatch
 cycle.
 
@@ -30,88 +42,93 @@
 -	Regular priority WRITE queue
 -	Low priority READ queue
 
+The marking of request as high/low priority will be done by the
+application adding the request and not the scheduler. See TODO section.
+If the request is not marked in any way (high/low) the scheduler
+assigns it to one of the regular priority queues:
+read/write/sync write.
+
 If in a certain dispatch cycle one of the queues was empty and didn't
-use its quantum that queue will be marked as "un-served". If we're in a
-middle of a dispatch cycle dispatching from queue Y and a request
+use its quantum that queue will be marked as "un-served". If we're in
+a middle of a dispatch cycle dispatching from queue Y and a request
 arrives for queue X that was un-served in the previous cycle, if X's
 priority is higher than Y's, queue X will be preempted in the favor of
-queue Y. This won't mean that cycle is restarted. The "dispatched"
-counter of queue X will remain unchanged. Once queue Y uses up it's quantum
-(or there will be no more requests left on it) we'll switch back to queue X
-and allow it to finish it's quantum.
+queue Y.
 
-For READ requests queues we allow idling in within a dispatch quantum in
-order to give the application a chance to insert more requests. Idling
-means adding some extra time for serving a certain queue even if the
-queue is empty. The idling is enabled if we identify the application is
-inserting requests in a high frequency.
+For READ request queues ROW IO scheduler allows idling within a
+dispatch quantum in order to give the application a chance to insert
+more requests. Idling means adding some extra time for serving a
+certain queue even if the queue is empty. The idling is enabled if
+the ROW IO scheduler identifies the application is inserting requests
+in a high frequency.
+Not all queues can idle. ROW scheduler exposes an enablement struct
+for idling.
+For idling on READ queues, the ROW IO scheduler uses timer mechanism.
+When the timer expires we schedule a delayed work that will signal the
+device driver to fetch another request for dispatch.
 
-For idling on READ queues we use timer mechanism. When the timer expires,
-if there are requests in the scheduler we will signal the underlying driver
-(for example the MMC driver) to fetch another request for dispatch.
-
-The ROW algorithm takes the scheduling policy one step further, making
-it a bit more "user-needs oriented", by allowing the application to
-hint on the urgency of its requests. For example: even among the READ
-requests several requests may be more urgent for completion then others.
-The former will go to the High priority READ queue, that is given the
-bigger dispatch quantum than any other queue.
-
-ROW scheduler will support special services for block devices that
-supports High Priority Requests. That is, the scheduler may inform the
-device upon urgent requests using new callback make_urgent_request.
+ROW scheduler will support additional services for block devices that
+supports Urgent Requests. That is, the scheduler may inform the
+device driver upon urgent requests using a newly defined callback.
 In addition it will support rescheduling of requests that were
-interrupted. For example, if the device issues a long write request and
-a sudden high priority read interrupt pops in, the scheduler will
-inform the device about the urgent request, so the device can stop the
-current write request and serve the high priority read request. In such
-a case the device may also send back to the scheduler the reminder of
-the interrupted write request, such that the scheduler may continue
-sending high priority requests without the need to interrupt the
-ongoing write again and again. The write remainder will be sent later on
-according to the scheduler policy.
-
-Design
-======
-Existing algorithms (cfq, deadline) sort the io requests according LBA.
-When deciding on the next request to dispatch they choose the closest
-request to the current disk head position (from handling last
-dispatched request). This is done in order to reduce the disk head
-movement to a minimum.
-We feel that this functionality isn't really needed in mobile devices.
-Usually applications that write/read large chunks of data insert the
-requests in already sorted LBA order. Thus dealing with sort trees adds
-unnecessary complexity.
-
-We're planing to try this enhancement in the future to check if the
-performance is influenced by it.
+interrupted. For example if the device driver issues a long write
+request and a sudden urgent request is received by the scheduler.
+The scheduler will inform the device driver about the urgent request,
+so the device driver can stop the current write request and serve the
+urgent request. In such a case the device driver may also insert back
+to the scheduler the remainder of the interrupted write request, such
+that the scheduler may continue sending urgent requests without the
+need to interrupt the ongoing write again and again. The write
+remainder will be sent later on according to the scheduler policy.
 
 SMP/multi-core
 ==============
-At the moment the code is acceded from 2 contexts:
+At the moment the code is accessed from 2 contexts:
 - Application context (from block/elevator layer): adding the requests.
-- Underlying driver context (for example the mmc driver thread): dispatching
-  the requests and notifying on completion.
+- device driver thread: dispatching the requests and notifying on
+  completion.
 
 One lock is used to synchronize between the two. This lock is provided
-by the underlying driver along with the dispatch queue.
+by the block device driver along with the dispatch queue.
 
 Config options
 ==============
 1. hp_read_quantum: dispatch quantum for the high priority READ queue
-2. rp_read_quantum: dispatch quantum for the regular priority READ queue
-3. hp_swrite_quantum: dispatch quantum for the high priority Synchronous
-   WRITE queue
+   (default is 100 requests)
+2. rp_read_quantum: dispatch quantum for the regular priority READ
+   queue (default is 100 requests)
+3. hp_swrite_quantum: dispatch quantum for the high priority
+   Synchronous WRITE queue (default is 2 requests)
 4. rp_swrite_quantum: dispatch quantum for the regular priority
-   Synchronous WRITE queue
+   Synchronous WRITE queue (default is 1 requests)
 5. rp_write_quantum: dispatch quantum for the regular priority WRITE
-   queue
+   queue (default is 1 requests)
 6. lp_read_quantum: dispatch quantum for the low priority READ queue
+   (default is 1 requests)
 7. lp_swrite_quantum: dispatch quantum for the low priority Synchronous
-   WRITE queue
+   WRITE queue (default is 1 requests)
 8. read_idle: how long to idle on read queue in Msec (in case idling
-   is enabled on that queue).
+   is enabled on that queue). (default is 5 Msec)
 9. read_idle_freq: frequency of inserting READ requests that will
    trigger idling. This is the time in Msec between inserting two READ
-   requests
+   requests. (default is 8 Msec)
 
+Note: Dispatch quantum is number of requests that will be dispatched
+from a certain queue in a dispatch cycle.
+
+To do
+=====
+The ROW algorithm takes the scheduling policy one step further, making
+it a bit more "user-needs oriented", by allowing the application to
+hint on the urgency of its requests. For example: even among the READ
+requests several requests may be more urgent for completion than other.
+The former will go to the High priority READ queue, that is given the
+bigger dispatch quantum than any other queue.
+
+Still need to design the way applications will "hint" on the urgency of
+their requests. May be done by ioctl(). We need to look into concrete
+use-cases in order to determine the best solution for this.
+This will be implemented as a second phase.
+
+Design and implement additional services for block devices that
+supports High Priority Requests.
\ No newline at end of file
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index 33d5cc1..e458ea0 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -11,6 +11,7 @@
 - compatible : should be "qcom,qpnp-iadc" for Current ADC driver.
 - reg : offset and length of the PMIC Aribter register map.
 - interrupts : The USR bank peripheral IADC interrupt.
+- interrupt-names : Should contain "eoc-int-en-set".
 - qcom,adc-bit-resolution : Bit resolution of the ADC.
 - qcom,adc-vdd-reference : Voltage reference used by the ADC.
 - qcom,rsense : Internal rsense resistor used for current measurements.
@@ -84,6 +85,7 @@
                         compatible = "qcom,qpnp-iadc";
                         reg = <0x3200 0x100>;
                         interrupts = <0 0x36 0>;
+			interrupt-names = "eoc-int-en-set";
                         qcom,adc-bit-resolution = <16>;
                         qcom,adc-vdd-reference = <1800>;
 			qcom,rsense = <1500>;
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index d7d3ec2..e23605c 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -11,6 +11,7 @@
 - compatible : should be "qcom,qpnp-vadc" for Voltage ADC driver.
 - reg : offset and length of the PMIC Aribter register map.
 - interrupts : The USR bank peripheral VADC interrupt.
+- interrupt-names : Should contain "eoc-int-en-set".
 - qcom,adc-bit-resolution : Bit resolution of the ADC.
 - qcom,adc-vdd-reference : Voltage reference used by the ADC.
 
@@ -82,6 +83,7 @@
                         compatible = "qcom,qpnp-vadc";
                         reg = <0x3100 0x100>;
                         interrupts = <0x0 0x31 0x0>;
+			interrupt-names = "eoc-int-en-set";
                         qcom,adc-bit-resolution = <15>;
                         qcom,adc-vdd-reference = <1800>;
 
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 10732cf..da0708f 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -6,14 +6,14 @@
 SPMI bus. This driver supports various LED modules such as
 WLED (white LED), RGB LED and flash LED.
 
-Required Properties:
-- compatible	: should be "qcom,leds-qpnp"
-
 Each LED module is represented as a node of "leds-qpnp". This
 node will further contain the type of LED supported and its
-properties.
+properties.  At least one child node is required for each LED
+module.  Each must have the required properties below, in addition
+to the properties for the LED type, WLED, Flash or RGB.
 
-Required properties:
+Required properties for each child node, WLED, Flash and RGB:
+- compatible		: should be "qcom,leds-qpnp"
 - qcom,id		: must be one of values supported in enum qpnp_led
 - label			: type of led that will be used, ie "wled"
 - qcom,max-current	: maximum current that the LED can sustain
diff --git a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
new file mode 100644
index 0000000..72b32be
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM CAMERA FLASH
+
+Required properties:
+- cell-index : Should contain flash source index to diffentiate
+    between different flash devices. These indexes represent flash devices
+    for multiple sensors.
+    - 0, 1, 2, 3
+- compatible :
+    - "qcom,camera-led-flash"
+- qcom,flash-type : Should contain type flash device
+    - 1 for LED flash
+    - 2 for strobe flash
+- qcom,flash-source : Should contain array of phandles to flash source nodes.
+    - pm8941_flash0 pm8941_flash1
+
+Example:
+
+qcom,camera-led-flash {
+	cell-index = <0>;
+	compatible = "qcom,camera-led-flash";
+	qcom,flash-type = <1>;
+	qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 6b03fab..e256265 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -62,9 +62,9 @@
     - 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,flash-src-index : should contain phandle to flash source node if flash
+    is supported for this sensor
+    - led_flash0, led_flash1
 - qcom,mount-angle : should contain the physical mount angle of the sensor on
     the target
     - 0, 90, 180, 360
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 213da90..c47d442 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -72,6 +72,11 @@
 
  - compatible : "msm-dai-q6"
 
+Optional properties:
+
+ - qcom,ext-spk-amp-supply : External speaker amplifier power supply.
+ - qcom,ext-spk-amp-gpio : External speaker amplifier enable signal.
+
 [Second Level Nodes]
 
 Required properties:
diff --git a/Documentation/dvb/qcom-mpq.txt b/Documentation/dvb/qcom-mpq.txt
index 28f5d39..1196da0 100644
--- a/Documentation/dvb/qcom-mpq.txt
+++ b/Documentation/dvb/qcom-mpq.txt
@@ -123,17 +123,15 @@
 
 Background Processing
 ---------------------
-When demux receives notifications from underlying HW drivers about new
-data, it schedules work to a single-threaded workqueue to process the
-notification.
+Demux allocates a kernel thread for each live-input to process
+the TS packets notified from the HW for specific input. There
+are two such inputs (TSIF0 and TSIF1), both can be processed in
+parallel by two seperate threads.
 
 The processing is the action of demuxing of the new data; it may sleep
 as it locks against the demux data-structure that may be accessed by
 user-space in the meanwhile.
 
-A single threaded workqueue exists for each live input (TSIF0 or TSIF1)
-to process the inputs in parallel.
-
 Dependencies
 ------------
 The demux driver depends on the following kernel drivers and subsystems:
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 502d34a..0decddc 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -38,7 +38,7 @@
 	};
 
 	timer {
-		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		compatible = "arm,armv7-timer";
 		interrupts = <1 2 0>, <1 3 0>;
 		clock-frequency = <19200000>;
 	};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 89d4df8..6538db5 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -487,6 +487,7 @@
 			compatible = "qcom,qpnp-vadc";
 			reg = <0x3100 0x100>;
 			interrupts = <0x0 0x31 0x0>;
+			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
 
@@ -698,12 +699,24 @@
 				qcom,hw-settle-time = <0>;
 				qcom,fast-avg-setup = <0>;
 			};
+
+			chan@185 {
+				label = "usb_id";
+				qcom,channel-num = <185>;
+				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>;
+			};
 		};
 
 		iadc@3600 {
 			compatible = "qcom,qpnp-iadc";
 			reg = <0x3600 0x100>;
 			interrupts = <0x0 0x36 0x0>;
+			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <16>;
 			qcom,adc-vdd-reference = <1800>;
 			qcom,rsense = <1500>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b900c3f..927ebcd 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -36,7 +36,7 @@
 	};
 
 	timer {
-		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		compatible = "arm,armv7-timer";
 		interrupts = <1 2 0 1 3 0>;
 		clock-frequency = <19200000>;
 	};
@@ -83,6 +83,74 @@
 		qcom,ipi-ping = <1>;
 	};
 
+	qcom,smem@fa00000 {
+		compatible = "qcom,smem";
+		reg = <0xfa00000 0x200000>,
+			<0xfa006000 0x1000>,
+			<0xfc428000 0x4000>;
+		reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+		qcom,smd-modem {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <0>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1000>;
+			qcom,pil-string = "modem";
+			interrupts = <0 25 1>;
+		};
+
+		qcom,smsm-modem {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <0>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x2000>;
+			interrupts = <0 26 1>;
+		};
+
+		qcom,smd-adsp {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <1>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x100>;
+			qcom,pil-string = "adsp";
+			interrupts = <0 156 1>;
+		};
+
+		qcom,smsm-adsp {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <1>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x200>;
+			interrupts = <0 157 1>;
+		};
+
+		qcom,smd-wcnss {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <6>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x20000>;
+			qcom,pil-string = "wcnss";
+			interrupts = <0 142 1>;
+		};
+
+		qcom,smsm-wcnss {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <6>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x80000>;
+			interrupts = <0 144 1>;
+		};
+
+		qcom,smd-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			qcom,irq-no-suspend;
+		};
+	};
+
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8910.dtsi b/arch/arm/boot/dts/msm8910.dtsi
index 9514e5a..a5cac86 100644
--- a/arch/arm/boot/dts/msm8910.dtsi
+++ b/arch/arm/boot/dts/msm8910.dtsi
@@ -35,7 +35,7 @@
 	};
 
 	timer {
-		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		compatible = "arm,armv7-timer";
 		interrupts = <1 2 0 1 3 0>;
 		clock-frequency = <19200000>;
 	};
@@ -194,6 +194,15 @@
 			qcom,irq-no-suspend;
 		};
 	};
+
+	qcom,wdt@f9017000 {
+		compatible = "qcom,msm-watchdog";
+		reg = <0xf9017000 0x1000>;
+		interrupts = <0 3 0>, <0 4 0>;
+		qcom,bark-time = <11000>;
+		qcom,pet-time = <10000>;
+		qcom,ipi-ping = <1>;
+	};
 };
 
 /include/ "msm8910-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index 25f79f8..c9b999f 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -19,7 +19,7 @@
 		reg = <0x6e 0x0>;
 		qcom,csi-if = <1>;
 		qcom,csid-core = <0>;
-		qcom,flash-type = <0>;
+		qcom,flash-src-index = <&led_flash0>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "s5k3l1yx";
 		cam_vdig-supply = <&pm8941_l3>;
@@ -61,7 +61,6 @@
 		reg = <0x6c 0x0>;
 		qcom,csi-if = <1>;
 		qcom,csid-core = <0>;
-		qcom,flash-type = <0>;
 		qcom,mount-angle = <180>;
 		qcom,sensor-name = "ov2720";
 		cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
index d804355..68da844 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
@@ -18,7 +18,7 @@
 		reg = <0x6e 0x0>;
 		qcom,csi-if = <1>;
 		qcom,csid-core = <0>;
-		qcom,flash-type = <0>;
+		qcom,flash-src-index = <&led_flash0>;
 		qcom,mount-angle = <90>;
 		qcom,sensor-name = "s5k3l1yx";
 		cam_vdig-supply = <&pm8941_l3>;
@@ -60,7 +60,6 @@
 		reg = <0x6c 0x0>;
 		qcom,csi-if = <1>;
 		qcom,csid-core = <0>;
-		qcom,flash-type = <0>;
 		qcom,mount-angle = <180>;
 		qcom,sensor-name = "ov2720";
 		cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 4b96811..48dd4dc 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -165,6 +165,13 @@
 		vdd-supply = <&gdsc_vfe>;
 	};
 
+	led_flash0: qcom,camera-led-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-led-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+	};
+
 	cci: qcom,cci@fda0C000 {
 		cell-index = <0>;
 		compatible = "qcom,cci";
@@ -189,7 +196,6 @@
 			reg = <0x90 0x0>;
 			qcom,csi-if = <1>;
 			qcom,csid-core = <0>;
-			qcom,flash-type = <0>;
 			qcom,mount-angle = <0>;
 			qcom,sensor-name = "mt9m114";
 			cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 7557fd1..00e9c7a 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -11,8 +11,8 @@
  */
 
 /include/ "dsi-panel-toshiba-720p-video.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
 /include/ "msm8974-leds.dtsi"
+/include/ "msm8974-camera-sensor.dtsi"
 
 / {
 	serial@f991e000 {
@@ -156,40 +156,7 @@
 	};
 
 	sound {
-		compatible = "qcom,msm8974-audio-taiko";
 		qcom,model = "msm8974-taiko-cdp-snd-card";
-
-		qcom,audio-routing =
-			"RX_BIAS", "MCLK",
-			"LDO_H", "MCLK",
-			"Ext Spk Bottom Pos", "LINEOUT1",
-			"Ext Spk Bottom Neg", "LINEOUT3",
-			"Ext Spk Top Pos", "LINEOUT2",
-			"Ext Spk Top Neg", "LINEOUT4",
-			"AMIC1", "MIC BIAS1 Internal1",
-			"MIC BIAS1 Internal1", "Handset Mic",
-			"AMIC2", "MIC BIAS2 External",
-			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCRight Headset Mic",
-			"AMIC4", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCLeft Headset Mic",
-			"DMIC1", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Digital Mic1",
-			"DMIC2", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Digital Mic2",
-			"DMIC3", "MIC BIAS3 External",
-			"MIC BIAS3 External", "Digital Mic3",
-			"DMIC4", "MIC BIAS3 External",
-			"MIC BIAS3 External", "Digital Mic4",
-			"DMIC5", "MIC BIAS4 External",
-			"MIC BIAS4 External", "Digital Mic5",
-			"DMIC6", "MIC BIAS4 External",
-			"MIC BIAS4 External", "Digital Mic6";
-
-		qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
-		taiko-mclk-clk = <&pm8941_clkdiv1>;
-		qcom,taiko-mclk-clk-freq = <9600000>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index cf45ceb..cac7d3c 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -172,40 +172,7 @@
 	};
 
 	sound {
-		compatible = "qcom,msm8974-audio-taiko";
 		qcom,model = "msm8974-taiko-fluid-snd-card";
-
-		qcom,audio-routing =
-			"RX_BIAS", "MCLK",
-			"LDO_H", "MCLK",
-			"Ext Spk Bottom Pos", "LINEOUT1",
-			"Ext Spk Bottom Neg", "LINEOUT3",
-			"Ext Spk Top Pos", "LINEOUT2",
-			"Ext Spk Top Neg", "LINEOUT4",
-			"AMIC1", "MIC BIAS1 Internal1",
-			"MIC BIAS1 Internal1", "Handset Mic",
-			"AMIC2", "MIC BIAS2 External",
-			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCRight Headset Mic",
-			"AMIC4", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCLeft Headset Mic",
-			"DMIC1", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Digital Mic1",
-			"DMIC2", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Digital Mic2",
-			"DMIC3", "MIC BIAS3 External",
-			"MIC BIAS3 External", "Digital Mic3",
-			"DMIC4", "MIC BIAS3 External",
-			"MIC BIAS3 External", "Digital Mic4",
-			"DMIC5", "MIC BIAS4 External",
-			"MIC BIAS4 External", "Digital Mic5",
-			"DMIC6", "MIC BIAS4 External",
-			"MIC BIAS4 External", "Digital Mic6";
-
-		qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
-		taiko-mclk-clk = <&pm8941_clkdiv1>;
-		qcom,taiko-mclk-clk-freq = <9600000>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index 89bb687..8ba3470 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -45,13 +45,13 @@
 			status = "disabled";
 		};
 
-		qcom,leds@d2000 {
+		qcom,leds@d200 {
 			status = "disabled";
 		};
 
 		qcom,leds@d300 {
 			status = "okay";
-			qcom,flash_0 {
+			pm8941_flash0: qcom,flash_0 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
 				qcom,headroom = <0>;
@@ -67,7 +67,7 @@
 				qcom,current = <625>;
 			};
 
-			qcom,flash_1 {
+			pm8941_flash1: qcom,flash_1 {
 				qcom,max-current = <1000>;
 				qcom,default-state = "off";
 				qcom,headroom = <0>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 0f65dc8..7da00d3 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
  */
 
-/include/ "msm8974-camera-sensor-liquid.dtsi"
 /include/ "msm8974-leds.dtsi"
+/include/ "msm8974-camera-sensor-liquid.dtsi"
 
 / {
 	serial@f991e000 {
@@ -214,6 +214,35 @@
 
 	sound {
 		qcom,model = "msm8974-taiko-liquid-snd-card";
+
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"Lineout_1 amp", "LINEOUT1",
+			"Lineout_3 amp", "LINEOUT3",
+			"Lineout_2 amp", "LINEOUT2",
+			"Lineout_4 amp", "LINEOUT4",
+			"AMIC1", "MIC BIAS1 Internal1",
+			"MIC BIAS1 Internal1", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCLeft Headset Mic",
+			"DMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic1",
+			"DMIC2", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic2",
+			"DMIC3", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic3",
+			"DMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic4",
+			"DMIC5", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic5",
+			"DMIC6", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic6";
+
 		qcom,ext-spk-amp-supply = <&ext_5v>;
 		qcom,ext-spk-amp-gpio = <&pm8841_mpps 1 0>;
 	};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 8563996..cdb1710 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -156,40 +156,7 @@
 	};
 
 	sound {
-		compatible = "qcom,msm8974-audio-taiko";
 		qcom,model = "msm8974-taiko-mtp-snd-card";
-
-		qcom,audio-routing =
-			"RX_BIAS", "MCLK",
-			"LDO_H", "MCLK",
-			"Ext Spk Bottom Pos", "LINEOUT1",
-			"Ext Spk Bottom Neg", "LINEOUT3",
-			"Ext Spk Top Pos", "LINEOUT2",
-			"Ext Spk Top Neg", "LINEOUT4",
-			"AMIC1", "MIC BIAS1 Internal1",
-			"MIC BIAS1 Internal1", "Handset Mic",
-			"AMIC2", "MIC BIAS2 External",
-			"MIC BIAS2 External", "Headset Mic",
-			"AMIC3", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCRight Headset Mic",
-			"AMIC4", "MIC BIAS2 External",
-			"MIC BIAS2 External", "ANCLeft Headset Mic",
-			"DMIC1", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Digital Mic1",
-			"DMIC2", "MIC BIAS1 External",
-			"MIC BIAS1 External", "Digital Mic2",
-			"DMIC3", "MIC BIAS3 External",
-			"MIC BIAS3 External", "Digital Mic3",
-			"DMIC4", "MIC BIAS3 External",
-			"MIC BIAS3 External", "Digital Mic4",
-			"DMIC5", "MIC BIAS4 External",
-			"MIC BIAS4 External", "Digital Mic5",
-			"DMIC6", "MIC BIAS4 External",
-			"MIC BIAS4 External", "Digital Mic6";
-
-		qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
-		taiko-mclk-clk = <&pm8941_clkdiv1>;
-		qcom,taiko-mclk-clk-freq = <9600000>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index 33656cd..4919391 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -10,6 +10,7 @@
  * GNU General Public License for more details.
  */
 
+/include/ "msm8974-leds.dtsi"
 /include/ "msm8974-camera-sensor.dtsi"
 
 / {
@@ -106,4 +107,36 @@
 	qcom,mss@fc880000 {
 		status = "disable";
 	};
+
+        qcom,kgsl-3d0@fdb00000 {
+		status = "disabled";
+	};
+};
+
+&gdsc_venus {
+        status = "disabled";
+};
+
+&gdsc_mdss {
+        status = "disabled";
+};
+
+&gdsc_jpeg {
+        status = "disabled";
+};
+
+&gdsc_vfe {
+        status = "disabled";
+};
+
+&gdsc_oxili_gx {
+        status = "disabled";
+};
+
+&gdsc_oxili_cx {
+        status = "disabled";
+};
+
+&gdsc_usb_hsic {
+        status = "disabled";
 };
diff --git a/arch/arm/boot/dts/msm8974-sim.dtsi b/arch/arm/boot/dts/msm8974-sim.dtsi
index 8e8b3c3..fb638f7 100644
--- a/arch/arm/boot/dts/msm8974-sim.dtsi
+++ b/arch/arm/boot/dts/msm8974-sim.dtsi
@@ -11,6 +11,7 @@
  */
 
 /include/ "dsi-panel-sim-video.dtsi"
+/include/ "msm8974-leds.dtsi"
 /include/ "msm8974-camera-sensor.dtsi"
 
 / {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 19b8828..62c3a85 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -52,7 +52,7 @@
 	};
 
 	timer {
-		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		compatible = "arm,armv7-timer";
 		interrupts = <1 2 0 1 3 0>;
 		clock-frequency = <19200000>;
 	};
@@ -151,24 +151,25 @@
 		qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 		qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
-		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000>;
 		qcom,sup-voltages = <2950 2950>;
 		qcom,bus-width = <8>;
 		qcom,nonremovable;
 		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
 
 		qcom,msm-bus,name = "sdcc1";
-		qcom,msm-bus,num-cases = <7>;
+		qcom,msm-bus,num-cases = <8>;
 		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <78 512 0 0>, /* No vote */
-				<78 512 6656 13312>, /* 13 MB/s*/
-				<78 512 13312 26624>, /* 26 MB/s */
-				<78 512 26624 53248>, /* 52 MB/s */
-				<78 512 53248 106496>, /* 104 MB/s */
-				<78 512 106496 212992>, /* 208 MB/s */
-				<78 512 2147483647 4294967295>; /* Max. bandwidth */
-		qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+				<78 512 1600 3200>,    /* 400 KB/s*/
+				<78 512 80000 160000>, /* 20 MB/s */
+				<78 512 100000 200000>, /* 25 MB/s */
+				<78 512 200000 400000>, /* 50 MB/s */
+				<78 512 400000 800000>, /* 100 MB/s */
+				<78 512 800000 1600000>, /* 200 MB/s */
+				<78 512 2048000 4096000>; /* Max. bandwidth */
+		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
 		qcom,dat1-mpm-int = <42>;
 	};
 
@@ -197,7 +198,7 @@
 		qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 		qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
-		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+		qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000>;
 		qcom,sup-voltages = <2950 2950>;
 		qcom,bus-width = <4>;
 		qcom,xpc;
@@ -205,17 +206,18 @@
 		qcom,current-limit = <800>;
 
 		qcom,msm-bus,name = "sdcc2";
-		qcom,msm-bus,num-cases = <7>;
+		qcom,msm-bus,num-cases = <8>;
 		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
-				<81 512 6656 13312>, /* 13 MB/s*/
-				<81 512 13312 26624>, /* 26 MB/s */
-				<81 512 26624 53248>, /* 52 MB/s */
-				<81 512 53248 106496>, /* 104 MB/s */
-				<81 512 106496 212992>, /* 208 MB/s */
-				<81 512 2147483647 4294967295>; /* Max. bandwidth */
-		qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+				<81 512 1600 3200>,    /* 400 KB/s*/
+				<81 512 80000 160000>, /* 20 MB/s */
+				<81 512 100000 200000>, /* 25 MB/s */
+				<81 512 200000 400000>, /* 50 MB/s */
+				<81 512 400000 800000>, /* 100 MB/s */
+				<81 512 800000 1600000>, /* 200 MB/s */
+				<81 512 2048000 4096000>; /* Max. bandwidth */
+		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
 		qcom,dat1-mpm-int = <44>;
 	};
 
@@ -244,23 +246,24 @@
 			<&msmgpio 35 0>; /* DATA3 */
 		qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
 
-		qcom,clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
 		qcom,sup-voltages = <1800 1800>;
 		qcom,bus-width = <4>;
 		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
 
 		qcom,msm-bus,name = "sdcc3";
-		qcom,msm-bus,num-cases = <7>;
+		qcom,msm-bus,num-cases = <8>;
 		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <79 512 0 0>, /* No vote */
-				<79 512 6656 13312>, /* 13 MB/s*/
-				<79 512 13312 26624>, /* 26 MB/s */
-				<79 512 26624 53248>, /* 52 MB/s */
-				<79 512 53248 106496>, /* 104 MB/s */
-				<79 512 106496 212992>, /* 208 MB/s */
-				<79 512 2147483647 4294967295>; /* Max. bandwidth */
-		qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+				<79 512 1600 3200>,    /* 400 KB/s*/
+				<79 512 80000 160000>, /* 20 MB/s */
+				<79 512 100000 200000>, /* 25 MB/s */
+				<79 512 200000 400000>, /* 50 MB/s */
+				<79 512 400000 800000>, /* 100 MB/s */
+				<79 512 800000 1600000>, /* 200 MB/s */
+				<79 512 2048000 4096000>; /* Max. bandwidth */
+		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
 		status = "disable";
 	};
 
@@ -289,23 +292,24 @@
 			<&msmgpio 92 0>; /* DATA3 */
 		qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
 
-		qcom,clk-rates = <400000 25000000 50000000 100000000>;
+		qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
 		qcom,sup-voltages = <1800 1800>;
 		qcom,bus-width = <4>;
 		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
 
 		qcom,msm-bus,name = "sdcc4";
-		qcom,msm-bus,num-cases = <7>;
+		qcom,msm-bus,num-cases = <8>;
 		qcom,msm-bus,active-only = <0>;
 		qcom,msm-bus,num-paths = <1>;
 		qcom,msm-bus,vectors-KBps = <80 512 0 0>, /* No vote */
-				<80 512 6656 13312>, /* 13 MB/s*/
-				<80 512 13312 26624>, /* 26 MB/s */
-				<80 512 26624 53248>, /* 52 MB/s */
-				<80 512 53248 106496>, /* 104 MB/s */
-				<80 512 106496 212992>, /* 208 MB/s */
-				<80 512 2147483647 4294967295>; /* Max. bandwidth */
-		qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+				<80 512 1600 3200>,    /* 400 KB/s*/
+				<80 512 80000 160000>, /* 20 MB/s */
+				<80 512 100000 200000>, /* 25 MB/s */
+				<80 512 200000 400000>, /* 50 MB/s */
+				<80 512 400000 800000>, /* 100 MB/s */
+				<80 512 800000 1600000>, /* 200 MB/s */
+				<80 512 2048000 4096000>; /* Max. bandwidth */
+		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
 		status = "disable";
 	};
 
@@ -416,10 +420,6 @@
 		qcom,audio-routing =
 			"RX_BIAS", "MCLK",
 			"LDO_H", "MCLK",
-			"Ext Spk Bottom Pos", "LINEOUT1",
-			"Ext Spk Bottom Neg", "LINEOUT3",
-			"Ext Spk Top Pos", "LINEOUT2",
-			"Ext Spk Top Neg", "LINEOUT4",
 			"AMIC1", "MIC BIAS1 Internal1",
 			"MIC BIAS1 Internal1", "Handset Mic",
 			"AMIC2", "MIC BIAS2 External",
@@ -849,6 +849,16 @@
 		};
 	};
 
+	qcom,msm-dai-mi2s {
+		compatible = "qcom,msm-dai-mi2s";
+		qcom,msm-dai-q6-mi2s-quat {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <3>;
+			qcom,msm-mi2s-rx-lines = <1>;
+			qcom,msm-mi2s-tx-lines = <2>;
+		};
+	};
+
 	qcom,msm-pcm-hostless {
 		compatible = "qcom,msm-pcm-hostless";
 	};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d1c731e..7462911 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -45,7 +45,7 @@
 	};
 
 	timer: msm-qtimer@f9021000 {
-		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		compatible = "arm,armv7-timer";
 		reg = <0xF9021000 0x1000>;
 		interrupts = <0 7 0>;
 		irq-is-not-percpu;
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
index 2dd4b30..de78559 100644
--- a/arch/arm/configs/msm8910_defconfig
+++ b/arch/arm/configs/msm8910_defconfig
@@ -99,6 +99,9 @@
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
@@ -125,6 +128,8 @@
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index f468fe0..bf44665 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -47,6 +47,7 @@
 CONFIG_MSM_BAM_DMUX=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
 CONFIG_MSM_QMI_INTERFACE=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_SUBSYSTEM_RESTART=y
@@ -296,6 +297,8 @@
 CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_MT9M114=y
 CONFIG_OV2720=y
+CONFIG_MSM_CAMERA_FLASH=y
+CONFIG_MSM_CAMERA_LED_TRIGGER_FLASH=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
 CONFIG_MSM_JPEG=y
@@ -355,6 +358,8 @@
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SPS_SUPPORT=y
 CONFIG_LEDS_QPNP=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 973eef9..f9dbc85 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -46,6 +46,7 @@
 CONFIG_MSM_BAM_DMUX=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
 CONFIG_MSM_QMI_INTERFACE=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_SUBSYSTEM_RESTART=y
@@ -298,6 +299,8 @@
 CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_MT9M114=y
 CONFIG_OV2720=y
+CONFIG_MSM_CAMERA_FLASH=y
+CONFIG_MSM_CAMERA_LED_TRIGGER_FLASH=y
 CONFIG_MSM_CAMERA_SENSOR=y
 CONFIG_MSM_ACTUATOR=y
 CONFIG_MSM_JPEG=y
@@ -357,6 +360,8 @@
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_MSM=y
 CONFIG_MMC_MSM_SPS_SUPPORT=y
 CONFIG_LEDS_QPNP=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 1a8bbfc..80f16d4 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -21,6 +21,7 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_KALLSYMS_ALL=y
 CONFIG_EMBEDDED=y
@@ -110,7 +111,7 @@
 # CONFIG_NET_VENDOR_SEEQ is not set
 # CONFIG_NET_VENDOR_SMSC is not set
 # CONFIG_NET_VENDOR_STMICRO is not set
-# CONFIG_WLAN is not set
+CONFIG_ATH6K_LEGACY_EXT=y
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_KEYBOARD is not set
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 2464140..3a52ddc 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -439,12 +439,12 @@
 
 	if (plat && plat->request_pmu_irq)
 		armpmu->request_pmu_irq = plat->request_pmu_irq;
-	else
+	else if (!armpmu->request_pmu_irq)
 		armpmu->request_pmu_irq = armpmu_generic_request_irq;
 
 	if (plat && plat->free_pmu_irq)
 		armpmu->free_pmu_irq = plat->free_pmu_irq;
-	else
+	else if (!armpmu->request_pmu_irq)
 		armpmu->free_pmu_irq = armpmu_generic_free_irq;
 
 	irqs = min(pmu_device->num_resources, num_possible_cpus());
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index ac17480..e7a9237 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -252,11 +252,6 @@
 		tick_nohz_idle_enter();
 		rcu_idle_enter();
 		while (!need_resched()) {
-#ifdef CONFIG_HOTPLUG_CPU
-			if (cpu_is_offline(smp_processor_id()))
-				cpu_die();
-#endif
-
 			/*
 			 * We need to disable interrupts here
 			 * to ensure we don't miss a wakeup call.
@@ -285,6 +280,10 @@
 		tick_nohz_idle_exit();
 		idle_notifier_call_chain(IDLE_END);
 		schedule_preempt_disabled();
+#ifdef CONFIG_HOTPLUG_CPU
+		if (cpu_is_offline(smp_processor_id()))
+			cpu_die();
+#endif
 	}
 }
 
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index f3a6fee..90aed03 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -178,6 +178,7 @@
 	select ARM_HAS_SG_CHAIN
 	select MSM_KRAIT_WFE_FIXUP
 	select MSM_ULTRASOUND_A
+	select MSM_IOMMU_GPU_SYNC
 	select GENERIC_TIME_VSYSCALL
 	select USE_USER_ACCESSIBLE_TIMERS
 	select ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -214,6 +215,7 @@
 	select HOLES_IN_ZONE if SPARSEMEM
 	select ARM_HAS_SG_CHAIN
 	select MSM_KRAIT_WFE_FIXUP
+	select MSM_IOMMU_GPU_SYNC
 	select GENERIC_TIME_VSYSCALL
 	select USE_USER_ACCESSIBLE_TIMERS
 	select ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -246,6 +248,7 @@
 	select ARM_HAS_SG_CHAIN
 	select MSM_KRAIT_WFE_FIXUP
 	select MSM_ULTRASOUND_A
+	select MSM_IOMMU_GPU_SYNC
 	select GENERIC_TIME_VSYSCALL
 	select USE_USER_ACCESSIBLE_TIMERS
 	select ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -1535,6 +1538,16 @@
 	help
 	  SMD Transport Layer for IPC Router
 
+config MSM_IPC_ROUTER_SECURITY
+	depends on MSM_IPC_ROUTER
+	bool "MSM IPC Router Security support"
+	help
+	  This feature of IPC Router will enforce security rules
+	  configured by a security script from the user-space. IPC Router
+	  once configured with the security rules will ensure that the
+	  sender of the message to a service belongs to the relevant
+	  Linux group as configured by the security script.
+
 config MSM_QMI_INTERFACE
 	depends on MSM_IPC_ROUTER
 	depends on QMI_ENCDEC
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 2c7424e..548f40e 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -138,6 +138,7 @@
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
 obj-$(CONFIG_MSM_IPC_ROUTER) += ipc_router.o
 obj-$(CONFIG_MSM_IPC_ROUTER)+= ipc_socket.o
+obj-$(CONFIG_MSM_IPC_ROUTER_SECURITY)+= msm_ipc_router_security.o
 obj-$(CONFIG_MSM_QMI_INTERFACE) += msm_qmi_interface.o
 obj-$(CONFIG_DEBUG_FS) += smd_rpc_sym.o
 obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 5c1d3e1..8174370 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -241,20 +241,127 @@
 
 static struct acpu_level tbl_PVS0_1700MHz[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
-	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   975000 },
-	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),  1000000 },
-	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),  1025000 },
-	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),  1075000 },
-	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1100000 },
-	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1125000 },
-	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
-	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
-	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
-	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
-	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
-	{ 1, {  1620000, HFPLL, 1, 0x3C }, L2(15), 1250000 },
-	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1250000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   950000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   950000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   962500 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),  1000000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1025000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1037500 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1087500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1150000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1175000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1225000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1250000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS1_1700MHz[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   950000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   950000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   962500 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   975000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),  1000000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),  1012500 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1037500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1050000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1087500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1150000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1187500 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1200000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS2_1700MHz[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   925000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   925000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   925000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   937500 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   950000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   975000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1162500 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS3_1700MHz[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   900000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   900000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   900000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   900000 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   925000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   950000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  975000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  987500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1037500 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1062500 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1100000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1125000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS4_1700MHz[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   875000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   875000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   875000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   887500 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   900000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   925000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  950000 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  962500 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  975000 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1037500 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1100000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS5_1700MHz[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   875000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   875000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   875000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   887500 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   900000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   925000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  950000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  962500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15),  987500 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1012500 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1075000 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS6_1700MHz[] __initdata = {
+	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(6),   875000 },
+	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(6),   875000 },
+	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(6),   875000 },
+	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(6),   887500 },
+	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(6),   900000 },
+	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(6),   925000 },
+	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15),  937500 },
+	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15),  950000 },
+	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15),  962500 },
+	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15),  975000 },
+	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1000000 },
+	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1025000 },
+	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1050000 },
 	{ 0, { 0 } }
 };
 
@@ -398,12 +505,12 @@
 	[0][PVS_FASTER]  = {tbl_faster, sizeof(tbl_faster), 25000 },
 
 	[1][0] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz),     0 },
-	[1][1] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz),     0 },
-	[1][2] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz),     0 },
-	[1][3] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz),     0 },
-	[1][4] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz),     0 },
-	[1][5] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz),     0 },
-	[1][6] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz),     0 },
+	[1][1] = { tbl_PVS1_1700MHz, sizeof(tbl_PVS1_1700MHz),     0 },
+	[1][2] = { tbl_PVS2_1700MHz, sizeof(tbl_PVS2_1700MHz),     0 },
+	[1][3] = { tbl_PVS3_1700MHz, sizeof(tbl_PVS3_1700MHz),     0 },
+	[1][4] = { tbl_PVS4_1700MHz, sizeof(tbl_PVS4_1700MHz),     0 },
+	[1][5] = { tbl_PVS5_1700MHz, sizeof(tbl_PVS5_1700MHz),     0 },
+	[1][6] = { tbl_PVS6_1700MHz, sizeof(tbl_PVS6_1700MHz),     0 },
 
 	[2][0] = { tbl_PVS0_2000MHz, sizeof(tbl_PVS0_2000MHz),     0 },
 	[2][1] = { tbl_PVS1_2000MHz, sizeof(tbl_PVS1_2000MHz),     0 },
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index e46599a..948ecdd 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -155,19 +155,19 @@
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
-	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
 	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   975000 },
-	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),  1000000 },
-	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1025000 },
-	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
-	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
-	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
-	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
 	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
 	{ 0, { 0 } }
@@ -175,19 +175,19 @@
 
 static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   925000 },
-	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   950000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(5),   950000 },
 	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   950000 },
-	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(5),   975000 },
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),   975000 },
-	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(5),  1000000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1000000 },
-	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
-	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
-	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
-	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
 	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
 	{ 0, { 0 } }
@@ -195,19 +195,19 @@
 
 static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
-	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   900000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(5),   900000 },
 	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   900000 },
-	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),   925000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(5),   925000 },
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),   925000 },
-	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),   950000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(5),   950000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),   950000 },
-	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
-	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
-	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
-	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
 	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
 	{ 0, { 0 } }
diff --git a/arch/arm/mach-msm/acpuclock-8930aa.c b/arch/arm/mach-msm/acpuclock-8930aa.c
index 9d2b6fc..8d48b54 100644
--- a/arch/arm/mach-msm/acpuclock-8930aa.c
+++ b/arch/arm/mach-msm/acpuclock-8930aa.c
@@ -119,23 +119,23 @@
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
-	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
 	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   975000 },
-	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),  1000000 },
-	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1025000 },
-	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
-	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
-	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
-	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
-	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
-	{ 1, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
 	{ 1, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
 	{ 0, { 0 } }
@@ -143,23 +143,23 @@
 
 static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   925000 },
-	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   950000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(5),   950000 },
 	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   950000 },
-	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),   975000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(5),   975000 },
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),   975000 },
-	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1000000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(5),  1000000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1000000 },
-	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
-	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
-	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
-	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
-	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1175000 },
-	{ 1, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1200000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1200000 },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1200000 },
 	{ 1, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1212500 },
 	{ 0, { 0 } }
@@ -167,23 +167,23 @@
 
 static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   900000 },
-	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   900000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(5),   900000 },
 	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   900000 },
-	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),   925000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(5),   925000 },
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),   925000 },
-	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),   950000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(5),   950000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),   950000 },
-	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
-	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
-	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
-	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
-	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1125000 },
-	{ 1, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1150000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1150000 },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1150000 },
 	{ 1, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1162500 },
 	{ 0, { 0 } }
diff --git a/arch/arm/mach-msm/acpuclock-8930ab.c b/arch/arm/mach-msm/acpuclock-8930ab.c
index 764ae41..96029b4 100644
--- a/arch/arm/mach-msm/acpuclock-8930ab.c
+++ b/arch/arm/mach-msm/acpuclock-8930ab.c
@@ -153,29 +153,29 @@
 
 static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
-	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
 	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   975000 },
-	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),  1000000 },
-	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1025000 },
-	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
-	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
-	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
-	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
-	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
-	{ 1, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
-	{ 1, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
 	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+	{ 0, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
 	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
-	{ 1, {  1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
+	{ 0, {  1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
 	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1262500 },
 	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1287500 },
 	{ 0, { 0 } }
@@ -183,29 +183,29 @@
 
 static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
-	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
 	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   975000 },
-	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),  1000000 },
-	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1025000 },
-	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
-	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
-	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
-	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
-	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
-	{ 1, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
-	{ 1, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
 	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+	{ 0, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
 	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
-	{ 1, {  1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
+	{ 0, {  1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
 	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1262500 },
 	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1287500 },
 	{ 0, { 0 } }
@@ -213,29 +213,29 @@
 
 static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
 	{ 1, {   384000, PLL_8, 0, 0x00 }, L2(0),   950000 },
-	{ 1, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
+	{ 0, {   432000, HFPLL, 2, 0x20 }, L2(5),   975000 },
 	{ 1, {   486000, HFPLL, 2, 0x24 }, L2(5),   975000 },
-	{ 1, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
+	{ 0, {   540000, HFPLL, 2, 0x28 }, L2(5),  1000000 },
 	{ 1, {   594000, HFPLL, 1, 0x16 }, L2(5),  1000000 },
-	{ 1, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
+	{ 0, {   648000, HFPLL, 1, 0x18 }, L2(5),  1025000 },
 	{ 1, {   702000, HFPLL, 1, 0x1A }, L2(5),  1025000 },
-	{ 1, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+	{ 0, {   756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
 	{ 1, {   810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
-	{ 1, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+	{ 0, {   864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
 	{ 1, {   918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
-	{ 1, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+	{ 0, {   972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
-	{ 1, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+	{ 0, {  1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
 	{ 1, {  1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
-	{ 1, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+	{ 0, {  1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
 	{ 1, {  1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
-	{ 1, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+	{ 0, {  1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
 	{ 1, {  1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
-	{ 1, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+	{ 0, {  1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
 	{ 1, {  1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+	{ 0, {  1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
 	{ 1, {  1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
-	{ 1, {  1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
+	{ 0, {  1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
 	{ 1, {  1674000, HFPLL, 1, 0x3E }, L2(15), 1262500 },
 	{ 1, {  1728000, HFPLL, 1, 0x40 }, L2(15), 1287500 },
 	{ 0, { 0 } }
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index fc44b18..cd3e636 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -479,6 +479,12 @@
 	.pull = GPIOMUX_PULL_NONE,
 };
 
+static struct gpiomux_setting gsbi5_uart_cfg = {
+	.func = GPIOMUX_FUNC_2,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 static struct gpiomux_setting gsbi6_spi_cfg = {
 	.func = GPIOMUX_FUNC_2,
 	.drv = GPIOMUX_DRV_16MA,
@@ -1547,6 +1553,21 @@
 	},
 };
 
+static struct msm_gpiomux_config mpq8064_gsbi5_uart_configs[] __initdata = {
+	{
+		.gpio      = 51,        /* GSBI5 UART TX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi5_uart_cfg,
+		},
+	},
+	{
+		.gpio      = 52,        /* GSBI5 UART RX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi5_uart_cfg,
+		},
+	},
+};
+
 void __init apq8064_init_gpiomux(void)
 {
 	int rc;
@@ -1565,6 +1586,8 @@
 		 machine_is_mpq8064_dtv()) {
 		msm_gpiomux_install(mpq8064_gsbi5_i2c_configs,
 				ARRAY_SIZE(mpq8064_gsbi5_i2c_configs));
+		msm_gpiomux_install(mpq8064_gsbi5_uart_configs,
+				ARRAY_SIZE(mpq8064_gsbi5_uart_configs));
 #ifdef CONFIG_MSM_VCAP
 		msm_gpiomux_install(vcap_configs,
 				ARRAY_SIZE(vcap_configs));
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index fe2d2d2..f6dd2ea 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -405,7 +405,7 @@
 	.resume_charge_percent	= 99,
 	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
-	.warm_temp		= 40,
+	.warm_temp		= 45,
 	.temp_check_period	= 1,
 	.max_bat_chg_current	= 1100,
 	.cool_bat_chg_current	= 350,
@@ -433,6 +433,8 @@
 	.shutdown_soc_valid_limit	= 20,
 	.adjust_soc_low_threshold	= 25,
 	.chg_term_ua			= CHG_TERM_MA * 1000,
+	.normal_voltage_calc_ms		= 20000,
+	.low_voltage_calc_ms		= 1000,
 };
 
 static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 95246a7..b3e682f 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -330,9 +330,7 @@
  * to each other.
  * Don't swap the order unless you know what you are doing!
  */
-static struct ion_platform_data apq8064_ion_pdata = {
-	.nr = MSM_ION_HEAP_NUM,
-	.heaps = {
+struct ion_platform_heap apq8064_heaps[] = {
 		{
 			.id	= ION_SYSTEM_HEAP_ID,
 			.type	= ION_HEAP_TYPE_SYSTEM,
@@ -395,7 +393,11 @@
 			.extra_data = (void *) &co_apq8064_ion_pdata,
 		},
 #endif
-	}
+};
+
+static struct ion_platform_data apq8064_ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = apq8064_heaps,
 };
 
 static struct platform_device apq8064_ion_dev = {
@@ -2696,6 +2698,7 @@
 #endif
 
 static struct platform_device *mpq_devices[] __initdata = {
+	&mpq8064_device_uart_gsbi5,
 	&msm_device_sps_apq8064,
 	&mpq8064_device_qup_i2c_gsbi5,
 #ifdef CONFIG_MSM_ROTATOR
@@ -2792,10 +2795,21 @@
 
 #define GSBI_DUAL_MODE_CODE 0x60
 #define MSM_GSBI1_PHYS		0x12440000
+#define MSM_GSBI5_PHYS		0x1A200000
 static void __init apq8064_i2c_init(void)
 {
 	void __iomem *gsbi_mem;
-
+	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+			machine_is_mpq8064_dtv()) {
+		gsbi_mem = ioremap_nocache(MSM_GSBI5_PHYS, 4);
+		writel_relaxed(GSBI_DUAL_MODE_CODE, gsbi_mem);
+		/* Ensure protocol code is written before proceeding */
+		wmb();
+		iounmap(gsbi_mem);
+		mpq8064_i2c_qup_gsbi5_pdata.use_gsbi_shared_mode = 1;
+		mpq8064_device_qup_i2c_gsbi5.dev.platform_data =
+					&mpq8064_i2c_qup_gsbi5_pdata;
+	}
 	apq8064_device_qup_i2c_gsbi1.dev.platform_data =
 					&apq8064_i2c_qup_gsbi1_pdata;
 	gsbi_mem = ioremap_nocache(MSM_GSBI1_PHYS, 4);
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
index 42fe1ea..b4a95ee 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8910.c
@@ -69,6 +69,7 @@
 	CLK_DUMMY("iface_clk",	NULL,		"msm_sdcc.2", OFF),
 	CLK_DUMMY("core_clk",	NULL,		"msm_sdcc.2", OFF),
 	CLK_DUMMY("bus_clk",	NULL,		"msm_sdcc.2", OFF),
+	CLK_DUMMY("dfab_clk",	DFAB_CLK,	"msm_sps", OFF),
 };
 
 static struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 618f83b..a5fded4 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -325,7 +325,7 @@
 	.resume_charge_percent	= 99,
 	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
-	.warm_temp		= 40,
+	.warm_temp		= 45,
 	.temp_check_period	= 1,
 	.max_bat_chg_current	= 1100,
 	.cool_bat_chg_current	= 350,
@@ -472,6 +472,8 @@
 	.adjust_soc_low_threshold	= 25,
 	.chg_term_ua			= CHG_TERM_MA * 1000,
 	.rconn_mohm			= 18,
+	.normal_voltage_calc_ms		= 20000,
+	.low_voltage_calc_ms		= 1000,
 };
 
 static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 512ae72..9464816 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -376,9 +376,7 @@
  * to each other.
  * Don't swap the order unless you know what you are doing!
  */
-static struct ion_platform_data msm8930_ion_pdata = {
-	.nr = MSM_ION_HEAP_NUM,
-	.heaps = {
+struct ion_platform_heap msm8930_heaps[] = {
 		{
 			.id	= ION_SYSTEM_HEAP_ID,
 			.type	= ION_HEAP_TYPE_SYSTEM,
@@ -441,7 +439,12 @@
 			.extra_data = (void *) &co_msm8930_ion_pdata,
 		},
 #endif
-	}
+};
+
+static struct ion_platform_data msm8930_ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = msm8930_heaps,
+
 };
 
 static struct platform_device msm8930_ion_dev = {
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 2071a55..f0ba1c9 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -406,7 +406,7 @@
 	.resume_charge_percent	= 99,
 	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
-	.warm_temp		= 40,
+	.warm_temp		= 45,
 	.temp_check_period	= 1,
 	.max_bat_chg_current	= 1100,
 	.cool_bat_chg_current	= 350,
@@ -431,6 +431,8 @@
 	.shutdown_soc_valid_limit	= 20,
 	.adjust_soc_low_threshold	= 25,
 	.chg_term_ua			= CHG_TERM_MA * 1000,
+	.normal_voltage_calc_ms		= 20000,
+	.low_voltage_calc_ms		= 1000,
 };
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
@@ -613,6 +615,6 @@
 		pm8921_bms_pdata.rconn_mohm = 20;
 
 	if (!machine_is_msm8960_fluid() && !machine_is_msm8960_liquid()
-			&& !machine_is_msm8960_fluid())
+			&& !machine_is_msm8960_mtp())
 		pm8921_chg_pdata.battery_less_hardware = 1;
 }
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index c9ebb24..32ab870 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -398,9 +398,7 @@
  * to each other.
  * Don't swap the order unless you know what you are doing!
  */
-static struct ion_platform_data msm8960_ion_pdata = {
-	.nr = MSM_ION_HEAP_NUM,
-	.heaps = {
+struct ion_platform_heap msm8960_heaps[] = {
 		{
 			.id	= ION_SYSTEM_HEAP_ID,
 			.type	= ION_HEAP_TYPE_SYSTEM,
@@ -463,7 +461,11 @@
 			.extra_data = (void *) &co_msm8960_ion_pdata,
 		},
 #endif
-	}
+};
+
+static struct ion_platform_data msm8960_ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = msm8960_heaps,
 };
 
 static struct platform_device msm8960_ion_dev = {
@@ -1676,7 +1678,7 @@
 		.reg_base_addr = MSM_SAW0_BASE,
 		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
 #if defined(CONFIG_MSM_AVS_HW)
-		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x50589464,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464,
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
@@ -1691,7 +1693,7 @@
 		.reg_base_addr = MSM_SAW1_BASE,
 		.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
 #if defined(CONFIG_MSM_AVS_HW)
-		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x50589464,
+		.reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464,
 		.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000,
 #endif
 		.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
@@ -3316,7 +3318,8 @@
 
 	msm8960_init_pmic();
 	if (machine_is_msm8960_liquid() || (machine_is_msm8960_mtp() &&
-		(socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)))
+		(socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE ||
+			cpu_is_msm8960ab())))
 		msm_isa1200_board_info[0].platform_data = &isa1200_1_pdata;
 	msm8960_i2c_init();
 	msm8960_gfx_init();
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 89ad4ef..ad74182 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -16,6 +16,7 @@
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
+#include <mach/socinfo.h>
 
 #define KS8851_IRQ_GPIO 94
 
@@ -249,6 +250,21 @@
 	},
 };
 
+static struct msm_gpiomux_config msm_rumi_blsp_configs[] __initdata = {
+	{
+		.gpio      = 45,	/* BLSP2 UART8 TX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+	{
+		.gpio      = 46,	/* BLSP2 UART8 RX */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
+		},
+	},
+};
+
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 	{
@@ -624,4 +640,8 @@
 
 	msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs));
 	msm_gpiomux_install(msm_mhl_configs, ARRAY_SIZE(msm_mhl_configs));
+
+	if (machine_is_msm8974_rumi())
+		msm_gpiomux_install(msm_rumi_blsp_configs,
+				    ARRAY_SIZE(msm_rumi_blsp_configs));
 }
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index c47b688..ca8f68a 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -304,8 +304,6 @@
 			"usb_bam", NULL),
 	OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9924000, \
 			"spi_qsd.1", NULL),
-	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
-			"spmi-pmic-arb.0", NULL),
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
 			"msm_sdcc.1", NULL),
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 39060ad..1dcd54f 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -81,9 +81,7 @@
 	.align = PAGE_SIZE,
 };
 
-static struct ion_platform_data ion_pdata = {
-	.nr = MSM_ION_HEAP_NUM,
-	.heaps = {
+static struct ion_platform_heap msm9615_heaps[] = {
 		{
 			.id	= ION_SYSTEM_HEAP_ID,
 			.type	= ION_HEAP_TYPE_SYSTEM,
@@ -102,7 +100,11 @@
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *) &co_ion_pdata,
 		},
-	}
+};
+
+static struct ion_platform_data ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = msm9615_heaps,
 };
 
 static struct platform_device ion_dev = {
@@ -621,7 +623,7 @@
 #define USB_BAM_PHY_BASE	0x12502000
 #define HSIC_BAM_PHY_BASE	0x12542000
 #define A2_BAM_PHY_BASE		0x124C2000
-static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][4][2] = {
+static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][8][2] = {
 	[HSUSB_BAM][0][USB_TO_PEER_PERIPHERAL] = {
 		.src_phy_addr = USB_BAM_PHY_BASE,
 		.src_pipe_index = 11,
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 2983dc0..8c52456 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -727,6 +727,15 @@
 	[KP_INDEX_SKU3(1, 1)] = KEY_CAMERA,
 };
 
+static unsigned int kp_row_gpios_skud[] = {31, 32};
+static unsigned int kp_col_gpios_skud[] = {37};
+
+static const unsigned short keymap_skud[] = {
+	[KP_INDEX_SKU3(0, 0)] = KEY_VOLUMEUP,
+	[KP_INDEX_SKU3(0, 1)] = KEY_VOLUMEDOWN,
+};
+
+
 static struct gpio_event_matrix_info kp_matrix_info_sku3 = {
 	.info.func      = gpio_event_matrix_func,
 	.keymap         = keymap_sku3,
@@ -887,13 +896,23 @@
 #endif
 
 	/* keypad */
+
+	if (machine_is_qrd_skud_prime()) {
+		kp_matrix_info_sku3.keymap = keymap_skud;
+		kp_matrix_info_sku3.output_gpios = kp_row_gpios_skud;
+		kp_matrix_info_sku3.input_gpios = kp_col_gpios_skud;
+		kp_matrix_info_sku3.noutputs = ARRAY_SIZE(kp_row_gpios_skud);
+		kp_matrix_info_sku3.ninputs = ARRAY_SIZE(kp_col_gpios_skud);
+	}
+
 	if (machine_is_msm8625_evt())
 		kp_matrix_info_8625.keymap = keymap_8625_evt;
 
 	if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
 			machine_is_msm8625_evt())
 		platform_device_register(&kp_pdev_8625);
-	else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+	else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()
+		|| machine_is_qrd_skud_prime())
 		platform_device_register(&kp_pdev_sku3);
 
 	/* leds */
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 4e14ff3..9fd5218 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -767,10 +767,7 @@
  * These heaps are listed in the order they will be allocated.
  * Don't swap the order unless you know what you are doing!
  */
-static struct ion_platform_data ion_pdata = {
-	.nr = MSM_ION_HEAP_NUM,
-	.has_outer_cache = 1,
-	.heaps = {
+struct ion_platform_heap msm7627a_heaps[] = {
 		{
 			.id	= ION_SYSTEM_HEAP_ID,
 			.type	= ION_HEAP_TYPE_SYSTEM,
@@ -802,7 +799,12 @@
 			.extra_data = (void *)&co_ion_pdata,
 		},
 #endif
-	}
+};
+
+static struct ion_platform_data ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.has_outer_cache = 1,
+	.heaps = msm7627a_heaps,
 };
 
 static struct platform_device ion_dev = {
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index ee13e04..9822aa9 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -7161,9 +7161,7 @@
  * These heaps are listed in the order they will be allocated.
  * Don't swap the order unless you know what you are doing!
  */
-static struct ion_platform_data ion_pdata = {
-	.nr = MSM_ION_HEAP_NUM,
-	.heaps = {
+struct ion_platform_heap msm7x30_heaps[] = {
 		{
 			.id	= ION_SYSTEM_HEAP_ID,
 			.type	= ION_HEAP_TYPE_SYSTEM,
@@ -7195,7 +7193,11 @@
 			.extra_data = (void *)&co_ion_pdata,
 		},
 #endif
-	}
+};
+
+static struct ion_platform_data ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = msm7x30_heaps,
 };
 
 static struct platform_device ion_dev = {
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index d831ad2..08e6a0d 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -5347,9 +5347,7 @@
  * to each other.
  * Don't swap the order unless you know what you are doing!
  */
-static struct ion_platform_data ion_pdata = {
-	.nr = MSM_ION_HEAP_NUM,
-	.heaps = {
+struct ion_platform_heap msm8x60_heaps [] = {
 		{
 			.id	= ION_SYSTEM_HEAP_ID,
 			.type	= ION_HEAP_TYPE_SYSTEM,
@@ -5424,7 +5422,11 @@
 			.extra_data = (void *)&co_ion_pdata,
 		},
 #endif
-	}
+};
+
+static struct ion_platform_data ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = msm8x60_heaps,
 };
 
 static struct platform_device ion_dev = {
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 023ce86..47a3120 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -46,6 +46,7 @@
 #include <mach/usbdiag.h>
 #include <mach/msm_memtypes.h>
 #include <mach/msm_serial_hs.h>
+#include <mach/msm_serial_pdata.h>
 #include <mach/pmic.h>
 #include <mach/socinfo.h>
 #include <mach/vreg.h>
@@ -82,6 +83,10 @@
 	.id             = -1,
 };
 
+static struct msm_serial_platform_data msm_8625_uart1_pdata = {
+	.userid		= 10,
+};
+
 static struct msm_gpio qup_i2c_gpios_io[] = {
 	{ GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
 		"qup_scl" },
@@ -797,10 +802,7 @@
  * These heaps are listed in the order they will be allocated.
  * Don't swap the order unless you know what you are doing!
  */
-static struct ion_platform_data ion_pdata = {
-	.nr = MSM_ION_HEAP_NUM,
-	.has_outer_cache = 1,
-	.heaps = {
+struct ion_platform_heap qrd7627a_heaps[] = {
 		{
 			.id	= ION_SYSTEM_HEAP_ID,
 			.type	= ION_HEAP_TYPE_SYSTEM,
@@ -832,7 +834,12 @@
 			.extra_data = (void *)&co_ion_pdata,
 		},
 #endif
-	}
+};
+
+static struct ion_platform_data ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.has_outer_cache = 1,
+	.heaps = qrd7627a_heaps,
 };
 
 static struct platform_device ion_dev = {
@@ -994,6 +1001,7 @@
 	if (machine_is_msm8625_evb() || machine_is_msm8625_qrd7()
 				|| machine_is_msm8625_evt()
 				|| machine_is_qrd_skud_prime()) {
+		msm8625_device_uart1.dev.platform_data = &msm_8625_uart1_pdata;
 		platform_add_devices(msm8625_evb_devices,
 				ARRAY_SIZE(msm8625_evb_devices));
 		platform_add_devices(qrd3_devices,
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index a4d7e61..f6386b4 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5282,7 +5282,7 @@
 	CLK_LOOKUP("core_clk",		gsbi2_uart_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gsbi3_uart_clk.c,	""),
 	CLK_LOOKUP("core_clk",		gsbi4_uart_clk.c,	""),
-	CLK_LOOKUP("core_clk",		gsbi5_uart_clk.c,	""),
+	CLK_LOOKUP("core_clk",		gsbi5_uart_clk.c, "msm_serial_hsl.2"),
 	CLK_LOOKUP("core_clk",		gsbi6_uart_clk.c, "msm_serial_hs.0"),
 	CLK_LOOKUP("core_clk",		gsbi7_uart_clk.c, "msm_serial_hsl.0"),
 	CLK_LOOKUP("core_clk",		gsbi1_qup_clk.c,	"qup_i2c.0"),
@@ -5331,6 +5331,7 @@
 	CLK_LOOKUP("iface_clk",		gsbi2_p_clk.c,		""),
 	CLK_LOOKUP("iface_clk",		gsbi3_p_clk.c,		"qup_i2c.3"),
 	CLK_LOOKUP("iface_clk",		gsbi4_p_clk.c,		"qup_i2c.4"),
+	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,	"msm_serial_hsl.2"),
 	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,		"spi_qsd.0"),
 	CLK_LOOKUP("iface_clk",		gsbi5_p_clk.c,		"qup_i2c.5"),
 	CLK_LOOKUP("iface_clk",		gsbi6_p_clk.c,	"msm_serial_hs.0"),
@@ -6319,12 +6320,12 @@
 	 */
 	/*
 	 * Initialize MM AHB registers: Enable the FPB clock and disable HW
-	 * gating on 8627, 8960 and 8930ab for all clocks. Also set VFE_AHB's
+	 * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
 	 * FORCE_CORE_ON bit to prevent its memory from being collapsed when
 	 * the clock is halted. The sleep and wake-up delays are set to safe
 	 * values.
 	 */
-	if (cpu_is_msm8627() || cpu_is_msm8960ab() || cpu_is_msm8930ab()) {
+	if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
 		rmwreg(0x00000003, AHB_EN_REG,  0x6C000103);
 		writel_relaxed(0x000007F9, AHB_EN2_REG);
 	} else {
@@ -6342,7 +6343,7 @@
 	/* Initialize MM AXI registers: Enable HW gating for all clocks that
 	 * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
 	 * delays to safe values. */
-	if (cpu_is_msm8960ab() || (cpu_is_msm8960() &&
+	if ((cpu_is_msm8960() &&
 			SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) ||
 			cpu_is_msm8627() || cpu_is_msm8930ab()) {
 		rmwreg(0x000007F9, MAXI_EN_REG,  0x0803FFFF);
@@ -6365,8 +6366,6 @@
 
 	if (cpu_is_msm8627() || cpu_is_msm8930ab())
 		rmwreg(0x000003C7, SAXI_EN_REG,  0x00003FFF);
-	else if (cpu_is_msm8960ab())
-		rmwreg(0x000001C6, SAXI_EN_REG,  0x00001DF6);
 	else
 		rmwreg(0x00003C38, SAXI_EN_REG,  0x00003FFF);
 
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index c0a553f..95f9327 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -522,6 +522,14 @@
 #define dsipll0_pixel_mm_source_val 1
 #define hdmipll_mm_source_val 3
 
+#define F_GCC_GND \
+	{ \
+		.freq_hz = 0, \
+		.m_val = 0, \
+		.n_val  = 0, \
+		.div_src_val = BVAL(4, 0, 1) | BVAL(10, 8, gnd_source_val), \
+	}
+
 #define F(f, s, div, m, n) \
 	{ \
 		.freq_hz = (f), \
@@ -792,11 +800,6 @@
 static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ocmemgx_core_clk, &ocmemgx_clk.c, LONG_MAX);
 
-static DEFINE_CLK_VOTER(pnoc_sdcc1_clk, &pnoc_clk.c, 0);
-static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, 0);
-static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, 0);
-static DEFINE_CLK_VOTER(pnoc_sdcc4_clk, &pnoc_clk.c, 0);
-
 static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, 0);
 
 static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
@@ -914,6 +917,7 @@
 };
 
 static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_6_apps_clk[] = {
+	F_GCC_GND,
 	F( 3686400,  gpll0,    1,  96,  15625),
 	F( 7372800,  gpll0,    1, 192,  15625),
 	F(14745600,  gpll0,    1, 384,  15625),
@@ -2960,7 +2964,7 @@
 };
 
 static struct clk_freq_tbl ftbl_mdss_edppixel_clk[] = {
-	F_MDSS(148500000, edppll_350,   2,   0,   0),
+	F_MDSS(138500000, edppll_350,   2,   0,   0),
 	F_MDSS(350000000, edppll_350,  11,   0,   0),
 	F_END
 };
@@ -3065,9 +3069,11 @@
 	 */
 	F_HDMI(        0, hdmipll, 1, 0, 0),
 	F_HDMI( 25200000, hdmipll, 1, 0, 0),
+	F_HDMI( 27000000, hdmipll, 1, 0, 0),
 	F_HDMI( 27030000, hdmipll, 1, 0, 0),
 	F_HDMI( 74250000, hdmipll, 1, 0, 0),
 	F_HDMI(148500000, hdmipll, 1, 0, 0),
+	F_HDMI(268500000, hdmipll, 1, 0, 0),
 	F_HDMI(297000000, hdmipll, 1, 0, 0),
 	F_END
 };
@@ -4976,16 +4982,12 @@
 static struct clk_lookup msm_clocks_8974_rumi[] = {
 	CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
-	CLK_LOOKUP("bus_clk", pnoc_sdcc1_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
 	CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
-	CLK_LOOKUP("bus_clk", pnoc_sdcc2_clk.c, "msm_sdcc.2"),
 	CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
 	CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
-	CLK_LOOKUP("bus_clk", pnoc_sdcc3_clk.c, "msm_sdcc.3"),
 	CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
 	CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
-	CLK_LOOKUP("bus_clk", pnoc_sdcc4_clk.c, "msm_sdcc.4"),
 	CLK_DUMMY("xo",		XO_CLK,		NULL,	OFF),
 	CLK_DUMMY("xo",		XO_CLK,		"pil_pronto",		OFF),
 	CLK_DUMMY("core_clk",	BLSP2_UART_CLK,	"f991f000.serial",	OFF),
@@ -5101,16 +5103,12 @@
 
 	CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
-	CLK_LOOKUP("bus_clk", pnoc_sdcc1_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
 	CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
-	CLK_LOOKUP("bus_clk", pnoc_sdcc2_clk.c, "msm_sdcc.2"),
 	CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
 	CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
-	CLK_LOOKUP("bus_clk", pnoc_sdcc3_clk.c, "msm_sdcc.3"),
 	CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
 	CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
-	CLK_LOOKUP("bus_clk", pnoc_sdcc4_clk.c, "msm_sdcc.4"),
 
 	CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
 	CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
@@ -5120,6 +5118,7 @@
 	CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c,    "msm_dwc3"),
 	CLK_LOOKUP("utmi_clk", gcc_usb30_mock_utmi_clk.c, "msm_dwc3"),
 	CLK_LOOKUP("iface_clk", gcc_sys_noc_usb3_axi_clk.c, "msm_dwc3"),
+	CLK_LOOKUP("iface_clk", gcc_sys_noc_usb3_axi_clk.c, "msm_usb3"),
 	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"),
@@ -5345,10 +5344,14 @@
 	CLK_LOOKUP("osr_clk", audio_core_lpaif_ter_osr_clk.c, ""),
 	CLK_LOOKUP("ebit_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
 	CLK_LOOKUP("ibit_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
-	CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c, ""),
-	CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c, ""),
-	CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c, ""),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c,
+			"msm-dai-q6-mi2s.3"),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c,
+			"msm-dai-q6-mi2s.3"),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c,
+			"msm-dai-q6-mi2s.3"),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c,
+			"msm-dai-q6-mi2s.3"),
 	CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
 						"msm-dai-q6.4106"),
 	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index b284168..d3a4bba 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -246,6 +246,14 @@
 #define lpapll0_lpass_source_val 1
 #define gpll0_lpass_source_val 5
 
+#define F_GCC_GND \
+	{ \
+		.freq_hz = 0, \
+		.m_val = 0, \
+		.n_val  = 0, \
+		.div_src_val = BVAL(4, 0, 1) | BVAL(10, 8, gnd_source_val), \
+	}
+
 #define F(f, s, div, m, n) \
 	{ \
 		.freq_hz = (f), \
@@ -611,6 +619,7 @@
 };
 
 static struct clk_freq_tbl ftbl_gcc_blsp1_uart1_6_apps_clk[] = {
+	F_GCC_GND,
 	F( 3686400,    gpll0,    1,    96,   15625),
 	F( 7372800,    gpll0,    1,   192,   15625),
 	F(14745600,    gpll0,    1,   384,   15625),
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index e7a596d..c30e566 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -37,30 +37,65 @@
 #define HDMI_PHY_PLL_SIZE	0x000000D4
 
 /* hdmi phy registers */
-#define HDMI_PHY_PD_CTRL0		(0x0010)
-#define HDMI_PHY_GLB_CFG		(0x0018)
-#define HDMI_PHY_STATUS			(0x005C)
+#define HDMI_PHY_ANA_CFG0               (0x0000)
+#define HDMI_PHY_ANA_CFG1               (0x0004)
+#define HDMI_PHY_ANA_CFG2               (0x0008)
+#define HDMI_PHY_ANA_CFG3               (0x000C)
+#define HDMI_PHY_PD_CTRL0               (0x0010)
+#define HDMI_PHY_PD_CTRL1               (0x0014)
+#define HDMI_PHY_GLB_CFG                (0x0018)
+#define HDMI_PHY_DCC_CFG0               (0x001C)
+#define HDMI_PHY_DCC_CFG1               (0x0020)
+#define HDMI_PHY_TXCAL_CFG0             (0x0024)
+#define HDMI_PHY_TXCAL_CFG1             (0x0028)
+#define HDMI_PHY_TXCAL_CFG2             (0x002C)
+#define HDMI_PHY_TXCAL_CFG3             (0x0030)
+#define HDMI_PHY_BIST_CFG0              (0x0034)
+#define HDMI_PHY_BIST_CFG1              (0x0038)
+#define HDMI_PHY_BIST_PATN0             (0x003C)
+#define HDMI_PHY_BIST_PATN1             (0x0040)
+#define HDMI_PHY_BIST_PATN2             (0x0044)
+#define HDMI_PHY_BIST_PATN3             (0x0048)
+#define HDMI_PHY_STATUS                 (0x005C)
 
 /* hdmi phy unified pll registers */
-#define	 HDMI_UNI_PLL_REFCLK_CF		(0x0000)
-#define	 HDMI_UNI_PLL_POSTDIV1_CFG	(0x0004)
-#define	 HDMI_UNI_PLL_VCOLPF_CFG	(0x000C)
-#define	 HDMI_UNI_PLL_GLB_CFG		(0x0020)
-#define	 HDMI_UNI_PLL_POSTDIV2_CFG	(0x0024)
-#define	 HDMI_UNI_PLL_POSTDIV3_CFG	(0x0028)
-#define	 HDMI_UNI_PLL_SDM_CFG0		(0x0038)
-#define	 HDMI_UNI_PLL_SDM_CFG1		(0x003C)
-#define	 HDMI_UNI_PLL_SDM_CFG2		(0x0040)
-#define	 HDMI_UNI_PLL_SDM_CFG3		(0x0044)
-#define	 HDMI_UNI_PLL_SDM_CFG4		(0x0048)
-#define	 HDMI_UNI_PLL_LKDET_CFG0	(0x005C)
-#define	 HDMI_UNI_PLL_LKDET_CFG1	(0x0060)
-#define	 HDMI_UNI_PLL_LKDET_CFG2	(0x0064)
-#define	 HDMI_UNI_PLL_CAL_CFG8		(0x008C)
-#define	 HDMI_UNI_PLL_CAL_CFG9		(0x0090)
-#define	 HDMI_UNI_PLL_CAL_CFG10		(0x0094)
-#define	 HDMI_UNI_PLL_CAL_CFG11		(0x0098)
-#define  HDMI_UNI_PLL_STATUS		(0x00C0)
+#define HDMI_UNI_PLL_REFCLK_CFG         (0x0000)
+#define HDMI_UNI_PLL_POSTDIV1_CFG       (0x0004)
+#define HDMI_UNI_PLL_CHFPUMP_CFG        (0x0008)
+#define HDMI_UNI_PLL_VCOLPF_CFG         (0x000C)
+#define HDMI_UNI_PLL_VREG_CFG           (0x0010)
+#define HDMI_UNI_PLL_PWRGEN_CFG         (0x0014)
+#define HDMI_UNI_PLL_GLB_CFG            (0x0020)
+#define HDMI_UNI_PLL_POSTDIV2_CFG       (0x0024)
+#define HDMI_UNI_PLL_POSTDIV3_CFG       (0x0028)
+#define HDMI_UNI_PLL_LPFR_CFG           (0x002C)
+#define HDMI_UNI_PLL_LPFC1_CFG          (0x0030)
+#define HDMI_UNI_PLL_LPFC2_CFG          (0x0034)
+#define HDMI_UNI_PLL_SDM_CFG0           (0x0038)
+#define HDMI_UNI_PLL_SDM_CFG1           (0x003C)
+#define HDMI_UNI_PLL_SDM_CFG2           (0x0040)
+#define HDMI_UNI_PLL_SDM_CFG3           (0x0044)
+#define HDMI_UNI_PLL_SDM_CFG4           (0x0048)
+#define HDMI_UNI_PLL_SSC_CFG0           (0x004C)
+#define HDMI_UNI_PLL_SSC_CFG1           (0x0050)
+#define HDMI_UNI_PLL_SSC_CFG2           (0x0054)
+#define HDMI_UNI_PLL_SSC_CFG3           (0x0058)
+#define HDMI_UNI_PLL_LKDET_CFG0         (0x005C)
+#define HDMI_UNI_PLL_LKDET_CFG1         (0x0060)
+#define HDMI_UNI_PLL_LKDET_CFG2         (0x0064)
+#define HDMI_UNI_PLL_CAL_CFG0           (0x006C)
+#define HDMI_UNI_PLL_CAL_CFG1           (0x0070)
+#define HDMI_UNI_PLL_CAL_CFG2           (0x0074)
+#define HDMI_UNI_PLL_CAL_CFG3           (0x0078)
+#define HDMI_UNI_PLL_CAL_CFG4           (0x007C)
+#define HDMI_UNI_PLL_CAL_CFG5           (0x0080)
+#define HDMI_UNI_PLL_CAL_CFG6           (0x0084)
+#define HDMI_UNI_PLL_CAL_CFG7           (0x0088)
+#define HDMI_UNI_PLL_CAL_CFG8           (0x008C)
+#define HDMI_UNI_PLL_CAL_CFG9           (0x0090)
+#define HDMI_UNI_PLL_CAL_CFG10          (0x0094)
+#define HDMI_UNI_PLL_CAL_CFG11          (0x0098)
+#define HDMI_UNI_PLL_STATUS             (0x00C0)
 
 #define VCO_CLK				424000000
 static unsigned char *mdss_dsi_base;
@@ -391,32 +426,106 @@
 
 	case 25200000:
 		/* 640x480p60 */
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
-		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
-		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
-		REG_W(0x4C, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+		REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+		REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
-		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0xB0, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
 		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
 		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
-		REG_W(0xFC, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+		REG_W(0xF4, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+		udelay(50);
+
+		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+		udelay(200);
+	break;
+
+	case 27000000:
+		/* 576p50/576i50 case */
+		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+		REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0X0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+		REG_W(0X0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x54, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+		REG_W(0X1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+		REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+		REG_W(0x2a, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+		REG_W(0X1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+		udelay(50);
+
+		REG_W(0X0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0XDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+		REG_W(0XD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+		REG_W(0X1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+		udelay(200);
 	break;
 
 	case 27030000:
 		/* 480p60/480i60 case */
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
-		REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
-		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
-		REG_W(0x14, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
-		REG_W(0x63, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+		REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+		REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x54, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0x66, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
 		REG_W(0x1D, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
@@ -425,10 +534,29 @@
 		REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
 		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
 		REG_W(0x2A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
 		REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+		udelay(50);
+
+		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+		udelay(200);
 	break;
 
 	case 74250000:
@@ -436,51 +564,148 @@
 		 * 720p60/720p50/1080i60/1080i50
 		 * 1080p24/1080p30/1080p25 case
 		 */
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
-		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
-		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+		REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+		REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
 		REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
-		REG_W(0xFD, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
-		REG_W(0x55, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0x56, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
 		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
-		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
-		REG_W(0x73, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
-	break;
-
-	case 148500000:
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
-		REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
-		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
-		REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
-		REG_W(0xFD, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
-		REG_W(0x55, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
-		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
-		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
-		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
-		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
 		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
 		REG_W(0xE6, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
 		REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+		udelay(50);
+
+		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+		udelay(200);
+	break;
+
+	case 148500000:
+		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+		REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+		REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0x56, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+		REG_W(0xE6, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+		udelay(50);
+
+		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+		udelay(200);
+	break;
+
+	case 268500000:
+		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+		REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+		REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x61, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0xF6, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+		REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
+		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+		REG_W(0x3E, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+		udelay(50);
+
+		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+		REG_W(0x11, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+		udelay(200);
 	break;
 
 	case 297000000:
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
-		REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
-		REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+		REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CFG);
+		REG_W(0x19, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+		REG_W(0x0E, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFR_CFG);
+		REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC1_CFG);
+		REG_W(0x0D, hdmi_phy_pll_base + HDMI_UNI_PLL_LPFC2_CFG);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
 		REG_W(0x65, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
-		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
 		REG_W(0xAC, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
 		REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
@@ -489,14 +714,31 @@
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+		REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG2);
 		REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
 		REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
 		REG_W(0xCD, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
 		REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+		REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+		udelay(50);
+
+		REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1);
+		REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0);
+		REG_W(0x43, hdmi_phy_base + HDMI_PHY_ANA_CFG1);
+		REG_W(0x06, hdmi_phy_base + HDMI_PHY_ANA_CFG2);
+		REG_W(0x03, hdmi_phy_base + HDMI_PHY_ANA_CFG3);
+		REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_VREG_CFG);
+		REG_W(0xD0, hdmi_phy_base + HDMI_PHY_DCC_CFG0);
+		REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0);
+		REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1);
+		REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2);
+		REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3);
+		udelay(200);
 	break;
 
-	case 27000000:
-		/* 576p50/576i50 case */
 	default:
 		pr_err("%s: not supported rate=%ld\n", __func__, rate);
 	}
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f559629..8d10d6a 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -59,6 +59,7 @@
 /* GSBI UART devices */
 #define MSM_UART1DM_PHYS	(MSM_GSBI1_PHYS + 0x10000)
 #define MSM_UART3DM_PHYS	(MSM_GSBI3_PHYS + 0x40000)
+#define MSM_UART5DM_PHYS	(MSM_GSBI5_PHYS + 0x40000)
 #define MSM_UART6DM_PHYS	(MSM_GSBI6_PHYS + 0x40000)
 #define MSM_UART7DM_PHYS	(MSM_GSBI7_PHYS + 0x40000)
 
@@ -465,6 +466,33 @@
 	.resource	= resources_qup_i2c_gsbi5,
 };
 
+static struct resource resources_uart_gsbi5[] = {
+	{
+		.start  = GSBI5_UARTDM_IRQ,
+		.end    = GSBI5_UARTDM_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.start  = MSM_UART5DM_PHYS,
+		.end    = MSM_UART5DM_PHYS + PAGE_SIZE - 1,
+		.name   = "uartdm_resource",
+		.flags  = IORESOURCE_MEM,
+	},
+	{
+		.start  = MSM_GSBI5_PHYS,
+		.end    = MSM_GSBI5_PHYS + PAGE_SIZE - 1,
+		.name   = "gsbi_resource",
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device mpq8064_device_uart_gsbi5 = {
+	.name	= "msm_serial_hsl",
+	.id	= 2,
+	.num_resources	= ARRAY_SIZE(resources_uart_gsbi5),
+	.resource	= resources_uart_gsbi5,
+};
+
 /* GSBI 6 used into UARTDM Mode */
 static struct resource msm_uart_dm6_resources[] = {
 	{
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 0faf500..aad512e 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -143,12 +143,12 @@
 		MSM_RPM_MAP(8930, PM8038_CLK2_0, PM8038_CLK2, 2),
 		MSM_RPM_MAP(8930, PM8038_LVS1, PM8038_LVS1, 1),
 		MSM_RPM_MAP(8930, PM8038_LVS2, PM8038_LVS2, 1),
-		MSM_RPM_MAP(8930, NCP_0, NCP, 2),
-		MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
-		MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
-		MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
-		MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
-		MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+		MSM_RPM_MAP_PMIC(8930, 8038, NCP_0, NCP, 2),
+		MSM_RPM_MAP_PMIC(8930, 8038, CXO_BUFFERS, CXO_BUFFERS, 1),
+		MSM_RPM_MAP_PMIC(8930, 8038, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+		MSM_RPM_MAP_PMIC(8930, 8038, HDMI_SWITCH, HDMI_SWITCH, 1),
+		MSM_RPM_MAP_PMIC(8930, 8038, QDSS_CLK, QDSS_CLK, 1),
+		MSM_RPM_MAP_PMIC(8930, 8038, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
 	},
 	.target_status = {
 		MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
@@ -369,12 +369,12 @@
 		MSM_RPM_MAP(8930, PM8917_LVS5, PM8917_LVS5, 1),
 		MSM_RPM_MAP(8930, PM8917_LVS6, PM8917_LVS6, 1),
 		MSM_RPM_MAP(8930, PM8917_LVS7, PM8917_LVS7, 1),
-		MSM_RPM_MAP(8930, NCP_0, NCP, 2),
-		MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
-		MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
-		MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
-		MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
-		MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+		MSM_RPM_MAP_PMIC(8930, 8917, NCP_0, NCP, 2),
+		MSM_RPM_MAP_PMIC(8930, 8917, CXO_BUFFERS, CXO_BUFFERS, 1),
+		MSM_RPM_MAP_PMIC(8930, 8917, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+		MSM_RPM_MAP_PMIC(8930, 8917, HDMI_SWITCH, HDMI_SWITCH, 1),
+		MSM_RPM_MAP_PMIC(8930, 8917, QDSS_CLK, QDSS_CLK, 1),
+		MSM_RPM_MAP_PMIC(8930, 8917, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
 	},
 	.target_status = {
 		MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index b4ef76d2..8fc5020 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -501,6 +501,18 @@
 	.exit_sleep3 = msm_gic_irq_exit_sleep3,
 };
 
+void msm_clk_dump_debug_info(void)
+{
+	pr_info("%s: GLBL_CLK_ENA: 0x%08X\n", __func__,
+		readl_relaxed(MSM_CLK_CTL_BASE + 0x0));
+	pr_info("%s: GLBL_CLK_STATE: 0x%08X\n", __func__,
+		readl_relaxed(MSM_CLK_CTL_BASE + 0x4));
+	pr_info("%s: GRP_NS_REG: 0x%08X\n", __func__,
+		readl_relaxed(MSM_CLK_CTL_BASE + 0x84));
+	pr_info("%s: CLK_HALT_STATEB: 0x%08X\n", __func__,
+		readl_relaxed(MSM_CLK_CTL_BASE + 0x10C));
+}
+
 void __init msm_pm_register_irqs(void)
 {
 	if (cpu_is_msm8625())
@@ -2135,6 +2147,7 @@
 static int msm7627a_panic_handler(struct notifier_block *this,
 		unsigned long event, void *ptr)
 {
+	msm_clk_dump_debug_info();
 	flush_cache_all();
 	outer_flush_all();
 	return NOTIFY_DONE;
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index bd9ea49..c0d73c2 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -56,6 +56,7 @@
 extern struct platform_device msm_device_uart_dm8;
 extern struct platform_device msm_device_uart_dm9;
 extern struct platform_device mpq8064_device_uartdm_gsbi6;
+extern struct platform_device mpq8064_device_uart_gsbi5;
 
 extern struct platform_device msm8960_device_uart_gsbi2;
 extern struct platform_device msm8960_device_uart_gsbi5;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index cbe2040..8b5c70f 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -599,6 +599,13 @@
 void msm_map_msm8910_io(void);
 void msm8910_init_irq(void);
 
+/* Dump debug info (states, rate, etc) of clocks */
+#if defined(CONFIG_ARCH_MSM7X27)
+void msm_clk_dump_debug_info(void);
+#else
+static inline void msm_clk_dump_debug_info(void) {}
+#endif
+
 struct mmc_platform_data;
 int msm_add_sdcc(unsigned int controller,
 		struct mmc_platform_data *plat);
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 57b4bd3..ea3fb64 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -147,6 +147,59 @@
 irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
 irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id);
 
+enum {
+	PROC_APPS,
+	PROC_GPU,
+	PROC_MAX
+};
+
+/* Expose structure to allow kgsl iommu driver to use the same structure to
+ * communicate to GPU the addresses of the flag and turn variables.
+ */
+struct remote_iommu_petersons_spinlock {
+	uint32_t flag[PROC_MAX];
+	uint32_t turn;
+};
+
+#ifdef CONFIG_MSM_IOMMU
+void *msm_iommu_lock_initialize(void);
+void msm_iommu_mutex_lock(void);
+void msm_iommu_mutex_unlock(void);
+#else
+static inline void *msm_iommu_lock_initialize(void)
+{
+	return NULL;
+}
+static inline void msm_iommu_mutex_lock(void) { }
+static inline void msm_iommu_mutex_unlock(void) { }
+#endif
+
+#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
+void msm_iommu_remote_p0_spin_lock(void);
+void msm_iommu_remote_p0_spin_unlock(void);
+
+#define msm_iommu_remote_lock_init() _msm_iommu_remote_spin_lock_init()
+#define msm_iommu_remote_spin_lock() msm_iommu_remote_p0_spin_lock()
+#define msm_iommu_remote_spin_unlock() msm_iommu_remote_p0_spin_unlock()
+#else
+#define msm_iommu_remote_lock_init()
+#define msm_iommu_remote_spin_lock()
+#define msm_iommu_remote_spin_unlock()
+#endif
+
+/* Allows kgsl iommu driver to acquire lock */
+#define msm_iommu_lock() \
+	do { \
+		msm_iommu_mutex_lock(); \
+		msm_iommu_remote_spin_lock(); \
+	} while (0)
+
+#define msm_iommu_unlock() \
+	do { \
+		msm_iommu_remote_spin_unlock(); \
+		msm_iommu_mutex_unlock(); \
+	} while (0)
+
 #ifdef CONFIG_MSM_IOMMU
 /*
  * Look up an IOMMU context device by its context name. NULL if none found.
diff --git a/arch/arm/mach-msm/include/mach/irqs-8064.h b/arch/arm/mach-msm/include/mach/irqs-8064.h
index 973034b..f4129fe 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8064.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8064.h
@@ -15,15 +15,6 @@
 
 /* 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 INT_VGIC				(GIC_PPI_START + 0)
 #define INT_DEBUG_TIMER_EXP			(GIC_PPI_START + 1)
 #define INT_GP_TIMER_EXP			(GIC_PPI_START + 2)
diff --git a/arch/arm/mach-msm/include/mach/irqs-8092.h b/arch/arm/mach-msm/include/mach/irqs-8092.h
index ae9634e..955e669 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8092.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8092.h
@@ -15,31 +15,12 @@
 
 /* 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 1020 /* Should be 256 - but higher due to bug in sim */
-#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-8226.h b/arch/arm/mach-msm/include/mach/irqs-8226.h
deleted file mode 100644
index 72602b1..0000000
--- a/arch/arm/mach-msm/include/mach/irqs-8226.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* 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
- * 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 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 NR_MSM_IRQS 256
-#define NR_GPIO_IRQS 117
-#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-8625.h b/arch/arm/mach-msm/include/mach/irqs-8625.h
index f591a9e..a83dd2e 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8625.h
@@ -13,9 +13,6 @@
 #ifndef __ASM_ARCH_MSM_IRQS_8625_H
 #define __ASM_ARCH_MSM_IRQS_8625_H
 
-#define GIC_PPI_START		16
-#define GIC_SPI_START		32
-
 #ifdef CONFIG_MSM_FIQ
 #define FIQ_START               0
 #endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8910.h b/arch/arm/mach-msm/include/mach/irqs-8910.h
deleted file mode 100644
index e883214..0000000
--- a/arch/arm/mach-msm/include/mach/irqs-8910.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* 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_8910_H
-#define __ASM_ARCH_MSM_IRQS_8910_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 INT_ARMQC_PERFMON			(GIC_PPI_START + 10)
-
-#define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
-#define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
-#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
-
-#define NR_MSM_IRQS 256
-#define NR_GPIO_IRQS 102
-#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-8930.h b/arch/arm/mach-msm/include/mach/irqs-8930.h
index bfc32f6..fbde7cb 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8930.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8930.h
@@ -15,13 +15,6 @@
 
 /* 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 INT_VGIC				(GIC_PPI_START + 0)
 #define INT_DEBUG_TIMER_EXP			(GIC_PPI_START + 1)
 #define INT_GP_TIMER_EXP			(GIC_PPI_START + 2)
diff --git a/arch/arm/mach-msm/include/mach/irqs-8960.h b/arch/arm/mach-msm/include/mach/irqs-8960.h
index 012dd74..64be113 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8960.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8960.h
@@ -15,13 +15,6 @@
 
 /* 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 INT_VGIC				(GIC_PPI_START + 0)
 #define INT_DEBUG_TIMER_EXP			(GIC_PPI_START + 1)
 #define INT_GP_TIMER_EXP			(GIC_PPI_START + 2)
diff --git a/arch/arm/mach-msm/include/mach/irqs-8974.h b/arch/arm/mach-msm/include/mach/irqs-8974.h
index 8152eca..f18b3df 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8974.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8974.h
@@ -15,29 +15,12 @@
 
 /* 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 INT_ARMQC_PERFMON			(GIC_PPI_START + 7)
 /* 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 1020 /* Should be 256 - but higher due to bug in sim */
-#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-8x60.h b/arch/arm/mach-msm/include/mach/irqs-8x60.h
index c9729f4..d08f645 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8x60.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8x60.h
@@ -16,13 +16,6 @@
 
 /* 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 INT_DEBUG_TIMER_EXP			(GIC_PPI_START + 0)
 #define INT_GP_TIMER_EXP			(GIC_PPI_START + 1)
 #define INT_GP_TIMER2_EXP			(GIC_PPI_START + 2)
diff --git a/arch/arm/mach-msm/include/mach/irqs-9615.h b/arch/arm/mach-msm/include/mach/irqs-9615.h
index 39058a6..b9c66c3 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9615.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9615.h
@@ -15,15 +15,7 @@
 
 /* MSM ACPU Interrupt Numbers */
 
-/*
- * 0-15:  STI/SGI (software triggered/generated interrupts)
- * 16-31: PPI (private peripheral interrupts)
- * 32+:   SPI (shared peripheral interrupts)
- */
-
 #define FIQ_START     16
-#define GIC_PPI_START 16
-#define GIC_SPI_START 32
 
 #define INT_DEBUG_TIMER_EXP			(GIC_PPI_START + 1)
 #define INT_GP_TIMER_EXP			(GIC_PPI_START + 2)
diff --git a/arch/arm/mach-msm/include/mach/irqs-9625.h b/arch/arm/mach-msm/include/mach/irqs-9625.h
index b1f65d1..15c7010 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9625.h
@@ -15,18 +15,8 @@
 
 /* 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 INT_ARMQC_PERFMON		(GIC_PPI_START + 7)
 
-#define GIC_SPI_START 32
-
 #define APCC_QGICL2PERFMONIRPTREQ	(GIC_SPI_START + 1)
 #define SC_SICL2PERFMONIRPTREQ		APCC_QGICL2PERFMONIRPTREQ
 #define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 7aff770..f5822fc 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -17,11 +17,44 @@
 #ifndef __ASM_ARCH_MSM_IRQS_H
 #define __ASM_ARCH_MSM_IRQS_H
 
+/*
+ * 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 MSM_IRQ_BIT(irq)     (1 << ((irq) & 31))
 
-#include "irqs-8625.h"
+#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MPQ8092)
 
-#if defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
+#ifdef CONFIG_ARCH_MSM8974
+#include "irqs-8974.h"
+#endif
+
+#ifdef CONFIG_ARCH_MPQ8092
+#include "irqs-8092.h"
+#endif
+
+#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
+#define NR_GPIO_IRQS 146
+#define NR_QPNP_IRQS 32768
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#elif defined(CONFIG_ARCH_MSM8910) || defined(CONFIG_ARCH_MSM8226)
+
+#define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
+#define NR_MSM_IRQS 256
+#define NR_GPIO_IRQS 117
+#define NR_QPNP_IRQS 32768
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#elif defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
 	defined(CONFIG_ARCH_MSM8930)
 
 #ifdef CONFIG_ARCH_MSM8960
@@ -58,18 +91,10 @@
 
 #else
 
-#if defined(CONFIG_ARCH_MSM8974)
-#include "irqs-8974.h"
-#elif defined(CONFIG_ARCH_MSM8910)
-#include "irqs-8910.h"
-#elif defined(CONFIG_ARCH_MPQ8092)
-#include "irqs-8092.h"
-#elif defined(CONFIG_ARCH_MSM9615)
+#if defined(CONFIG_ARCH_MSM9615)
 #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)
@@ -78,7 +103,8 @@
 #elif defined(CONFIG_ARCH_MSM8X60)
 #include "irqs-8x60.h"
 #elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7X25) \
-	|| defined(CONFIG_ARCH_MSM7X27)
+	|| defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM8625)
+#include "irqs-8625.h"
 #include "irqs-7xxx.h"
 
 #define NR_GPIO_IRQS 133
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index 84a7dc0..ab0e72f 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -29,6 +29,7 @@
 	unsigned int len;
 	int ahb;
 	const char *fabclk[NUM_CTX];
+	const char *iface_clk;
 	unsigned int offset;
 	unsigned int haltid;
 	unsigned int rpm_enabled;
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
index 45a7e19..c68c783 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -55,6 +55,7 @@
 
 	void *endpoint;
 	void (*notify)(unsigned event, void *priv);
+	int (*check_send_permissions)(void *data);
 
 	uint32_t num_tx;
 	uint32_t num_rx;
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_pdata.h b/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
index 4153cb2..40bdc9d 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
@@ -10,8 +10,8 @@
  * GNU General Public License for more details.
 */
 
-#ifndef __ASM_ARCH_MSM_SERIAL_HS_H
-#define __ASM_ARCH_MSM_SERIAL_HS_H
+#ifndef __ASM_ARCH_MSM_SERIAL_H
+#define __ASM_ARCH_MSM_SERIAL_H
 
 #include <linux/serial_core.h>
 
@@ -22,6 +22,7 @@
 	/* bool: inject char into rx tty on wakeup */
 	unsigned char inject_rx_on_wakeup;
 	char rx_to_inject;
+	int userid;
 };
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index 6124cd6..5355215 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -16,6 +16,7 @@
 #include <asm/page.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
+#include <linux/err.h>
 
 #define OCMEM_MIN_ALLOC SZ_64K
 #define OCMEM_MIN_ALIGN SZ_64K
@@ -99,6 +100,7 @@
 };
 
 /* APIS */
+#ifdef CONFIG_MSM_OCMEM
 /* Notification APIs */
 struct ocmem_notifier *ocmem_notifier_register(int client_id,
 						struct notifier_block *nb);
@@ -151,4 +153,111 @@
 
 struct ocmem_vectors *ocmem_get_vectors(int client_id,
 						struct ocmem_buf *buf);
+
+#else
+/* Notification APIs */
+static inline struct ocmem_notifier *ocmem_notifier_register
+				(int client_id, struct notifier_block *nb)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline int ocmem_notifier_unregister(struct ocmem_notifier *notif_hndl,
+				struct notifier_block *nb)
+{
+	return -ENODEV;
+}
+
+/* Obtain the maximum quota for the client */
+static inline unsigned long get_max_quota(int client_id)
+{
+	return 0;
+}
+
+/* Allocation APIs */
+static inline struct ocmem_buf *ocmem_allocate(int client_id,
+						unsigned long size)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline struct ocmem_buf *ocmem_allocate_nowait(int client_id,
+							unsigned long size)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline struct ocmem_buf *ocmem_allocate_nb(int client_id,
+							unsigned long size)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline struct ocmem_buf *ocmem_allocate_range(int client_id,
+		unsigned long min, unsigned long goal, unsigned long step)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+/* Free APIs */
+static inline int ocmem_free(int client_id, struct ocmem_buf *buf)
+{
+	return -ENODEV;
+}
+
+/* Dynamic Resize APIs */
+static inline int ocmem_shrink(int client_id, struct ocmem_buf *buf,
+			unsigned long new_size)
+{
+	return -ENODEV;
+}
+
+/* Transfer APIs */
+static inline int ocmem_map(int client_id, struct ocmem_buf *buffer,
+			struct ocmem_map_list *list)
+{
+	return -ENODEV;
+}
+
+static inline int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
+			struct ocmem_map_list *list)
+{
+	return -ENODEV;
+}
+
+static inline int ocmem_dump(int client_id, struct ocmem_buf *buffer,
+				unsigned long dst_phys_addr)
+{
+	return -ENODEV;
+}
+
+/* Priority Enforcement APIs */
+static inline int ocmem_evict(int client_id)
+{
+	return -ENODEV;
+}
+
+static inline int ocmem_restore(int client_id)
+{
+	return -ENODEV;
+}
+
+/* Power Control APIs */
+static inline int ocmem_set_power_state(int client_id,
+		struct ocmem_buf *buf, enum ocmem_power_state new_state)
+{
+	return -ENODEV;
+}
+
+static inline enum ocmem_power_state ocmem_get_power_state(int client_id,
+				struct ocmem_buf *buf)
+{
+	return -ENODEV;
+}
+static inline struct ocmem_vectors *ocmem_get_vectors(int client_id,
+						struct ocmem_buf *buf)
+{
+	return ERR_PTR(-ENODEV);
+}
+#endif
 #endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 4ac9192..bc1b918 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -219,182 +219,190 @@
 		MSM_RPM_8930_ID_MM_FABRIC_ARB_0	+ 10,
 
 	/* PMIC 8038 */
-	MSM_RPM_8930_ID_PM8038_S1_0	= 90,
-	MSM_RPM_8930_ID_PM8038_S1_1	= 91,
-	MSM_RPM_8930_ID_PM8038_S2_0	= 92,
-	MSM_RPM_8930_ID_PM8038_S2_1	= 93,
-	MSM_RPM_8930_ID_PM8038_S3_0	= 94,
-	MSM_RPM_8930_ID_PM8038_S3_1	= 95,
-	MSM_RPM_8930_ID_PM8038_S4_0	= 96,
-	MSM_RPM_8930_ID_PM8038_S4_1	= 97,
-	MSM_RPM_8930_ID_PM8038_S5_0	= 98,
-	MSM_RPM_8930_ID_PM8038_S5_1	= 99,
-	MSM_RPM_8930_ID_PM8038_S6_0	= 100,
-	MSM_RPM_8930_ID_PM8038_S6_1	= 101,
-	MSM_RPM_8930_ID_PM8038_L1_0	= 102,
-	MSM_RPM_8930_ID_PM8038_L1_1	= 103,
-	MSM_RPM_8930_ID_PM8038_L2_0	= 104,
-	MSM_RPM_8930_ID_PM8038_L2_1	= 105,
-	MSM_RPM_8930_ID_PM8038_L3_0	= 106,
-	MSM_RPM_8930_ID_PM8038_L3_1	= 107,
-	MSM_RPM_8930_ID_PM8038_L4_0	= 108,
-	MSM_RPM_8930_ID_PM8038_L4_1	= 109,
-	MSM_RPM_8930_ID_PM8038_L5_0	= 110,
-	MSM_RPM_8930_ID_PM8038_L5_1	= 111,
-	MSM_RPM_8930_ID_PM8038_L6_0	= 112,
-	MSM_RPM_8930_ID_PM8038_L6_1	= 113,
-	MSM_RPM_8930_ID_PM8038_L7_0	= 114,
-	MSM_RPM_8930_ID_PM8038_L7_1	= 115,
-	MSM_RPM_8930_ID_PM8038_L8_0	= 116,
-	MSM_RPM_8930_ID_PM8038_L8_1	= 117,
-	MSM_RPM_8930_ID_PM8038_L9_0	= 118,
-	MSM_RPM_8930_ID_PM8038_L9_1	= 119,
-	MSM_RPM_8930_ID_PM8038_L10_0	= 120,
-	MSM_RPM_8930_ID_PM8038_L10_1	= 121,
-	MSM_RPM_8930_ID_PM8038_L11_0	= 122,
-	MSM_RPM_8930_ID_PM8038_L11_1	= 123,
-	MSM_RPM_8930_ID_PM8038_L12_0	= 124,
-	MSM_RPM_8930_ID_PM8038_L12_1	= 125,
-	MSM_RPM_8930_ID_PM8038_L13_0	= 126,
-	MSM_RPM_8930_ID_PM8038_L13_1	= 127,
-	MSM_RPM_8930_ID_PM8038_L14_0	= 128,
-	MSM_RPM_8930_ID_PM8038_L14_1	= 129,
-	MSM_RPM_8930_ID_PM8038_L15_0	= 130,
-	MSM_RPM_8930_ID_PM8038_L15_1	= 131,
-	MSM_RPM_8930_ID_PM8038_L16_0	= 132,
-	MSM_RPM_8930_ID_PM8038_L16_1	= 133,
-	MSM_RPM_8930_ID_PM8038_L17_0	= 134,
-	MSM_RPM_8930_ID_PM8038_L17_1	= 135,
-	MSM_RPM_8930_ID_PM8038_L18_0	= 136,
-	MSM_RPM_8930_ID_PM8038_L18_1	= 137,
-	MSM_RPM_8930_ID_PM8038_L19_0	= 138,
-	MSM_RPM_8930_ID_PM8038_L19_1	= 139,
-	MSM_RPM_8930_ID_PM8038_L20_0	= 140,
-	MSM_RPM_8930_ID_PM8038_L20_1	= 141,
-	MSM_RPM_8930_ID_PM8038_L21_0	= 142,
-	MSM_RPM_8930_ID_PM8038_L21_1	= 143,
-	MSM_RPM_8930_ID_PM8038_L22_0	= 144,
-	MSM_RPM_8930_ID_PM8038_L22_1	= 145,
-	MSM_RPM_8930_ID_PM8038_L23_0	= 146,
-	MSM_RPM_8930_ID_PM8038_L23_1	= 147,
-	MSM_RPM_8930_ID_PM8038_L24_0	= 148,
-	MSM_RPM_8930_ID_PM8038_L24_1	= 149,
-	MSM_RPM_8930_ID_PM8038_L25_0	= 150,
-	MSM_RPM_8930_ID_PM8038_L25_1	= 151,
-	MSM_RPM_8930_ID_PM8038_L26_0	= 152,
-	MSM_RPM_8930_ID_PM8038_L26_1	= 153,
-	MSM_RPM_8930_ID_PM8038_L27_0	= 154,
-	MSM_RPM_8930_ID_PM8038_L27_1	= 155,
-	MSM_RPM_8930_ID_PM8038_CLK1_0	= 156,
-	MSM_RPM_8930_ID_PM8038_CLK1_1	= 157,
-	MSM_RPM_8930_ID_PM8038_CLK2_0	= 158,
-	MSM_RPM_8930_ID_PM8038_CLK2_1	= 159,
-	MSM_RPM_8930_ID_PM8038_LVS1	= 160,
-	MSM_RPM_8930_ID_PM8038_LVS2	= 161,
+	MSM_RPM_8930_ID_PM8038_S1_0		= 90,
+	MSM_RPM_8930_ID_PM8038_S1_1		= 91,
+	MSM_RPM_8930_ID_PM8038_S2_0		= 92,
+	MSM_RPM_8930_ID_PM8038_S2_1		= 93,
+	MSM_RPM_8930_ID_PM8038_S3_0		= 94,
+	MSM_RPM_8930_ID_PM8038_S3_1		= 95,
+	MSM_RPM_8930_ID_PM8038_S4_0		= 96,
+	MSM_RPM_8930_ID_PM8038_S4_1		= 97,
+	MSM_RPM_8930_ID_PM8038_S5_0		= 98,
+	MSM_RPM_8930_ID_PM8038_S5_1		= 99,
+	MSM_RPM_8930_ID_PM8038_S6_0		= 100,
+	MSM_RPM_8930_ID_PM8038_S6_1		= 101,
+	MSM_RPM_8930_ID_PM8038_L1_0		= 102,
+	MSM_RPM_8930_ID_PM8038_L1_1		= 103,
+	MSM_RPM_8930_ID_PM8038_L2_0		= 104,
+	MSM_RPM_8930_ID_PM8038_L2_1		= 105,
+	MSM_RPM_8930_ID_PM8038_L3_0		= 106,
+	MSM_RPM_8930_ID_PM8038_L3_1		= 107,
+	MSM_RPM_8930_ID_PM8038_L4_0		= 108,
+	MSM_RPM_8930_ID_PM8038_L4_1		= 109,
+	MSM_RPM_8930_ID_PM8038_L5_0		= 110,
+	MSM_RPM_8930_ID_PM8038_L5_1		= 111,
+	MSM_RPM_8930_ID_PM8038_L6_0		= 112,
+	MSM_RPM_8930_ID_PM8038_L6_1		= 113,
+	MSM_RPM_8930_ID_PM8038_L7_0		= 114,
+	MSM_RPM_8930_ID_PM8038_L7_1		= 115,
+	MSM_RPM_8930_ID_PM8038_L8_0		= 116,
+	MSM_RPM_8930_ID_PM8038_L8_1		= 117,
+	MSM_RPM_8930_ID_PM8038_L9_0		= 118,
+	MSM_RPM_8930_ID_PM8038_L9_1		= 119,
+	MSM_RPM_8930_ID_PM8038_L10_0		= 120,
+	MSM_RPM_8930_ID_PM8038_L10_1		= 121,
+	MSM_RPM_8930_ID_PM8038_L11_0		= 122,
+	MSM_RPM_8930_ID_PM8038_L11_1		= 123,
+	MSM_RPM_8930_ID_PM8038_L12_0		= 124,
+	MSM_RPM_8930_ID_PM8038_L12_1		= 125,
+	MSM_RPM_8930_ID_PM8038_L13_0		= 126,
+	MSM_RPM_8930_ID_PM8038_L13_1		= 127,
+	MSM_RPM_8930_ID_PM8038_L14_0		= 128,
+	MSM_RPM_8930_ID_PM8038_L14_1		= 129,
+	MSM_RPM_8930_ID_PM8038_L15_0		= 130,
+	MSM_RPM_8930_ID_PM8038_L15_1		= 131,
+	MSM_RPM_8930_ID_PM8038_L16_0		= 132,
+	MSM_RPM_8930_ID_PM8038_L16_1		= 133,
+	MSM_RPM_8930_ID_PM8038_L17_0		= 134,
+	MSM_RPM_8930_ID_PM8038_L17_1		= 135,
+	MSM_RPM_8930_ID_PM8038_L18_0		= 136,
+	MSM_RPM_8930_ID_PM8038_L18_1		= 137,
+	MSM_RPM_8930_ID_PM8038_L19_0		= 138,
+	MSM_RPM_8930_ID_PM8038_L19_1		= 139,
+	MSM_RPM_8930_ID_PM8038_L20_0		= 140,
+	MSM_RPM_8930_ID_PM8038_L20_1		= 141,
+	MSM_RPM_8930_ID_PM8038_L21_0		= 142,
+	MSM_RPM_8930_ID_PM8038_L21_1		= 143,
+	MSM_RPM_8930_ID_PM8038_L22_0		= 144,
+	MSM_RPM_8930_ID_PM8038_L22_1		= 145,
+	MSM_RPM_8930_ID_PM8038_L23_0		= 146,
+	MSM_RPM_8930_ID_PM8038_L23_1		= 147,
+	MSM_RPM_8930_ID_PM8038_L24_0		= 148,
+	MSM_RPM_8930_ID_PM8038_L24_1		= 149,
+	MSM_RPM_8930_ID_PM8038_L25_0		= 150,
+	MSM_RPM_8930_ID_PM8038_L25_1		= 151,
+	MSM_RPM_8930_ID_PM8038_L26_0		= 152,
+	MSM_RPM_8930_ID_PM8038_L26_1		= 153,
+	MSM_RPM_8930_ID_PM8038_L27_0		= 154,
+	MSM_RPM_8930_ID_PM8038_L27_1		= 155,
+	MSM_RPM_8930_ID_PM8038_CLK1_0		= 156,
+	MSM_RPM_8930_ID_PM8038_CLK1_1		= 157,
+	MSM_RPM_8930_ID_PM8038_CLK2_0		= 158,
+	MSM_RPM_8930_ID_PM8038_CLK2_1		= 159,
+	MSM_RPM_8930_ID_PM8038_LVS1		= 160,
+	MSM_RPM_8930_ID_PM8038_LVS2		= 161,
+	MSM_RPM_8930_ID_PM8038_NCP_0		= 162,
+	MSM_RPM_8930_ID_PM8038_NCP_1		= 163,
+	MSM_RPM_8930_ID_PM8038_CXO_BUFFERS	= 164,
+	MSM_RPM_8930_ID_PM8038_USB_OTG_SWITCH	= 165,
+	MSM_RPM_8930_ID_PM8038_HDMI_SWITCH	= 166,
+	MSM_RPM_8930_ID_PM8038_QDSS_CLK		= 167,
+	MSM_RPM_8930_ID_PM8038_VOLTAGE_CORNER	= 168,
+	MSM_RPM_8930_ID_PM8038_LAST = MSM_RPM_8930_ID_PM8038_VOLTAGE_CORNER,
 
 	/* PMIC 8917 */
-	MSM_RPM_8930_ID_PM8917_S1_0	= 90,
-	MSM_RPM_8930_ID_PM8917_S1_1	= 91,
-	MSM_RPM_8930_ID_PM8917_S2_0	= 92,
-	MSM_RPM_8930_ID_PM8917_S2_1	= 93,
-	MSM_RPM_8930_ID_PM8917_S3_0	= 94,
-	MSM_RPM_8930_ID_PM8917_S3_1	= 95,
-	MSM_RPM_8930_ID_PM8917_S4_0	= 96,
-	MSM_RPM_8930_ID_PM8917_S4_1	= 97,
-	MSM_RPM_8930_ID_PM8917_S5_0	= 98,
-	MSM_RPM_8930_ID_PM8917_S5_1	= 99,
-	MSM_RPM_8930_ID_PM8917_S6_0	= 100,
-	MSM_RPM_8930_ID_PM8917_S6_1	= 101,
-	MSM_RPM_8930_ID_PM8917_S7_0	= 102,
-	MSM_RPM_8930_ID_PM8917_S7_1	= 103,
-	MSM_RPM_8930_ID_PM8917_S8_0	= 104,
-	MSM_RPM_8930_ID_PM8917_S8_1	= 105,
-	MSM_RPM_8930_ID_PM8917_L1_0	= 106,
-	MSM_RPM_8930_ID_PM8917_L1_1	= 107,
-	MSM_RPM_8930_ID_PM8917_L2_0	= 108,
-	MSM_RPM_8930_ID_PM8917_L2_1	= 109,
-	MSM_RPM_8930_ID_PM8917_L3_0	= 110,
-	MSM_RPM_8930_ID_PM8917_L3_1	= 111,
-	MSM_RPM_8930_ID_PM8917_L4_0	= 112,
-	MSM_RPM_8930_ID_PM8917_L4_1	= 113,
-	MSM_RPM_8930_ID_PM8917_L5_0	= 114,
-	MSM_RPM_8930_ID_PM8917_L5_1	= 115,
-	MSM_RPM_8930_ID_PM8917_L6_0	= 116,
-	MSM_RPM_8930_ID_PM8917_L6_1	= 117,
-	MSM_RPM_8930_ID_PM8917_L7_0	= 118,
-	MSM_RPM_8930_ID_PM8917_L7_1	= 119,
-	MSM_RPM_8930_ID_PM8917_L8_0	= 120,
-	MSM_RPM_8930_ID_PM8917_L8_1	= 121,
-	MSM_RPM_8930_ID_PM8917_L9_0	= 122,
-	MSM_RPM_8930_ID_PM8917_L9_1	= 123,
-	MSM_RPM_8930_ID_PM8917_L10_0	= 124,
-	MSM_RPM_8930_ID_PM8917_L10_1	= 125,
-	MSM_RPM_8930_ID_PM8917_L11_0	= 126,
-	MSM_RPM_8930_ID_PM8917_L11_1	= 127,
-	MSM_RPM_8930_ID_PM8917_L12_0	= 128,
-	MSM_RPM_8930_ID_PM8917_L12_1	= 129,
-	MSM_RPM_8930_ID_PM8917_L14_0	= 130,
-	MSM_RPM_8930_ID_PM8917_L14_1	= 131,
-	MSM_RPM_8930_ID_PM8917_L15_0	= 132,
-	MSM_RPM_8930_ID_PM8917_L15_1	= 133,
-	MSM_RPM_8930_ID_PM8917_L16_0	= 134,
-	MSM_RPM_8930_ID_PM8917_L16_1	= 135,
-	MSM_RPM_8930_ID_PM8917_L17_0	= 136,
-	MSM_RPM_8930_ID_PM8917_L17_1	= 137,
-	MSM_RPM_8930_ID_PM8917_L18_0	= 138,
-	MSM_RPM_8930_ID_PM8917_L18_1	= 139,
-	MSM_RPM_8930_ID_PM8917_L21_0	= 140,
-	MSM_RPM_8930_ID_PM8917_L21_1	= 141,
-	MSM_RPM_8930_ID_PM8917_L22_0	= 142,
-	MSM_RPM_8930_ID_PM8917_L22_1	= 143,
-	MSM_RPM_8930_ID_PM8917_L23_0	= 144,
-	MSM_RPM_8930_ID_PM8917_L23_1	= 145,
-	MSM_RPM_8930_ID_PM8917_L24_0	= 146,
-	MSM_RPM_8930_ID_PM8917_L24_1	= 147,
-	MSM_RPM_8930_ID_PM8917_L25_0	= 148,
-	MSM_RPM_8930_ID_PM8917_L25_1	= 149,
-	MSM_RPM_8930_ID_PM8917_L26_0	= 150,
-	MSM_RPM_8930_ID_PM8917_L26_1	= 151,
-	MSM_RPM_8930_ID_PM8917_L27_0	= 152,
-	MSM_RPM_8930_ID_PM8917_L27_1	= 153,
-	MSM_RPM_8930_ID_PM8917_L28_0	= 154,
-	MSM_RPM_8930_ID_PM8917_L28_1	= 155,
-	MSM_RPM_8930_ID_PM8917_L29_0	= 156,
-	MSM_RPM_8930_ID_PM8917_L29_1	= 157,
-	MSM_RPM_8930_ID_PM8917_L30_0	= 158,
-	MSM_RPM_8930_ID_PM8917_L30_1	= 159,
-	MSM_RPM_8930_ID_PM8917_L31_0	= 160,
-	MSM_RPM_8930_ID_PM8917_L31_1	= 161,
-	MSM_RPM_8930_ID_PM8917_L32_0	= 162,
-	MSM_RPM_8930_ID_PM8917_L32_1	= 163,
-	MSM_RPM_8930_ID_PM8917_L33_0	= 164,
-	MSM_RPM_8930_ID_PM8917_L33_1	= 165,
-	MSM_RPM_8930_ID_PM8917_L34_0	= 166,
-	MSM_RPM_8930_ID_PM8917_L34_1	= 167,
-	MSM_RPM_8930_ID_PM8917_L35_0	= 168,
-	MSM_RPM_8930_ID_PM8917_L35_1	= 169,
-	MSM_RPM_8930_ID_PM8917_L36_0	= 170,
-	MSM_RPM_8930_ID_PM8917_L36_1	= 171,
-	MSM_RPM_8930_ID_PM8917_CLK1_0	= 172,
-	MSM_RPM_8930_ID_PM8917_CLK1_1	= 173,
-	MSM_RPM_8930_ID_PM8917_CLK2_0	= 174,
-	MSM_RPM_8930_ID_PM8917_CLK2_1	= 175,
-	MSM_RPM_8930_ID_PM8917_LVS1	= 176,
-	MSM_RPM_8930_ID_PM8917_LVS3	= 177,
-	MSM_RPM_8930_ID_PM8917_LVS4	= 178,
-	MSM_RPM_8930_ID_PM8917_LVS5	= 179,
-	MSM_RPM_8930_ID_PM8917_LVS6	= 180,
-	MSM_RPM_8930_ID_PM8917_LVS7	= 181,
+	MSM_RPM_8930_ID_PM8917_S1_0		= 90,
+	MSM_RPM_8930_ID_PM8917_S1_1		= 91,
+	MSM_RPM_8930_ID_PM8917_S2_0		= 92,
+	MSM_RPM_8930_ID_PM8917_S2_1		= 93,
+	MSM_RPM_8930_ID_PM8917_S3_0		= 94,
+	MSM_RPM_8930_ID_PM8917_S3_1		= 95,
+	MSM_RPM_8930_ID_PM8917_S4_0		= 96,
+	MSM_RPM_8930_ID_PM8917_S4_1		= 97,
+	MSM_RPM_8930_ID_PM8917_S5_0		= 98,
+	MSM_RPM_8930_ID_PM8917_S5_1		= 99,
+	MSM_RPM_8930_ID_PM8917_S6_0		= 100,
+	MSM_RPM_8930_ID_PM8917_S6_1		= 101,
+	MSM_RPM_8930_ID_PM8917_S7_0		= 102,
+	MSM_RPM_8930_ID_PM8917_S7_1		= 103,
+	MSM_RPM_8930_ID_PM8917_S8_0		= 104,
+	MSM_RPM_8930_ID_PM8917_S8_1		= 105,
+	MSM_RPM_8930_ID_PM8917_L1_0		= 106,
+	MSM_RPM_8930_ID_PM8917_L1_1		= 107,
+	MSM_RPM_8930_ID_PM8917_L2_0		= 108,
+	MSM_RPM_8930_ID_PM8917_L2_1		= 109,
+	MSM_RPM_8930_ID_PM8917_L3_0		= 110,
+	MSM_RPM_8930_ID_PM8917_L3_1		= 111,
+	MSM_RPM_8930_ID_PM8917_L4_0		= 112,
+	MSM_RPM_8930_ID_PM8917_L4_1		= 113,
+	MSM_RPM_8930_ID_PM8917_L5_0		= 114,
+	MSM_RPM_8930_ID_PM8917_L5_1		= 115,
+	MSM_RPM_8930_ID_PM8917_L6_0		= 116,
+	MSM_RPM_8930_ID_PM8917_L6_1		= 117,
+	MSM_RPM_8930_ID_PM8917_L7_0		= 118,
+	MSM_RPM_8930_ID_PM8917_L7_1		= 119,
+	MSM_RPM_8930_ID_PM8917_L8_0		= 120,
+	MSM_RPM_8930_ID_PM8917_L8_1		= 121,
+	MSM_RPM_8930_ID_PM8917_L9_0		= 122,
+	MSM_RPM_8930_ID_PM8917_L9_1		= 123,
+	MSM_RPM_8930_ID_PM8917_L10_0		= 124,
+	MSM_RPM_8930_ID_PM8917_L10_1		= 125,
+	MSM_RPM_8930_ID_PM8917_L11_0		= 126,
+	MSM_RPM_8930_ID_PM8917_L11_1		= 127,
+	MSM_RPM_8930_ID_PM8917_L12_0		= 128,
+	MSM_RPM_8930_ID_PM8917_L12_1		= 129,
+	MSM_RPM_8930_ID_PM8917_L14_0		= 130,
+	MSM_RPM_8930_ID_PM8917_L14_1		= 131,
+	MSM_RPM_8930_ID_PM8917_L15_0		= 132,
+	MSM_RPM_8930_ID_PM8917_L15_1		= 133,
+	MSM_RPM_8930_ID_PM8917_L16_0		= 134,
+	MSM_RPM_8930_ID_PM8917_L16_1		= 135,
+	MSM_RPM_8930_ID_PM8917_L17_0		= 136,
+	MSM_RPM_8930_ID_PM8917_L17_1		= 137,
+	MSM_RPM_8930_ID_PM8917_L18_0		= 138,
+	MSM_RPM_8930_ID_PM8917_L18_1		= 139,
+	MSM_RPM_8930_ID_PM8917_L21_0		= 140,
+	MSM_RPM_8930_ID_PM8917_L21_1		= 141,
+	MSM_RPM_8930_ID_PM8917_L22_0		= 142,
+	MSM_RPM_8930_ID_PM8917_L22_1		= 143,
+	MSM_RPM_8930_ID_PM8917_L23_0		= 144,
+	MSM_RPM_8930_ID_PM8917_L23_1		= 145,
+	MSM_RPM_8930_ID_PM8917_L24_0		= 146,
+	MSM_RPM_8930_ID_PM8917_L24_1		= 147,
+	MSM_RPM_8930_ID_PM8917_L25_0		= 148,
+	MSM_RPM_8930_ID_PM8917_L25_1		= 149,
+	MSM_RPM_8930_ID_PM8917_L26_0		= 150,
+	MSM_RPM_8930_ID_PM8917_L26_1		= 151,
+	MSM_RPM_8930_ID_PM8917_L27_0		= 152,
+	MSM_RPM_8930_ID_PM8917_L27_1		= 153,
+	MSM_RPM_8930_ID_PM8917_L28_0		= 154,
+	MSM_RPM_8930_ID_PM8917_L28_1		= 155,
+	MSM_RPM_8930_ID_PM8917_L29_0		= 156,
+	MSM_RPM_8930_ID_PM8917_L29_1		= 157,
+	MSM_RPM_8930_ID_PM8917_L30_0		= 158,
+	MSM_RPM_8930_ID_PM8917_L30_1		= 159,
+	MSM_RPM_8930_ID_PM8917_L31_0		= 160,
+	MSM_RPM_8930_ID_PM8917_L31_1		= 161,
+	MSM_RPM_8930_ID_PM8917_L32_0		= 162,
+	MSM_RPM_8930_ID_PM8917_L32_1		= 163,
+	MSM_RPM_8930_ID_PM8917_L33_0		= 164,
+	MSM_RPM_8930_ID_PM8917_L33_1		= 165,
+	MSM_RPM_8930_ID_PM8917_L34_0		= 166,
+	MSM_RPM_8930_ID_PM8917_L34_1		= 167,
+	MSM_RPM_8930_ID_PM8917_L35_0		= 168,
+	MSM_RPM_8930_ID_PM8917_L35_1		= 169,
+	MSM_RPM_8930_ID_PM8917_L36_0		= 170,
+	MSM_RPM_8930_ID_PM8917_L36_1		= 171,
+	MSM_RPM_8930_ID_PM8917_CLK1_0		= 172,
+	MSM_RPM_8930_ID_PM8917_CLK1_1		= 173,
+	MSM_RPM_8930_ID_PM8917_CLK2_0		= 174,
+	MSM_RPM_8930_ID_PM8917_CLK2_1		= 175,
+	MSM_RPM_8930_ID_PM8917_LVS1		= 176,
+	MSM_RPM_8930_ID_PM8917_LVS3		= 177,
+	MSM_RPM_8930_ID_PM8917_LVS4		= 178,
+	MSM_RPM_8930_ID_PM8917_LVS5		= 179,
+	MSM_RPM_8930_ID_PM8917_LVS6		= 180,
+	MSM_RPM_8930_ID_PM8917_LVS7		= 181,
+	MSM_RPM_8930_ID_PM8917_NCP_0		= 182,
+	MSM_RPM_8930_ID_PM8917_NCP_1		= 183,
+	MSM_RPM_8930_ID_PM8917_CXO_BUFFERS	= 184,
+	MSM_RPM_8930_ID_PM8917_USB_OTG_SWITCH	= 185,
+	MSM_RPM_8930_ID_PM8917_HDMI_SWITCH	= 186,
+	MSM_RPM_8930_ID_PM8917_QDSS_CLK		= 187,
+	MSM_RPM_8930_ID_PM8917_VOLTAGE_CORNER	= 188,
 
-	MSM_RPM_8930_ID_NCP_0		= 182,
-	MSM_RPM_8930_ID_NCP_1		= 183,
-	MSM_RPM_8930_ID_CXO_BUFFERS	= 184,
-	MSM_RPM_8930_ID_USB_OTG_SWITCH	= 185,
-	MSM_RPM_8930_ID_HDMI_SWITCH	= 186,
-	MSM_RPM_8930_ID_QDSS_CLK	= 187,
-	MSM_RPM_8930_ID_VOLTAGE_CORNER	= 188,
-
-	MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
+	MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_PM8917_VOLTAGE_CORNER,
+	MSM_RPM_8930_ID_PM8917_LAST = MSM_RPM_8930_ID_LAST,
 };
 
 /* RPM status ID enum */
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index 4ee1997..200a8cf 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -1086,6 +1086,14 @@
 		.count = c, \
 	}
 
+#define MSM_RPM_MAP_PMIC(_target, _pmic, _id, _select, _count) \
+	[MSM_RPM_ID_##_id] = \
+	{\
+		.id = MSM_RPM_##_target##_ID_PM##_pmic##_##_id, \
+		.sel = MSM_RPM_##_target##_SEL_##_select, \
+		.count = _count, \
+	}
+
 #define MSM_RPM_STATUS_ID_VALID BIT(31)
 
 #define MSM_RPM_STATUS_ID_MAP(t, i) \
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 5333c2e..a000c3e 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -160,6 +160,8 @@
 	SPS_O_AUTO_ENABLE = 0x20000000,
 	/* DISABLE endpoint synchronization for config/enable/disable */
 	SPS_O_NO_EP_SYNC = 0x40000000,
+	/* Allow partial polling duing IRQ mode */
+	SPS_O_HYBRID = 0x80000000,
 };
 
 /**
diff --git a/arch/arm/mach-msm/include/mach/usbdiag.h b/arch/arm/mach-msm/include/mach/usbdiag.h
index 4d0f63a..d9320c3 100644
--- a/arch/arm/mach-msm/include/mach/usbdiag.h
+++ b/arch/arm/mach-msm/include/mach/usbdiag.h
@@ -21,6 +21,8 @@
 #ifndef _DRIVERS_USB_DIAG_H_
 #define _DRIVERS_USB_DIAG_H_
 
+#include <linux/err.h>
+
 #define DIAG_LEGACY		"diag"
 #define DIAG_MDM		"diag_mdm"
 #define DIAG_QSC		"diag_qsc"
@@ -46,6 +48,7 @@
 	void *priv_usb;
 };
 
+#ifdef CONFIG_USB_G_ANDROID
 struct usb_diag_ch *usb_diag_open(const char *name, void *priv,
 		void (*notify)(void *, unsigned, struct diag_request *));
 void usb_diag_close(struct usb_diag_ch *ch);
@@ -53,7 +56,32 @@
 void usb_diag_free_req(struct usb_diag_ch *ch);
 int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req);
 int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req);
-
-int diag_read_from_cb(unsigned char * , int);
-
+#else
+static inline struct usb_diag_ch *usb_diag_open(const char *name, void *priv,
+		void (*notify)(void *, unsigned, struct diag_request *))
+{
+	return ERR_PTR(-ENODEV);
+}
+static inline void usb_diag_close(struct usb_diag_ch *ch)
+{
+}
+static inline
+int usb_diag_alloc_req(struct usb_diag_ch *ch, int n_write, int n_read)
+{
+	return -ENODEV;
+}
+static inline void usb_diag_free_req(struct usb_diag_ch *ch)
+{
+}
+static inline
+int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req)
+{
+	return -ENODEV;
+}
+static inline
+int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_USB_G_ANDROID */
 #endif /* _DRIVERS_USB_DIAG_H_ */
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 8f1d197..fde43b0 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -37,6 +37,7 @@
 
 #include "ipc_router.h"
 #include "modem_notifier.h"
+#include "msm_ipc_router_security.h"
 
 enum {
 	SMEM_LOG = 1U << 0,
@@ -114,6 +115,7 @@
 	struct msm_ipc_port_name name;
 	char pdev_name[32];
 	int next_pdev_id;
+	int synced_sec_rule;
 	struct list_head server_port_list;
 };
 
@@ -133,6 +135,7 @@
 	wait_queue_head_t quota_wait;
 	uint32_t tx_quota_cnt;
 	struct mutex quota_lock;
+	void *sec_rule;
 };
 
 struct msm_ipc_router_xprt_info {
@@ -651,6 +654,7 @@
 	rport_ptr->port_id = port_id;
 	rport_ptr->node_id = node_id;
 	rport_ptr->restart_state = RESTART_NORMAL;
+	rport_ptr->sec_rule = NULL;
 	rport_ptr->tx_quota_cnt = 0;
 	init_waitqueue_head(&rport_ptr->quota_wait);
 	mutex_init(&rport_ptr->quota_lock);
@@ -770,6 +774,7 @@
 	}
 	server->name.service = service;
 	server->name.instance = instance;
+	server->synced_sec_rule = 0;
 	INIT_LIST_HEAD(&server->server_port_list);
 	list_add_tail(&server->list, &server_list[key]);
 	scnprintf(server->pdev_name, sizeof(server->pdev_name),
@@ -1312,6 +1317,95 @@
 	msm_ipc_cleanup_routing_table(xprt_info);
 }
 
+/**
+ * sync_sec_rule() - Synchrnoize the security rule into the server structure
+ * @server: Server structure where the rule has to be synchronized.
+ * @rule: Security tule to be synchronized.
+ *
+ * This function is used to update the server structure with the security
+ * rule configured for the <service:instance> corresponding to that server.
+ */
+static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
+{
+	struct msm_ipc_server_port *server_port;
+	struct msm_ipc_router_remote_port *rport_ptr = NULL;
+
+	list_for_each_entry(server_port, &server->server_port_list, list) {
+		rport_ptr = msm_ipc_router_lookup_remote_port(
+				server_port->server_addr.node_id,
+				server_port->server_addr.port_id);
+		if (!rport_ptr)
+			continue;
+		rport_ptr->sec_rule = rule;
+	}
+	server->synced_sec_rule = 1;
+}
+
+/**
+ * msm_ipc_sync_sec_rule() - Sync the security rule to the service
+ * @service: Service for which the rule has to be synchronized.
+ * @instance: Instance for which the rule has to be synchronized.
+ * @rule: Security rule to be synchronized.
+ *
+ * This function is used to syncrhonize the security rule with the server
+ * hash table, if the user-space script configures the rule after the service
+ * has come up. This function is used to synchronize the security rule to a
+ * specific service and optionally a specific instance.
+ */
+void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
+{
+	int key = (service & (SRV_HASH_SIZE - 1));
+	struct msm_ipc_server *server;
+
+	mutex_lock(&server_list_lock);
+	list_for_each_entry(server, &server_list[key], list) {
+		if (server->name.service != service)
+			continue;
+
+		if (server->name.instance != instance &&
+		    instance != ALL_INSTANCE)
+			continue;
+
+		/*
+		 * If the rule applies to all instances and if the specific
+		 * instance of a service has a rule synchronized already,
+		 * do not apply the rule for that specific instance.
+		 */
+		if (instance == ALL_INSTANCE && server->synced_sec_rule)
+			continue;
+
+		sync_sec_rule(server, rule);
+	}
+	mutex_unlock(&server_list_lock);
+}
+
+/**
+ * msm_ipc_sync_default_sec_rule() - Default security rule to all services
+ * @rule: Security rule to be synchronized.
+ *
+ * This function is used to syncrhonize the security rule with the server
+ * hash table, if the user-space script configures the rule after the service
+ * has come up. This function is used to synchronize the security rule that
+ * applies to all services, if the concerned service do not have any rule
+ * defined.
+ */
+void msm_ipc_sync_default_sec_rule(void *rule)
+{
+	int key;
+	struct msm_ipc_server *server;
+
+	mutex_lock(&server_list_lock);
+	for (key = 0; key < SRV_HASH_SIZE; key++) {
+		list_for_each_entry(server, &server_list[key], list) {
+			if (server->synced_sec_rule)
+				continue;
+
+			sync_sec_rule(server, rule);
+		}
+	}
+	mutex_unlock(&server_list_lock);
+}
+
 static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
 			     struct rr_header *hdr)
 {
@@ -1491,6 +1585,9 @@
 				if (!rport_ptr)
 					pr_err("%s: Remote port create "
 					       "failed\n", __func__);
+				rport_ptr->sec_rule =
+					msm_ipc_get_security_rule(
+					msg->srv.service, msg->srv.instance);
 			}
 			wake_up(&newserver_wait);
 		}
@@ -1989,6 +2086,15 @@
 		return -ENOMEM;
 	}
 
+	if (src->check_send_permissions) {
+		ret = src->check_send_permissions(rport_ptr->sec_rule);
+		if (ret <= 0) {
+			pr_err("%s: permission failure for %s\n",
+				__func__, current->comm);
+			return -EPERM;
+		}
+	}
+
 	pkt = create_pkt(data);
 	if (!pkt) {
 		pr_err("%s: Pkt creation failed\n", __func__);
@@ -2781,6 +2887,10 @@
 	if (ret < 0)
 		pr_err("%s: Init sockets failed\n", __func__);
 
+	ret = msm_ipc_router_security_init();
+	if (ret < 0)
+		pr_err("%s: Security Init failed\n", __func__);
+
 	complete_all(&msm_ipc_local_router_up);
 	return ret;
 }
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 39038f2..39bde30 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -52,6 +52,9 @@
 
 #define ALIGN_SIZE(x) ((4 - ((x) & 3)) & 3)
 
+#define ALL_SERVICE 0xFFFFFFFF
+#define ALL_INSTANCE 0xFFFFFFFF
+
 union rr_control_msg {
 	uint32_t cmd;
 	struct {
@@ -139,6 +142,10 @@
 int msm_ipc_router_init_sockets(void);
 void msm_ipc_router_exit_sockets(void);
 
+void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule);
+
+void msm_ipc_sync_default_sec_rule(void *rule);
+
 #if defined CONFIG_MSM_IPC_ROUTER_SMD_XPRT
 extern void *msm_ipc_load_default_node(void);
 
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 3a6abbd..5d21fa5 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -21,10 +21,6 @@
 #include <linux/gfp.h>
 #include <linux/msm_ipc.h>
 
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
-#include <linux/android_aid.h>
-#endif
-
 #include <asm/string.h>
 #include <asm/atomic.h>
 
@@ -33,6 +29,7 @@
 #include <mach/msm_ipc_router.h>
 
 #include "ipc_router.h"
+#include "msm_ipc_router_security.h"
 
 #define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
 #define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
@@ -41,21 +38,6 @@
 static struct proto msm_ipc_proto;
 static const struct proto_ops msm_ipc_proto_ops;
 
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
-static inline int check_permissions(void)
-{
-	int rc = 0;
-	if (!current_euid() || in_egroup_p(AID_NET_RAW))
-		rc = 1;
-	return rc;
-}
-# else
-static inline int check_permissions(void)
-{
-	return 1;
-}
-#endif
-
 static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
 					  struct iovec const *msg_sect,
 					  size_t total_len)
@@ -193,7 +175,8 @@
 	void *pil;
 
 	if (!check_permissions()) {
-		pr_err("%s: Do not have permissions\n", __func__);
+		pr_err("%s: %s Do not have permissions\n",
+			__func__, current->comm);
 		return -EPERM;
 	}
 
@@ -223,6 +206,7 @@
 		return -ENOMEM;
 	}
 
+	port_ptr->check_send_permissions = msm_ipc_check_send_permissions;
 	sock->ops = &msm_ipc_proto_ops;
 	sock_init_data(sock, sk);
 	sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
@@ -445,6 +429,10 @@
 		ret = msm_ipc_router_bind_control_port(port_ptr);
 		break;
 
+	case IPC_ROUTER_IOCTL_CONFIG_SEC_RULES:
+		ret = msm_ipc_config_sec_rules((void *)arg);
+		break;
+
 	default:
 		ret = -EINVAL;
 	}
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index b81832e..aef4ac9 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -300,6 +300,7 @@
 		if (ret)
 			pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
 				   __func__, ret);
+		put_user(ret, (unsigned long __user *) arg);
 		break;
 	default:
 		pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
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 5c20a4e..dbfa5ec 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
@@ -642,6 +642,8 @@
 		.qport = qports_crypto_c0,
 		.mas_hw_id = MAS_CRYPTO_CORE0,
 		.hw_sel = MSM_BUS_NOC,
+		.prio_rd = 1,
+		.prio_wr = 1,
 	},
 	{
 		.id = MSM_BUS_MASTER_CRYPTO_CORE1,
@@ -653,6 +655,8 @@
 		.qport = qports_crypto_c1,
 		.mas_hw_id = MAS_CRYPTO_CORE1,
 		.hw_sel = MSM_BUS_NOC,
+		.prio_rd = 1,
+		.prio_wr = 1,
 	},
 	{
 		.id = MSM_BUS_MASTER_LPASS_PROC,
@@ -722,6 +726,7 @@
 		.prio_rd = 2,
 		.prio_wr = 2,
 		.hw_sel = MSM_BUS_NOC,
+		.iface_clk_node = "msm_usb3",
 	},
 	{
 		.id = MSM_BUS_SLAVE_AMPSS,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 12d6862..2c6efb8 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -71,6 +71,7 @@
 	int hw_sel;
 	const char *slaveclk[NUM_CTX];
 	const char *memclk[NUM_CTX];
+	const char *iface_clk_node;
 	unsigned int buswidth;
 	unsigned int ws;
 	unsigned int mode;
@@ -117,6 +118,7 @@
 	int commit_index;
 	struct nodeclk nodeclk[NUM_CTX];
 	struct nodeclk memclk[NUM_CTX];
+	struct nodeclk iface_clk;
 	void *hw_data;
 };
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 7169440..b6870c6 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -175,6 +175,15 @@
 			}
 		}
 
+		if (info->node_info->iface_clk_node) {
+			info->iface_clk.clk = clk_get_sys(info->node_info->
+				iface_clk_node, "iface_clk");
+			if (IS_ERR(info->iface_clk.clk)) {
+				MSM_BUS_ERR("ERR: Couldn't get clk %s\n",
+					info->node_info->iface_clk_node);
+			}
+		}
+
 		ret = info->node_info->gateway ?
 			msm_bus_fabric_add_fab(fabric, info) :
 			msm_bus_fabric_add_node(fabric, info);
@@ -187,6 +196,12 @@
 		if (fabric->fabdev.hw_algo.node_init == NULL)
 			continue;
 
+		if (info->iface_clk.clk) {
+			MSM_BUS_DBG("Enabled iface clock for node init: %d\n",
+				info->node_info->priv_id);
+			clk_prepare_enable(info->iface_clk.clk);
+		}
+
 		for (j = 0; j < NUM_CTX; j++)
 			clk_prepare_enable(fabric->info.nodeclk[j].clk);
 
@@ -198,6 +213,14 @@
 
 		for (j = 0; j < NUM_CTX; j++)
 			clk_disable_unprepare(fabric->info.nodeclk[j].clk);
+
+		if (info->iface_clk.clk) {
+			MSM_BUS_DBG("Disable iface_clk after node init: %d\n",
+				info->node_info->priv_id);
+			clk_disable_unprepare(info->iface_clk.clk);
+		}
+
+
 	}
 
 	MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
@@ -355,14 +378,35 @@
 		return;
 	}
 
+	/* Enable clocks before accessing QoS registers */
 	for (i = 0; i < NUM_CTX; i++)
 		clk_prepare_enable(fabric->info.nodeclk[i].clk);
 
+	if (info->iface_clk.clk)
+		clk_prepare_enable(info->iface_clk.clk);
+
+	if (hop->iface_clk.clk)
+		clk_prepare_enable(hop->iface_clk.clk);
+
 	fabdev->hw_algo.update_bw(hop, info, fabric->pdata, sel_cdata,
 		master_tiers, add_bw);
+
+	/* Disable clocks after accessing QoS registers */
 	for (i = 0; i < NUM_CTX; i++)
 		clk_disable_unprepare(fabric->info.nodeclk[i].clk);
 
+	if (info->iface_clk.clk) {
+		MSM_BUS_DBG("Commented: Will disable clock for info: %d\n",
+			info->node_info->priv_id);
+		clk_disable_unprepare(info->iface_clk.clk);
+	}
+
+	if (hop->iface_clk.clk) {
+		MSM_BUS_DBG("Commented Will disable clock for hop: %d\n",
+			hop->node_info->priv_id);
+		clk_disable_unprepare(hop->iface_clk.clk);
+	}
+
 	fabric->arb_dirty = true;
 }
 
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 41afd24..3b9656e 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -65,6 +65,7 @@
 	struct kobj_attribute thermal_poll_ms;
 
 	struct kobj_attribute freq_tbl;
+	struct kobj_attribute offset_tbl;
 
 	struct attribute_group attrib_group;
 };
@@ -295,9 +296,14 @@
 			continue;
 
 		if (gpu->pending_freq != STOP_FREQ_CHANGE &&
-		    gpu->set_floor_frequency)
+		    gpu->set_floor_frequency) {
 			gpu->set_floor_frequency(gpu->type_core_num,
 						 gpu_floor_freq);
+			/* TZ will know about a freq change (if any)
+			 * at next idle exit. */
+			gpu->actual_freq =
+				gpu->get_frequency(gpu->type_core_num);
+		}
 	}
 
 	mutex_unlock(&gpu_floor_mutex);
@@ -715,6 +721,77 @@
 
 DCVS_PARAM_STORE(thermal_poll_ms)
 
+static ssize_t msm_dcvs_attr_offset_tbl_show(struct kobject *kobj,
+					     struct kobj_attribute *attr,
+					     char *buf)
+{
+	struct msm_dcvs_freq_entry *freq_tbl;
+	char *buf_idx = buf;
+	int i, len;
+	struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, offset_tbl);
+
+	freq_tbl = core->info->freq_tbl;
+	*buf_idx = '\0';
+
+	/* limit the number of frequencies we will print into
+	 * the PAGE_SIZE sysfs show buffer. */
+	if (core->info->power_param.num_freq > 64)
+		return 0;
+
+	for (i = 0; i < core->info->power_param.num_freq; i++) {
+		len = snprintf(buf_idx, 30, "%7d %7d %7d\n",
+			       freq_tbl[i].freq,
+			       freq_tbl[i].active_energy_offset,
+			       freq_tbl[i].leakage_energy_offset);
+		/* buf_idx always points at terminating null */
+		buf_idx += len;
+	}
+	return buf_idx - buf;
+}
+
+static ssize_t msm_dcvs_attr_offset_tbl_store(struct kobject *kobj,
+					      struct kobj_attribute *attr,
+					      const char *buf,
+					      size_t count)
+{
+	struct msm_dcvs_freq_entry *freq_tbl;
+	uint32_t freq, active_energy_offset, leakage_energy_offset;
+	int i, ret;
+	struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, offset_tbl);
+
+	freq_tbl = core->info->freq_tbl;
+
+	ret = sscanf(buf, "%u %u %u",
+		     &freq, &active_energy_offset, &leakage_energy_offset);
+	if (ret != 3) {
+		__err("Invalid input %s for offset_tbl\n", buf);
+		return count;
+	}
+
+	for (i = 0; i < core->info->power_param.num_freq; i++)
+		if (freq_tbl[i].freq == freq) {
+			freq_tbl[i].active_energy_offset =
+				active_energy_offset;
+			freq_tbl[i].leakage_energy_offset =
+				leakage_energy_offset;
+			break;
+		}
+
+	if (i >= core->info->power_param.num_freq) {
+		__err("Invalid frequency for offset_tbl: %d\n", freq);
+		return count;
+	}
+
+	ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id,
+					    &core->info->power_param,
+					    &core->info->freq_tbl[0],
+					    &core->coeffs);
+	if (ret)
+		__err("Error %d in updating active/leakage energy\n", ret);
+
+	return count;
+}
+
 static ssize_t msm_dcvs_attr_freq_tbl_show(struct kobject *kobj,
 					   struct kobj_attribute *attr,
 					   char *buf)
@@ -791,7 +868,7 @@
 {
 	int ret = 0;
 	struct kobject *core_kobj = NULL;
-	const int attr_count = 25;
+	const int attr_count = 26;
 
 	BUG_ON(!cores_kobj);
 
@@ -830,8 +907,9 @@
 	DCVS_RW_ATTRIB(22, thermal_poll_ms);
 
 	DCVS_RW_ATTRIB(23, freq_tbl);
+	DCVS_RW_ATTRIB(24, offset_tbl);
 
-	core->attrib.attrib_group.attrs[24] = NULL;
+	core->attrib.attrib_group.attrs[25] = NULL;
 
 	core_kobj = kobject_create_and_add(core->core_name, cores_kobj);
 	if (!core_kobj) {
@@ -919,27 +997,6 @@
 	num_cpu_freqs++;
 }
 
-static void update_cpu_dcvs_params(struct msm_dcvs_core_info *info)
-{
-	int i;
-
-	BUG_ON(num_cpu_freqs == 0);
-
-	info->freq_tbl = cpu_freq_tbl;
-	info->power_param.num_freq = num_cpu_freqs;
-
-	if (!dcvs_pdata || dcvs_pdata->num_sync_rules == 0)
-		return;
-
-	/* the first sync rule shows what the turbo frequencies are -
-	 * these frequencies need energy offsets set */
-	for (i = 0; i < DCVS_MAX_NUM_FREQS && cpu_freq_tbl[i].freq != 0; i++)
-		if (cpu_freq_tbl[i].freq > dcvs_pdata->sync_rules[0].cpu_khz) {
-			cpu_freq_tbl[i].active_energy_offset = 100;
-			cpu_freq_tbl[i].leakage_energy_offset = 100;
-		}
-}
-
 int msm_dcvs_register_core(
 	enum msm_dcvs_core_type type,
 	int type_core_num,
@@ -975,8 +1032,11 @@
 	core->set_floor_frequency = set_floor_frequency;
 
 	core->info = info;
-	if (type == MSM_DCVS_CORE_TYPE_CPU)
-		update_cpu_dcvs_params(info);
+	if (type == MSM_DCVS_CORE_TYPE_CPU) {
+		BUG_ON(num_cpu_freqs == 0);
+		info->freq_tbl = cpu_freq_tbl;
+		info->power_param.num_freq = num_cpu_freqs;
+	}
 
 	memcpy(&core->algo_param, &info->algo_param,
 			sizeof(struct msm_dcvs_algo_param));
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.c b/arch/arm/mach-msm/msm_ipc_router_security.c
new file mode 100644
index 0000000..27cf524
--- /dev/null
+++ b/arch/arm/mach-msm/msm_ipc_router_security.c
@@ -0,0 +1,271 @@
+/* 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/types.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/gfp.h>
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/msm_ipc.h>
+
+#include <asm/uaccess.h>
+
+#include <net/sock.h>
+#include "ipc_router.h"
+#include "msm_ipc_router_security.h"
+
+#define SEC_RULES_HASH_SZ 32
+struct security_rule {
+	struct list_head list;
+	uint32_t service_id;
+	uint32_t instance_id;
+	unsigned reserved;
+	int num_group_info;
+	int *group_id;
+};
+
+static DEFINE_MUTEX(security_rules_lock);
+static struct list_head security_rules[SEC_RULES_HASH_SZ];
+
+/**
+ * check_permisions() - Check whether the process has permissions to
+ *                      create an interface handle with IPC Router
+ *
+ * @return: true if the process has permissions, else false.
+ */
+int check_permissions(void)
+{
+	int rc = 0;
+	if (!current_euid() || in_egroup_p(AID_NET_RAW))
+		rc = 1;
+	return rc;
+}
+EXPORT_SYMBOL(check_permissions);
+
+/**
+ * msm_ipc_config_sec_rules() - Add a security rule to the database
+ * @arg: Pointer to the buffer containing the rule.
+ *
+ * @return: 0 if successfully added, < 0 for error.
+ *
+ * A security rule is defined using <Service_ID: Group_ID> tuple. The rule
+ * implies that a user-space process in order to send a QMI message to
+ * service Service_ID should belong to the Linux group Group_ID.
+ */
+int msm_ipc_config_sec_rules(void *arg)
+{
+	struct config_sec_rules_args sec_rules_arg;
+	struct security_rule *rule, *temp_rule;
+	int key;
+	int ret;
+
+	if (current_euid())
+		return -EPERM;
+
+	ret = copy_from_user(&sec_rules_arg, (void *)arg,
+			     sizeof(sec_rules_arg));
+	if (ret)
+		return -EFAULT;
+
+	if (sec_rules_arg.num_group_info <= 0)
+		return -EINVAL;
+
+	rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
+	if (!rule) {
+		pr_err("%s: security_rule alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	rule->group_id = kzalloc((sec_rules_arg.num_group_info * sizeof(int)),
+				 GFP_KERNEL);
+	if (!rule->group_id) {
+		pr_err("%s: group_id alloc failed\n", __func__);
+		kfree(rule);
+		return -ENOMEM;
+	}
+
+	rule->service_id = sec_rules_arg.service_id;
+	rule->instance_id = sec_rules_arg.instance_id;
+	rule->reserved = sec_rules_arg.reserved;
+	rule->num_group_info = sec_rules_arg.num_group_info;
+	ret = copy_from_user(rule->group_id,
+			     ((void *)(arg + sizeof(sec_rules_arg))),
+			     (rule->num_group_info * sizeof(uint32_t)));
+	if (ret) {
+		kfree(rule->group_id);
+		kfree(rule);
+		return -EFAULT;
+	}
+
+	key = rule->service_id & (SEC_RULES_HASH_SZ - 1);
+	mutex_lock(&security_rules_lock);
+	if (rule->service_id == ALL_SERVICE) {
+		temp_rule = list_first_entry(&security_rules[key],
+					     struct security_rule, list);
+		list_del(&temp_rule->list);
+		kfree(temp_rule->group_id);
+		kfree(temp_rule);
+	}
+	list_add_tail(&rule->list, &security_rules[key]);
+	mutex_unlock(&security_rules_lock);
+
+	if (rule->service_id == ALL_SERVICE)
+		msm_ipc_sync_default_sec_rule((void *)rule);
+	else
+		msm_ipc_sync_sec_rule(rule->service_id, rule->instance_id,
+				      (void *)rule);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_ipc_config_sec_rules);
+
+/**
+ * msm_ipc_add_default_rule() - Add default security rule
+ *
+ * @return: 0 on success, < 0 on error/
+ *
+ * This function is used to ensure the basic security, if there is no
+ * security rule defined for a service. It can be overwritten by the
+ * default security rule from user-space script.
+ */
+static int msm_ipc_add_default_rule(void)
+{
+	struct security_rule *rule;
+	int key;
+
+	rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
+	if (!rule) {
+		pr_err("%s: security_rule alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	rule->group_id = kzalloc(sizeof(int), GFP_KERNEL);
+	if (!rule->group_id) {
+		pr_err("%s: group_id alloc failed\n", __func__);
+		kfree(rule);
+		return -ENOMEM;
+	}
+
+	rule->service_id = ALL_SERVICE;
+	rule->instance_id = ALL_INSTANCE;
+	rule->num_group_info = 1;
+	*(rule->group_id) = AID_NET_RAW;
+	mutex_lock(&security_rules_lock);
+	key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
+	list_add_tail(&rule->list, &security_rules[key]);
+	mutex_unlock(&security_rules_lock);
+	return 0;
+}
+
+/**
+ * msm_ipc_get_security_rule() - Get the security rule corresponding to a
+ *                               service
+ * @service_id: Service ID for which the rule has to be got.
+ * @instance_id: Instance ID for which the rule has to be got.
+ *
+ * @return: Returns the rule info on success, NULL on error.
+ *
+ * This function is used when the service comes up and gets registered with
+ * the IPC Router.
+ */
+void *msm_ipc_get_security_rule(uint32_t service_id, uint32_t instance_id)
+{
+	int key;
+	struct security_rule *rule;
+
+	key = (service_id & (SEC_RULES_HASH_SZ - 1));
+	mutex_lock(&security_rules_lock);
+	/* Return the rule for a specific <service:instance>, if found. */
+	list_for_each_entry(rule, &security_rules[key], list) {
+		if ((rule->service_id == service_id) &&
+		    (rule->instance_id == instance_id)) {
+			mutex_unlock(&security_rules_lock);
+			return (void *)rule;
+		}
+	}
+
+	/* Return the rule for a specific service, if found. */
+	list_for_each_entry(rule, &security_rules[key], list) {
+		if ((rule->service_id == service_id) &&
+		    (rule->instance_id == ALL_INSTANCE)) {
+			mutex_unlock(&security_rules_lock);
+			return (void *)rule;
+		}
+	}
+
+	/* Return the default rule, if no rule defined for a service. */
+	key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
+	list_for_each_entry(rule, &security_rules[key], list) {
+		if ((rule->service_id == ALL_SERVICE) &&
+		    (rule->instance_id == ALL_INSTANCE)) {
+			mutex_unlock(&security_rules_lock);
+			return (void *)rule;
+		}
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(msm_ipc_get_security_rule);
+
+/**
+ * msm_ipc_check_send_permissions() - Check if the sendng process has
+ *                                    permissions specified as per the rule
+ * @data: Security rule to be checked.
+ *
+ * @return: true if the process has permissions, else false.
+ *
+ * This function is used to check if the current executing process has
+ * permissions to send message to the remote entity. The security rule
+ * corresponding to the remote entity is specified by "data" parameter
+ */
+int msm_ipc_check_send_permissions(void *data)
+{
+	int i;
+	struct security_rule *rule = (struct security_rule *)data;
+
+	/* Source/Sender is Root user */
+	if (!current_euid())
+		return 1;
+
+	/* Destination has no rules defined, possibly a client. */
+	if (!rule)
+		return 1;
+
+	for (i = 0; i < rule->num_group_info; i++) {
+		if (in_egroup_p(rule->group_id[i]))
+			return 1;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(msm_ipc_check_send_permissions);
+
+/**
+ * msm_ipc_router_security_init() - Initialize the security rule database
+ *
+ * @return: 0 if successful, < 0 for error.
+ */
+int msm_ipc_router_security_init(void)
+{
+	int i;
+
+	for (i = 0; i < SEC_RULES_HASH_SZ; i++)
+		INIT_LIST_HEAD(&security_rules[i]);
+
+	msm_ipc_add_default_rule();
+	return 0;
+}
+EXPORT_SYMBOL(msm_ipc_router_security_init);
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.h b/arch/arm/mach-msm/msm_ipc_router_security.h
new file mode 100644
index 0000000..8701343
--- /dev/null
+++ b/arch/arm/mach-msm/msm_ipc_router_security.h
@@ -0,0 +1,104 @@
+/* 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 _MSM_IPC_ROUTER_SECURITY_H
+#define _MSM_IPC_ROUTER_SECURITY_H
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+
+#ifdef CONFIG_MSM_IPC_ROUTER_SECURITY
+#include <linux/android_aid.h>
+
+/**
+ * check_permisions() - Check whether the process has permissions to
+ *                      create an interface handle with IPC Router
+ *
+ * @return: true if the process has permissions, else false.
+ */
+int check_permissions(void);
+
+/**
+ * msm_ipc_config_sec_rules() - Add a security rule to the database
+ * @arg: Pointer to the buffer containing the rule.
+ *
+ * @return: 0 if successfully added, < 0 for error.
+ *
+ * A security rule is defined using <Service_ID: Group_ID> tuple. The rule
+ * implies that a user-space process in order to send a QMI message to
+ * service Service_ID should belong to the Linux group Group_ID.
+ */
+int msm_ipc_config_sec_rules(void *arg);
+
+/**
+ * msm_ipc_get_security_rule() - Get the security rule corresponding to a
+ *                               service
+ * @service_id: Service ID for which the rule has to be got.
+ * @instance_id: Instance ID for which the rule has to be got.
+ *
+ * @return: Returns the rule info on success, NULL on error.
+ *
+ * This function is used when the service comes up and gets registered with
+ * the IPC Router.
+ */
+void *msm_ipc_get_security_rule(uint32_t service_id, uint32_t instance_id);
+
+/**
+ * msm_ipc_check_send_permissions() - Check if the sendng process has
+ *                                    permissions specified as per the rule
+ * @data: Security rule to be checked.
+ *
+ * @return: true if the process has permissions, else false.
+ *
+ * This function is used to check if the current executing process has
+ * permissions to send message to the remote entity. The security rule
+ * corresponding to the remote entity is specified by "data" parameter
+ */
+int msm_ipc_check_send_permissions(void *data);
+
+/**
+ * msm_ipc_router_security_init() - Initialize the security rule database
+ *
+ * @return: 0 if successful, < 0 for error.
+ */
+int msm_ipc_router_security_init(void);
+
+#else
+
+static inline int check_permissions(void)
+{
+	return 1;
+}
+
+static inline int msm_ipc_config_sec_rules(void *arg)
+{
+	return -ENODEV;
+}
+
+static inline void *msm_ipc_get_security_rule(uint32_t service_id,
+					      uint32_t instance_id)
+{
+	return NULL;
+}
+
+static inline int msm_ipc_check_send_permissions(void *data)
+{
+	return 1;
+}
+
+static inline int msm_ipc_router_security_init(void)
+{
+	return 0;
+}
+#endif
+#endif
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 65e05a9..e3a3563 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -382,6 +382,7 @@
 
 	if (priv->region)
 		ion_free(ion, priv->region);
+	priv->region = NULL;
 	list_for_each_entry_safe(p, tmp, &priv->segs, list) {
 		list_del(&p->list);
 		kfree(p);
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 6e8d127..162a7f7 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -229,6 +229,30 @@
 	.proxy_unvote = pil_pronto_remove_proxy_vote,
 };
 
+static int pil_pronto_init_image_trusted(struct pil_desc *pil,
+			const u8 *metadata, size_t size)
+{
+	return pas_init_image(PAS_WCNSS, metadata, size);
+}
+
+static int pil_pronto_reset_trusted(struct pil_desc *pil)
+{
+	return pas_auth_and_reset(PAS_WCNSS);
+}
+
+static int pil_pronto_shutdown_trusted(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_WCNSS);
+}
+
+static struct pil_reset_ops pil_pronto_ops_trusted = {
+	.init_image = pil_pronto_init_image_trusted,
+	.auth_and_reset = pil_pronto_reset_trusted,
+	.shutdown = pil_pronto_shutdown_trusted,
+	.proxy_vote = pil_pronto_make_proxy_vote,
+	.proxy_unvote = pil_pronto_remove_proxy_vote,
+};
+
 #define subsys_to_drv(d) container_of(d, struct pronto_data, subsys_desc)
 
 static int pronto_start(const struct subsys_desc *desc)
@@ -418,9 +442,13 @@
 	desc->owner = THIS_MODULE;
 	desc->proxy_timeout = 10000;
 
-	/* TODO: need to add secure boot when the support is available */
-	desc->ops = &pil_pronto_ops;
-	dev_info(&pdev->dev, "using non-secure boot\n");
+	if (pas_supported(PAS_WCNSS) > 0) {
+		desc->ops = &pil_pronto_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_pronto_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
 
 	drv->vreg = devm_regulator_get(&pdev->dev, "vdd_pronto_pll");
 	if (IS_ERR(drv->vreg)) {
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 7993090..74fae98 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -542,7 +542,7 @@
 	}
 
 	ret = devm_request_irq(&pdev->dev, drv->irq, riva_wdog_bite_irq_hdlr,
-			IRQF_TRIGGER_HIGH, "riva_wdog", drv);
+			IRQF_TRIGGER_RISING, "riva_wdog", drv);
 	if (ret < 0)
 		goto err;
 
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index 47799cc..103fd9f 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -28,6 +28,8 @@
 #include <mach/iommu.h>
 #include <mach/iommu_domains.h>
 #include <mach/subsystem_restart.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
@@ -77,6 +79,7 @@
 	u32 fw_sz;
 	u32 fw_min_paddr;
 	u32 fw_max_paddr;
+	u32 bus_perf_client;
 };
 
 #define subsys_to_drv(d) container_of(d, struct venus_data, subsys_desc)
@@ -147,6 +150,41 @@
 		clk_disable_unprepare(drv->clks[i]);
 }
 
+static struct msm_bus_vectors pil_venus_unvote_bw_vector[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors pil_venus_vote_bw_vector[] = {
+	{
+		.src = MSM_BUS_MASTER_VIDEO_P0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 16 * 19 * 1000000UL, /* At least 19.2MHz on bus. */
+	},
+};
+
+static struct msm_bus_paths pil_venus_bw_tbl[] = {
+	{
+		.num_paths = ARRAY_SIZE(pil_venus_unvote_bw_vector),
+		.vectors = pil_venus_unvote_bw_vector,
+	},
+	{
+		.num_paths = ARRAY_SIZE(pil_venus_vote_bw_vector),
+		.vectors = pil_venus_vote_bw_vector,
+	},
+};
+
+static struct msm_bus_scale_pdata pil_venus_client_pdata = {
+	.usecase = pil_venus_bw_tbl,
+	.num_usecases = ARRAY_SIZE(pil_venus_bw_tbl),
+	.name = "pil-venus",
+};
+
 static int pil_venus_make_proxy_vote(struct pil_desc *pil)
 {
 	struct venus_data *drv = dev_get_drvdata(pil->dev);
@@ -161,13 +199,28 @@
 	rc = regulator_enable(drv->gdsc);
 	if (rc) {
 		dev_err(pil->dev, "GDSC enable failed\n");
-		return rc;
+		goto err_regulator;
 	}
 
 	rc = venus_clock_prepare_enable(pil->dev);
-	if (rc)
-		regulator_disable(drv->gdsc);
+	if (rc) {
+		dev_err(pil->dev, "clock prepare and enable failed\n");
+		goto err_clock;
+	}
 
+	rc = msm_bus_scale_client_update_request(drv->bus_perf_client, 1);
+	if (rc) {
+		dev_err(pil->dev, "bandwith request failed\n");
+		goto err_bw;
+	}
+
+	return 0;
+
+err_bw:
+	venus_clock_disable_unprepare(pil->dev);
+err_clock:
+	regulator_disable(drv->gdsc);
+err_regulator:
 	return rc;
 }
 
@@ -175,6 +228,8 @@
 {
 	struct venus_data *drv = dev_get_drvdata(pil->dev);
 
+	msm_bus_scale_client_update_request(drv->bus_perf_client, 0);
+
 	venus_clock_disable_unprepare(pil->dev);
 
 	/* Disable GDSC */
@@ -438,6 +493,13 @@
 	if (rc)
 		return rc;
 
+	drv->bus_perf_client =
+			msm_bus_scale_register_client(&pil_venus_client_pdata);
+	if (!drv->bus_perf_client) {
+		dev_err(&pdev->dev, "Failed to register bus client\n");
+		return -EINVAL;
+	}
+
 	drv->iommu_fw_ctx  = msm_iommu_get_ctx("venus_fw");
 	if (!drv->iommu_fw_ctx) {
 		dev_err(&pdev->dev, "No iommu fw context found\n");
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 0933d20..b1d2464 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -175,6 +175,9 @@
 {
 	BUG_ON(cpu >= get_core_count());
 
+	if (machine_is_msm8974_rumi())
+		return 0;
+
 	if (cpu_is_msm8x60())
 		return scorpion_release_secondary();
 
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 66d6bda..08a6de6 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -20,10 +20,10 @@
 obj-$(CONFIG_MSM_QDSP6_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
 obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
 obj-$(CONFIG_MSM_QDSP6_CODECS) += rtac.o q6audio_v1.o q6audio_v1_aio.o
-obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_amrwbplus.o audio_evrc.o audio_qcelp.o amrwb_in.o
 obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
 obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
 obj-$(CONFIG_MSM_QDSP6V2_CODECS) += rtac_v2.o q6audio_v2.o q6audio_v2_aio.o
-obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS)  += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
 obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
 obj-$(CONFIG_MSM_ULTRASOUND_A) += ultrasound/version_a/
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
new file mode 100644
index 0000000..2889c14
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
@@ -0,0 +1,234 @@
+/* amr-wbplus audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2010-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.
+ *
+ */
+#include <linux/msm_audio_amrwbplus.h>
+#include "audio_utils_aio.h"
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrwbplus_debug_fops = {
+	.read = audio_aio_debug_read,
+	.open = audio_aio_debug_open,
+};
+static void config_debug_fs(struct q6audio_aio *audio)
+{
+	if (audio != NULL) {
+		char name[sizeof("msm_amrwbplus_") + 5];
+		snprintf(name, sizeof(name), "msm_amrwbplus_%04x",
+			audio->ac->session);
+		audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+						NULL, (void *)audio,
+						&audio_amrwbplus_debug_fops);
+		if (IS_ERR(audio->dentry))
+			pr_debug("debugfs_create_file failed\n");
+	}
+}
+#else
+static void config_debug_fs(struct q6audio_aio *)
+{
+}
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct asm_amrwbplus_cfg q6_amrwbplus_cfg;
+	struct msm_audio_amrwbplus_config_v2 *amrwbplus_drv_config;
+	struct q6audio_aio *audio = file->private_data;
+	int rc = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		pr_err("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+			audio, audio->ac->session);
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+			audio->pcm_cfg.sample_rate,
+			audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+		amrwbplus_drv_config =
+		(struct msm_audio_amrwbplus_config_v2 *)audio->codec_cfg;
+
+		q6_amrwbplus_cfg.size_bytes     =
+			amrwbplus_drv_config->size_bytes;
+		q6_amrwbplus_cfg.version        =
+			amrwbplus_drv_config->version;
+		q6_amrwbplus_cfg.num_channels   =
+			amrwbplus_drv_config->num_channels;
+		q6_amrwbplus_cfg.amr_band_mode  =
+			amrwbplus_drv_config->amr_band_mode;
+		q6_amrwbplus_cfg.amr_dtx_mode   =
+			amrwbplus_drv_config->amr_dtx_mode;
+		q6_amrwbplus_cfg.amr_frame_fmt  =
+			amrwbplus_drv_config->amr_frame_fmt;
+		q6_amrwbplus_cfg.amr_lsf_idx    =
+			amrwbplus_drv_config->amr_lsf_idx;
+
+		rc = q6asm_media_format_block_amrwbplus(audio->ac,
+							&q6_amrwbplus_cfg);
+		if (rc < 0) {
+			pr_err("q6asm_media_format_block_amrwb+ failed...\n");
+			break;
+		}
+		rc = audio_aio_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_debug("%s:AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+			audio->ac->session,
+			audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+			break;
+		}
+	case AUDIO_GET_AMRWBPLUS_CONFIG_V2: {
+		if ((audio) && (arg) && (audio->codec_cfg)) {
+			if (copy_to_user((void *)arg, audio->codec_cfg,
+				sizeof(struct msm_audio_amrwbplus_config_v2))) {
+				rc = -EFAULT;
+				pr_err("wb+ config get copy_to_user failed");
+				break;
+			}
+			} else {
+				pr_err("wb+ config v2 invalid parameters..");
+				rc = -EFAULT;
+				break;
+			}
+		break;
+	}
+	case AUDIO_SET_AMRWBPLUS_CONFIG_V2: {
+		if ((audio) && (arg) && (audio->codec_cfg)) {
+			if (copy_from_user(audio->codec_cfg, (void *)arg,
+			sizeof(struct msm_audio_amrwbplus_config_v2))) {
+				rc = -EFAULT;
+				pr_err("wb+ config set copy_to_user_failed");
+				break;
+			}
+			} else {
+				pr_err("wb+ config invalid parameters..");
+				rc = -EFAULT;
+				break;
+			}
+		break;
+	}
+	default:
+		pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+		rc = audio->codec_ioctl(file, cmd, arg);
+	}
+	return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_aio *audio = NULL;
+	int rc = 0;
+
+	audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("kzalloc failed for amrwb+ decode driver\n");
+		return -ENOMEM;
+	}
+	audio->codec_cfg =
+	kzalloc(sizeof(struct msm_audio_amrwbplus_config_v2), GFP_KERNEL);
+	if (audio->codec_cfg == NULL) {
+		pr_err("%s:failed kzalloc for amrwb+ config structure",
+			__func__);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+	audio->ac =
+	q6asm_audio_client_alloc((app_cb) q6_audio_cb, (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio->codec_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					FORMAT_AMR_WB_PLUS);
+		if (rc < 0) {
+			pr_err("amrwbplus NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		audio->buf_cfg.frames_per_buf = 0x01;
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+			rc = q6asm_open_write(audio->ac, FORMAT_AMR_WB_PLUS);
+			if (rc < 0) {
+				pr_err("wb+ T mode Open failed rc=%d\n", rc);
+				rc = -ENODEV;
+				goto fail;
+			}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("audio_amrwbplus Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	rc = audio_aio_open(audio, file);
+
+	config_debug_fs(audio);
+	pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
+		audio->feedback,
+		audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->codec_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_amrwbplus_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_aio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_amrwbplus_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_amrwbplus",
+	.fops = &audio_amrwbplus_fops,
+};
+
+static int __init audio_amrwbplus_init(void)
+{
+	return misc_register(&audio_amrwbplus_misc);
+}
+
+device_initcall(audio_amrwbplus_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index fb0ace7..a4a6b906 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -1142,6 +1142,11 @@
 			mutex_unlock(&audio->lock);
 			break;
 		}
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
+					__func__, audio);
+			wake_up(&audio->write_wait);
+		}
 		mutex_unlock(&audio->lock);
 		break;
 	}
@@ -1178,6 +1183,11 @@
 		mutex_lock(&audio->lock);
 		audio->rflush = 1;
 		audio->wflush = 1;
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
+				__func__, audio);
+			wake_up(&audio->write_wait);
+		}
 		/* Flush DSP */
 		rc = audio_aio_flush(audio);
 		/* Flush input / Output buffer in software*/
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
index f566e82..94192cf 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
@@ -16,15 +16,38 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/input/mt.h>
+#include <linux/syscalls.h>
 #include "usfcdev.h"
 
+#define UNDEF_ID    0xffffffff
+#define SLOT_CMD_ID 0
+#define MAX_RETRIES 10
+
+
+
+enum usdev_event_status {
+	USFCDEV_EVENT_ENABLED,
+	USFCDEV_EVENT_DISABLING,
+	USFCDEV_EVENT_DISABLED,
+};
+
 struct usfcdev_event {
 	bool (*match_cb)(uint16_t, struct input_dev *dev);
 	bool registered_event;
-	bool filter;
+	bool interleaved;
+	enum usdev_event_status event_status;
 };
 static struct usfcdev_event s_usfcdev_events[MAX_EVENT_TYPE_NUM];
 
+struct usfcdev_input_command {
+	unsigned int type;
+	unsigned int code;
+	unsigned int value;
+};
+
+static long  s_usf_pid;
+
 static bool usfcdev_filter(struct input_handle *handle,
 			 unsigned int type, unsigned int code, int value);
 static bool usfcdev_match(struct input_handler *handler,
@@ -83,6 +106,22 @@
 	},
 };
 
+static struct usfcdev_input_command initial_clear_cmds[] = {
+	{EV_ABS, ABS_PRESSURE,               0},
+	{EV_KEY, BTN_TOUCH,                  0},
+};
+
+static struct usfcdev_input_command slot_clear_cmds[] = {
+	{EV_ABS, ABS_MT_SLOT,               0},
+	{EV_ABS, ABS_MT_TRACKING_ID, UNDEF_ID},
+};
+
+static struct usfcdev_input_command no_filter_cmds[] = {
+	{EV_ABS, ABS_MT_SLOT,               0},
+	{EV_ABS, ABS_MT_TRACKING_ID, UNDEF_ID},
+	{EV_SYN, SYN_REPORT,                0},
+};
+
 static bool usfcdev_match(struct input_handler *handler, struct input_dev *dev)
 {
 	bool rc = false;
@@ -91,7 +130,7 @@
 	pr_debug("%s: name=[%s]; ind=%d\n", __func__, dev->name, ind);
 
 	if (s_usfcdev_events[ind].registered_event &&
-			s_usfcdev_events[ind].match_cb) {
+		s_usfcdev_events[ind].match_cb) {
 		rc = (*s_usfcdev_events[ind].match_cb)((uint16_t)ind, dev);
 		pr_debug("%s: [%s]; rc=%d\n", __func__, dev->name, rc);
 	}
@@ -139,16 +178,39 @@
 static bool usfcdev_filter(struct input_handle *handle,
 			unsigned int type, unsigned int code, int value)
 {
+	uint16_t i = 0;
 	uint16_t ind = (uint16_t)handle->handler->minor;
+	bool rc = (s_usfcdev_events[ind].event_status != USFCDEV_EVENT_ENABLED);
 
-	pr_debug("%s: event_type=%d; filter=%d; abs_xy=%ld; abs_y_mt[]=%ld\n",
-		__func__,
-		ind,
-		s_usfcdev_events[ind].filter,
-		 usfc_tsc_ids[0].absbit[0],
-		 usfc_tsc_ids[1].absbit[1]);
+	if (s_usf_pid == sys_getpid()) {
+		/* Pass events from usfcdev driver */
+		rc = false;
+		pr_debug("%s: event_type=%d; type=%d; code=%d; val=%d",
+			__func__,
+			ind,
+			type,
+			code,
+			value);
+	} else if (s_usfcdev_events[ind].event_status ==
+						USFCDEV_EVENT_DISABLING) {
+		uint32_t u_value = value;
+		s_usfcdev_events[ind].interleaved = true;
+		/* Pass events for freeing slots from TSC driver */
+		for (i = 0; i < ARRAY_SIZE(no_filter_cmds); ++i) {
+			if ((no_filter_cmds[i].type == type) &&
+			    (no_filter_cmds[i].code == code) &&
+			    (no_filter_cmds[i].value <= u_value)) {
+				rc = false;
+				pr_debug("%s: no_filter_cmds[%d]; %d",
+					__func__,
+					i,
+					no_filter_cmds[i].value);
+				break;
+			}
+		}
+	}
 
-	return s_usfcdev_events[ind].filter;
+	return rc;
 }
 
 bool usfcdev_register(
@@ -175,7 +237,7 @@
 
 	s_usfcdev_events[event_type_ind].registered_event = true;
 	s_usfcdev_events[event_type_ind].match_cb = match_cb;
-	s_usfcdev_events[event_type_ind].filter = false;
+	s_usfcdev_events[event_type_ind].event_status = USFCDEV_EVENT_ENABLED;
 	ret = input_register_handler(&s_usfc_handlers[event_type_ind]);
 	if (!ret) {
 		rc = true;
@@ -209,7 +271,64 @@
 			event_type_ind);
 		s_usfcdev_events[event_type_ind].registered_event = false;
 		s_usfcdev_events[event_type_ind].match_cb = NULL;
-		s_usfcdev_events[event_type_ind].filter = false;
+		s_usfcdev_events[event_type_ind].event_status =
+							USFCDEV_EVENT_ENABLED;
+
+	}
+}
+
+static inline void usfcdev_send_cmd(
+	struct input_dev *dev,
+	struct usfcdev_input_command cmd)
+{
+	input_event(dev, cmd.type, cmd.code, cmd.value);
+}
+
+static void usfcdev_clean_dev(uint16_t event_type_ind)
+{
+	struct input_dev *dev = NULL;
+	int i;
+	int j;
+	int retries = 0;
+
+	if (event_type_ind >= MAX_EVENT_TYPE_NUM) {
+		pr_err("%s: wrong input: event_type_ind=%d\n",
+			__func__,
+			event_type_ind);
+		return;
+	}
+
+	dev = s_usfc_handles[event_type_ind].dev;
+
+	for (i = 0; i < ARRAY_SIZE(initial_clear_cmds); i++)
+		usfcdev_send_cmd(dev, initial_clear_cmds[i]);
+	input_sync(dev);
+
+	/* Send commands to free all slots */
+	for (i = 0; i < dev->mtsize; i++) {
+		s_usfcdev_events[event_type_ind].interleaved = false;
+		if (input_mt_get_value(&(dev->mt[i]), ABS_MT_TRACKING_ID) < 0) {
+			pr_debug("%s: skipping slot %d",
+				__func__, i);
+			continue;
+		}
+		slot_clear_cmds[SLOT_CMD_ID].value = i;
+		for (j = 0; j < ARRAY_SIZE(slot_clear_cmds); j++)
+			usfcdev_send_cmd(dev, slot_clear_cmds[j]);
+
+		if (s_usfcdev_events[event_type_ind].interleaved) {
+			pr_debug("%s: interleaved(%d): slot(%d)",
+				__func__, i, dev->slot);
+			if (retries++ < MAX_RETRIES) {
+				--i;
+				continue;
+			}
+			pr_warning("%s: index(%d) reached max retires",
+				__func__, i);
+		}
+
+		retries = 0;
+		input_sync(dev);
 	}
 }
 
@@ -225,12 +344,22 @@
 	}
 
 	if (s_usfcdev_events[event_type_ind].registered_event) {
-		s_usfcdev_events[event_type_ind].filter = filter;
+
 		pr_debug("%s: event_type[%d]; filter=%d\n",
 			__func__,
 			event_type_ind,
 			filter
 			);
+		if (filter) {
+			s_usfcdev_events[event_type_ind].event_status =
+						USFCDEV_EVENT_DISABLING;
+			s_usf_pid = sys_getpid();
+			usfcdev_clean_dev(event_type_ind);
+			s_usfcdev_events[event_type_ind].event_status =
+						USFCDEV_EVENT_DISABLED;
+		} else
+			s_usfcdev_events[event_type_ind].event_status =
+						USFCDEV_EVENT_ENABLED;
 	} else {
 		pr_err("%s: event_type[%d] isn't registered\n",
 			__func__,
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index a59b338..1db3d34 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -973,7 +973,7 @@
 
 static bool msm_rpm_set_standalone(void)
 {
-	if (machine_is_msm9625()) {
+	if (machine_is_msm9625() || machine_is_msm8974_rumi()) {
 		pr_warn("%s(): Running in standalone mode, requests "
 				"will not be sent to RPM\n", __func__);
 		standalone = true;
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 3af066d..212ad77 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1012,6 +1012,19 @@
 };
 #endif /* CONFIG_LOCAL_TIMERS */
 
+#ifdef CONFIG_ARCH_MSM8625
+static void fixup_msm8625_timer(void)
+{
+	struct msm_clock *dgt = &msm_clocks[MSM_CLOCK_DGT];
+	struct msm_clock *gpt = &msm_clocks[MSM_CLOCK_GPT];
+	dgt->irq = MSM8625_INT_DEBUG_TIMER_EXP;
+	gpt->irq = MSM8625_INT_GP_TIMER_EXP;
+	global_timer_offset =  MSM_TMR0_BASE - MSM_TMR_BASE;
+}
+#else
+static inline void fixup_msm8625_timer(void) { };
+#endif
+
 static void __init msm_timer_init(void)
 {
 	int i;
@@ -1032,11 +1045,8 @@
 		gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT
 			   |  MSM_CLOCK_FLAGS_ODD_MATCH_WRITE
 			   |  MSM_CLOCK_FLAGS_DELAYED_WRITE_POST;
-		if (cpu_is_msm8625()) {
-			dgt->irq = MSM8625_INT_DEBUG_TIMER_EXP;
-			gpt->irq = MSM8625_INT_GP_TIMER_EXP;
-			global_timer_offset =  MSM_TMR0_BASE - MSM_TMR_BASE;
-		}
+		if (cpu_is_msm8625())
+			fixup_msm8625_timer();
 	} else if (cpu_is_qsd8x50()) {
 		dgt->freq = 4800000;
 		gpt->regbase = MSM_TMR_BASE;
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 8994d6d..93b8ef1 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1059,7 +1059,7 @@
 	dpm_wait_for_children(dev, async);
 
 	if (async_error)
-		return 0;
+		goto Complete;
 
 	/*
 	 * If a device configured to wake up the system from sleep states
@@ -1072,7 +1072,7 @@
 
 	if (pm_wakeup_pending()) {
 		async_error = -EBUSY;
-		return 0;
+		goto Complete;
 	}
 
 	data.dev = dev;
@@ -1141,6 +1141,7 @@
 	del_timer_sync(&timer);
 	destroy_timer_on_stack(&timer);
 
+ Complete:
 	complete_all(&dev->power.completion);
 
 	if (error)
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 50b3362..b5531d6 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -43,6 +43,9 @@
 #include <net/bluetooth/hci_core.h>
 
 #include "hci_uart.h"
+#ifdef CONFIG_SERIAL_MSM_HS
+#include <mach/msm_serial_hs.h>
+#endif
 
 unsigned int enableuartsleep = 1;
 module_param(enableuartsleep, uint, 0644);
@@ -52,8 +55,8 @@
 /** Global state flags */
 static unsigned long flags;
 
-/** Tasklet to respond to change in hostwake line */
-static struct tasklet_struct hostwake_task;
+/** Workqueue to respond to change in hostwake line */
+static void wakeup_host_work(struct work_struct *work);
 
 /** Transmission timer */
 static void bluesleep_tx_timer_expire(unsigned long data);
@@ -89,11 +92,23 @@
 
 	struct sk_buff_head txq;
 	struct work_struct ctxtsw;
+	struct work_struct ws_sleep;
 };
 
-static void hostwake_interrupt(unsigned long data)
+static void hsuart_serial_clock_on(struct tty_struct *tty)
 {
-	BT_INFO(" wakeup host\n");
+	struct uart_state *state = tty->driver_data;
+	struct uart_port *port = state->uart_port;
+	BT_DBG("");
+	msm_hs_request_clock_on(port);
+}
+
+static void hsuart_serial_clock_off(struct tty_struct *tty)
+{
+	struct uart_state *state = tty->driver_data;
+	struct uart_port *port = state->uart_port;
+	BT_DBG("");
+	msm_hs_request_clock_off(port);
 }
 
 static void modify_timer_task(void)
@@ -109,6 +124,7 @@
 {
 	int status = 0;
 	if (test_bit(BT_TXEXPIRED, &flags)) {
+		hsuart_serial_clock_on(tty);
 		BT_INFO("wakeup device\n");
 		gpio_set_value(bsi->ext_wake, 0);
 		msleep(20);
@@ -118,6 +134,19 @@
 	return status;
 }
 
+static void wakeup_host_work(struct work_struct *work)
+{
+	struct ath_struct *ath =
+		container_of(work, struct ath_struct, ws_sleep);
+
+	BT_INFO("wake up host");
+	if (test_bit(BT_SLEEPENABLE, &flags)) {
+		if (test_bit(BT_TXEXPIRED, &flags))
+			hsuart_serial_clock_on(ath->hu->tty);
+	}
+	modify_timer_task();
+}
+
 static void ath_hci_uart_work(struct work_struct *work)
 {
 	int status;
@@ -141,11 +170,14 @@
 static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
 {
 	/* schedule a tasklet to handle the change in the host wake line */
-	tasklet_schedule(&hostwake_task);
+	struct ath_struct *ath = (struct ath_struct *)dev_id;
+
+	schedule_work(&ath->ws_sleep);
+
 	return IRQ_HANDLED;
 }
 
-static int ath_bluesleep_gpio_config(int on)
+static int ath_bluesleep_gpio_config(struct ath_struct *ath, int on)
 {
 	int ret = 0;
 
@@ -193,19 +225,16 @@
 	/* Initialize timer */
 	init_timer(&tx_timer);
 	tx_timer.function = bluesleep_tx_timer_expire;
-	tx_timer.data = 0;
-
-	/* initialize host wake tasklet */
-	tasklet_init(&hostwake_task, hostwake_interrupt, 0);
+	tx_timer.data = (u_long)ath->hu;
 
 	if (bsi->irq_polarity == POLARITY_LOW) {
 		ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
 				IRQF_DISABLED | IRQF_TRIGGER_FALLING,
-				"bluetooth hostwake", NULL);
+				"bluetooth hostwake", (void *)ath);
 	} else  {
 		ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
 				IRQF_DISABLED | IRQF_TRIGGER_RISING,
-				"bluetooth hostwake", NULL);
+				"bluetooth hostwake", (void *)ath);
 	}
 	if (ret  < 0) {
 		BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
@@ -221,7 +250,7 @@
 	return 0;
 
 free_host_wake_irq:
-	free_irq(bsi->host_wake_irq, NULL);
+	free_irq(bsi->host_wake_irq, (void *)ath);
 delete_timer:
 	del_timer(&tx_timer);
 gpio_ext_wake:
@@ -242,11 +271,6 @@
 	if (!bsi)
 		return -EIO;
 
-	if (ath_bluesleep_gpio_config(1) < 0) {
-		BT_ERR("HCIATH3K GPIO Config failed");
-		return -EIO;
-	}
-
 	ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
 	if (!ath)
 		return -ENOMEM;
@@ -256,13 +280,20 @@
 	hu->priv = ath;
 	ath->hu = hu;
 
+	if (ath_bluesleep_gpio_config(ath, 1) < 0) {
+		BT_ERR("HCIATH3K GPIO Config failed");
+		hu->priv = NULL;
+		kfree(ath);
+		return -EIO;
+	}
+
 	ath->cur_sleep = enableuartsleep;
 	if (ath->cur_sleep == 1) {
 		set_bit(BT_SLEEPENABLE, &flags);
 		modify_timer_task();
 	}
 	INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
-
+	INIT_WORK(&ath->ws_sleep, wakeup_host_work);
 	return 0;
 }
 
@@ -289,11 +320,13 @@
 
 	cancel_work_sync(&ath->ctxtsw);
 
-	hu->priv = NULL;
-	kfree(ath);
+	cancel_work_sync(&ath->ws_sleep);
 
 	if (bsi)
-		ath_bluesleep_gpio_config(0);
+		ath_bluesleep_gpio_config(ath, 0);
+
+	hu->priv = NULL;
+	kfree(ath);
 
 	return 0;
 }
@@ -383,11 +416,14 @@
 
 static void bluesleep_tx_timer_expire(unsigned long data)
 {
+	struct hci_uart *hu = (struct hci_uart *) data;
+
 	if (!test_bit(BT_SLEEPENABLE, &flags))
 		return;
 	BT_INFO("Tx timer expired\n");
 
 	set_bit(BT_TXEXPIRED, &flags);
+	hsuart_serial_clock_off(hu->tty);
 }
 
 static struct hci_uart_proto athp = {
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index e78a2aa..24fc99a 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -38,6 +38,8 @@
 struct mutex dci_log_mask_mutex;
 struct mutex dci_event_mask_mutex;
 
+smd_channel_t *ch_dci_temp;
+
 #define DCI_CHK_CAPACITY(entry, new_data_len)				\
 ((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0)	\
 
@@ -306,28 +308,100 @@
 	diag_smd_dci_send_req(MODEM_PROC);
 }
 
-static void diag_smd_dci_notify(void *ctxt, unsigned event)
+void diag_update_smd_dci_work_fn(struct work_struct *work)
 {
-	queue_work(driver->diag_dci_wq, &(driver->diag_read_smd_dci_work));
+	int i, j;
+	char dirty_bits[16];
+	uint8_t *client_log_mask_ptr;
+	uint8_t *log_mask_ptr;
+	int ret;
+
+	/* Update the peripheral(s) with the dci log and event masks */
+
+	/* If the cntl channel is not up, we can't update logs and events */
+	if (!driver->ch_cntl)
+		return;
+
+	memset(dirty_bits, 0, 16 * sizeof(uint8_t));
+
+	/*
+	 * From each log entry used by each client, determine
+	 * which log entries in the cumulative logs that need
+	 * to be updated on the peripheral.
+	 */
+	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+		if (driver->dci_client_tbl[i].client) {
+			client_log_mask_ptr =
+				driver->dci_client_tbl[i].dci_log_mask;
+			for (j = 0; j < 16; j++) {
+				if (*(client_log_mask_ptr+1))
+					dirty_bits[j] = 1;
+				client_log_mask_ptr += 514;
+			}
+		}
+	}
+
+	mutex_lock(&dci_log_mask_mutex);
+	/* Update the appropriate dirty bits in the cumulative mask */
+	log_mask_ptr = dci_cumulative_log_mask;
+	for (i = 0; i < 16; i++) {
+		if (dirty_bits[i])
+			*(log_mask_ptr+1) = dirty_bits[i];
+
+		log_mask_ptr += 514;
+	}
+	mutex_unlock(&dci_log_mask_mutex);
+
+	ret = diag_send_dci_log_mask(driver->ch_cntl);
+
+	ret = diag_send_dci_event_mask(driver->ch_cntl);
 }
 
-void diag_dci_notify_client(int peripheral_mask)
+void diag_dci_notify_client(int peripheral_mask, int data)
 {
 	int i, stat;
+	struct siginfo info;
+	memset(&info, 0, sizeof(struct siginfo));
+	info.si_code = SI_QUEUE;
+	info.si_int = (peripheral_mask | data);
 
 	/* Notify the DCI process that the peripheral DCI Channel is up */
 	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
 		if (driver->dci_client_tbl[i].list & peripheral_mask) {
-			pr_info("diag: sending signal now\n");
-			stat = send_sig(driver->dci_client_tbl[i].signal_type,
-					 driver->dci_client_tbl[i].client, 0);
+			info.si_signo = driver->dci_client_tbl[i].signal_type;
+			stat = send_sig_info(
+				driver->dci_client_tbl[i].signal_type,
+				&info, driver->dci_client_tbl[i].client);
 			if (stat)
-				pr_err("diag: Err send sig stat: %d\n", stat);
+				pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n",
+				info.si_int, stat);
 			break;
 		}
 	} /* end of loop for all DCI clients */
 }
 
+static void diag_smd_dci_notify(void *ctxt, unsigned event)
+{
+	if (event == SMD_EVENT_CLOSE) {
+		driver->ch_dci = 0;
+		/* Notify the clients of the close */
+		diag_dci_notify_client(DIAG_CON_MPSS, DIAG_STATUS_CLOSED);
+		return;
+	} else if (event == SMD_EVENT_OPEN) {
+
+		if (ch_dci_temp)
+			driver->ch_dci = ch_dci_temp;
+
+		queue_work(driver->diag_dci_wq,
+			&(driver->diag_update_smd_dci_work));
+
+		/* Notify the clients of the open */
+		diag_dci_notify_client(DIAG_CON_MPSS, DIAG_STATUS_OPEN);
+	}
+
+	queue_work(driver->diag_dci_wq, &(driver->diag_read_smd_dci_work));
+}
+
 static int diag_dci_probe(struct platform_device *pdev)
 {
 	int err = 0;
@@ -339,12 +413,11 @@
 			pr_err("diag: cannot open DCI port, Id = %d, err ="
 				" %d\n", pdev->id, err);
 		else
-			diag_dci_notify_client(DIAG_CON_MPSS);
+			ch_dci_temp = driver->ch_dci;
 	}
 	return err;
 }
 
-
 int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
 					 int len, int index)
 {
@@ -414,6 +487,11 @@
 	uint8_t *event_mask_ptr;
 	int offset = 0;
 
+	if (!driver->ch_dci) {
+		pr_err("diag: ch_dci not valid for dci updates\n");
+		return DIAG_DCI_SEND_DATA_FAIL;
+	}
+
 	/* This is Pkt request/response transaction */
 	if (*(int *)temp > 0) {
 		/* enter this UID into kernel table and return index */
@@ -535,7 +613,7 @@
 			ret = DIAG_DCI_NO_ERROR;
 		}
 		/* send updated mask to peripherals */
-		diag_send_dci_log_mask(driver->ch_cntl);
+		ret = diag_send_dci_log_mask(driver->ch_cntl);
 	} else if (*(int *)temp == DCI_EVENT_TYPE) {
 		/* find client id and table */
 		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
@@ -581,7 +659,7 @@
 			ret = DIAG_DCI_NO_ERROR;
 		}
 		/* send updated mask to peripherals */
-		diag_send_dci_event_mask(driver->ch_cntl);
+		ret = diag_send_dci_event_mask(driver->ch_cntl);
 	} else {
 		pr_alert("diag: Incorrect DCI transaction\n");
 	}
@@ -614,11 +692,12 @@
 	mutex_unlock(&dci_event_mask_mutex);
 }
 
-void diag_send_dci_event_mask(smd_channel_t *ch)
+int diag_send_dci_event_mask(smd_channel_t *ch)
 {
 	void *buf = driver->buf_event_mask_update;
 	int header_size = sizeof(struct diag_ctrl_event_mask);
 	int wr_size = -ENOMEM, retry_count = 0, timer;
+	int ret = DIAG_DCI_NO_ERROR;
 
 	mutex_lock(&driver->diag_cntl_mutex);
 	/* send event mask update */
@@ -642,12 +721,18 @@
 				break;
 			}
 		}
-		if (wr_size != header_size + DCI_EVENT_MASK_SIZE)
+		if (wr_size != header_size + DCI_EVENT_MASK_SIZE) {
 			pr_err("diag: error writing dci event mask %d, tried %d\n",
 				 wr_size, header_size + DCI_EVENT_MASK_SIZE);
-	} else
+			ret = DIAG_DCI_SEND_DATA_FAIL;
+		}
+	} else {
 		pr_err("diag: ch not valid for dci event mask update\n");
+		ret = DIAG_DCI_SEND_DATA_FAIL;
+	}
 	mutex_unlock(&driver->diag_cntl_mutex);
+
+	return ret;
 }
 
 void update_dci_cumulative_log_mask(int offset, int byte_index,
@@ -686,12 +771,18 @@
 	mutex_unlock(&dci_log_mask_mutex);
 }
 
-void diag_send_dci_log_mask(smd_channel_t *ch)
+int diag_send_dci_log_mask(smd_channel_t *ch)
 {
 	void *buf = driver->buf_log_mask_update;
 	int header_size = sizeof(struct diag_ctrl_log_mask);
 	uint8_t *log_mask_ptr = dci_cumulative_log_mask;
 	int i, wr_size = -ENOMEM, retry_count = 0, timer;
+	int ret = DIAG_DCI_NO_ERROR;
+
+	if (!ch) {
+		pr_err("diag: ch not valid for dci log mask update\n");
+		return DIAG_DCI_SEND_DATA_FAIL;
+	}
 
 	mutex_lock(&driver->diag_cntl_mutex);
 	for (i = 0; i < 16; i++) {
@@ -715,10 +806,12 @@
 				} else
 					break;
 			}
-			if (wr_size != header_size + 512)
+			if (wr_size != header_size + 512) {
 				pr_err("diag: dci log mask update failed %d, tried %d",
 					 wr_size, header_size + 512);
-			else {
+				ret = DIAG_DCI_SEND_DATA_FAIL;
+
+			} else {
 				*(log_mask_ptr+1) = 0; /* clear dirty byte */
 				pr_debug("diag: updated dci log equip ID %d\n",
 						 *log_mask_ptr);
@@ -727,6 +820,8 @@
 		log_mask_ptr += 514;
 	}
 	mutex_unlock(&driver->diag_cntl_mutex);
+
+	return ret;
 }
 
 void create_dci_log_mask_tbl(unsigned char *tbl_buf)
@@ -778,6 +873,8 @@
 {
 	int success = 0;
 
+	ch_dci_temp = NULL;
+
 	driver->dci_tag = 0;
 	driver->dci_client_id = 0;
 	driver->num_dci_client = 0;
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 435c750..3f62e5e 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -79,6 +79,7 @@
 int diag_dci_init(void);
 void diag_dci_exit(void);
 void diag_read_smd_dci_work_fn(struct work_struct *);
+void diag_update_smd_dci_work_fn(struct work_struct *);
 int diag_process_dci_transaction(unsigned char *buf, int len);
 int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
 							 int len, int index);
@@ -87,11 +88,11 @@
 void create_dci_log_mask_tbl(unsigned char *tbl_buf);
 void update_dci_cumulative_log_mask(int offset, int byte_index,
 						uint8_t byte_mask);
-void diag_send_dci_log_mask(smd_channel_t *ch);
+int diag_send_dci_log_mask(smd_channel_t *ch);
 void extract_dci_log(unsigned char *buf);
 /* DCI event streaming functions */
 void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask);
-void diag_send_dci_event_mask(smd_channel_t *ch);
+int diag_send_dci_event_mask(smd_channel_t *ch);
 void extract_dci_events(unsigned char *buf);
 void create_dci_event_mask_tbl(unsigned char *tbl_buf);
 #endif
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 7863f74..c404229 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -113,7 +113,8 @@
 		"diag_modem_mask_update_work: %d\n"
 		"diag_lpass_mask_update_work: %d\n"
 		"diag_wcnss_mask_update_work: %d\n"
-		"diag_read_smd_dci_work: %d\n",
+		"diag_read_smd_dci_work: %d\n"
+		"diag_update_smd_dci_work: %d\n",
 		work_pending(&(driver->diag_drain_work)),
 		work_pending(&(driver->diag_read_smd_work)),
 		work_pending(&(driver->diag_read_smd_cntl_work)),
@@ -124,7 +125,8 @@
 		work_pending(&(driver->diag_modem_mask_update_work)),
 		work_pending(&(driver->diag_lpass_mask_update_work)),
 		work_pending(&(driver->diag_wcnss_mask_update_work)),
-		work_pending(&(driver->diag_read_smd_dci_work)));
+		work_pending(&(driver->diag_read_smd_dci_work)),
+		work_pending(&(driver->diag_update_smd_dci_work)));
 
 #ifdef CONFIG_DIAG_OVER_USB
 	ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index d1ec5f2..ec3bb81 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -67,6 +67,15 @@
 #define DIAG_CON_LPASS (0x0004)	/* Bit mask for LPASS */
 #define DIAG_CON_WCNSS (0x0008)	/* Bit mask for WCNSS */
 
+/*
+ * The status bit masks when received in a signal handler are to be
+ * used in conjunction with the peripheral list bit mask to determine the
+ * status for a peripheral. For instance, 0x00010002 would denote an open
+ * status on the MPSS
+ */
+#define DIAG_STATUS_OPEN (0x00010000)	/* DCI channel open status mask   */
+#define DIAG_STATUS_CLOSED (0x00020000)	/* DCI channel closed status mask */
+
 /* Maximum number of pkt reg supported at initialization*/
 extern unsigned int diag_max_reg;
 extern unsigned int diag_threshold_reg;
@@ -235,6 +244,7 @@
 	struct work_struct diag_lpass_mask_update_work;
 	struct work_struct diag_wcnss_mask_update_work;
 	struct work_struct diag_read_smd_dci_work;
+	struct work_struct diag_update_smd_dci_work;
 	struct work_struct diag_clean_modem_reg_work;
 	struct work_struct diag_clean_lpass_reg_work;
 	struct work_struct diag_clean_wcnss_reg_work;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 645d916..34ff345 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1613,7 +1613,9 @@
 		INIT_WORK(&(driver->diag_read_smd_wcnss_cntl_work),
 			diag_read_smd_wcnss_cntl_work_fn);
 		INIT_WORK(&(driver->diag_read_smd_dci_work),
-						 diag_read_smd_dci_work_fn);
+						diag_read_smd_dci_work_fn);
+		INIT_WORK(&(driver->diag_update_smd_dci_work),
+						diag_update_smd_dci_work_fn);
 		INIT_WORK(&(driver->diag_clean_modem_reg_work),
 						 diag_clean_modem_reg_fn);
 		INIT_WORK(&(driver->diag_clean_lpass_reg_work),
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
new file mode 100644
index 0000000..6c8dd6d
--- /dev/null
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -0,0 +1,179 @@
+/*
+ * drivers/gpu/ion/ion_cma_heap.c
+ *
+ * Copyright (C) Linaro 2012
+ * Author: <benjamin.gaignard@linaro.org> for ST-Ericsson.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/ion.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+
+/* for ion_heap_ops structure */
+#include "ion_priv.h"
+
+#define ION_CMA_ALLOCATE_FAILED -1
+
+struct ion_cma_buffer_info {
+	void *cpu_addr;
+	dma_addr_t handle;
+	struct sg_table *table;
+};
+
+/*
+ * Create scatter-list for the already allocated DMA buffer.
+ * This function could be replace by dma_common_get_sgtable
+ * as soon as it will avalaible.
+ */
+int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt,
+			void *cpu_addr, dma_addr_t handle, size_t size)
+{
+	struct page *page = virt_to_page(cpu_addr);
+	int ret;
+
+	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
+	if (unlikely(ret))
+		return ret;
+
+	sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
+	return 0;
+}
+
+/* ION CMA heap operations functions */
+static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
+			    unsigned long len, unsigned long align,
+			    unsigned long flags)
+{
+	struct device *dev = heap->priv;
+	struct ion_cma_buffer_info *info;
+
+	dev_dbg(dev, "Request buffer allocation len %ld\n", len);
+
+	info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL);
+	if (!info) {
+		dev_err(dev, "Can't allocate buffer info\n");
+		return ION_CMA_ALLOCATE_FAILED;
+	}
+
+	info->cpu_addr = dma_alloc_coherent(dev, len, &(info->handle), 0);
+
+	if (!info->cpu_addr) {
+		dev_err(dev, "Fail to allocate buffer\n");
+		goto err;
+	}
+
+	info->table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!info->table) {
+		dev_err(dev, "Fail to allocate sg table\n");
+		goto err;
+	}
+
+	ion_cma_get_sgtable(dev,
+			info->table, info->cpu_addr, info->handle, len);
+
+	/* keep this for memory release */
+	buffer->priv_virt = info;
+	dev_dbg(dev, "Allocate buffer %p\n", buffer);
+	return 0;
+
+err:
+	kfree(info);
+	return ION_CMA_ALLOCATE_FAILED;
+}
+
+static void ion_cma_free(struct ion_buffer *buffer)
+{
+	struct device *dev = buffer->heap->priv;
+	struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+	dev_dbg(dev, "Release buffer %p\n", buffer);
+	/* release memory */
+	dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
+	/* release sg table */
+	kfree(info->table);
+	kfree(info);
+}
+
+/* return physical address in addr */
+static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer,
+			ion_phys_addr_t *addr, size_t *len)
+{
+	struct device *dev = heap->priv;
+	struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+	dev_dbg(dev, "Return buffer %p physical address 0x%x\n", buffer,
+		virt_to_phys(info->cpu_addr));
+
+	*addr = virt_to_phys(info->cpu_addr);
+	*len = buffer->size;
+
+	return 0;
+}
+
+struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap,
+					 struct ion_buffer *buffer)
+{
+	struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+	return info->table;
+}
+
+void ion_cma_heap_unmap_dma(struct ion_heap *heap,
+			       struct ion_buffer *buffer)
+{
+	return;
+}
+
+static int ion_cma_mmap(struct ion_heap *mapper, struct ion_buffer *buffer,
+			struct vm_area_struct *vma)
+{
+	struct device *dev = buffer->heap->priv;
+	struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+	return dma_mmap_coherent(dev, vma, info->cpu_addr, info->handle,
+				 buffer->size);
+}
+
+static struct ion_heap_ops ion_cma_ops = {
+	.allocate = ion_cma_allocate,
+	.free = ion_cma_free,
+	.map_dma = ion_cma_heap_map_dma,
+	.unmap_dma = ion_cma_heap_unmap_dma,
+	.phys = ion_cma_phys,
+	.map_user = ion_cma_mmap,
+};
+
+struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data)
+{
+	struct ion_heap *heap;
+
+	heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
+
+	if (!heap)
+		return ERR_PTR(-ENOMEM);
+
+	heap->ops = &ion_cma_ops;
+	/* set device as private heaps data, later it will be
+	 * used to make the link with reserved CMA memory */
+	heap->priv = data->priv;
+	heap->type = ION_HEAP_TYPE_DMA;
+	return heap;
+}
+
+void ion_cma_heap_destroy(struct ion_heap *heap)
+{
+	kfree(heap);
+}
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 4c83d75..0670468 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -40,6 +40,11 @@
 	case ION_HEAP_TYPE_CP:
 		heap = ion_cp_heap_create(heap_data);
 		break;
+#ifdef CONFIG_CMA
+	case ION_HEAP_TYPE_DMA:
+		heap = ion_cma_heap_create(heap_data);
+		break;
+#endif
 	default:
 		pr_err("%s: Invalid heap type %d\n", __func__,
 		       heap_data->type);
@@ -55,6 +60,7 @@
 
 	heap->name = heap_data->name;
 	heap->id = heap_data->id;
+	heap->priv = heap_data->priv;
 	return heap;
 }
 
@@ -79,6 +85,11 @@
 	case ION_HEAP_TYPE_CP:
 		ion_cp_heap_destroy(heap);
 		break;
+#ifdef CONFIG_CMA
+	case ION_HEAP_TYPE_DMA:
+		ion_cma_heap_destroy(heap);
+		break;
+#endif
 	default:
 		pr_err("%s: Invalid heap type %d\n", __func__,
 		       heap->type);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 991a310..7713875 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -162,6 +162,7 @@
  *			allocating.  These are specified by platform data and
  *			MUST be unique
  * @name:		used for debugging
+ * @priv:		private heap data
  *
  * Represents a pool of memory from which buffers can be made.  In some
  * systems the only heap is regular system memory allocated via vmalloc.
@@ -175,6 +176,7 @@
 	struct ion_heap_ops *ops;
 	int id;
 	const char *name;
+	void *priv;
 };
 
 /**
@@ -257,6 +259,10 @@
 void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
 		       unsigned long size);
 
+#ifdef CONFIG_CMA
+struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *);
+void ion_cma_heap_destroy(struct ion_heap *);
+#endif
 
 struct ion_heap *msm_get_contiguous_heap(void);
 /**
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 8699178..e422fd26 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -424,6 +424,7 @@
 	unsigned int i;
 	for (i = 0; i < pdata->nr; ++i)
 		kfree(pdata->heaps[i].extra_data);
+	kfree(pdata->heaps);
 	kfree(pdata);
 }
 
@@ -553,6 +554,7 @@
 					const struct device_node *dt_node)
 {
 	struct ion_platform_data *pdata = 0;
+	struct ion_platform_heap *heaps = NULL;
 	struct device_node *node;
 	uint32_t val = 0;
 	int ret = 0;
@@ -565,11 +567,17 @@
 	if (!num_heaps)
 		return ERR_PTR(-EINVAL);
 
-	pdata = kzalloc(sizeof(struct ion_platform_data) +
-			num_heaps*sizeof(struct ion_platform_heap), GFP_KERNEL);
+	pdata = kzalloc(sizeof(struct ion_platform_data), GFP_KERNEL);
 	if (!pdata)
 		return ERR_PTR(-ENOMEM);
 
+	heaps = kzalloc(sizeof(struct ion_platform_heap)*num_heaps, GFP_KERNEL);
+	if (!heaps) {
+		kfree(pdata);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pdata->heaps = heaps;
 	pdata->nr = num_heaps;
 
 	for_each_child_of_node(dt_node, node) {
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index fa66e96..060e89a 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -393,13 +393,6 @@
 		*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
 		*cmds++ = 0x7fff;
 		sizedwords += 2;
-		/*
-		 * add an interrupt at the end of commands so that the smmu
-		 * disable clock off function will get called
-		 */
-		*cmds++ = cp_type3_packet(CP_INTERRUPT, 1);
-		*cmds++ = CP_INT_CNTL__RB_INT_MASK;
-		sizedwords += 2;
 		/* This returns the per context timestamp but we need to
 		 * use the global timestamp for iommu clock disablement */
 		adreno_ringbuffer_issuecmds(device, adreno_ctx,
@@ -2097,6 +2090,67 @@
 	return context_id;
 }
 
+static void adreno_next_event(struct kgsl_device *device,
+		struct kgsl_event *event)
+{
+	int status;
+	unsigned int ref_ts, enableflag;
+	unsigned int context_id = _get_context_id(event->context);
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	status = kgsl_check_timestamp(device, event->context, event->timestamp);
+	if (!status) {
+		kgsl_sharedmem_readl(&device->memstore, &enableflag,
+			KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
+		/*
+		 * Barrier is needed here to make sure the read from memstore
+		 * has posted
+		 */
+
+		mb();
+
+		if (enableflag) {
+			kgsl_sharedmem_readl(&device->memstore, &ref_ts,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					ref_wait_ts));
+
+			/* Make sure the memstore read has posted */
+			mb();
+			if (timestamp_cmp(ref_ts, event->timestamp) >= 0) {
+				kgsl_sharedmem_writel(&device->memstore,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					ref_wait_ts), event->timestamp);
+				/* Make sure the memstore write is posted */
+				wmb();
+			}
+		} else {
+			unsigned int cmds[2];
+			kgsl_sharedmem_writel(&device->memstore,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					ref_wait_ts), event->timestamp);
+			enableflag = 1;
+			kgsl_sharedmem_writel(&device->memstore,
+				KGSL_MEMSTORE_OFFSET(context_id,
+					ts_cmp_enable), enableflag);
+
+			/* Make sure the memstore write gets posted */
+			wmb();
+
+			/*
+			 * submit a dummy packet so that even if all
+			 * commands upto timestamp get executed we will still
+			 * get an interrupt
+			 */
+			cmds[0] = cp_type3_packet(CP_NOP, 1);
+			cmds[1] = 0;
+
+			if (adreno_dev->drawctxt_active)
+				adreno_ringbuffer_issuecmds_intr(device,
+						event->context, &cmds[0], 2);
+		}
+	}
+}
+
 static int kgsl_check_interrupt_timestamp(struct kgsl_device *device,
 		struct kgsl_context *context, unsigned int timestamp)
 {
@@ -2606,6 +2660,7 @@
 	.drawctxt_destroy = adreno_drawctxt_destroy,
 	.setproperty = adreno_setproperty,
 	.postmortem_dump = adreno_dump,
+	.next_event = adreno_next_event,
 };
 
 static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index e069fa5..6e0d6ad 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/vmalloc.h>
+#include <mach/board.h>
 
 #include "kgsl.h"
 #include "kgsl_sharedmem.h"
@@ -737,6 +738,8 @@
 
 	mb();
 
+	msm_clk_dump_debug_info();
+
 	if (adreno_is_a2xx(adreno_dev))
 		adreno_dump_a2xx(device);
 	else if (adreno_is_a3xx(adreno_dev))
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index ed9d00f..deafa7a 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -28,6 +28,7 @@
 #include <linux/msm_ion.h>
 #include <linux/io.h>
 #include <mach/socinfo.h>
+#include <linux/mman.h>
 
 #include "kgsl.h"
 #include "kgsl_debugfs.h"
@@ -323,9 +324,19 @@
 }
 EXPORT_SYMBOL(kgsl_mem_entry_destroy);
 
-static
-void kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
-				   struct kgsl_process_private *process)
+/**
+ * kgsl_mem_entry_track_gpuaddr - Insert a mem_entry in the address tree
+ * @process: the process that owns the memory
+ * @entry: the memory entry
+ *
+ * Insert a kgsl_mem_entry in to the rb_tree for searching by GPU address.
+ * Not all mem_entries will have gpu addresses when first created, so this
+ * function may be called after creation when the GPU address is finally
+ * assigned.
+ */
+static void
+kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process,
+				struct kgsl_mem_entry *entry)
 {
 	struct rb_node **node;
 	struct rb_node *parent = NULL;
@@ -350,8 +361,48 @@
 	rb_insert_color(&entry->node, &process->mem_rb);
 
 	spin_unlock(&process->mem_lock);
+}
 
+/**
+ * kgsl_mem_entry_attach_process - Attach a mem_entry to its owner process
+ * @entry: the memory entry
+ * @process: the owner process
+ *
+ * Attach a newly created mem_entry to its owner process so that
+ * it can be found later. The mem_entry will be added to mem_idr and have
+ * its 'id' field assigned. If the GPU address has been set, the entry
+ * will also be added to the mem_rb tree.
+ *
+ * @returns - 0 on success or error code on failure.
+ */
+static int
+kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
+				   struct kgsl_process_private *process)
+{
+	int ret;
+
+	while (1) {
+		if (idr_pre_get(&process->mem_idr, GFP_KERNEL) == 0) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		spin_lock(&process->mem_lock);
+		ret = idr_get_new_above(&process->mem_idr, entry, 1,
+					&entry->id);
+		spin_unlock(&process->mem_lock);
+
+		if (ret == 0)
+			break;
+		else if (ret != -EAGAIN)
+			goto err;
+	}
 	entry->priv = process;
+
+	if (entry->memdesc.gpuaddr != 0)
+		kgsl_mem_entry_track_gpuaddr(process, entry);
+err:
+	return ret;
 }
 
 /* Detach a memory entry from a process and unmap it from the MMU */
@@ -361,6 +412,17 @@
 	if (entry == NULL)
 		return;
 
+	spin_lock(&entry->priv->mem_lock);
+
+	if (entry->id != 0)
+		idr_remove(&entry->priv->mem_idr, entry->id);
+	entry->id = 0;
+
+	if (entry->memdesc.gpuaddr != 0)
+		rb_erase(&entry->node, &entry->priv->mem_rb);
+
+	spin_unlock(&entry->priv->mem_lock);
+
 	entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
 	entry->priv = NULL;
 
@@ -504,6 +566,22 @@
 		kfree(event);
 	}
 
+	/* Send the next pending event for each context to the device */
+	if (device->ftbl->next_event) {
+		unsigned int id = KGSL_MEMSTORE_GLOBAL;
+
+		list_for_each_entry(event, &device->events, list) {
+
+			if (!event->context)
+				continue;
+
+			if (event->context->id != id) {
+				device->ftbl->next_event(device, event);
+				id = event->context->id;
+			}
+		}
+	}
+
 	mutex_unlock(&device->mutex);
 }
 EXPORT_SYMBOL(kgsl_timestamp_expired);
@@ -761,6 +839,8 @@
 	private->pid = task_tgid_nr(current);
 	private->mem_rb = RB_ROOT;
 
+	idr_init(&private->mem_idr);
+
 	if (kgsl_mmu_enabled())
 	{
 		unsigned long pt_name;
@@ -789,7 +869,7 @@
 			 struct kgsl_process_private *private)
 {
 	struct kgsl_mem_entry *entry = NULL;
-	struct rb_node *node;
+	int next = 0;
 
 	if (!private)
 		return;
@@ -804,14 +884,22 @@
 
 	list_del(&private->list);
 
-	for (node = rb_first(&private->mem_rb); node; ) {
-		entry = rb_entry(node, struct kgsl_mem_entry, node);
-		node = rb_next(&entry->node);
-
-		rb_erase(&entry->node, &private->mem_rb);
+	while (1) {
+		rcu_read_lock();
+		entry = idr_get_next(&private->mem_idr, &next);
+		rcu_read_unlock();
+		if (entry == NULL)
+			break;
 		kgsl_mem_entry_detach_process(entry);
+		/*
+		 * Always start back at the beginning, to
+		 * ensure all entries are removed,
+		 * like list_for_each_entry_safe.
+		 */
+		next = 0;
 	}
 	kgsl_mmu_putpagetable(private->pagetable);
+	idr_destroy(&private->mem_idr);
 	kfree(private);
 unlock:
 	mutex_unlock(&kgsl_driver.process_mutex);
@@ -990,6 +1078,77 @@
 	return kgsl_sharedmem_find_region(private, gpuaddr, 1);
 }
 
+/**
+ * kgsl_sharedmem_region_empty - Check if an addression region is empty
+ *
+ * @private: private data for the process to check.
+ * @gpuaddr: start address of the region
+ * @size: length of the region.
+ *
+ * Checks that there are no existing allocations within an address
+ * region. Note that unlike other kgsl_sharedmem* search functions,
+ * this one manages locking on its own.
+ */
+int
+kgsl_sharedmem_region_empty(struct kgsl_process_private *private,
+	unsigned int gpuaddr, size_t size)
+{
+	int result = 1;
+	unsigned int gpuaddr_end = gpuaddr + size;
+
+	struct rb_node *node = private->mem_rb.rb_node;
+
+	if (!kgsl_mmu_gpuaddr_in_range(gpuaddr))
+		return 0;
+
+	/* don't overflow */
+	if (gpuaddr_end < gpuaddr)
+		return 0;
+
+	spin_lock(&private->mem_lock);
+	node = private->mem_rb.rb_node;
+	while (node != NULL) {
+		struct kgsl_mem_entry *entry;
+		unsigned int memdesc_start, memdesc_end;
+
+		entry = rb_entry(node, struct kgsl_mem_entry, node);
+
+		memdesc_start = entry->memdesc.gpuaddr;
+		memdesc_end = memdesc_start
+				+ kgsl_memdesc_mmapsize(&entry->memdesc);
+
+		if (gpuaddr_end <= memdesc_start)
+			node = node->rb_left;
+		else if (memdesc_end <= gpuaddr)
+			node = node->rb_right;
+		else {
+			result = 0;
+			break;
+		}
+	}
+	spin_unlock(&private->mem_lock);
+	return result;
+}
+
+/**
+ * kgsl_sharedmem_find_id - find a memory entry by id
+ * @process: the owning process
+ * @id: id to find
+ *
+ * @returns - the mem_entry or NULL
+ */
+static inline struct kgsl_mem_entry *
+kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id)
+{
+	struct kgsl_mem_entry *entry;
+
+	rcu_read_lock();
+	entry = idr_find(&process->mem_idr, id);
+	rcu_read_unlock();
+
+	return entry;
+}
+
 /*call all ioctl sub functions with driver locked*/
 static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
 					  unsigned int cmd, void *data)
@@ -1277,9 +1436,6 @@
 	void *priv, u32 id, u32 timestamp)
 {
 	struct kgsl_mem_entry *entry = priv;
-	spin_lock(&entry->priv->mem_lock);
-	rb_erase(&entry->node, &entry->priv->mem_rb);
-	spin_unlock(&entry->priv->mem_lock);
 	trace_kgsl_mem_timestamp_free(device, entry, id, timestamp, 0);
 	kgsl_mem_entry_detach_process(entry);
 }
@@ -1391,34 +1547,52 @@
 static long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv,
 					unsigned int cmd, void *data)
 {
-	int result = 0;
 	struct kgsl_sharedmem_free *param = data;
 	struct kgsl_process_private *private = dev_priv->process_priv;
 	struct kgsl_mem_entry *entry = NULL;
 
 	spin_lock(&private->mem_lock);
 	entry = kgsl_sharedmem_find(private, param->gpuaddr);
-	if (entry)
-		rb_erase(&entry->node, &private->mem_rb);
-
 	spin_unlock(&private->mem_lock);
 
-	if (entry) {
-		trace_kgsl_mem_free(entry);
-
-		kgsl_memfree_hist_set_event(
-			entry->priv->pid,
-			entry->memdesc.gpuaddr,
-			entry->memdesc.size,
-			entry->memdesc.flags);
-
-		kgsl_mem_entry_detach_process(entry);
-	} else {
-		KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
-		result = -EINVAL;
+	if (!entry) {
+		KGSL_MEM_INFO(dev_priv->device, "invalid gpuaddr %08x\n",
+				param->gpuaddr);
+		return -EINVAL;
 	}
+	trace_kgsl_mem_free(entry);
 
-	return result;
+	kgsl_memfree_hist_set_event(entry->priv->pid,
+				    entry->memdesc.gpuaddr,
+				    entry->memdesc.size,
+				    entry->memdesc.flags);
+
+	kgsl_mem_entry_detach_process(entry);
+	return 0;
+}
+
+static long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv,
+					unsigned int cmd, void *data)
+{
+	struct kgsl_gpumem_free_id *param = data;
+	struct kgsl_process_private *private = dev_priv->process_priv;
+	struct kgsl_mem_entry *entry = NULL;
+
+	entry = kgsl_sharedmem_find_id(private, param->id);
+
+	if (!entry) {
+		KGSL_MEM_INFO(dev_priv->device, "invalid id %d\n", param->id);
+		return -EINVAL;
+	}
+	trace_kgsl_mem_free(entry);
+
+	kgsl_memfree_hist_set_event(entry->priv->pid,
+				    entry->memdesc.gpuaddr,
+				    entry->memdesc.size,
+				    entry->memdesc.flags);
+
+	kgsl_mem_entry_detach_process(entry);
+	return 0;
 }
 
 static struct vm_area_struct *kgsl_get_vma_from_start_addr(unsigned int addr)
@@ -1527,6 +1701,8 @@
 	entry->memdesc.size = size;
 	entry->memdesc.physaddr = phys + offset;
 	entry->memdesc.hostptr = (void *) (virt + offset);
+	/* USE_CPU_MAP is not impemented for PMEM. */
+	entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
 
 	ret = memdesc_sg_phys(&entry->memdesc, phys + offset, size);
 	if (ret)
@@ -1643,6 +1819,8 @@
 	entry->memdesc.pagetable = pagetable;
 	entry->memdesc.size = size;
 	entry->memdesc.useraddr = useraddr + (offset & PAGE_MASK);
+	if (kgsl_memdesc_use_cpu_map(&entry->memdesc))
+		entry->memdesc.gpuaddr = entry->memdesc.useraddr;
 
 	return memdesc_sg_virt(&entry->memdesc, entry->memdesc.useraddr,
 				size);
@@ -1695,6 +1873,8 @@
 	entry->memdesc.pagetable = pagetable;
 	entry->memdesc.size = ALIGN(size, PAGE_SIZE);
 	entry->memdesc.useraddr = useraddr;
+	if (kgsl_memdesc_use_cpu_map(&entry->memdesc))
+		entry->memdesc.gpuaddr = entry->memdesc.useraddr;
 
 	ret = memdesc_sg_virt(&entry->memdesc, useraddr, size);
 	if (ret)
@@ -1740,6 +1920,8 @@
 	entry->priv_data = handle;
 	entry->memdesc.pagetable = pagetable;
 	entry->memdesc.size = 0;
+	/* USE_CPU_MAP is not impemented for ION. */
+	entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
 
 	sg_table = ion_sg_table(kgsl_ion_client, handle);
 
@@ -1763,6 +1945,13 @@
 	return -ENOMEM;
 }
 
+static inline int
+can_use_cpu_map(void)
+{
+	return (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU
+		&& kgsl_mmu_is_perprocess());
+}
+
 static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
 				     unsigned int cmd, void *data)
 {
@@ -1782,7 +1971,20 @@
 	else
 		memtype = param->memtype;
 
+	/*
+	 * Mask off unknown flags from userspace. This way the caller can
+	 * check if a flag is supported by looking at the returned flags.
+	 * Note: CACHEMODE is ignored for this call. Caching should be
+	 * determined by type of allocation being mapped.
+	 */
+	param->flags &= KGSL_MEMFLAGS_GPUREADONLY
+			| KGSL_MEMTYPE_MASK
+			| KGSL_MEMALIGN_MASK
+			| KGSL_MEMFLAGS_USE_CPU_MAP;
+
 	entry->memdesc.flags = param->flags;
+	if (!can_use_cpu_map())
+		entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
 
 	switch (memtype) {
 	case KGSL_USER_MEM_TYPE_PMEM:
@@ -1856,18 +2058,25 @@
 
 	/* Adjust the returned value for a non 4k aligned offset */
 	param->gpuaddr = entry->memdesc.gpuaddr + (param->offset & ~PAGE_MASK);
+	/* echo back flags */
+	param->flags = entry->memdesc.flags;
+
+	result = kgsl_mem_entry_attach_process(entry, private);
+	if (result)
+		goto error_unmap;
 
 	KGSL_STATS_ADD(param->len, kgsl_driver.stats.mapped,
 		kgsl_driver.stats.mapped_max);
 
 	kgsl_process_add_stats(private, entry->memtype, param->len);
 
-	kgsl_mem_entry_attach_process(entry, private);
 	trace_kgsl_mem_map(entry, param->fd);
 
 	kgsl_check_idle(dev_priv->device);
 	return result;
 
+error_unmap:
+	kgsl_mmu_unmap(private->pagetable, &entry->memdesc);
 error_put_file_ptr:
 	switch (entry->memtype) {
 	case KGSL_MEM_ENTRY_PMEM:
@@ -1887,33 +2096,134 @@
 	return result;
 }
 
-/*This function flushes a graphics memory allocation from CPU cache
- *when caching is enabled with MMU*/
+static int _kgsl_gpumem_sync_cache(struct kgsl_mem_entry *entry, int op)
+{
+	int ret = 0;
+	int cacheop;
+	int mode;
+
+	/*
+	 * Flush is defined as (clean | invalidate).  If both bits are set, then
+	 * do a flush, otherwise check for the individual bits and clean or inv
+	 * as requested
+	 */
+
+	if ((op & KGSL_GPUMEM_CACHE_FLUSH) == KGSL_GPUMEM_CACHE_FLUSH)
+		cacheop = KGSL_CACHE_OP_FLUSH;
+	else if (op & KGSL_GPUMEM_CACHE_CLEAN)
+		cacheop = KGSL_CACHE_OP_CLEAN;
+	else if (op & KGSL_GPUMEM_CACHE_INV)
+		cacheop = KGSL_CACHE_OP_INV;
+	else {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	mode = kgsl_memdesc_get_cachemode(&entry->memdesc);
+	if (mode != KGSL_CACHEMODE_UNCACHED
+		&& mode != KGSL_CACHEMODE_WRITECOMBINE)
+		kgsl_cache_range_op(&entry->memdesc, cacheop);
+
+done:
+	return ret;
+}
+
+/* New cache sync function - supports both directions (clean and invalidate) */
+
+static long
+kgsl_ioctl_gpumem_sync_cache(struct kgsl_device_private *dev_priv,
+	unsigned int cmd, void *data)
+{
+	struct kgsl_gpumem_sync_cache *param = data;
+	struct kgsl_process_private *private = dev_priv->process_priv;
+	struct kgsl_mem_entry *entry = NULL;
+
+	if (param->id != 0) {
+		entry = kgsl_sharedmem_find_id(private, param->id);
+		if (entry == NULL) {
+			KGSL_MEM_INFO(dev_priv->device, "can't find id %d\n",
+					param->id);
+			return -EINVAL;
+		}
+	} else if (param->gpuaddr != 0) {
+		spin_lock(&private->mem_lock);
+		entry = kgsl_sharedmem_find(private, param->gpuaddr);
+		spin_unlock(&private->mem_lock);
+		if (entry == NULL) {
+			KGSL_MEM_INFO(dev_priv->device,
+					"can't find gpuaddr %x\n",
+					param->gpuaddr);
+			return -EINVAL;
+		}
+	} else {
+		return -EINVAL;
+	}
+
+	return _kgsl_gpumem_sync_cache(entry, param->op);
+}
+
+/* Legacy cache function, does a flush (clean  + invalidate) */
+
 static long
 kgsl_ioctl_sharedmem_flush_cache(struct kgsl_device_private *dev_priv,
 				 unsigned int cmd, void *data)
 {
-	int result = 0;
-	struct kgsl_mem_entry *entry;
 	struct kgsl_sharedmem_free *param = data;
 	struct kgsl_process_private *private = dev_priv->process_priv;
+	struct kgsl_mem_entry *entry = NULL;
 
 	spin_lock(&private->mem_lock);
 	entry = kgsl_sharedmem_find(private, param->gpuaddr);
-	if (!entry) {
-		KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
-		result = -EINVAL;
-		goto done;
-	}
-	if (!entry->memdesc.hostptr) {
-		KGSL_CORE_ERR("invalid hostptr with gpuaddr %08x\n",
-			param->gpuaddr);
-			goto done;
+	spin_unlock(&private->mem_lock);
+	if (entry == NULL) {
+		KGSL_MEM_INFO(dev_priv->device,
+				"can't find gpuaddr %x\n",
+				param->gpuaddr);
+		return -EINVAL;
 	}
 
-	kgsl_cache_range_op(&entry->memdesc, KGSL_CACHE_OP_CLEAN);
-done:
-	spin_unlock(&private->mem_lock);
+	return _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+}
+
+/*
+ * The common parts of kgsl_ioctl_gpumem_alloc and kgsl_ioctl_gpumem_alloc_id.
+ */
+int
+_gpumem_alloc(struct kgsl_device_private *dev_priv,
+		struct kgsl_mem_entry **ret_entry,
+		unsigned int size, unsigned int flags)
+{
+	int result;
+	struct kgsl_process_private *private = dev_priv->process_priv;
+	struct kgsl_mem_entry *entry;
+
+	/*
+	 * Mask off unknown flags from userspace. This way the caller can
+	 * check if a flag is supported by looking at the returned flags.
+	 */
+	flags &= KGSL_MEMFLAGS_GPUREADONLY
+		| KGSL_CACHEMODE_MASK
+		| KGSL_MEMTYPE_MASK
+		| KGSL_MEMALIGN_MASK
+		| KGSL_MEMFLAGS_USE_CPU_MAP;
+
+	entry = kgsl_mem_entry_create();
+	if (entry == NULL)
+		return -ENOMEM;
+
+	result = kgsl_allocate_user(&entry->memdesc, private->pagetable, size,
+				    flags);
+	if (result != 0)
+		goto err;
+
+	entry->memtype = KGSL_MEM_ENTRY_KERNEL;
+
+	kgsl_check_idle(dev_priv->device);
+	*ret_entry = entry;
+	return result;
+err:
+	kfree(entry);
+	*ret_entry = NULL;
 	return result;
 }
 
@@ -1923,29 +2233,117 @@
 {
 	struct kgsl_process_private *private = dev_priv->process_priv;
 	struct kgsl_gpumem_alloc *param = data;
-	struct kgsl_mem_entry *entry;
+	struct kgsl_mem_entry *entry = NULL;
 	int result;
 
-	entry = kgsl_mem_entry_create();
-	if (entry == NULL)
-		return -ENOMEM;
+	param->flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
+	result = _gpumem_alloc(dev_priv, &entry, param->size, param->flags);
+	if (result)
+		return result;
 
-	result = kgsl_allocate_user(&entry->memdesc, private->pagetable,
-		param->size, param->flags);
+	result = kgsl_mmu_map(private->pagetable, &entry->memdesc,
+				kgsl_memdesc_protflags(&entry->memdesc));
+	if (result)
+		goto err;
 
-	if (result == 0) {
-		entry->memtype = KGSL_MEM_ENTRY_KERNEL;
-		kgsl_mem_entry_attach_process(entry, private);
-		param->gpuaddr = entry->memdesc.gpuaddr;
+	result = kgsl_mem_entry_attach_process(entry, private);
+	if (result != 0)
+		goto err;
 
-		kgsl_process_add_stats(private, entry->memtype, param->size);
-		trace_kgsl_mem_alloc(entry);
-	} else
-		kfree(entry);
+	kgsl_process_add_stats(private, entry->memtype, param->size);
+	trace_kgsl_mem_alloc(entry);
 
-	kgsl_check_idle(dev_priv->device);
+	param->gpuaddr = entry->memdesc.gpuaddr;
+	param->size = entry->memdesc.size;
+	param->flags = entry->memdesc.flags;
+	return result;
+err:
+	kgsl_sharedmem_free(&entry->memdesc);
+	kfree(entry);
 	return result;
 }
+
+static long
+kgsl_ioctl_gpumem_alloc_id(struct kgsl_device_private *dev_priv,
+			unsigned int cmd, void *data)
+{
+	struct kgsl_process_private *private = dev_priv->process_priv;
+	struct kgsl_gpumem_alloc_id *param = data;
+	struct kgsl_mem_entry *entry = NULL;
+	int result;
+
+	if (!can_use_cpu_map())
+		param->flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
+
+	result = _gpumem_alloc(dev_priv, &entry, param->size, param->flags);
+	if (result != 0)
+		goto err;
+
+	if (!kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
+		result = kgsl_mmu_map(private->pagetable, &entry->memdesc,
+				kgsl_memdesc_protflags(&entry->memdesc));
+		if (result)
+			goto err;
+	}
+
+	result = kgsl_mem_entry_attach_process(entry, private);
+	if (result != 0)
+		goto err;
+
+	kgsl_process_add_stats(private, entry->memtype, param->size);
+	trace_kgsl_mem_alloc(entry);
+
+	param->id = entry->id;
+	param->flags = entry->memdesc.flags;
+	param->size = entry->memdesc.size;
+	param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc);
+	param->gpuaddr = entry->memdesc.gpuaddr;
+	return result;
+err:
+	if (entry)
+		kgsl_sharedmem_free(&entry->memdesc);
+	kfree(entry);
+	return result;
+}
+
+static long
+kgsl_ioctl_gpumem_get_info(struct kgsl_device_private *dev_priv,
+			unsigned int cmd, void *data)
+{
+	struct kgsl_process_private *private = dev_priv->process_priv;
+	struct kgsl_gpumem_get_info *param = data;
+	struct kgsl_mem_entry *entry = NULL;
+	int result = 0;
+
+	if (param->id != 0) {
+		entry = kgsl_sharedmem_find_id(private, param->id);
+		if (entry == NULL) {
+			KGSL_MEM_INFO(dev_priv->device, "can't find id %d\n",
+					param->id);
+			return -EINVAL;
+		}
+	} else if (param->gpuaddr != 0) {
+		spin_lock(&private->mem_lock);
+		entry = kgsl_sharedmem_find(private, param->gpuaddr);
+		spin_unlock(&private->mem_lock);
+		if (entry == NULL) {
+			KGSL_MEM_INFO(dev_priv->device,
+					"can't find gpuaddr %lx\n",
+					param->gpuaddr);
+			return -EINVAL;
+		}
+	} else {
+		return -EINVAL;
+	}
+	param->gpuaddr = entry->memdesc.gpuaddr;
+	param->id = entry->id;
+	param->flags = entry->memdesc.flags;
+	param->size = entry->memdesc.size;
+	param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc);
+	param->useraddr = entry->memdesc.useraddr;
+	return result;
+}
+
 static long kgsl_ioctl_cff_syncmem(struct kgsl_device_private *dev_priv,
 					unsigned int cmd, void *data)
 {
@@ -2145,6 +2543,14 @@
 			kgsl_ioctl_timestamp_event, 1),
 	KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
 			kgsl_ioctl_device_setproperty, 1),
+	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID,
+			kgsl_ioctl_gpumem_alloc_id, 0),
+	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
+			kgsl_ioctl_gpumem_free_id, 0),
+	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_GET_INFO,
+			kgsl_ioctl_gpumem_get_info, 0),
+	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE,
+			kgsl_ioctl_gpumem_sync_cache, 0),
 };
 
 static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -2312,33 +2718,26 @@
 	.close = kgsl_gpumem_vm_close,
 };
 
-static int kgsl_mmap(struct file *file, struct vm_area_struct *vma)
+static int
+get_mmap_entry(struct kgsl_process_private *private,
+		struct kgsl_mem_entry **out_entry, unsigned long pgoff,
+		unsigned long len)
 {
-	unsigned int ret;
-	unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT;
-	struct kgsl_device_private *dev_priv = file->private_data;
-	struct kgsl_process_private *private = dev_priv->process_priv;
-	struct kgsl_mem_entry *entry = NULL;
-	struct kgsl_device *device = dev_priv->device;
+	int ret = -EINVAL;
+	struct kgsl_mem_entry *entry;
 
-	/* Handle leagacy behavior for memstore */
+	entry = kgsl_sharedmem_find_id(private, pgoff);
+	if (entry == NULL) {
+		spin_lock(&private->mem_lock);
+		entry = kgsl_sharedmem_find(private, pgoff << PAGE_SHIFT);
+		spin_unlock(&private->mem_lock);
+	}
 
-	if (vma_offset == device->memstore.gpuaddr)
-		return kgsl_mmap_memstore(device, vma);
-
-	/* Find a chunk of GPU memory */
-
-	spin_lock(&private->mem_lock);
-	entry = kgsl_sharedmem_find(private, vma_offset);
-
-	if (entry)
-		kgsl_mem_entry_get(entry);
-
-	spin_unlock(&private->mem_lock);
-
-	if (entry == NULL)
+	if (!entry)
 		return -EINVAL;
 
+	kgsl_mem_entry_get(entry);
+
 	if (!entry->memdesc.ops ||
 		!entry->memdesc.ops->vmflags ||
 		!entry->memdesc.ops->vmfault) {
@@ -2351,24 +2750,173 @@
 		goto err_put;
 	}
 
-	if (entry->memdesc.size != (vma->vm_end - vma->vm_start)) {
+	if (len != kgsl_memdesc_mmapsize(&entry->memdesc)) {
 		ret = -ERANGE;
 		goto err_put;
 	}
 
+	*out_entry = entry;
+	return 0;
+err_put:
+	kgsl_mem_entry_put(entry);
+	return ret;
+}
+
+static unsigned long
+kgsl_get_unmapped_area(struct file *file, unsigned long addr,
+			unsigned long len, unsigned long pgoff,
+			unsigned long flags)
+{
+	unsigned long ret = 0;
+	unsigned long vma_offset = pgoff << PAGE_SHIFT;
+	struct kgsl_device_private *dev_priv = file->private_data;
+	struct kgsl_process_private *private = dev_priv->process_priv;
+	struct kgsl_device *device = dev_priv->device;
+	struct kgsl_mem_entry *entry = NULL;
+	unsigned int align;
+	unsigned int retry = 0;
+
+	if (vma_offset == device->memstore.gpuaddr)
+		return get_unmapped_area(NULL, addr, len, pgoff, flags);
+
+	ret = get_mmap_entry(private, &entry, pgoff, len);
+	if (ret)
+		return ret;
+
+	if (!kgsl_memdesc_use_cpu_map(&entry->memdesc) || (flags & MAP_FIXED)) {
+		/*
+		 * If we're not going to use the same mapping on the gpu,
+		 * any address is fine.
+		 * For MAP_FIXED, hopefully the caller knows what they're doing,
+		 * but we may fail in mmap() if there is already something
+		 * at the virtual address chosen.
+		 */
+		ret = get_unmapped_area(NULL, addr, len, pgoff, flags);
+		goto put;
+	}
+	if (entry->memdesc.gpuaddr != 0) {
+		KGSL_MEM_INFO(device,
+				"pgoff %lx already mapped to gpuaddr %x\n",
+				pgoff, entry->memdesc.gpuaddr);
+		ret = -EBUSY;
+		goto put;
+	}
+
+	align = kgsl_memdesc_get_align(&entry->memdesc);
+	if (align >= ilog2(SZ_1M))
+		align = ilog2(SZ_1M);
+	else if (align >= ilog2(SZ_64K))
+		align = ilog2(SZ_64K);
+	else if (align <= PAGE_SHIFT)
+		align = 0;
+
+	if (align)
+		len += 1 << align;
+	do {
+		ret = get_unmapped_area(NULL, addr, len, pgoff, flags);
+		if (IS_ERR_VALUE(ret))
+			break;
+		if (align)
+			ret = ALIGN(ret, (1 << align));
+
+		/*make sure there isn't a GPU only mapping at this address */
+		if (kgsl_sharedmem_region_empty(private, ret, len))
+			break;
+
+		trace_kgsl_mem_unmapped_area_collision(entry, addr, len, ret);
+
+		/*
+		 * If we collided, bump the hint address so that
+		 * get_umapped_area knows to look somewhere else.
+		 */
+		addr = (addr == 0) ? ret + len : addr + len;
+
+		/*
+		 * The addr hint can be set by userspace to be near
+		 * the end of the address space. Make sure we search
+		 * the whole address space at least once by wrapping
+		 * back around once.
+		 */
+		if (!retry && (addr + len >= TASK_SIZE)) {
+			addr = 0;
+			retry = 1;
+		} else {
+			ret = -EBUSY;
+		}
+	} while (addr + len < TASK_SIZE);
+
+	if (IS_ERR_VALUE(ret))
+		KGSL_MEM_INFO(device,
+				"pid %d pgoff %lx len %ld failed error %ld\n",
+				private->pid, pgoff, len, ret);
+put:
+	kgsl_mem_entry_put(entry);
+	return ret;
+}
+
+static int kgsl_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	unsigned int ret, cache;
+	unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct kgsl_device_private *dev_priv = file->private_data;
+	struct kgsl_process_private *private = dev_priv->process_priv;
+	struct kgsl_mem_entry *entry = NULL;
+	struct kgsl_device *device = dev_priv->device;
+
+	/* Handle leagacy behavior for memstore */
+
+	if (vma_offset == device->memstore.gpuaddr)
+		return kgsl_mmap_memstore(device, vma);
+
+	ret = get_mmap_entry(private, &entry, vma->vm_pgoff,
+				vma->vm_end - vma->vm_start);
+	if (ret)
+		return ret;
+
+	if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
+		entry->memdesc.gpuaddr = vma->vm_start;
+
+		ret = kgsl_mmu_map(private->pagetable, &entry->memdesc,
+				   kgsl_memdesc_protflags(&entry->memdesc));
+		if (ret) {
+			kgsl_mem_entry_put(entry);
+			return ret;
+		}
+		kgsl_mem_entry_track_gpuaddr(private, entry);
+	}
+
 	vma->vm_flags |= entry->memdesc.ops->vmflags(&entry->memdesc);
 
 	vma->vm_private_data = entry;
-	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	/* Determine user-side caching policy */
+
+	cache = kgsl_memdesc_get_cachemode(&entry->memdesc);
+
+	switch (cache) {
+	case KGSL_CACHEMODE_UNCACHED:
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		break;
+	case KGSL_CACHEMODE_WRITETHROUGH:
+		vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
+		break;
+	case KGSL_CACHEMODE_WRITEBACK:
+		vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
+		break;
+	case KGSL_CACHEMODE_WRITECOMBINE:
+	default:
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+		break;
+	}
+
 	vma->vm_ops = &kgsl_gpumem_vm_ops;
 	vma->vm_file = file;
 
 	entry->memdesc.useraddr = vma->vm_start;
 
+	trace_kgsl_mem_mmap(entry);
+
 	return 0;
-err_put:
-	kgsl_mem_entry_put(entry);
-	return ret;
 }
 
 static irqreturn_t kgsl_irq_handler(int irq, void *data)
@@ -2384,6 +2932,7 @@
 	.release = kgsl_release,
 	.open = kgsl_open,
 	.mmap = kgsl_mmap,
+	.get_unmapped_area = kgsl_get_unmapped_area,
 	.unlocked_ioctl = kgsl_ioctl,
 };
 
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index d22cb6d..72e7776 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -185,6 +185,7 @@
 	int flags;
 	void *priv_data;
 	struct rb_node node;
+	unsigned int id;
 	unsigned int context_id;
 	/* back pointer to private structure under whose context this
 	* allocation is made */
@@ -241,6 +242,10 @@
 static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
 				unsigned int gpuaddr, unsigned int size)
 {
+	/* don't overflow */
+	if ((gpuaddr + size) < gpuaddr)
+		return 0;
+
 	if (gpuaddr >= memdesc->gpuaddr &&
 	    ((gpuaddr + size) <= (memdesc->gpuaddr + memdesc->size))) {
 		return 1;
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 07a5ff4..3bc107f 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -221,35 +221,70 @@
 	return '-';
 }
 
+static char get_cacheflag(const struct kgsl_memdesc *m)
+{
+	static const char table[] = {
+		[KGSL_CACHEMODE_WRITECOMBINE] = '-',
+		[KGSL_CACHEMODE_UNCACHED] = 'u',
+		[KGSL_CACHEMODE_WRITEBACK] = 'b',
+		[KGSL_CACHEMODE_WRITETHROUGH] = 't',
+	};
+	return table[kgsl_memdesc_get_cachemode(m)];
+}
+
+static void print_mem_entry(struct seq_file *s, struct kgsl_mem_entry *entry)
+{
+	char flags[6];
+	char usage[16];
+	struct kgsl_memdesc *m = &entry->memdesc;
+
+	flags[0] = kgsl_memdesc_is_global(m) ?  'g' : '-';
+	flags[1] = m->flags & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
+	flags[2] = get_alignflag(m);
+	flags[3] = get_cacheflag(m);
+	flags[4] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-';
+	flags[5] = '\0';
+
+	kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
+
+	seq_printf(s, "%08x %8d %5d %5s %10s %16s %5d\n",
+			m->gpuaddr, m->size, entry->id, flags,
+			memtype_str(entry->memtype), usage, m->sglen);
+}
+
 static int process_mem_print(struct seq_file *s, void *unused)
 {
 	struct kgsl_mem_entry *entry;
 	struct rb_node *node;
 	struct kgsl_process_private *private = s->private;
-	char flags[4];
-	char usage[16];
+	int next = 0;
 
+	seq_printf(s, "%8s %8s %5s %5s %10s %16s %5s\n",
+		   "gpuaddr", "size", "id", "flags", "type", "usage", "sglen");
+
+	/* print all entries with a GPU address */
 	spin_lock(&private->mem_lock);
-	seq_printf(s, "%8s %8s %5s %10s %16s %5s\n",
-		   "gpuaddr", "size", "flags", "type", "usage", "sglen");
+
 	for (node = rb_first(&private->mem_rb); node; node = rb_next(node)) {
-		struct kgsl_memdesc *m;
-
 		entry = rb_entry(node, struct kgsl_mem_entry, node);
-		m = &entry->memdesc;
-
-		flags[0] = kgsl_memdesc_is_global(m) ?  'g' : '-';
-		flags[1] = m->flags & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
-		flags[2] = get_alignflag(m);
-		flags[3] = '\0';
-
-		kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
-
-		seq_printf(s, "%08x %8d %5s %10s %16s %5d\n",
-			   m->gpuaddr, m->size, flags,
-			   memtype_str(entry->memtype), usage, m->sglen);
+		print_mem_entry(s, entry);
 	}
+
 	spin_unlock(&private->mem_lock);
+
+	/* now print all the unbound entries */
+	while (1) {
+		rcu_read_lock();
+		entry = idr_get_next(&private->mem_idr, &next);
+		rcu_read_unlock();
+
+		if (entry == NULL)
+			break;
+		if (entry->memdesc.gpuaddr == 0)
+			print_mem_entry(s, entry);
+		next++;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index ec9a123..ce3820c 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -58,6 +58,7 @@
 struct kgsl_device_private;
 struct kgsl_context;
 struct kgsl_power_stats;
+struct kgsl_event;
 
 struct kgsl_functable {
 	/* Mandatory functions - these functions must be implemented
@@ -112,6 +113,8 @@
 		enum kgsl_property_type type, void *value,
 		unsigned int sizebytes);
 	int (*postmortem_dump) (struct kgsl_device *device, int manual);
+	void (*next_event)(struct kgsl_device *device,
+		struct kgsl_event *event);
 };
 
 /* MH register values */
@@ -265,6 +268,7 @@
 	pid_t pid;
 	spinlock_t mem_lock;
 	struct rb_root mem_rb;
+	struct idr mem_idr;
 	struct kgsl_pagetable *pagetable;
 	struct list_head list;
 	struct kobject kobj;
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6fe119d..533f02f 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -25,9 +25,7 @@
 #include "kgsl_mmu.h"
 #include "kgsl_device.h"
 #include "kgsl_sharedmem.h"
-
-#define KGSL_MMU_ALIGN_SHIFT    13
-#define KGSL_MMU_ALIGN_MASK     (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
+#include "adreno.h"
 
 static enum kgsl_mmutype kgsl_mmu_type;
 
@@ -446,10 +444,10 @@
 	if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) &&
 		((KGSL_MMU_GLOBAL_PT == name) ||
 		(KGSL_MMU_PRIV_BANK_TABLE_NAME == name))) {
-		pagetable->kgsl_pool = gen_pool_create(PAGE_SHIFT, -1);
+		pagetable->kgsl_pool = gen_pool_create(ilog2(SZ_8K), -1);
 		if (pagetable->kgsl_pool == NULL) {
 			KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
-					KGSL_MMU_ALIGN_SHIFT);
+					ilog2(SZ_8K));
 			goto err_alloc;
 		}
 		if (gen_pool_add(pagetable->kgsl_pool,
@@ -460,10 +458,10 @@
 		}
 	}
 
-	pagetable->pool = gen_pool_create(KGSL_MMU_ALIGN_SHIFT, -1);
+	pagetable->pool = gen_pool_create(PAGE_SHIFT, -1);
 	if (pagetable->pool == NULL) {
 		KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
-			      KGSL_MMU_ALIGN_SHIFT);
+			      PAGE_SHIFT);
 		goto err_kgsl_pool;
 	}
 
@@ -536,6 +534,12 @@
 			uint32_t flags)
 {
 	struct kgsl_device *device = mmu->device;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	if (!(flags & (KGSL_MMUFLAGS_TLBFLUSH | KGSL_MMUFLAGS_PTUPDATE))
+		&& !adreno_is_a2xx(adreno_dev))
+		return;
+
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
 		return;
 	else if (device->ftbl->setstate)
@@ -578,7 +582,7 @@
 				unsigned int protflags)
 {
 	int ret;
-	struct gen_pool *pool;
+	struct gen_pool *pool = NULL;
 	int size;
 	int page_align = ilog2(PAGE_SIZE);
 
@@ -628,6 +632,10 @@
 				  pagetable->name);
 				return -EINVAL;
 			}
+		} else if (kgsl_memdesc_use_cpu_map(memdesc)) {
+			if (memdesc->gpuaddr == 0)
+				return -EINVAL;
+			pool = NULL;
 		}
 	}
 	if (pool) {
@@ -708,9 +716,11 @@
 
 	pool = pagetable->pool;
 
-	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()
-		&& kgsl_memdesc_is_global(memdesc)) {
-		pool = pagetable->kgsl_pool;
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
+		if (kgsl_memdesc_is_global(memdesc))
+			pool = pagetable->kgsl_pool;
+		else if (kgsl_memdesc_use_cpu_map(memdesc))
+			pool = NULL;
 	}
 	if (pool)
 		gen_pool_free(pool, memdesc->gpuaddr, size);
@@ -847,8 +857,13 @@
 {
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
 		return 1;
-	return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
-		(gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
+	if (gpuaddr >= kgsl_mmu_get_base_addr() &&
+		gpuaddr < kgsl_mmu_get_base_addr() + kgsl_mmu_get_ptsize())
+		return 1;
+	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU
+		&& kgsl_mmu_is_perprocess())
+		return (gpuaddr > 0 && gpuaddr < TASK_SIZE);
+	return 0;
 }
 EXPORT_SYMBOL(kgsl_mmu_gpuaddr_in_range);
 
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index b8eff60..c8d637e 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -19,11 +19,10 @@
  * These defines control the address range for allocations that
  * are mapped into all pagetables.
  */
-#define KGSL_IOMMU_GLOBAL_MEM_BASE	0xC0000000
+#define KGSL_IOMMU_GLOBAL_MEM_BASE	0xf8000000
 #define KGSL_IOMMU_GLOBAL_MEM_SIZE	SZ_4M
 
-#define KGSL_MMU_ALIGN_SHIFT    13
-#define KGSL_MMU_ALIGN_MASK     (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
+#define KGSL_MMU_ALIGN_MASK     (~((1 << PAGE_SHIFT) - 1))
 
 /* Identifier for the global page table */
 /* Per process page tables will probably pass in the thread group
@@ -350,32 +349,52 @@
 /*
  * kgsl_mmu_base_addr() - Get gpu virtual address base.
  *
- * Returns the start address of the gpu
- * virtual address space.
+ * Returns the start address of the allocatable gpu
+ * virtual address space. Other mappings that mirror
+ * the CPU address space are possible outside this range.
  */
 static inline unsigned int kgsl_mmu_get_base_addr(void)
 {
-	return KGSL_PAGETABLE_BASE;
+	if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype()
+		|| !kgsl_mmu_is_perprocess())
+		return KGSL_PAGETABLE_BASE;
+	/*
+	 * This is the start of the kernel address
+	 * space, so allocations from this range will
+	 * never conflict with userpace addresses
+	 */
+	return PAGE_OFFSET;
 }
 
 /*
  * kgsl_mmu_get_ptsize() - Get gpu pagetable size
  *
- * Returns the usable size of the gpu address space.
+ * Returns the usable size of the gpu allocatable
+ * address space.
  */
 static inline unsigned int kgsl_mmu_get_ptsize(void)
 {
 	/*
-	 * For IOMMU, we could do up to 4G virtual range if we wanted to, but
-	 * it makes more sense to return a smaller range and leave the rest of
-	 * the virtual range for future improvements
+	 * For IOMMU per-process pagetables, the allocatable range
+	 * and the kernel global range must both be outside
+	 * the userspace address range. There is a 1Mb gap
+	 * between these address ranges to make overrun
+	 * detection easier.
+	 * For the shared pagetable case use 2GB and because
+	 * mirroring the CPU address space is not possible and
+	 * we're better off with extra room.
 	 */
 	enum kgsl_mmutype mmu_type = kgsl_mmu_get_mmutype();
 
 	if (KGSL_MMU_TYPE_GPU == mmu_type)
 		return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
-	else if (KGSL_MMU_TYPE_IOMMU == mmu_type)
-		return SZ_2G;
+	else if (KGSL_MMU_TYPE_IOMMU == mmu_type) {
+		if (kgsl_mmu_is_perprocess())
+			return KGSL_IOMMU_GLOBAL_MEM_BASE
+				- kgsl_mmu_get_base_addr() - SZ_1M;
+		else
+			return SZ_2G;
+	}
 	return 0;
 }
 
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 7a7a8dc..df44166 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -86,63 +86,296 @@
 	clkstats->start = ktime_get();
 }
 
+/*
+ * Given a requested power level do bounds checking on the constraints and
+ * return the nearest possible level
+ */
+
+static inline int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level)
+{
+	unsigned int max_pwrlevel = max_t(int, pwr->thermal_pwrlevel,
+		pwr->max_pwrlevel);
+
+	unsigned int min_pwrlevel = max_t(int, pwr->thermal_pwrlevel,
+		pwr->min_pwrlevel);
+
+	if (level < max_pwrlevel)
+		return max_pwrlevel;
+	if (level > min_pwrlevel)
+		return min_pwrlevel;
+
+	return level;
+}
+
 void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
 				unsigned int new_level)
 {
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
-	if (new_level < (pwr->num_pwrlevels - 1) &&
-		new_level >= pwr->thermal_pwrlevel &&
-		new_level != pwr->active_pwrlevel) {
-		struct kgsl_pwrlevel *pwrlevel = &pwr->pwrlevels[new_level];
-		int diff = new_level - pwr->active_pwrlevel;
-		int d = (diff > 0) ? 1 : -1;
-		int level = pwr->active_pwrlevel;
-		/* Update the clock stats */
-		update_clk_statistics(device, true);
-		/* Finally set active level */
-		pwr->active_pwrlevel = new_level;
-		if ((test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) ||
-			(device->state == KGSL_STATE_NAP)) {
-			/*
-			 * On some platforms, instability is caused on
-			 * changing clock freq when the core is busy.
-			 * Idle the gpu core before changing the clock freq.
-			 */
-			if (pwr->idle_needed == true)
-				device->ftbl->idle(device);
+	struct kgsl_pwrlevel *pwrlevel;
+	int delta;
 
-			/* Don't shift by more than one level at a time to
-			 * avoid glitches.
-			 */
-			while (level != new_level) {
-				level += d;
-				clk_set_rate(pwr->grp_clks[0],
-						pwr->pwrlevels[level].gpu_freq);
-			}
+	/* Adjust the power level to the current constraints */
+	new_level = _adjust_pwrlevel(pwr, new_level);
+
+	if (new_level == pwr->active_pwrlevel)
+		return;
+
+	delta = new_level < pwr->active_pwrlevel ? -1 : 1;
+
+	update_clk_statistics(device, true);
+
+	if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) ||
+		(device->state == KGSL_STATE_NAP)) {
+
+		/*
+		 * On some platforms, instability is caused on
+		 * changing clock freq when the core is busy.
+		 * Idle the gpu core before changing the clock freq.
+		 */
+
+		if (pwr->idle_needed == true)
+			device->ftbl->idle(device);
+
+		/*
+		 * Don't shift by more than one level at a time to
+		 * avoid glitches.
+		 */
+
+		while (pwr->active_pwrlevel != new_level) {
+			pwr->active_pwrlevel += delta;
+
+			clk_set_rate(pwr->grp_clks[0],
+				pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq);
 		}
-		if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
-			if (pwr->pcl)
-				msm_bus_scale_client_update_request(pwr->pcl,
-					pwrlevel->bus_freq);
-			else if (pwr->ebi1_clk)
-				clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
-		}
-		trace_kgsl_pwrlevel(device, pwr->active_pwrlevel,
-				    pwrlevel->gpu_freq);
 	}
+
+	pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
+
+	if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
+
+		if (pwr->pcl)
+			msm_bus_scale_client_update_request(pwr->pcl,
+				pwrlevel->bus_freq);
+		else if (pwr->ebi1_clk)
+			clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
+	}
+
+	trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq);
 }
+
 EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change);
 
-static int __gpuclk_store(int max, struct device *dev,
-						  struct device_attribute *attr,
-						  const char *buf, size_t count)
-{	int ret, i, delta = 5000000;
-	unsigned long val;
+static int kgsl_pwrctrl_thermal_pwrlevel_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
 	struct kgsl_pwrctrl *pwr;
+	int ret, level;
 
 	if (device == NULL)
 		return 0;
+
+	pwr = &device->pwrctrl;
+
+	ret = sscanf(buf, "%d", &level);
+	if (ret != 1)
+		return count;
+
+	if (level < 0)
+		return count;
+
+	mutex_lock(&device->mutex);
+
+	if (level > pwr->num_pwrlevels - 2)
+		level = pwr->num_pwrlevels - 2;
+
+	pwr->thermal_pwrlevel = level;
+
+	/*
+	 * If there is no power policy set the clock to the requested thermal
+	 * level - if thermal now happens to be higher than max, then that will
+	 * be limited by the pwrlevel change function.  Otherwise if there is
+	 * a policy only change the active clock if it is higher then the new
+	 * thermal level
+	 */
+
+	if (device->pwrscale.policy == NULL ||
+		pwr->thermal_pwrlevel > pwr->active_pwrlevel)
+		kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
+
+	mutex_unlock(&device->mutex);
+
+	return count;
+}
+
+static int kgsl_pwrctrl_thermal_pwrlevel_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_pwrctrl *pwr;
+	if (device == NULL)
+		return 0;
+	pwr = &device->pwrctrl;
+	return snprintf(buf, PAGE_SIZE, "%d\n", pwr->thermal_pwrlevel);
+}
+
+static int kgsl_pwrctrl_max_pwrlevel_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_pwrctrl *pwr;
+	int ret, level, max_level;
+
+	if (device == NULL)
+		return 0;
+
+	pwr = &device->pwrctrl;
+
+	ret = sscanf(buf, "%d", &level);
+	if (ret != 1)
+		return count;
+
+	/* If the use specifies a negative number, then don't change anything */
+	if (level < 0)
+		return count;
+
+	mutex_lock(&device->mutex);
+
+	/* You can't set a maximum power level lower than the minimum */
+	if (level > pwr->min_pwrlevel)
+		level = pwr->min_pwrlevel;
+
+	pwr->max_pwrlevel = level;
+
+
+	max_level = max_t(int, pwr->thermal_pwrlevel, pwr->max_pwrlevel);
+
+	/*
+	 * If there is no policy then move to max by default.  Otherwise only
+	 * move max if the current level happens to be higher then the new max
+	 */
+
+	if (device->pwrscale.policy == NULL ||
+		(max_level > pwr->active_pwrlevel))
+		kgsl_pwrctrl_pwrlevel_change(device, max_level);
+
+	mutex_unlock(&device->mutex);
+
+	return count;
+}
+
+static int kgsl_pwrctrl_max_pwrlevel_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_pwrctrl *pwr;
+	if (device == NULL)
+		return 0;
+	pwr = &device->pwrctrl;
+	return snprintf(buf, PAGE_SIZE, "%d\n", pwr->max_pwrlevel);
+}
+
+static int kgsl_pwrctrl_min_pwrlevel_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_pwrctrl *pwr;
+	int ret, level, min_level;
+
+	if (device == NULL)
+		return 0;
+
+	pwr = &device->pwrctrl;
+
+	ret = sscanf(buf, "%d", &level);
+	if (ret != 1)
+		return count;
+
+	/* Don't do anything on obviously incorrect values */
+	if (level < 0)
+		return count;
+
+	mutex_lock(&device->mutex);
+	if (level > pwr->num_pwrlevels - 2)
+		level = pwr->num_pwrlevels - 2;
+
+	/* You can't set a minimum power level lower than the maximum */
+	if (level < pwr->max_pwrlevel)
+		level = pwr->max_pwrlevel;
+
+	pwr->min_pwrlevel = level;
+
+	min_level = max_t(int, pwr->thermal_pwrlevel, pwr->min_pwrlevel);
+
+	/* Only move the power level higher if minimum is higher then the
+	 * current level
+	 */
+
+	if (min_level < pwr->active_pwrlevel)
+		kgsl_pwrctrl_pwrlevel_change(device, min_level);
+
+	mutex_unlock(&device->mutex);
+
+	return count;
+}
+
+static int kgsl_pwrctrl_min_pwrlevel_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_pwrctrl *pwr;
+	if (device == NULL)
+		return 0;
+	pwr = &device->pwrctrl;
+	return snprintf(buf, PAGE_SIZE, "%d\n", pwr->min_pwrlevel);
+}
+
+static int kgsl_pwrctrl_num_pwrlevels_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_pwrctrl *pwr;
+	if (device == NULL)
+		return 0;
+	pwr = &device->pwrctrl;
+	return snprintf(buf, PAGE_SIZE, "%d\n", pwr->num_pwrlevels - 1);
+}
+
+/* Given a GPU clock value, return the nearest powerlevel */
+
+static int _get_nearest_pwrlevel(struct kgsl_pwrctrl *pwr, unsigned int clock)
+{
+	int i;
+
+	for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
+		if (abs(pwr->pwrlevels[i].gpu_freq - clock) < 5000000)
+			return i;
+	}
+
+	return -ERANGE;
+}
+
+static int kgsl_pwrctrl_max_gpuclk_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_pwrctrl *pwr;
+	unsigned long val;
+	int ret, level;
+
+	if (device == NULL)
+		return 0;
+
 	pwr = &device->pwrctrl;
 
 	ret = sscanf(buf, "%ld", &val);
@@ -150,44 +383,30 @@
 		return count;
 
 	mutex_lock(&device->mutex);
-	for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
-		if (abs(pwr->pwrlevels[i].gpu_freq - val) < delta) {
-			if (max)
-				pwr->thermal_pwrlevel = i;
-			break;
-		}
-	}
-
-	if (i == (pwr->num_pwrlevels - 1))
+	level = _get_nearest_pwrlevel(pwr, val);
+	if (level < 0)
 		goto done;
 
+	pwr->thermal_pwrlevel = level;
+
 	/*
-	 * If the current or requested clock speed is greater than the
-	 * thermal limit, bump down immediately.
+	 * if the thermal limit is lower than the current setting,
+	 * move the speed down immediately
 	 */
 
-	if (pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq >
-	    pwr->pwrlevels[pwr->thermal_pwrlevel].gpu_freq)
+	if (pwr->thermal_pwrlevel > pwr->active_pwrlevel)
 		kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
-	else if (!max || (NULL == device->pwrscale.policy))
-		kgsl_pwrctrl_pwrlevel_change(device, i);
 
 done:
 	mutex_unlock(&device->mutex);
 	return count;
 }
 
-static int kgsl_pwrctrl_max_gpuclk_store(struct device *dev,
-					 struct device_attribute *attr,
-					 const char *buf, size_t count)
-{
-	return __gpuclk_store(1, dev, attr, buf, count);
-}
-
 static int kgsl_pwrctrl_max_gpuclk_show(struct device *dev,
 					struct device_attribute *attr,
 					char *buf)
 {
+
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
 	struct kgsl_pwrctrl *pwr;
 	if (device == NULL)
@@ -201,7 +420,27 @@
 				     struct device_attribute *attr,
 				     const char *buf, size_t count)
 {
-	return __gpuclk_store(0, dev, attr, buf, count);
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_pwrctrl *pwr;
+	unsigned long val;
+	int ret, level;
+
+	if (device == NULL)
+		return 0;
+
+	pwr = &device->pwrctrl;
+
+	ret = sscanf(buf, "%ld", &val);
+	if (ret != 1)
+		return count;
+
+	mutex_lock(&device->mutex);
+	level = _get_nearest_pwrlevel(pwr, val);
+	if (level >= 0)
+		kgsl_pwrctrl_pwrlevel_change(device, level);
+
+	mutex_unlock(&device->mutex);
+	return count;
 }
 
 static int kgsl_pwrctrl_gpuclk_show(struct device *dev,
@@ -382,6 +621,18 @@
 DEVICE_ATTR(gpu_available_frequencies, 0444,
 	kgsl_pwrctrl_gpu_available_frequencies_show,
 	NULL);
+DEVICE_ATTR(max_pwrlevel, 0644,
+	kgsl_pwrctrl_max_pwrlevel_show,
+	kgsl_pwrctrl_max_pwrlevel_store);
+DEVICE_ATTR(min_pwrlevel, 0644,
+	kgsl_pwrctrl_min_pwrlevel_show,
+	kgsl_pwrctrl_min_pwrlevel_store);
+DEVICE_ATTR(thermal_pwrlevel, 0644,
+	kgsl_pwrctrl_thermal_pwrlevel_show,
+	kgsl_pwrctrl_thermal_pwrlevel_store);
+DEVICE_ATTR(num_pwrlevels, 0444,
+	kgsl_pwrctrl_num_pwrlevels_show,
+	NULL);
 
 static const struct device_attribute *pwrctrl_attr_list[] = {
 	&dev_attr_gpuclk,
@@ -391,6 +642,10 @@
 	&dev_attr_gpubusy,
 	&dev_attr_gputop,
 	&dev_attr_gpu_available_frequencies,
+	&dev_attr_max_pwrlevel,
+	&dev_attr_min_pwrlevel,
+	&dev_attr_thermal_pwrlevel,
+	&dev_attr_num_pwrlevels,
 	NULL
 };
 
@@ -623,6 +878,13 @@
 		goto done;
 	}
 	pwr->num_pwrlevels = pdata->num_levels;
+
+	/* Initialize the user and thermal clock constraints */
+
+	pwr->max_pwrlevel = 0;
+	pwr->min_pwrlevel = pdata->num_levels - 2;
+	pwr->thermal_pwrlevel = 0;
+
 	pwr->active_pwrlevel = pdata->init_level;
 	pwr->default_pwrlevel = pdata->init_level;
 	for (i = 0; i < pdata->num_levels; i++) {
@@ -885,6 +1147,9 @@
 				kgsl_pwrstate_to_str(device->state));
 		break;
 	}
+
+	kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
+
 	return 0;
 }
 
@@ -994,6 +1259,7 @@
 		pm_qos_update_request(&device->pm_qos_req_dma,
 					GPU_SWFI_LATENCY);
 	case KGSL_STATE_ACTIVE:
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 		break;
 	default:
 		KGSL_PWR_WARN(device, "unhandled state %s\n",
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index c02a9fc..e51ec54 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -38,6 +38,30 @@
 	unsigned int elapsed_old;
 };
 
+/**
+ * struct kgsl_pwrctrl - Power control settings for a KGSL device
+ * @interrupt_num - The interrupt number for the device
+ * @ebi1_clk - Pointer to the EBI clock structure
+ * @grp_clks - Array of clocks structures that we control
+ * @power_flags - Control flags for power
+ * @pwrlevels - List of supported power levels
+ * @active_pwrlevel - The currently active power level
+ * @thermal_pwrlevel - maximum powerlevel constraint from thermal
+ * @max_pwrlevel - maximum allowable powerlevel per the user
+ * @min_pwrlevel - minimum allowable powerlevel per the user
+ * @num_pwrlevels - number of available power levels
+ * @interval_timeout - timeout in jiffies to be idle before a power event
+ * @strtstp_sleepwake - true if the device supports low latency GPU start/stop
+ * @gpu_reg - pointer to the regulator structure for gpu_reg
+ * @gpu_cx - pointer to the regulator structure for gpu_cx
+ * @pcl - bus scale identifier
+ * @nap_allowed - true if the device supports naps
+ * @idle_needed - true if the device needs a idle before clock change
+ * @irq_name - resource name for the IRQ
+ * @restore_slumber - Flag to indicate that we are in a suspend/restore sequence
+ * @clk_stats - structure of clock statistics
+ */
+
 struct kgsl_pwrctrl {
 	int interrupt_num;
 	struct clk *ebi1_clk;
@@ -47,6 +71,8 @@
 	unsigned int active_pwrlevel;
 	int thermal_pwrlevel;
 	unsigned int default_pwrlevel;
+	unsigned int max_pwrlevel;
+	unsigned int min_pwrlevel;
 	unsigned int num_pwrlevels;
 	unsigned int interval_timeout;
 	bool strtstp_sleepwake;
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index f6277b3..aad1a8d 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -299,8 +299,14 @@
 {
 	if (device->pwrscale.policy != NULL) {
 		device->pwrscale.policy->close(device, &device->pwrscale);
+
+		/*
+		 * Try to set max pwrlevel which will be limited to thermal by
+		 * kgsl_pwrctrl_pwrlevel_change if thermal is indeed lower
+		 */
+
 		kgsl_pwrctrl_pwrlevel_change(device,
-				device->pwrctrl.thermal_pwrlevel);
+				device->pwrctrl.max_pwrlevel);
 	}
 	device->pwrscale.policy = NULL;
 }
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 7c2514b..e01932b 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -93,7 +93,7 @@
 		priv->governor = TZ_GOVERNOR_PERFORMANCE;
 
 	if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
-		kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
+		kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
 
 	mutex_unlock(&device->mutex);
 	return count;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index be51c11..08353ee 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -511,7 +511,14 @@
 
 void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op)
 {
-	void *addr = memdesc->hostptr;
+	/*
+	 * If the buffer is mapped in the kernel operate on that address
+	 * otherwise use the user address
+	 */
+
+	void *addr = (memdesc->hostptr) ?
+		memdesc->hostptr : (void *) memdesc->useraddr;
+
 	int size = memdesc->size;
 
 	if (addr !=  NULL) {
@@ -534,7 +541,7 @@
 static int
 _kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
 			struct kgsl_pagetable *pagetable,
-			size_t size, unsigned int protflags)
+			size_t size)
 {
 	int pcount = 0, order, ret = 0;
 	int j, len, page_size, sglen_alloc, sglen = 0;
@@ -548,7 +555,8 @@
 	page_size = (align >= ilog2(SZ_64K) && size >= SZ_64K)
 			? SZ_64K : PAGE_SIZE;
 	/* update align flags for what we actually use */
-	kgsl_memdesc_set_align(memdesc, ilog2(page_size));
+	if (page_size != PAGE_SIZE)
+		kgsl_memdesc_set_align(memdesc, ilog2(page_size));
 
 	/*
 	 * There needs to be enough room in the sg structure to be able to
@@ -698,11 +706,6 @@
 	outer_cache_range_op_sg(memdesc->sg, memdesc->sglen,
 				KGSL_CACHE_OP_FLUSH);
 
-	ret = kgsl_mmu_map(pagetable, memdesc, protflags);
-
-	if (ret)
-		goto done;
-
 	KGSL_STATS_ADD(size, kgsl_driver.stats.page_alloc,
 		kgsl_driver.stats.page_alloc_max);
 
@@ -729,8 +732,7 @@
 
 	size = ALIGN(size, PAGE_SIZE * 2);
 
-	ret =  _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
-		GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+	ret =  _kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
 	if (!ret)
 		ret = kgsl_page_alloc_map_kernel(memdesc);
 	if (ret)
@@ -744,17 +746,7 @@
 			    struct kgsl_pagetable *pagetable,
 			    size_t size)
 {
-	unsigned int protflags;
-
-	if (size == 0)
-		return -EINVAL;
-
-	protflags = GSL_PT_PAGE_RV;
-	if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
-		protflags |= GSL_PT_PAGE_WV;
-
-	return _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
-		protflags);
+	return _kgsl_sharedmem_page_alloc(memdesc, pagetable, PAGE_ALIGN(size));
 }
 EXPORT_SYMBOL(kgsl_sharedmem_page_alloc_user);
 
@@ -832,12 +824,6 @@
 	if (result)
 		goto err;
 
-	result = kgsl_mmu_map(pagetable, memdesc,
-		GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
-
-	if (result)
-		goto err;
-
 	KGSL_STATS_ADD(size, kgsl_driver.stats.coherent,
 		kgsl_driver.stats.coherent_max);
 
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 53e88be..d937699 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -83,6 +83,18 @@
 }
 
 /*
+ * kgsl_memdesc_get_cachemode - Get cache mode of a memdesc
+ * @memdesc: the memdesc
+ *
+ * Returns a KGSL_CACHEMODE* value.
+ */
+static inline int
+kgsl_memdesc_get_cachemode(const struct kgsl_memdesc *memdesc)
+{
+	return (memdesc->flags & KGSL_CACHEMODE_MASK) >> KGSL_CACHEMODE_SHIFT;
+}
+
+/*
  * kgsl_memdesc_set_align - Set alignment flags of a memdesc
  * @memdesc - the memdesc
  * @align - alignment requested, as a power of 2 exponent.
@@ -168,14 +180,79 @@
 	return (memdesc->priv & KGSL_MEMDESC_GLOBAL) != 0;
 }
 
+/*
+ * kgsl_memdesc_has_guard_page - is the last page a guard page?
+ * @memdesc - the memdesc
+ *
+ * Returns nonzero if there is a guard page, 0 otherwise
+ */
+static inline int
+kgsl_memdesc_has_guard_page(const struct kgsl_memdesc *memdesc)
+{
+	return (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE) != 0;
+}
+
+/*
+ * kgsl_memdesc_protflags - get mmu protection flags
+ * @memdesc - the memdesc
+ * Returns a mask of GSL_PT_PAGE* values based on the
+ * memdesc flags.
+ */
+static inline unsigned int
+kgsl_memdesc_protflags(const struct kgsl_memdesc *memdesc)
+{
+	unsigned int protflags = GSL_PT_PAGE_RV;
+	if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
+		protflags |= GSL_PT_PAGE_WV;
+	return protflags;
+}
+
+/*
+ * kgsl_memdesc_use_cpu_map - use the same virtual mapping on CPU and GPU?
+ * @memdesc - the memdesc
+ */
+static inline int
+kgsl_memdesc_use_cpu_map(const struct kgsl_memdesc *memdesc)
+{
+	return (memdesc->flags & KGSL_MEMFLAGS_USE_CPU_MAP) != 0;
+}
+
+/*
+ * kgsl_memdesc_mmapsize - get the size of the mmap region
+ * @memdesc - the memdesc
+ *
+ * The entire memdesc must be mapped. Additionally if the
+ * CPU mapping is going to be mirrored, there must be room
+ * for the guard page to be mapped so that the address spaces
+ * match up.
+ */
+static inline unsigned int
+kgsl_memdesc_mmapsize(const struct kgsl_memdesc *memdesc)
+{
+	unsigned int size = memdesc->size;
+	if (kgsl_memdesc_use_cpu_map(memdesc) &&
+		kgsl_memdesc_has_guard_page(memdesc))
+		size += SZ_4K;
+	return size;
+}
+
 static inline int
 kgsl_allocate(struct kgsl_memdesc *memdesc,
 		struct kgsl_pagetable *pagetable, size_t size)
 {
+	int ret;
+	memdesc->priv |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
 	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
 		return kgsl_sharedmem_ebimem(memdesc, pagetable, size);
-	memdesc->flags |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
-	return kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
+
+	ret = kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
+	if (ret)
+		return ret;
+	ret = kgsl_mmu_map(pagetable, memdesc,
+			   kgsl_memdesc_protflags(memdesc));
+	if (ret)
+		kgsl_sharedmem_free(memdesc);
+	return ret;
 }
 
 static inline int
@@ -185,6 +262,9 @@
 {
 	int ret;
 
+	if (size == 0)
+		return -EINVAL;
+
 	memdesc->flags = flags;
 
 	if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 0b247e5..9662fce 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -317,6 +317,8 @@
 		__field(unsigned int, size)
 		__field(unsigned int, tgid)
 		__array(char, usage, 16)
+		__field(unsigned int, id)
+		__field(unsigned int, flags)
 	),
 
 	TP_fast_assign(
@@ -325,12 +327,76 @@
 		__entry->tgid = mem_entry->priv->pid;
 		kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
 				     mem_entry->memdesc.flags);
+		__entry->id = mem_entry->id;
+		__entry->flags = mem_entry->memdesc.flags;
 	),
 
 	TP_printk(
-		"gpuaddr=0x%08x size=%d tgid=%d usage=%s",
+		"gpuaddr=0x%08x size=%d tgid=%d usage=%s id=%d flags=0x%08x",
 		__entry->gpuaddr, __entry->size, __entry->tgid,
-		__entry->usage
+		__entry->usage, __entry->id, __entry->flags
+	)
+);
+
+TRACE_EVENT(kgsl_mem_mmap,
+
+	TP_PROTO(struct kgsl_mem_entry *mem_entry),
+
+	TP_ARGS(mem_entry),
+
+	TP_STRUCT__entry(
+		__field(unsigned long, useraddr)
+		__field(unsigned int, gpuaddr)
+		__field(unsigned int, size)
+		__array(char, usage, 16)
+		__field(unsigned int, id)
+		__field(unsigned int, flags)
+	),
+
+	TP_fast_assign(
+		__entry->useraddr = mem_entry->memdesc.useraddr;
+		__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
+		__entry->size = mem_entry->memdesc.size;
+		kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
+				     mem_entry->memdesc.flags);
+		__entry->id = mem_entry->id;
+		__entry->flags = mem_entry->memdesc.flags;
+	),
+
+	TP_printk(
+		"useraddr=%lx gpuaddr=0x%08x size=%d usage=%s id=%d"
+		" flags=0x%08x",
+		__entry->useraddr, __entry->gpuaddr, __entry->size,
+		__entry->usage, __entry->id, __entry->flags
+	)
+);
+
+TRACE_EVENT(kgsl_mem_unmapped_area_collision,
+
+	TP_PROTO(struct kgsl_mem_entry *mem_entry,
+		 unsigned long hint,
+		 unsigned long len,
+		 unsigned long addr),
+
+	TP_ARGS(mem_entry, hint, len, addr),
+
+	TP_STRUCT__entry(
+		__field(unsigned int, id)
+		__field(unsigned long, hint)
+		__field(unsigned long, len)
+		__field(unsigned long, addr)
+	),
+
+	TP_fast_assign(
+		__entry->id = mem_entry->id;
+		__entry->hint  = hint;
+		__entry->len = len;
+		__entry->addr = addr;
+	),
+
+	TP_printk(
+		"id=%d hint=0x%lx len=%ld addr=0x%lx",
+		__entry->id, __entry->hint, __entry->len, __entry->addr
 	)
 );
 
@@ -347,6 +413,7 @@
 		__field(int, type)
 		__field(unsigned int, tgid)
 		__array(char, usage, 16)
+		__field(unsigned int, id)
 	),
 
 	TP_fast_assign(
@@ -357,13 +424,14 @@
 		__entry->tgid = mem_entry->priv->pid;
 		kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
 				     mem_entry->memdesc.flags);
+		__entry->id = mem_entry->id;
 	),
 
 	TP_printk(
-		"gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage %s",
+		"gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage=%s id=%d",
 		__entry->gpuaddr, __entry->size,
 		__entry->type, __entry->fd, __entry->tgid,
-		__entry->usage
+		__entry->usage, __entry->id
 	)
 );
 
@@ -380,6 +448,7 @@
 		__field(int, fd)
 		__field(unsigned int, tgid)
 		__array(char, usage, 16)
+		__field(unsigned int, id)
 	),
 
 	TP_fast_assign(
@@ -389,12 +458,13 @@
 		__entry->tgid = mem_entry->priv->pid;
 		kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
 				     mem_entry->memdesc.flags);
+		__entry->id = mem_entry->id;
 	),
 
 	TP_printk(
-		"gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s",
+		"gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s id=%d",
 		__entry->gpuaddr, __entry->size, __entry->type,
-		__entry->tgid, __entry->usage
+		__entry->tgid, __entry->usage, __entry->id
 	)
 );
 
@@ -411,6 +481,7 @@
 		__field(unsigned int, size)
 		__field(int, type)
 		__array(char, usage, 16)
+		__field(unsigned int, id)
 		__field(unsigned int, drawctxt_id)
 		__field(unsigned int, curr_ts)
 		__field(unsigned int, free_ts)
@@ -422,6 +493,7 @@
 		__entry->size = mem_entry->memdesc.size;
 		kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
 				     mem_entry->memdesc.flags);
+		__entry->id = mem_entry->id;
 		__entry->drawctxt_id = id;
 		__entry->type = mem_entry->memtype;
 		__entry->curr_ts = curr_ts;
@@ -429,13 +501,14 @@
 	),
 
 	TP_printk(
-		"d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s ctx=%u"
+		"d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s id=%d ctx=%u"
 		" curr_ts=0x%x free_ts=0x%x",
 		__get_str(device_name),
 		__entry->gpuaddr,
 		__entry->size,
 		__entry->type,
 		__entry->usage,
+		__entry->id,
 		__entry->drawctxt_id,
 		__entry->curr_ts,
 		__entry->free_ts
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index e319813..5fb041d 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -616,6 +616,63 @@
 }
 EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu2);
 
+int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
+{
+	int64_t adc_voltage = 0;
+	struct qpnp_vadc_linear_graph param1;
+	int negative_offset;
+
+	qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
+
+	adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref;
+	if (adc_voltage < 0) {
+		negative_offset = 1;
+		adc_voltage = -adc_voltage;
+	}
+
+	do_div(adc_voltage, param1.dy);
+
+	qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
+		ARRAY_SIZE(adcmap_100k_104ef_104fb),
+		adc_voltage, result);
+	if (negative_offset)
+		adc_voltage = -adc_voltage;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_voltage_therm_pu2);
+
+int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
+{
+	struct qpnp_vadc_linear_graph param1;
+	int rc;
+
+	qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
+
+	rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
+		ARRAY_SIZE(adcmap_100k_104ef_104fb),
+		param->low_thr_temp, &param->low_thr_voltage);
+	if (rc)
+		return rc;
+
+	param->low_thr_voltage *= param1.dy;
+	do_div(param->low_thr_voltage, param1.adc_vref);
+	param->low_thr_voltage += param1.adc_gnd;
+
+	rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
+		ARRAY_SIZE(adcmap_100k_104ef_104fb),
+		param->high_thr_temp, &param->high_thr_voltage);
+	if (rc)
+		return rc;
+
+	param->high_thr_voltage *= param1.dy;
+	do_div(param->high_thr_voltage, param1.adc_vref);
+	param->high_thr_voltage += param1.adc_gnd;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_therm_voltage_pu2);
+
 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,
@@ -689,6 +746,65 @@
 }
 EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
 
+int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_usbid_param *param,
+		uint32_t *low_threshold, uint32_t *high_threshold)
+{
+	struct qpnp_vadc_linear_graph usb_param;
+
+	qpnp_get_vadc_gain_and_offset(&usb_param, CALIB_ABSOLUTE);
+
+	*low_threshold = param->low_thr * usb_param.dy;
+	do_div(*low_threshold, usb_param.adc_vref);
+	*low_threshold += usb_param.adc_gnd;
+
+	*high_threshold = param->high_thr * usb_param.dy;
+	do_div(*high_threshold, usb_param.adc_vref);
+	*high_threshold += usb_param.adc_gnd;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_usb_scaler);
+
+int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
+		uint32_t *low_threshold, uint32_t *high_threshold)
+{
+	struct qpnp_vadc_linear_graph btm_param;
+	int64_t *low_output = 0, *high_output = 0;
+	int rc = 0;
+
+	qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
+
+	rc = qpnp_adc_map_temp_voltage(
+		adcmap_btm_threshold,
+		ARRAY_SIZE(adcmap_btm_threshold),
+		(param->low_temp),
+		low_output);
+	if (rc)
+		return rc;
+
+	*low_output *= btm_param.dy;
+	do_div(*low_output, btm_param.adc_vref);
+	*low_output += btm_param.adc_gnd;
+
+	rc = qpnp_adc_map_temp_voltage(
+		adcmap_btm_threshold,
+		ARRAY_SIZE(adcmap_btm_threshold),
+		(param->high_temp),
+		high_output);
+	if (rc)
+		return rc;
+
+	*high_output *= btm_param.dy;
+	do_div(*high_output, btm_param.adc_vref);
+	*high_output += btm_param.adc_gnd;
+
+	low_threshold = (uint32_t *) low_output;
+	high_threshold = (uint32_t *) high_output;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_btm_scaler);
+
 int32_t qpnp_vadc_check_result(int32_t *data)
 {
 	if (*data < QPNP_VADC_MIN_ADC_CODE)
@@ -731,7 +847,7 @@
 		return -ENOMEM;
 	}
 	adc_channel_list = devm_kzalloc(&spmi->dev,
-		sizeof(struct qpnp_vadc_amux) * count_adc_channel_list,
+		((sizeof(struct qpnp_vadc_amux)) * count_adc_channel_list),
 				GFP_KERNEL);
 	if (!adc_channel_list) {
 		dev_err(&spmi->dev, "Unable to allocate memory\n");
@@ -844,8 +960,9 @@
 	adc_qpnp->offset = res->start;
 
 	/* Register the ADC peripheral interrupt */
-	adc_qpnp->adc_irq = spmi_get_irq(spmi, 0, 0);
-	if (adc_qpnp->adc_irq < 0) {
+	adc_qpnp->adc_irq_eoc = spmi_get_irq_byname(spmi, NULL,
+						"eoc-int-en-set");
+	if (adc_qpnp->adc_irq_eoc < 0) {
 		pr_err("Invalid irq\n");
 		return -ENXIO;
 	}
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 0e82cf7..b5ee104 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.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
@@ -695,14 +695,14 @@
 		return -EINVAL;
 	}
 
-	rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq,
+	rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
 				qpnp_iadc_isr,
 	IRQF_TRIGGER_RISING, "qpnp_iadc_interrupt", iadc);
 	if (rc) {
 		dev_err(&spmi->dev, "failed to request adc irq\n");
 		return rc;
 	} else
-		enable_irq_wake(iadc->adc->adc_irq);
+		enable_irq_wake(iadc->adc->adc_irq_eoc);
 
 	iadc->iadc_init_calib = false;
 	dev_set_drvdata(&spmi->dev, iadc);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index c59aa5b..b71c998 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.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
@@ -509,6 +509,39 @@
 	return rc;
 }
 
+int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
+				enum qpnp_adc_calib_type calib_type)
+{
+
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+
+	switch (calib_type) {
+	case CALIB_RATIOMETRIC:
+	param->dy =
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy;
+	param->dx =
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx;
+	param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
+	param->adc_gnd =
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
+	break;
+	case CALIB_ABSOLUTE:
+	param->dy =
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
+	param->dx =
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
+	param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
+	param->adc_gnd =
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
+	break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
+
 int32_t qpnp_vadc_is_ready(void)
 {
 	struct qpnp_vadc_drv *vadc = qpnp_vadc;
@@ -743,7 +776,7 @@
 		return rc;
 	}
 
-	rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq,
+	rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
 				qpnp_vadc_isr, IRQF_TRIGGER_RISING,
 				"qpnp_vadc_interrupt", vadc);
 	if (rc) {
@@ -751,7 +784,7 @@
 			"failed to request adc irq with error %d\n", rc);
 		return rc;
 	} else {
-		enable_irq_wake(vadc->adc->adc_irq);
+		enable_irq_wake(vadc->adc->adc_irq_eoc);
 	}
 
 	qpnp_vadc = vadc;
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index ec3429b..332138c 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -25,6 +25,17 @@
 
 	  If unsure, say N here.
 
+# MSM IOMMU CPU-GPU sync programming support
+config MSM_IOMMU_GPU_SYNC
+	bool "MSM IOMMU CPU-GPU Sync Support"
+	depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930) && MSM_IOMMU && MSM_REMOTE_SPINLOCK_SFPB
+	help
+	  Say Y here if you want to synchronize access to IOMMU configuration
+	  port between CPU and GPU. CPU will grab a remote spinlock before
+	  accessing IOMMU configuration registers and GPU will do the same.
+
+	  If unsure, say N here.
+
 config IOMMU_PGTABLES_L2
 	bool "Allow SMMU page tables in the L2 cache (Experimental)"
 	depends on MSM_IOMMU && MMU && SMP && CPU_DCACHE_DISABLE=n
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index f8c9809..4c72df7 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -29,6 +29,7 @@
 
 #include <mach/iommu_hw-8xxx.h>
 #include <mach/iommu.h>
+#include <mach/msm_smsm.h>
 
 #define MRC(reg, processor, op1, crn, crm, op2)				\
 __asm__ __volatile__ (							\
@@ -66,6 +67,69 @@
 
 DEFINE_MUTEX(msm_iommu_lock);
 
+/**
+ * Remote spinlock implementation based on Peterson's algorithm to be used
+ * to synchronize IOMMU config port access between CPU and GPU.
+ * This implements Process 0 of the spin lock algorithm. GPU implements
+ * Process 1. Flag and turn is stored in shared memory to allow GPU to
+ * access these.
+ */
+struct msm_iommu_remote_lock {
+	int initialized;
+	struct remote_iommu_petersons_spinlock *lock;
+};
+
+static struct msm_iommu_remote_lock msm_iommu_remote_lock;
+
+#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
+static void _msm_iommu_remote_spin_lock_init(void)
+{
+	msm_iommu_remote_lock.lock = smem_alloc(SMEM_SPINLOCK_ARRAY, 32);
+	memset(msm_iommu_remote_lock.lock, 0,
+			sizeof(*msm_iommu_remote_lock.lock));
+}
+
+void msm_iommu_remote_p0_spin_lock(void)
+{
+	msm_iommu_remote_lock.lock->flag[PROC_APPS] = 1;
+	msm_iommu_remote_lock.lock->turn = 1;
+
+	smp_mb();
+
+	while (msm_iommu_remote_lock.lock->flag[PROC_GPU] == 1 &&
+	       msm_iommu_remote_lock.lock->turn == 1)
+		cpu_relax();
+}
+
+void msm_iommu_remote_p0_spin_unlock(void)
+{
+	smp_mb();
+
+	msm_iommu_remote_lock.lock->flag[PROC_APPS] = 0;
+}
+#endif
+
+inline void msm_iommu_mutex_lock(void)
+{
+	mutex_lock(&msm_iommu_lock);
+}
+
+inline void msm_iommu_mutex_unlock(void)
+{
+	mutex_unlock(&msm_iommu_lock);
+}
+
+void *msm_iommu_lock_initialize(void)
+{
+	mutex_lock(&msm_iommu_lock);
+	if (!msm_iommu_remote_lock.initialized) {
+		msm_iommu_remote_lock_init();
+		msm_iommu_remote_lock.initialized = 1;
+	}
+	mutex_unlock(&msm_iommu_lock);
+	return msm_iommu_remote_lock.lock;
+}
+
 struct msm_priv {
 	unsigned long *pgtable;
 	int redirect;
@@ -116,12 +180,17 @@
 		if (ret)
 			goto fail;
 
+		msm_iommu_remote_spin_lock();
+
 		asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
 					   ctx_drvdata->num);
 
 		SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
 			   asid | (va & TLBIVA_VA));
 		mb();
+
+		msm_iommu_remote_spin_unlock();
+
 		__disable_clocks(iommu_drvdata);
 	}
 fail:
@@ -148,11 +217,16 @@
 		if (ret)
 			goto fail;
 
+		msm_iommu_remote_spin_lock();
+
 		asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
 					   ctx_drvdata->num);
 
 		SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, asid);
 		mb();
+
+		msm_iommu_remote_spin_unlock();
+
 		__disable_clocks(iommu_drvdata);
 	}
 fail:
@@ -189,6 +263,9 @@
 {
 	unsigned int prrr, nmrr;
 	int i, j, found;
+
+	msm_iommu_remote_spin_lock();
+
 	__reset_context(base, ctx);
 
 	/* Set up HTW mode */
@@ -278,6 +355,8 @@
 	/* Enable the MMU */
 	SET_M(base, ctx, 1);
 	mb();
+
+	msm_iommu_remote_spin_unlock();
 }
 
 static int msm_iommu_domain_init(struct iommu_domain *domain, int flags)
@@ -417,10 +496,15 @@
 	if (ret)
 		goto fail;
 
+	msm_iommu_remote_spin_lock();
+
 	SET_TLBIASID(iommu_drvdata->base, ctx_dev->num,
 		     GET_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_dev->num));
 
 	__reset_context(iommu_drvdata->base, ctx_dev->num);
+
+	msm_iommu_remote_spin_unlock();
+
 	__disable_clocks(iommu_drvdata);
 	list_del_init(&ctx_drvdata->attached_elm);
 	ctx_drvdata->attached_domain = NULL;
@@ -1083,6 +1167,8 @@
 	if (ret)
 		goto fail;
 
+	msm_iommu_remote_spin_lock();
+
 	SET_V2PPR(base, ctx, va & V2Pxx_VA);
 
 	mb();
@@ -1097,6 +1183,8 @@
 	if (GET_FAULT(base, ctx))
 		ret = 0;
 
+	msm_iommu_remote_spin_unlock();
+
 	__disable_clocks(iommu_drvdata);
 fail:
 	mutex_unlock(&msm_iommu_lock);
@@ -1157,6 +1245,8 @@
 	if (ret)
 		goto fail;
 
+	msm_iommu_remote_spin_lock();
+
 	fsr = GET_FSR(base, num);
 
 	if (fsr) {
@@ -1188,6 +1278,8 @@
 	} else
 		ret = IRQ_NONE;
 
+	msm_iommu_remote_spin_unlock();
+
 	__disable_clocks(drvdata);
 fail:
 	mutex_unlock(&msm_iommu_lock);
@@ -1258,6 +1350,8 @@
 	if (!msm_soc_version_supports_iommu_v1())
 		return -ENODEV;
 
+	msm_iommu_lock_initialize();
+
 	setup_iommu_tex_classes();
 	bus_set_iommu(&platform_bus_type, &msm_iommu_ops);
 	return 0;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index d658217..e7d514e 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -1260,10 +1260,10 @@
 
 static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
 {
-	struct qpnp_led_data *led;
+	struct qpnp_led_data *led, *led_array;
 	struct resource *led_resource;
 	struct device_node *node, *temp;
-	int rc, i, num_leds = 0;
+	int rc, i, num_leds = 0, parsed_leds = 0;
 	const char *led_label;
 
 	node = spmi->dev.of_node;
@@ -1274,34 +1274,34 @@
 	while ((temp = of_get_next_child(node, temp)))
 		num_leds++;
 
-	led = devm_kzalloc(&spmi->dev,
+	if (!num_leds)
+		return -ECHILD;
+
+	led_array = devm_kzalloc(&spmi->dev,
 		(sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
-	if (!led) {
+	if (!led_array) {
 		dev_err(&spmi->dev, "Unable to allocate memory\n");
 		return -ENOMEM;
 	}
 
-	led->num_leds = num_leds;
-	num_leds = 0;
-
 	for_each_child_of_node(node, temp) {
+		led = &led_array[parsed_leds];
+		led->num_leds = num_leds;
 		led->spmi_dev = spmi;
 
 		led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
 		if (!led_resource) {
 			dev_err(&spmi->dev, "Unable to get LED base address\n");
-			return -ENXIO;
+			rc = -ENXIO;
+			goto fail_id_check;
 		}
 		led->base = led_resource->start;
 
-		dev_set_drvdata(&spmi->dev, led);
-
-
 		rc = of_property_read_string(temp, "label", &led_label);
 		if (rc < 0) {
 			dev_err(&led->spmi_dev->dev,
 				"Failure reading label, rc = %d\n", rc);
-			return rc;
+			goto fail_id_check;
 		}
 
 		rc = of_property_read_string(temp, "linux,name",
@@ -1309,7 +1309,7 @@
 		if (rc < 0) {
 			dev_err(&led->spmi_dev->dev,
 				"Failure reading led name, rc = %d\n", rc);
-			return rc;
+			goto fail_id_check;
 		}
 
 		rc = of_property_read_u32(temp, "qcom,max-current",
@@ -1317,14 +1317,14 @@
 		if (rc < 0) {
 			dev_err(&led->spmi_dev->dev,
 				"Failure reading max_current, rc =  %d\n", rc);
-			return rc;
+			goto fail_id_check;
 		}
 
 		rc = of_property_read_u32(temp, "qcom,id", &led->id);
 		if (rc < 0) {
 			dev_err(&led->spmi_dev->dev,
 				"Failure reading led id, rc =  %d\n", rc);
-			return rc;
+			goto fail_id_check;
 		}
 
 		rc = qpnp_get_common_configs(led, temp);
@@ -1332,7 +1332,7 @@
 			dev_err(&led->spmi_dev->dev,
 				"Failure reading common led configuration," \
 				" rc = %d\n", rc);
-			return rc;
+			goto fail_id_check;
 		}
 
 		led->cdev.brightness_set    = qpnp_led_set;
@@ -1343,7 +1343,7 @@
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev,
 					"Unable to read wled config data\n");
-				return rc;
+				goto fail_id_check;
 			}
 		} else if (strncmp(led_label, "flash", sizeof("flash"))
 				== 0) {
@@ -1351,18 +1351,19 @@
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev,
 					"Unable to read flash config data\n");
-				return rc;
+				goto fail_id_check;
 			}
 		} else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
 			rc = qpnp_get_config_rgb(led, temp);
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev,
 					"Unable to read rgb config data\n");
-				return rc;
+				goto fail_id_check;
 			}
 		} else {
 			dev_err(&led->spmi_dev->dev, "No LED matching label\n");
-			return -EINVAL;
+			rc = -EINVAL;
+			goto fail_id_check;
 		}
 
 		spin_lock_init(&led->lock);
@@ -1388,24 +1389,25 @@
 			led->cdev.brightness = LED_OFF;
 
 		qpnp_led_set(&led->cdev, led->cdev.brightness);
-		led++;
-		num_leds++;
+
+		parsed_leds++;
 	}
+	dev_set_drvdata(&spmi->dev, led_array);
 	return 0;
 
 fail_id_check:
-	for (i = 0; i < num_leds; i++)
-		led_classdev_unregister(&led[i].cdev);
+	for (i = 0; i < parsed_leds; i++)
+		led_classdev_unregister(&led_array[i].cdev);
 	return rc;
 }
 
 static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
 {
-	struct qpnp_led_data *led  = dev_get_drvdata(&spmi->dev);
-	int i;
+	struct qpnp_led_data *led_array  = dev_get_drvdata(&spmi->dev);
+	int i, parsed_leds = led_array->num_leds;
 
-	for (i = 0; i < led->num_leds; i++)
-		led_classdev_unregister(&led[i].cdev);
+	for (i = 0; i < parsed_leds; i++)
+		led_classdev_unregister(&led_array[i].cdev);
 
 	return 0;
 }
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 6d66d45..978cb38d 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -42,8 +42,6 @@
 */
 // #define DVB_DEMUX_SECTION_LOSS_LOG
 
-#define TIMESTAMP_LEN	4
-
 static int dvb_demux_tscheck;
 module_param(dvb_demux_tscheck, int, 0644);
 MODULE_PARM_DESC(dvb_demux_tscheck,
@@ -608,7 +606,7 @@
 	((f)->feed.ts.is_filtering) &&					\
 	(((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
 
-static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
+void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
 				const u8 timestamp[TIMESTAMP_LEN])
 {
 	struct dvb_demux_feed *feed;
@@ -688,6 +686,7 @@
 			dvb_dmx_swfilter_output_packet(feed, buf, timestamp);
 	}
 }
+EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
 
 void dvb_dmx_swfilter_section_packets(struct dvb_demux *demux, const u8 *buf,
 			      size_t count)
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 4e6dfaf..f89367b 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -47,6 +47,8 @@
 
 #define MAX_PID 0x1fff
 
+#define TIMESTAMP_LEN	4
+
 #define SPEED_PKTS_INTERVAL 50000
 
 struct dvb_demux_filter {
@@ -189,6 +191,8 @@
 			struct dvb_demux *demux, const u8 *buf,
 			size_t count,
 			enum dmx_tsp_format_t tsp_format);
+void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
+				const u8 timestamp[TIMESTAMP_LEN]);
 
 
 #endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index 51d66cd..e2ef6a0 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -473,16 +473,23 @@
 	 * when dvb-demux is terminated.
 	 */
 	mpq_demux->hw_notification_count = 0;
-	mpq_demux->hw_notification_rate = 0;
+	mpq_demux->hw_notification_interval = 0;
 	mpq_demux->hw_notification_size = 0;
 	mpq_demux->decoder_tsp_drop_count = 0;
+	mpq_demux->hw_notification_min_size = 0xFFFFFFFF;
 
 	if (mpq_demux->demux.dmx.debugfs_demux_dir != NULL) {
 		debugfs_create_u32(
-			"hw_notification_rate",
+			"hw_notification_interval",
 			S_IRUGO|S_IWUGO,
 			mpq_demux->demux.dmx.debugfs_demux_dir,
-			&mpq_demux->hw_notification_rate);
+			&mpq_demux->hw_notification_interval);
+
+		debugfs_create_u32(
+			"hw_notification_min_interval",
+			S_IRUGO|S_IWUGO,
+			mpq_demux->demux.dmx.debugfs_demux_dir,
+			&mpq_demux->hw_notification_min_interval);
 
 		debugfs_create_u32(
 			"hw_notification_count",
@@ -497,6 +504,12 @@
 			&mpq_demux->hw_notification_size);
 
 		debugfs_create_u32(
+			"hw_notification_min_size",
+			S_IRUGO|S_IWUGO,
+			mpq_demux->demux.dmx.debugfs_demux_dir,
+			&mpq_demux->hw_notification_min_size);
+
+		debugfs_create_u32(
 			"decoder_tsp_drop_count",
 			S_IRUGO|S_IWUGO,
 			mpq_demux->demux.dmx.debugfs_demux_dir,
@@ -520,10 +533,17 @@
 					curr_time,
 					mpq_demux->last_notification_time);
 
-		delta_time_ms = (u64)timespec_to_ns(&delta_time);
-		delta_time_ms = div64_u64(delta_time_ms, 1000000); /* ns->ms */
+		delta_time_ms = ((u64)delta_time.tv_sec * MSEC_PER_SEC) +
+					delta_time.tv_nsec / NSEC_PER_MSEC;
 
-		mpq_demux->hw_notification_rate = delta_time_ms;
+		mpq_demux->hw_notification_interval = delta_time_ms;
+
+		if ((mpq_demux->hw_notification_count == 1) ||
+			(mpq_demux->hw_notification_interval &&
+			 mpq_demux->hw_notification_interval <
+				mpq_demux->hw_notification_min_interval))
+			mpq_demux->hw_notification_min_interval =
+				mpq_demux->hw_notification_interval;
 	}
 
 	mpq_demux->hw_notification_count++;
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 3500eda..69305b6 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -30,7 +30,7 @@
 /**
  * TSIF alias name length
  */
-#define TSIF_NAME_LENGTH				10
+#define TSIF_NAME_LENGTH				20
 
 #define MPQ_MAX_FOUND_PATTERNS				5
 
@@ -44,9 +44,14 @@
  *                  initialized or not.
  * @ion_client: ION demux client used to allocate memory from ION.
  * @feed_lock: Lock used to protect against private feed data
- * @hw_notification_rate: Notification rate in msec, exposed in debugfs.
+ * @hw_notification_interval: Notification interval in msec,
+ *                            exposed in debugfs.
+ * @hw_notification_min_interval: Minimum notification internal in msec,
+ * exposed in debugfs.
  * @hw_notification_count: Notification count, exposed in debugfs.
  * @hw_notification_size: Notification size in bytes, exposed in debugfs.
+ * @hw_notification_min_size: Minimum notification size in bytes,
+ *                            exposed in debugfs.
  * @decoder_tsp_drop_count: Counter of number of dropped TS packets
  * due to decoder buffer fullness, exposed in debugfs.
  * @last_notification_time: Time of last HW notification.
@@ -61,9 +66,11 @@
 	spinlock_t feed_lock;
 
 	/* debug-fs */
-	u32 hw_notification_rate;
+	u32 hw_notification_interval;
+	u32 hw_notification_min_interval;
 	u32 hw_notification_count;
 	u32 hw_notification_size;
+	u32 hw_notification_min_size;
 	u32 decoder_tsp_drop_count;
 	struct timespec last_notification_time;
 };
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
index 2e783f6..bbf9d0a 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -13,7 +13,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/tsif_api.h>
-#include <linux/workqueue.h>
+#include <linux/kthread.h>
 #include <linux/moduleparam.h>
 #include "mpq_dvb_debug.h"
 #include "mpq_dmx_plugin_common.h"
@@ -38,17 +38,8 @@
 static int tsif_mode = DMX_TSIF_DRIVER_MODE_DEF;
 static int clock_inv;
 module_param(threshold, int, S_IRUGO);
-module_param(tsif_mode, int, S_IRUGO);
-module_param(clock_inv, int, S_IRUGO);
-
-/*
- * Work scheduled each time TSIF notifies dmx
- * of new TS packet
- */
-struct tsif_work {
-	struct work_struct work;
-	int tsif_id;
-};
+module_param(tsif_mode, int, S_IRUGO | S_IWUSR);
+module_param(clock_inv, int, S_IRUGO | S_IWUSR);
 
 
 /*
@@ -78,11 +69,12 @@
 {
 	/* Information for each TSIF input processing */
 	struct {
-		/* work used to submit to workqueue for processing */
-		struct tsif_work work;
+		/* thread processing TS packets from TSIF */
+		struct task_struct *thread;
+		wait_queue_head_t wait_queue;
 
-		/* workqueue that processes TS packets from specific TSIF */
-		struct workqueue_struct *workqueue;
+		/* Counter for data notifications from TSIF */
+		atomic_t data_cnt;
 
 		/* TSIF alias */
 		char name[TSIF_NAME_LENGTH];
@@ -103,94 +95,72 @@
 
 
 /**
- * Worker function that processes the TS packets notified by the TSIF driver.
+ * Demux thread function handling data from specific TSIF.
  *
- * @worker: the executed work
+ * @arg: TSIF number
  */
-static void mpq_dmx_tsif_work(struct work_struct *worker)
+static int mpq_dmx_tsif_thread(void *arg)
 {
-	struct tsif_work *tsif_work =
-		container_of(worker, struct tsif_work, work);
 	struct mpq_demux *mpq_demux;
 	struct tsif_driver_info *tsif_driver;
 	size_t packets = 0;
-	int tsif = tsif_work->tsif_id;
+	int tsif = (int)arg;
+	int ret;
 
-	mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
-	tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
+	do {
+		ret = wait_event_interruptible(
+			mpq_dmx_tsif_info.tsif[tsif].wait_queue,
+			(atomic_read(
+				&mpq_dmx_tsif_info.tsif[tsif].data_cnt) != 0) ||
+			kthread_should_stop());
 
-	MPQ_DVB_DBG_PRINT(
-		"%s executed, tsif = %d\n",
-		__func__,
-		tsif);
+		if ((ret < 0) || kthread_should_stop()) {
+			MPQ_DVB_DBG_PRINT("%s: exit\n", __func__);
+			break;
+		}
 
-	if (mutex_lock_interruptible(&mpq_dmx_tsif_info.tsif[tsif].mutex))
-		return;
+		if (mutex_lock_interruptible(
+			&mpq_dmx_tsif_info.tsif[tsif].mutex))
+			return -ERESTARTSYS;
 
-	/* Check if driver handler is still valid */
-	if (tsif_driver->tsif_handler == NULL) {
-		mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
-		MPQ_DVB_ERR_PRINT("%s: tsif_driver->tsif_handler is NULL!\n",
+		tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
+		mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
+
+		/* Check if driver handler is still valid */
+		if (tsif_driver->tsif_handler == NULL) {
+			mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+			MPQ_DVB_DBG_PRINT(
+				"%s: tsif was detached\n",
 				__func__);
-		return;
-	}
+			continue;
+		}
 
-	tsif_get_state(tsif_driver->tsif_handler, &(tsif_driver->ri),
-				&(tsif_driver->wi), &(tsif_driver->state));
+		tsif_get_state(
+			tsif_driver->tsif_handler, &(tsif_driver->ri),
+			&(tsif_driver->wi), &(tsif_driver->state));
 
-	if ((tsif_driver->wi == tsif_driver->ri) ||
-		(tsif_driver->state == tsif_state_stopped) ||
-		(tsif_driver->state == tsif_state_error)) {
+		if ((tsif_driver->wi == tsif_driver->ri) ||
+			(tsif_driver->state == tsif_state_stopped) ||
+			(tsif_driver->state == tsif_state_error)) {
 
-		mpq_demux->hw_notification_size = 0;
+			mpq_demux->hw_notification_size = 0;
 
-		mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+			mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
 
-		MPQ_DVB_ERR_PRINT(
-			"%s: invalid TSIF state (%d), wi = (%d), ri = (%d)\n",
-			__func__,
-			tsif_driver->state, tsif_driver->wi, tsif_driver->ri);
-		return;
-	}
+			MPQ_DVB_DBG_PRINT(
+				"%s: TSIF invalid state %d, %d, %d\n",
+				__func__,
+				tsif_driver->state,
+				tsif_driver->wi,
+				tsif_driver->ri);
+			continue;
+		}
 
-	if (tsif_driver->wi > tsif_driver->ri) {
-		packets = (tsif_driver->wi - tsif_driver->ri);
-		mpq_demux->hw_notification_size = packets;
+		atomic_dec(&mpq_dmx_tsif_info.tsif[tsif].data_cnt);
 
-		dvb_dmx_swfilter_format(
-			&mpq_demux->demux,
-			(tsif_driver->data_buffer +
-			(tsif_driver->ri * TSIF_PKT_SIZE)),
-			(packets * TSIF_PKT_SIZE),
-			DMX_TSP_FORMAT_192_TAIL);
-
-		tsif_driver->ri =
-			(tsif_driver->ri + packets) % tsif_driver->buffer_size;
-
-		tsif_reclaim_packets(tsif_driver->tsif_handler,
-					tsif_driver->ri);
-	} else {
-		/*
-		 * wi < ri, means wraparound on cyclic buffer.
-		 * Handle in two stages.
-		 */
-		packets = (tsif_driver->buffer_size - tsif_driver->ri);
-		mpq_demux->hw_notification_size = packets;
-
-		dvb_dmx_swfilter_format(
-			&mpq_demux->demux,
-			(tsif_driver->data_buffer +
-			(tsif_driver->ri * TSIF_PKT_SIZE)),
-			(packets * TSIF_PKT_SIZE),
-			DMX_TSP_FORMAT_192_TAIL);
-
-		/* tsif_driver->ri should be 0 after this */
-		tsif_driver->ri =
-			(tsif_driver->ri + packets) % tsif_driver->buffer_size;
-
-		packets = tsif_driver->wi;
-		if (packets > 0) {
-			mpq_demux->hw_notification_size += packets;
+		if (tsif_driver->wi > tsif_driver->ri) {
+			packets = (tsif_driver->wi - tsif_driver->ri);
+			mpq_demux->hw_notification_size = packets;
 
 			dvb_dmx_swfilter_format(
 				&mpq_demux->demux,
@@ -202,13 +172,55 @@
 			tsif_driver->ri =
 				(tsif_driver->ri + packets) %
 				tsif_driver->buffer_size;
+
+			tsif_reclaim_packets(
+				tsif_driver->tsif_handler,
+					tsif_driver->ri);
+		} else {
+			/*
+			 * wi < ri, means wraparound on cyclic buffer.
+			 * Handle in two stages.
+			 */
+			packets = (tsif_driver->buffer_size - tsif_driver->ri);
+			mpq_demux->hw_notification_size = packets;
+
+			dvb_dmx_swfilter_format(
+				&mpq_demux->demux,
+				(tsif_driver->data_buffer +
+				(tsif_driver->ri * TSIF_PKT_SIZE)),
+				(packets * TSIF_PKT_SIZE),
+				DMX_TSP_FORMAT_192_TAIL);
+
+			/* tsif_driver->ri should be 0 after this */
+			tsif_driver->ri =
+				(tsif_driver->ri + packets) %
+				tsif_driver->buffer_size;
+
+			packets = tsif_driver->wi;
+			if (packets > 0) {
+				mpq_demux->hw_notification_size += packets;
+
+				dvb_dmx_swfilter_format(
+					&mpq_demux->demux,
+					(tsif_driver->data_buffer +
+					(tsif_driver->ri * TSIF_PKT_SIZE)),
+					(packets * TSIF_PKT_SIZE),
+					DMX_TSP_FORMAT_192_TAIL);
+
+				tsif_driver->ri =
+					(tsif_driver->ri + packets) %
+					tsif_driver->buffer_size;
+			}
+
+			tsif_reclaim_packets(
+				tsif_driver->tsif_handler,
+				tsif_driver->ri);
 		}
 
-		tsif_reclaim_packets(tsif_driver->tsif_handler,
-					tsif_driver->ri);
-	}
+		mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+	} while (1);
 
-	mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+	return 0;
 }
 
 
@@ -220,7 +232,6 @@
 static void mpq_tsif_callback(void *user)
 {
 	int tsif = (int)user;
-	struct work_struct *work;
 	struct mpq_demux *mpq_demux;
 
 	MPQ_DVB_DBG_PRINT("%s executed, tsif = %d\n", __func__,	tsif);
@@ -229,11 +240,8 @@
 	mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
 	mpq_dmx_update_hw_statistics(mpq_demux);
 
-	work = &mpq_dmx_tsif_info.tsif[tsif].work.work;
-
-	/* Scheudle a new work to demux workqueue */
-	if (!work_pending(work))
-		queue_work(mpq_dmx_tsif_info.tsif[tsif].workqueue, work);
+	atomic_inc(&mpq_dmx_tsif_info.tsif[tsif].data_cnt);
+	wake_up(&mpq_dmx_tsif_info.tsif[tsif].wait_queue);
 }
 
 
@@ -376,20 +384,10 @@
 		tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
 		tsif_stop(tsif_driver->tsif_handler);
 		tsif_detach(tsif_driver->tsif_handler);
-		/*
-		 * temporarily release mutex and flush the work queue
-		 * before setting tsif_handler to NULL
-		 */
-		mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
-		flush_workqueue(mpq_dmx_tsif_info.tsif[tsif].workqueue);
-		/* re-acquire mutex */
-		if (mutex_lock_interruptible(
-				&mpq_dmx_tsif_info.tsif[tsif].mutex))
-			return -ERESTARTSYS;
-
 		tsif_driver->tsif_handler = NULL;
 		tsif_driver->data_buffer = NULL;
 		tsif_driver->buffer_size = 0;
+		atomic_set(&mpq_dmx_tsif_info.tsif[tsif].data_cnt, 0);
 		mpq_dmx_tsif_info.tsif[tsif].mpq_demux = NULL;
 	}
 
@@ -708,31 +706,28 @@
 	}
 
 	for (i = 0; i < TSIF_COUNT; i++) {
-		mpq_dmx_tsif_info.tsif[i].work.tsif_id = i;
-
-		INIT_WORK(&mpq_dmx_tsif_info.tsif[i].work.work,
-				  mpq_dmx_tsif_work);
-
 		snprintf(mpq_dmx_tsif_info.tsif[i].name,
 				TSIF_NAME_LENGTH,
-				"tsif_%d",
+				"dmx_tsif%d",
 				i);
 
-		mpq_dmx_tsif_info.tsif[i].workqueue =
-			create_singlethread_workqueue(
+		atomic_set(&mpq_dmx_tsif_info.tsif[i].data_cnt, 0);
+		init_waitqueue_head(&mpq_dmx_tsif_info.tsif[i].wait_queue);
+		mpq_dmx_tsif_info.tsif[i].thread =
+			kthread_run(
+				mpq_dmx_tsif_thread, (void *)i,
 				mpq_dmx_tsif_info.tsif[i].name);
 
-		if (mpq_dmx_tsif_info.tsif[i].workqueue == NULL) {
+		if (IS_ERR(mpq_dmx_tsif_info.tsif[i].thread)) {
 			int j;
 
 			for (j = 0; j < i; j++) {
-				destroy_workqueue(
-					mpq_dmx_tsif_info.tsif[j].workqueue);
+				kthread_stop(mpq_dmx_tsif_info.tsif[j].thread);
 				mutex_destroy(&mpq_dmx_tsif_info.tsif[j].mutex);
 			}
 
 			MPQ_DVB_ERR_PRINT(
-				"%s: create_singlethread_workqueue failed\n",
+				"%s: kthread_run failed\n",
 				__func__);
 
 			return -ENOMEM;
@@ -753,7 +748,7 @@
 			ret);
 
 		for (i = 0; i < TSIF_COUNT; i++) {
-			destroy_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
+			kthread_stop(mpq_dmx_tsif_info.tsif[i].thread);
 			mutex_destroy(&mpq_dmx_tsif_info.tsif[i].mutex);
 		}
 	}
@@ -781,16 +776,13 @@
 			if (tsif_driver->tsif_handler)
 				tsif_stop(tsif_driver->tsif_handler);
 		}
+
 		/* Detach from TSIF driver to avoid further notifications. */
 		if (tsif_driver->tsif_handler)
 			tsif_detach(tsif_driver->tsif_handler);
 
-		/* release mutex to allow work queue to finish scheduled work */
 		mutex_unlock(&mpq_dmx_tsif_info.tsif[i].mutex);
-		/* flush the work queue and destroy it */
-		flush_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
-		destroy_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
-
+		kthread_stop(mpq_dmx_tsif_info.tsif[i].thread);
 		mutex_destroy(&mpq_dmx_tsif_info.tsif[i].mutex);
 	}
 
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index 360d96a..ac03e43 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -12,12 +12,11 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/workqueue.h>
+#include <linux/kthread.h>
 #include <mach/msm_tspp.h>
 #include "mpq_dvb_debug.h"
 #include "mpq_dmx_plugin_common.h"
 
-
 #define TSIF_COUNT			2
 
 #define TSPP_MAX_PID_FILTER_NUM		16
@@ -28,6 +27,7 @@
 /* For each TSIF we allocate two pipes, one for PES and one for sections */
 #define TSPP_PES_CHANNEL			0
 #define TSPP_SECTION_CHANNEL			1
+#define TSPP_CHANNEL_COUNT			2
 
 /* the channel_id set to TSPP driver based on TSIF number and channel type */
 #define TSPP_CHANNEL_ID(tsif, ch)		((tsif << 1) + ch)
@@ -35,45 +35,36 @@
 #define TSPP_GET_TSIF_NUM(ch_id)		(ch_id >> 1)
 
 /* mask that set to care for all bits in pid filter */
-#define TSPP_PID_MASK				0x1FFF
+#define TSPP_PID_MASK			0x1FFF
 
 /* dvb-demux defines pid 0x2000 as full capture pid */
-#define TSPP_PASS_THROUGH_PID			0x2000
+#define TSPP_PASS_THROUGH_PID		0x2000
 
-/* TODO - NEED TO SET THESE PROPERLY
- * once TSPP driver is ready, reduce TSPP_BUFFER_SIZE
- * to single packet and set TSPP_BUFFER_COUNT accordingly
- */
+#define TSPP_RAW_TTS_SIZE		192
+#define TSPP_RAW_SIZE			188
 
-#define TSPP_RAW_TTS_SIZE				192
+#define MAX_BAM_DESCRIPTOR_SIZE	(32*1024 - 1)
 
-#define MAX_BAM_DESCRIPTOR_SIZE		(32*1024 - 1)
+#define TSPP_BUFFER_SIZE		(500 * 1024) /* 500KB */
 
-/* Size of single descriptor for PES/rec pipe.
+#define TSPP_PES_BUFFER_SIZE		(TSPP_RAW_TTS_SIZE)
+
+#define TSPP_SECTION_BUFFER_SIZE	(TSPP_RAW_TTS_SIZE)
+
+#define TSPP_BUFFER_COUNT(buffer_size)	\
+	((buffer_size) / TSPP_RAW_TTS_SIZE)
+
+/* When TSPP notifies demux that new packets are received.
  * Using max descriptor size (170 packets).
  * Assuming 20MBit/sec stream, with 170 packets
  * per descriptor there would be about 82 descriptors,
  * Meanning about 82 notifications per second.
  */
-#define TSPP_PES_BUFFER_SIZE			\
-	((MAX_BAM_DESCRIPTOR_SIZE / TSPP_RAW_TTS_SIZE) * TSPP_RAW_TTS_SIZE)
-
-/* Size of single descriptor for section pipe.
- * Assuming 8MBit/sec section rate, with 65 packets
- * per descriptor there would be about 85 descriptors,
- * Meanning about 85 notifications per second.
- */
-#define TSPP_SECTION_BUFFER_SIZE			\
-	(65 * TSPP_RAW_TTS_SIZE)
-
-/* Number of descriptors, total size: TSPP_BUFFER_SIZE*TSPP_BUFFER_COUNT */
-#define TSPP_BUFFER_COUNT				(32)
-
-/* When TSPP notifies demux that new packets are received */
-#define TSPP_NOTIFICATION_SIZE			1
+#define TSPP_NOTIFICATION_SIZE(desc_size)		\
+	(MAX_BAM_DESCRIPTOR_SIZE / (desc_size))
 
 /* Channel timeout in msec */
-#define TSPP_CHANNEL_TIMEOUT			16
+#define TSPP_CHANNEL_TIMEOUT			100
 
 enum mem_buffer_allocation_mode {
 	MPQ_DMX_TSPP_INTERNAL_ALLOC = 0,
@@ -84,18 +75,17 @@
 static int clock_inv;
 static int tsif_mode = 2;
 static int allocation_mode = MPQ_DMX_TSPP_INTERNAL_ALLOC;
-module_param(tsif_mode, int, S_IRUGO);
-module_param(clock_inv, int, S_IRUGO);
-module_param(allocation_mode, int, S_IRUGO);
+static int tspp_out_buffer_size = TSPP_BUFFER_SIZE;
+static int tspp_notification_size = TSPP_NOTIFICATION_SIZE(TSPP_RAW_TTS_SIZE);
+static int tspp_channel_timeout = TSPP_CHANNEL_TIMEOUT;
 
-/*
- * Work scheduled each time TSPP notifies dmx
- * of new TS packet in some channel
- */
-struct tspp_work {
-	struct work_struct work;
-	int channel_id;
-};
+module_param(tsif_mode, int, S_IRUGO | S_IWUSR);
+module_param(clock_inv, int, S_IRUGO | S_IWUSR);
+module_param(allocation_mode, int, S_IRUGO);
+module_param(tspp_out_buffer_size, int, S_IRUGO);
+module_param(tspp_notification_size, int, S_IRUGO | S_IWUSR);
+module_param(tspp_channel_timeout, int, S_IRUGO | S_IWUSR);
+
 
 /* The following structure hold singelton information
  * required for dmx implementation on top of TSPP.
@@ -111,8 +101,8 @@
 		 */
 		int pes_channel_ref;
 
-		/* work used to submit to workqueue to process pes channel */
-		struct tspp_work pes_work;
+		/* Counter for data notifications on PES pipe */
+		atomic_t pes_data_cnt;
 
 		/* ION handle used for TSPP data buffer allocation */
 		struct ion_handle *pes_mem_heap_handle;
@@ -130,8 +120,8 @@
 		 */
 		int section_channel_ref;
 
-		/* work used to submit to workqueue to process pes channel */
-		struct tspp_work section_work;
+		/* Counter for data notifications on section pipe */
+		atomic_t section_data_cnt;
 
 		/* ION handle used for TSPP data buffer allocation */
 		struct ion_handle *section_mem_heap_handle;
@@ -142,6 +132,8 @@
 		/* buffer allocation index */
 		int section_index;
 
+		u32 buffer_count;
+
 		/*
 		 * Holds PIDs of allocated TSPP filters along with
 		 * how many feeds are opened on same PID.
@@ -151,8 +143,9 @@
 			int ref_count;
 		} filters[TSPP_MAX_PID_FILTER_NUM];
 
-		/* workqueue that processes TS packets from specific TSIF */
-		struct workqueue_struct *workqueue;
+		/* thread processing TS packets from TSPP */
+		struct task_struct *thread;
+		wait_queue_head_t wait_queue;
 
 		/* TSIF alias */
 		char name[TSIF_NAME_LENGTH];
@@ -175,7 +168,8 @@
 	int i = TSPP_GET_TSIF_NUM(channel_id);
 
 	if (TSPP_IS_PES_CHANNEL(channel_id)) {
-		if (mpq_dmx_tspp_info.tsif[i].pes_index == TSPP_BUFFER_COUNT)
+		if (mpq_dmx_tspp_info.tsif[i].pes_index ==
+			mpq_dmx_tspp_info.tsif[i].buffer_count)
 			return NULL;
 		virt_addr =
 			(mpq_dmx_tspp_info.tsif[i].pes_mem_heap_virt_base +
@@ -186,7 +180,7 @@
 		mpq_dmx_tspp_info.tsif[i].pes_index++;
 	} else {
 		if (mpq_dmx_tspp_info.tsif[i].section_index ==
-						TSPP_BUFFER_COUNT)
+			mpq_dmx_tspp_info.tsif[i].buffer_count)
 			return NULL;
 		virt_addr =
 			(mpq_dmx_tspp_info.tsif[i].section_mem_heap_virt_base +
@@ -274,55 +268,105 @@
 }
 
 /**
- * Worker function that processes the TS packets notified by TSPP.
+ * Demux thread function handling data from specific TSIF.
  *
- * @worker: the executed work
+ * @arg: TSIF number
  */
-static void mpq_dmx_tspp_work(struct work_struct *worker)
+static int mpq_dmx_tspp_thread(void *arg)
 {
-	struct tspp_work *tspp_work =
-		container_of(worker, struct tspp_work, work);
+	int tsif = (int)arg;
 	struct mpq_demux *mpq_demux;
-	int channel_id = tspp_work->channel_id;
-	int tsif = TSPP_GET_TSIF_NUM(channel_id);
 	const struct tspp_data_descriptor *tspp_data_desc;
+	atomic_t *data_cnt;
+	u32 notif_size;
 	int ref_count;
+	int ret;
+	int i;
+	int j;
 
-	mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+	do {
+		ret = wait_event_interruptible(
+			mpq_dmx_tspp_info.tsif[tsif].wait_queue,
+			(atomic_read(
+			 &mpq_dmx_tspp_info.tsif[tsif].pes_data_cnt)) ||
+			(atomic_read(
+			 &mpq_dmx_tspp_info.tsif[tsif].section_data_cnt)) ||
+			kthread_should_stop());
 
-	/* Lock against the TSPP filters data-structure */
-	if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex))
-		return;
+		if ((ret < 0) || kthread_should_stop()) {
+			MPQ_DVB_ERR_PRINT("%s: exit\n", __func__);
+			break;
+		}
 
-	/* Make sure channel is still active */
-	if (TSPP_IS_PES_CHANNEL(channel_id))
-		ref_count = mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
-	else
-		ref_count = mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+		/* Lock against the TSPP filters data-structure */
+		if (mutex_lock_interruptible(
+			&mpq_dmx_tspp_info.tsif[tsif].mutex))
+			return -ERESTARTSYS;
 
-	if (ref_count == 0) {
+		for (i = 0; i < TSPP_CHANNEL_COUNT; i++) {
+			int channel_id = TSPP_CHANNEL_ID(tsif, i);
+
+			if (TSPP_IS_PES_CHANNEL(channel_id)) {
+				ref_count =
+				 mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+				data_cnt =
+				 &mpq_dmx_tspp_info.tsif[tsif].pes_data_cnt;
+			} else {
+				ref_count =
+				 mpq_dmx_tspp_info.tsif[tsif].
+					section_channel_ref;
+				data_cnt =
+				 &mpq_dmx_tspp_info.tsif[tsif].section_data_cnt;
+			}
+
+			/* Make sure channel is still active */
+			if (ref_count == 0)
+				continue;
+
+			atomic_dec(data_cnt);
+
+			mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+			mpq_demux->hw_notification_size = 0;
+
+			/*
+			 * Go through all filled descriptors
+			 * and perform demuxing on them
+			 */
+			while ((tspp_data_desc =
+				tspp_get_buffer(0, channel_id)) != NULL) {
+				notif_size =
+					tspp_data_desc->size /
+					TSPP_RAW_TTS_SIZE;
+
+				mpq_demux->hw_notification_size +=
+					notif_size;
+
+				for (j = 0; j < notif_size; j++)
+					dvb_dmx_swfilter_packet(
+					 &mpq_demux->demux,
+					 ((u8 *)tspp_data_desc->virt_base) +
+					 j * TSPP_RAW_TTS_SIZE,
+					 ((u8 *)tspp_data_desc->virt_base) +
+					 j * TSPP_RAW_TTS_SIZE + TSPP_RAW_SIZE);
+				/*
+				 * Notify TSPP that the buffer
+				 * is no longer needed
+				 */
+				tspp_release_buffer(0,
+					channel_id, tspp_data_desc->id);
+			}
+
+			if (mpq_demux->hw_notification_size &&
+				(mpq_demux->hw_notification_size <
+				mpq_demux->hw_notification_min_size))
+				mpq_demux->hw_notification_min_size =
+					mpq_demux->hw_notification_size;
+		}
+
 		mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
-		return;
-	}
+	} while (1);
 
-	mpq_demux->hw_notification_size = 0;
-
-	/* Go through all filled descriptors and perform demuxing on them */
-	while ((tspp_data_desc = tspp_get_buffer(0, channel_id)) != NULL) {
-		mpq_demux->hw_notification_size +=
-			(tspp_data_desc->size / TSPP_RAW_TTS_SIZE);
-
-		dvb_dmx_swfilter_format(
-				&mpq_demux->demux,
-				tspp_data_desc->virt_base,
-				tspp_data_desc->size,
-				DMX_TSP_FORMAT_192_TAIL);
-
-		/* Notify TSPP that the buffer is no longer needed */
-		tspp_release_buffer(0, channel_id, tspp_data_desc->id);
-	}
-
-	mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+	return 0;
 }
 
 /**
@@ -334,7 +378,6 @@
 static void mpq_tspp_callback(int channel_id, void *user)
 {
 	int tsif = (int)user;
-	struct work_struct *work;
 	struct mpq_demux *mpq_demux;
 
 	/* Save statistics on TSPP notifications */
@@ -342,13 +385,11 @@
 	mpq_dmx_update_hw_statistics(mpq_demux);
 
 	if (TSPP_IS_PES_CHANNEL(channel_id))
-		work = &mpq_dmx_tspp_info.tsif[tsif].pes_work.work;
+		atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].pes_data_cnt);
 	else
-		work = &mpq_dmx_tspp_info.tsif[tsif].section_work.work;
+		atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].section_data_cnt);
 
-	/* Scheudle a new work to demux workqueue */
-	if (!work_pending(work))
-		queue_work(mpq_dmx_tspp_info.tsif[tsif].workqueue, work);
+	wake_up(&mpq_dmx_tspp_info.tsif[tsif].wait_queue);
 }
 
 /**
@@ -438,7 +479,6 @@
 	/* check if required TSPP pipe is already allocated or not */
 	if (*channel_ref_count == 0) {
 		ret = tspp_open_channel(0, channel_id);
-
 		if (ret < 0) {
 			MPQ_DVB_ERR_PRINT(
 				"%s: tspp_open_channel(%d) failed (%d)\n",
@@ -467,7 +507,7 @@
 					   channel_id,
 					   mpq_tspp_callback,
 					   (void *)tsif,
-					   TSPP_CHANNEL_TIMEOUT);
+					   tspp_channel_timeout);
 
 		/* register allocater and provide allocation function
 		 * that allocates from continous memory so that we can have
@@ -479,23 +519,15 @@
 		 * allocate TSPP data buffers
 		 */
 		if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) {
-			ret = tspp_allocate_buffers(0,
-						    channel_id,
-						    TSPP_BUFFER_COUNT,
-						    buffer_size,
-						    TSPP_NOTIFICATION_SIZE,
-						    tspp_mem_allocator,
-						    tspp_mem_free,
-						    NULL);
+			ret = tspp_allocate_buffers(0, channel_id,
+				   mpq_dmx_tspp_info.tsif[tsif].buffer_count,
+				   buffer_size, tspp_notification_size,
+				   tspp_mem_allocator, tspp_mem_free, NULL);
 		} else {
-			ret = tspp_allocate_buffers(0,
-						    channel_id,
-						    TSPP_BUFFER_COUNT,
-						    buffer_size,
-						    TSPP_NOTIFICATION_SIZE,
-						    NULL,
-						    NULL,
-						    NULL);
+			ret = tspp_allocate_buffers(0, channel_id,
+				   mpq_dmx_tspp_info.tsif[tsif].buffer_count,
+				   buffer_size, tspp_notification_size,
+				   NULL, NULL, NULL);
 		}
 		if (ret < 0) {
 			MPQ_DVB_ERR_PRINT(
@@ -586,6 +618,7 @@
 	int tsif;
 	int ret;
 	int channel_id;
+	atomic_t *data_cnt;
 	int *channel_ref_count;
 	struct tspp_filter tspp_filter;
 	struct mpq_demux *mpq_demux = feed->demux->priv;
@@ -613,10 +646,12 @@
 		channel_id = TSPP_CHANNEL_ID(tsif, TSPP_PES_CHANNEL);
 		channel_ref_count =
 			&mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+		data_cnt = &mpq_dmx_tspp_info.tsif[tsif].pes_data_cnt;
 	} else {
 		channel_id = TSPP_CHANNEL_ID(tsif, TSPP_SECTION_CHANNEL);
 		channel_ref_count =
 			&mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+		data_cnt = &mpq_dmx_tspp_info.tsif[tsif].section_data_cnt;
 	}
 
 	/* check if required TSPP pipe is already allocated or not */
@@ -677,6 +712,7 @@
 		tspp_unregister_notification(0, channel_id);
 		tspp_close_channel(0, channel_id);
 		tspp_close_stream(0, channel_id);
+		atomic_set(data_cnt, 0);
 	}
 
 	mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
@@ -735,7 +771,7 @@
 		ret = mpq_dmx_init_video_feed(feed);
 
 		if (ret < 0) {
-			MPQ_DVB_DBG_PRINT(
+			MPQ_DVB_ERR_PRINT(
 				"%s: mpq_dmx_init_video_feed failed(%d)\n",
 				__func__,
 				ret);
@@ -917,11 +953,11 @@
 		for (i = 0; i < TSIF_COUNT; i++) {
 			mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle =
 				ion_alloc(mpq_dmx_tspp_info.ion_client,
-					(TSPP_BUFFER_COUNT *
-					 TSPP_PES_BUFFER_SIZE),
-					TSPP_RAW_TTS_SIZE,
-					ION_HEAP(ION_CP_MM_HEAP_ID),
-					0); /* non-cached */
+				 (mpq_dmx_tspp_info.tsif[i].buffer_count *
+				  TSPP_PES_BUFFER_SIZE),
+				 TSPP_RAW_TTS_SIZE,
+				 ION_HEAP(ION_CP_MM_HEAP_ID),
+				 0); /* non-cached */
 			if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
 						pes_mem_heap_handle)) {
 				MPQ_DVB_ERR_PRINT("%s: ion_alloc() failed\n",
@@ -956,11 +992,11 @@
 
 			mpq_dmx_tspp_info.tsif[i].section_mem_heap_handle =
 				ion_alloc(mpq_dmx_tspp_info.ion_client,
-					(TSPP_BUFFER_COUNT *
-					 TSPP_SECTION_BUFFER_SIZE),
-					TSPP_RAW_TTS_SIZE,
-					ION_HEAP(ION_CP_MM_HEAP_ID),
-					0); /* non-cached */
+				 (mpq_dmx_tspp_info.tsif[i].buffer_count *
+				  TSPP_SECTION_BUFFER_SIZE),
+				 TSPP_RAW_TTS_SIZE,
+				 ION_HEAP(ION_CP_MM_HEAP_ID),
+				 0); /* non-cached */
 			if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
 						section_mem_heap_handle)) {
 				MPQ_DVB_ERR_PRINT("%s: ion_alloc() failed\n",
@@ -1074,29 +1110,22 @@
 	MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
 
 	for (i = 0; i < TSIF_COUNT; i++) {
+		mpq_dmx_tspp_info.tsif[i].buffer_count =
+				TSPP_BUFFER_COUNT(tspp_out_buffer_size);
+
 		mpq_dmx_tspp_info.tsif[i].pes_channel_ref = 0;
 		mpq_dmx_tspp_info.tsif[i].pes_index = 0;
 		mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle = NULL;
 		mpq_dmx_tspp_info.tsif[i].pes_mem_heap_virt_base = NULL;
 		mpq_dmx_tspp_info.tsif[i].pes_mem_heap_phys_base = 0;
-
-		mpq_dmx_tspp_info.tsif[i].pes_work.channel_id =
-			TSPP_CHANNEL_ID(i, TSPP_PES_CHANNEL);
-
-		INIT_WORK(&mpq_dmx_tspp_info.tsif[i].pes_work.work,
-				  mpq_dmx_tspp_work);
+		atomic_set(&mpq_dmx_tspp_info.tsif[i].pes_data_cnt, 0);
 
 		mpq_dmx_tspp_info.tsif[i].section_channel_ref = 0;
 		mpq_dmx_tspp_info.tsif[i].section_index = 0;
 		mpq_dmx_tspp_info.tsif[i].section_mem_heap_handle = NULL;
 		mpq_dmx_tspp_info.tsif[i].section_mem_heap_virt_base = NULL;
 		mpq_dmx_tspp_info.tsif[i].section_mem_heap_phys_base = 0;
-
-		mpq_dmx_tspp_info.tsif[i].section_work.channel_id =
-			TSPP_CHANNEL_ID(i, TSPP_SECTION_CHANNEL);
-
-		INIT_WORK(&mpq_dmx_tspp_info.tsif[i].section_work.work,
-				  mpq_dmx_tspp_work);
+		atomic_set(&mpq_dmx_tspp_info.tsif[i].section_data_cnt, 0);
 
 		for (j = 0; j < TSPP_MAX_PID_FILTER_NUM; j++) {
 			mpq_dmx_tspp_info.tsif[i].filters[j].pid = -1;
@@ -1105,22 +1134,23 @@
 
 		snprintf(mpq_dmx_tspp_info.tsif[i].name,
 				TSIF_NAME_LENGTH,
-				"tsif_%d",
+				"dmx_tsif%d",
 				i);
 
-		mpq_dmx_tspp_info.tsif[i].workqueue =
-			create_singlethread_workqueue(
+		init_waitqueue_head(&mpq_dmx_tspp_info.tsif[i].wait_queue);
+		mpq_dmx_tspp_info.tsif[i].thread =
+			kthread_run(
+				mpq_dmx_tspp_thread, (void *)i,
 				mpq_dmx_tspp_info.tsif[i].name);
 
-		if (mpq_dmx_tspp_info.tsif[i].workqueue == NULL) {
+		if (IS_ERR(mpq_dmx_tspp_info.tsif[i].thread)) {
 			for (j = 0; j < i; j++) {
-				destroy_workqueue(
-					mpq_dmx_tspp_info.tsif[j].workqueue);
-
+				kthread_stop(mpq_dmx_tspp_info.tsif[j].thread);
 				mutex_destroy(&mpq_dmx_tspp_info.tsif[j].mutex);
 			}
+
 			MPQ_DVB_ERR_PRINT(
-				"%s: create_singlethread_workqueue failed\n",
+				"%s: kthread_run failed\n",
 				__func__);
 
 			return -ENOMEM;
@@ -1138,7 +1168,7 @@
 			ret);
 
 		for (i = 0; i < TSIF_COUNT; i++) {
-			destroy_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
+			kthread_stop(mpq_dmx_tspp_info.tsif[i].thread);
 			mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
 		}
 	}
@@ -1179,8 +1209,7 @@
 			mpq_dmx_tsif_ion_cleanup(i);
 
 		mutex_unlock(&mpq_dmx_tspp_info.tsif[i].mutex);
-		flush_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
-		destroy_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
+		kthread_stop(mpq_dmx_tspp_info.tsif[i].thread);
 		mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
 	}
 
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index be9c43c..24f6556 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -186,6 +186,17 @@
 	  It is a Texas Instruments multiple LED Flash
 	  for camera flash and video light applications.
 
+config MSM_CAMERA_LED_TRIGGER_FLASH
+	bool "Qualcomm MSM LED trigger flash support"
+	depends on MSM_CAMERA
+	default n
+	---help---
+	  Enable support for LED flash for msm camera.
+	  It creates LED trigger client, reads LED flash
+	  hardware properties provided in board file /
+	  device tree and uses these information to configure
+	  LED flash using LED trigger event function.
+
 config IMX072
 	bool "Sensor imx072 (Sony 5M)"
 	default n
diff --git a/drivers/media/video/msm/flash/Makefile b/drivers/media/video/msm/flash/Makefile
index e83f052..8d0812b 100644
--- a/drivers/media/video/msm/flash/Makefile
+++ b/drivers/media/video/msm/flash/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_MSM_CAMERA_FLASH_PMIC_FLASH) += pmic8058_flash.o
 obj-$(CONFIG_MSM_CAMERA_FLASH_SGM3141) += sgm3141.o
 obj-$(CONFIG_MSM_CAMERA_FLASH_PMIC8058_PWM) += pmic8058_pwm.o
+obj-$(CONFIG_MSM_CAMERA_LED_TRIGGER_FLASH) += led_trigger_flash.o
diff --git a/drivers/media/video/msm/flash/led_trigger_flash.c b/drivers/media/video/msm/flash/led_trigger_flash.c
new file mode 100644
index 0000000..cd34cde
--- /dev/null
+++ b/drivers/media/video/msm/flash/led_trigger_flash.c
@@ -0,0 +1,162 @@
+/* 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/export.h>
+#include "msm_flash.h"
+
+#define FLASH_NAME "camera-led-flash"
+static struct msm_flash_ctrl_t fctrl;
+
+static int msm_camera_led_trigger_flash(struct msm_flash_ctrl_t *fctrl,
+	uint8_t led_state)
+{
+	int rc = 0;
+	CDBG("%s:%d called led_state %d\n", __func__, __LINE__, led_state);
+
+	if (!fctrl->led_trigger[0]) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	switch (led_state) {
+	case MSM_CAMERA_LED_OFF:
+		led_trigger_event(fctrl->led_trigger[0], 0);
+		break;
+
+	case MSM_CAMERA_LED_LOW:
+		led_trigger_event(fctrl->led_trigger[0],
+			fctrl->max_current[0] / 2);
+		break;
+
+	case MSM_CAMERA_LED_HIGH:
+		led_trigger_event(fctrl->led_trigger[0], fctrl->max_current[0]);
+		break;
+
+	case MSM_CAMERA_LED_INIT:
+	case MSM_CAMERA_LED_RELEASE:
+		led_trigger_event(fctrl->led_trigger[0], 0);
+		break;
+
+	default:
+		rc = -EFAULT;
+		break;
+	}
+	CDBG("flash_set_led_state: return %d\n", rc);
+	return rc;
+}
+
+static const struct of_device_id msm_camera_flash_dt_match[] = {
+	{.compatible = "qcom,camera-led-flash"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, msm_camera_flash_dt_match);
+
+static struct platform_driver msm_led_trigger_flash_driver = {
+	.driver = {
+		.name = FLASH_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_camera_flash_dt_match,
+	},
+};
+
+static int32_t msm_led_trigger_flash_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0, i = 0;
+	struct device_node *of_node = pdev->dev.of_node;
+	struct device_node *flash_src_node = NULL;
+	uint32_t count = 0;
+
+	CDBG("%s called\n", __func__);
+
+	if (!of_node) {
+		pr_err("%s of_node NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	fctrl.pdev = pdev;
+
+	rc = of_property_read_u32(of_node, "cell-index", &pdev->id);
+	if (rc < 0) {
+		pr_err("%s:%d failed\n", __func__, __LINE__);
+		return -EINVAL;
+	}
+	CDBG("%s:%d pdev id %d\n", __func__, __LINE__, pdev->id);
+
+	if (of_get_property(of_node, "qcom,flash-source", &count)) {
+		count /= sizeof(uint32_t);
+		CDBG("%s count %d\n", __func__, count);
+		if (count > MAX_LED_TRIGGERS) {
+			pr_err("%s:%d failed\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+		for (i = 0; i < count; i++) {
+			flash_src_node = of_parse_phandle(of_node,
+				"qcom,flash-source", i);
+			if (!flash_src_node) {
+				pr_err("%s:%d flash_src_node NULL\n", __func__,
+					__LINE__);
+				continue;
+			}
+
+			rc = of_property_read_string(flash_src_node,
+				"linux,default-trigger",
+				&fctrl.led_trigger_name[i]);
+			if (rc < 0) {
+				pr_err("%s:%d failed\n", __func__, __LINE__);
+				of_node_put(flash_src_node);
+				continue;
+			}
+
+			CDBG("%s default trigger %s\n", __func__,
+				fctrl.led_trigger_name[i]);
+
+			rc = of_property_read_u32(flash_src_node,
+				"qcom,max-current", &fctrl.max_current[i]);
+			if (rc < 0) {
+				pr_err("%s:%d failed rc %d\n", __func__,
+					__LINE__, rc);
+				of_node_put(flash_src_node);
+				continue;
+			}
+
+			of_node_put(flash_src_node);
+
+			CDBG("%s max_current[%d] %d\n", __func__, i,
+				fctrl.max_current[i]);
+
+			led_trigger_register_simple(fctrl.led_trigger_name[i],
+				&fctrl.led_trigger[i]);
+		}
+	}
+	rc = msm_flash_platform_probe(pdev, &fctrl);
+	return rc;
+}
+
+static int __init msm_flash_add_driver(void)
+{
+	CDBG("%s called\n", __func__);
+	return platform_driver_probe(&msm_led_trigger_flash_driver,
+		msm_led_trigger_flash_probe);
+}
+
+static struct msm_flash_fn_t msm_led_trigger_flash_func_tbl = {
+	.flash_led_config = msm_camera_led_trigger_flash,
+};
+
+static struct msm_flash_ctrl_t fctrl = {
+	.func_tbl = &msm_led_trigger_flash_func_tbl,
+};
+
+module_init(msm_flash_add_driver);
+MODULE_DESCRIPTION("LED TRIGGER FLASH");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/flash/msm_flash.h b/drivers/media/video/msm/flash/msm_flash.h
index a7c8846..2513995 100644
--- a/drivers/media/video/msm/flash/msm_flash.h
+++ b/drivers/media/video/msm/flash/msm_flash.h
@@ -55,7 +55,7 @@
 	struct msm_flash_reg_t *reg_setting;
 	const char *led_trigger_name[MAX_LED_TRIGGERS];
 	struct led_trigger *led_trigger[MAX_LED_TRIGGERS];
-	uint32_t max_brightness[MAX_LED_TRIGGERS];
+	uint32_t max_current[MAX_LED_TRIGGERS];
 	void *data;
 };
 
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
index ff99aa3..31286dd 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
@@ -126,5 +126,11 @@
 #define JPEG_VBIF_OUT_WR_LIM_CONF0             0xD4
 #define JPEG_VBIF_DDR_OUT_MAX_BURST            0xD8
 #define JPEG_VBIF_OCMEM_OUT_MAX_BURST          0xDC
+#define JPEG_VBIF_ARB_CTL                      0xF0
+#define JPEG_VBIF_OUT_AXI_AOOO_EN              0x178
+#define JPEG_VBIF_OUT_AXI_AOOO                 0x17c
+#define JPEG_VBIF_ROUND_ROBIN_QOS_ARB          0x124
+#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0       0x160
+#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1       0x164
 
 #endif /* MSM_JPEG_HW_REG_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
index 06135ec..38a0ffb 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
@@ -108,12 +108,26 @@
 		jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF2);
 	writel_relaxed(0x00001010,
 		jpeg_vbif_base + JPEG_VBIF_OUT_RD_LIM_CONF0);
-	writel_relaxed(0x00001010,
+	writel_relaxed(0x00000110,
 		jpeg_vbif_base + JPEG_VBIF_OUT_WR_LIM_CONF0);
 	writel_relaxed(0x00000707,
 		jpeg_vbif_base + JPEG_VBIF_DDR_OUT_MAX_BURST);
-	writel_relaxed(0x00000707,
+	writel_relaxed(0x7,
 		jpeg_vbif_base + JPEG_VBIF_OCMEM_OUT_MAX_BURST);
+	writel_relaxed(0x00000030,
+		jpeg_vbif_base + JPEG_VBIF_ARB_CTL);
+	writel_relaxed(0x00000FFF,
+		jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO_EN);
+	writel_relaxed(0x0FFF0FFF,
+		jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO);
+	/*FE and WE QOS configuration need to be set when
+	QOS RR arbitration is enabled*/
+	writel_relaxed(0x00000001,
+		jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB);
+	writel_relaxed(0x22222222,
+		jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+	writel_relaxed(0x2222,
+		jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1);
 }
 
 
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 63cf38e..907523c 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -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
@@ -603,6 +603,8 @@
 {
 	int32_t rc = 0;
 	uint32_t val = 0;
+	struct msm_camera_sensor_flash_data *flash_data = NULL;
+	struct device_node *flash_src_node = NULL;
 
 	sensordata->flash_data = kzalloc(sizeof(
 		struct msm_camera_sensor_flash_data), GFP_KERNEL);
@@ -611,16 +613,42 @@
 		return -ENOMEM;
 	}
 
-	rc = of_property_read_u32(of_node, "qcom,flash-type", &val);
+	if (!of_get_property(of_node, "qcom,flash-src-index", &val)) {
+		CDBG("%s flash not available\n", __func__);
+		return rc;
+	}
+	flash_data = sensordata->flash_data;
+
+	flash_src_node = of_parse_phandle(of_node, "qcom,flash-src-index", 0);
+	if (!flash_src_node) {
+		pr_err("%s:%d flash_src_node NULL\n", __func__,
+			__LINE__);
+		goto ERROR1;
+	}
+
+	rc = of_property_read_u32(flash_src_node, "qcom,flash-type", &val);
 	CDBG("%s qcom,flash-type %d, rc %d\n", __func__, val, rc);
 	if (rc < 0) {
 		pr_err("%s failed %d\n", __func__, __LINE__);
-		goto ERROR;
+		goto ERROR2;
 	}
-	sensordata->flash_data->flash_type = val;
+	flash_data->flash_type = val;
+
+	rc = of_property_read_u32(flash_src_node, "cell-index", &val);
+	CDBG("%s qcom,flash-src-index %d, rc %d\n", __func__, val, rc);
+	if (rc < 0) {
+		pr_err("%s failed %d\n", __func__, __LINE__);
+		goto ERROR2;
+	}
+	flash_data->flash_src_index = val;
+
+	of_node_put(flash_src_node);
+
 	return rc;
-ERROR:
-	kfree(sensordata->flash_data);
+ERROR2:
+	of_node_put(flash_src_node);
+ERROR1:
+	flash_data->flash_type = MSM_CAMERA_FLASH_NONE;
 	return rc;
 }
 
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index b2a7f71..f61b74f 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -473,16 +473,15 @@
 	kfree(ctrlcmd);
 	free_qcmd(rcmd);
 	D("%s: rc %d\n", __func__, rc);
-	/* rc is the time elapsed. */
-	if (rc >= 0) {
-		/* TODO: Refactor msm_ctrl_cmd::status field */
-		if (out->status == 0)
-			rc = -1;
-		else if (out->status == 1 || out->status == 4)
-			rc = 0;
-		else
-			rc = -EINVAL;
-	}
+	/* rc is the time elapsed.
+	 * This means that the communication with the daemon itself was
+	 * successful(irrespective of the handling of the ctrlcmd).
+	 * So, just reset the rc to 0 to indicate success.
+	 * Its upto the caller to parse the ctrlcmd to check the status. We
+	 * dont need to parse it here. */
+	if (rc >= 0)
+		rc = 0;
+
 	return rc;
 
 ctrlcmd_alloc_fail:
@@ -846,9 +845,9 @@
 			rc = -EINVAL;
 			goto end;
 		}
-
+		tmp_cmd.status = cmd_ptr->status = ctrlcmd.status;
 		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
-			(void *)&tmp_cmd, cmd_len)) {
+			(void *)cmd_ptr, cmd_len)) {
 			pr_err("%s: copy_to_user failed in cpy, size=%d\n",
 				__func__, cmd_len);
 			rc = -EINVAL;
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 287c77c..81a6dd2 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -5170,39 +5170,44 @@
 
 static void msm_vfe40_init_vbif_parms(void __iomem *vfe_vbif_base)
 {
-	msm_camera_io_w_mb(0x1,
+	msm_camera_io_w(0x1,
 		vfe_vbif_base + VFE40_VBIF_CLKON);
-	msm_camera_io_w_mb(0x1,
-		vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
-	msm_camera_io_w_mb(0xFFFF,
-		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
-	msm_camera_io_w_mb(0xFFFFFFFF,
-		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
-
-	msm_camera_io_w_mb(0x10101010,
+	msm_camera_io_w(0x01010101,
 		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
-	msm_camera_io_w_mb(0x10101010,
+	msm_camera_io_w(0x01010101,
 		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
-	msm_camera_io_w_mb(0x10101010,
+	msm_camera_io_w(0x10010110,
 		vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
-	msm_camera_io_w_mb(0x10101010,
+	msm_camera_io_w(0x10101010,
 		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
-	msm_camera_io_w_mb(0x10101010,
+	msm_camera_io_w(0x10101010,
 		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
-	msm_camera_io_w_mb(0x10101010,
+	msm_camera_io_w(0x10101010,
 		vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
-	msm_camera_io_w_mb(0x00001010,
+	msm_camera_io_w(0x00001010,
 		vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
-	msm_camera_io_w_mb(0x00001010,
+	msm_camera_io_w(0x00001010,
 		vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
-	msm_camera_io_w_mb(0x00000707,
+	msm_camera_io_w(0x00000707,
 		vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
-	msm_camera_io_w_mb(0x00000030,
+	msm_camera_io_w(0x00000707,
+		vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
+	msm_camera_io_w(0x00000030,
 		vfe_vbif_base + VFE40_VBIF_ARB_CTL);
-	msm_camera_io_w_mb(0x04210842,
+	msm_camera_io_w(0x04210842,
 		vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF0);
-	msm_camera_io_w_mb(0x04210842,
+	msm_camera_io_w(0x04210842,
 		vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF1);
+	msm_camera_io_w(0x00000001,
+		vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+	msm_camera_io_w(0x22222222,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+	msm_camera_io_w(0x00002222,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+	msm_camera_io_w(0x00000FFF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+	msm_camera_io_w(0x0FFF0FFF,
+		vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
 }
 
 int msm_axi_subdev_init(struct v4l2_subdev *sd)
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index 4acc7e4..a94c428 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -901,22 +901,25 @@
 #define VFE40_OUTPUT_MODE_TERTIARY1		BIT(10)
 #define VFE40_OUTPUT_MODE_TERTIARY2		BIT(11)
 
-#define VFE40_VBIF_CLKON				0x4
-#define VFE40_VBIF_IN_RD_LIM_CONF0		0xB0
-#define VFE40_VBIF_IN_RD_LIM_CONF1		0xB4
-#define VFE40_VBIF_IN_RD_LIM_CONF2		0xB8
-#define VFE40_VBIF_IN_WR_LIM_CONF0		0xC0
-#define VFE40_VBIF_IN_WR_LIM_CONF1		0xC4
-#define VFE40_VBIF_IN_WR_LIM_CONF2		0xC8
-#define VFE40_VBIF_OUT_RD_LIM_CONF0		0xD0
-#define VFE40_VBIF_OUT_WR_LIM_CONF0		0xD4
-#define VFE40_VBIF_DDR_OUT_MAX_BURST	0xD8
-#define VFE40_VBIF_ARB_CTL				0xF0
-#define VFE40_VBIF_DDR_ARB_CONF0		0xF4
-#define VFE40_VBIF_DDR_ARB_CONF1		0xF8
-#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB	0x124
-#define VFE40_VBIF_OUT_AXI_AOOO_EN		0x178
-#define VFE40_VBIF_OUT_AXI_AOOO			0x17C
+#define VFE40_VBIF_CLKON					0x4
+#define VFE40_VBIF_IN_RD_LIM_CONF0			0xB0
+#define VFE40_VBIF_IN_RD_LIM_CONF1			0xB4
+#define VFE40_VBIF_IN_RD_LIM_CONF2			0xB8
+#define VFE40_VBIF_IN_WR_LIM_CONF0			0xC0
+#define VFE40_VBIF_IN_WR_LIM_CONF1			0xC4
+#define VFE40_VBIF_IN_WR_LIM_CONF2			0xC8
+#define VFE40_VBIF_OUT_RD_LIM_CONF0			0xD0
+#define VFE40_VBIF_OUT_WR_LIM_CONF0			0xD4
+#define VFE40_VBIF_DDR_OUT_MAX_BURST		0xD8
+#define VFE40_VBIF_OCMEM_OUT_MAX_BURST		0xDC
+#define VFE40_VBIF_ARB_CTL					0xF0
+#define VFE40_VBIF_DDR_ARB_CONF0			0xF4
+#define VFE40_VBIF_DDR_ARB_CONF1			0xF8
+#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB		0x124
+#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0	0x160
+#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1	0x164
+#define VFE40_VBIF_OUT_AXI_AOOO_EN			0x178
+#define VFE40_VBIF_OUT_AXI_AOOO				0x17C
 
 struct vfe_stats_control {
 	uint32_t droppedStatsFrameCount;
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 83f33a1..e1b73ef 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -32,8 +32,6 @@
 				clnt, hndl, iova, buffer_size);
 		return -EINVAL;
 	}
-	if (align < 4096)
-		align = 4096;
 	dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
 		domain_num, partition_num);
 	if (flags & SMEM_SECURE) {
@@ -74,6 +72,7 @@
 	unsigned long iova = 0;
 	unsigned long buffer_size = 0;
 	int rc = 0;
+	int align = SZ_4K;
 	hndl = ion_import_dma_buf(client->clnt, fd);
 	if (IS_ERR_OR_NULL(hndl)) {
 		dprintk(VIDC_ERR, "Failed to get handle: %p, %d, %d, %p\n",
@@ -85,8 +84,12 @@
 	mem->domain = domain;
 	mem->partition_num = partition;
 	mem->flags = flags;
+
+	if (flags & SMEM_SECURE)
+		align = ALIGN(align, SZ_1M);
+
 	rc = get_device_address(client->clnt, hndl, mem->domain,
-		mem->partition_num, 4096, &iova, &buffer_size, flags);
+		mem->partition_num, align, &iova, &buffer_size, flags);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
 		goto fail_device_address;
@@ -121,15 +124,16 @@
 	else
 		ionflags = ION_SET_UNCACHED(ionflags);
 
+	align = ALIGN(align, SZ_4K);
+	size = ALIGN(size, SZ_4K);
+
 	if (flags & SMEM_SECURE) {
 		ionflags |= ION_SECURE;
-		size = (size + 0xfffff) & (~0xfffff);
+		size = ALIGN(size, SZ_1M);
+		align = ALIGN(align, SZ_1M);
 	}
 
 	heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
-	if (align < 4096)
-		align = 4096;
-	size = (size + 4095) & (~4095);
 	dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
 		domain, partition);
 	hndl = ion_alloc(client->clnt, size, align, heap_mask, ionflags);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 4f2373e..38e8de1 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -591,7 +591,7 @@
 	}
 
 	v4l2_inst->vidc_inst = msm_vidc_open(core->id, vid_dev->type);
-	if (rc) {
+	if (!v4l2_inst->vidc_inst) {
 		dprintk(VIDC_ERR,
 		"Failed to create video instance, core: %d, type = %d\n",
 		core->id, vid_dev->type);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index a95a296..e0a341a 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -462,7 +462,7 @@
 					b->m.planes[extra_idx].m.userptr;
 			else
 				buffer_info.extradata_addr = 0;
-
+			buffer_info.response_required = false;
 			rc = vidc_hal_session_release_buffers(
 					(void *)inst->session, &buffer_info);
 			if (rc)
@@ -631,10 +631,7 @@
 	}
 	inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
 	if (inst->prop.fps) {
-		if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
-			dprintk(VIDC_WARN,
-					"Failed to scale clocks\n");
-		}
+		msm_comm_scale_clocks_and_bus(inst);
 	}
 exit:
 	return rc;
@@ -881,11 +878,7 @@
 			"Failed to set persist buffers: %d\n", rc);
 		goto fail_start;
 	}
-	if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
-		dprintk(VIDC_WARN,
-			"Failed to scale clocks. Performance might be impacted\n");
-	}
-
+	msm_comm_scale_clocks_and_bus(inst);
 	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
 	if (rc) {
 		dprintk(VIDC_ERR,
@@ -976,10 +969,7 @@
 		rc = -EINVAL;
 		break;
 	}
-	if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
-		dprintk(VIDC_WARN,
-			"Failed to scale clocks. Power might be impacted\n");
-	}
+	msm_comm_scale_clocks_and_bus(inst);
 
 	if (rc)
 		dprintk(VIDC_ERR,
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index d01841d..f436cf3 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -639,10 +639,7 @@
 		dprintk(VIDC_ERR, "Failed to set persist buffers: %d\n", rc);
 		goto fail_start;
 	}
-	if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
-		dprintk(VIDC_WARN,
-			"Failed to scale clocks. Performance might be impacted\n");
-	}
+	msm_comm_scale_clocks_and_bus(inst);
 
 	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
 	if (rc) {
@@ -718,10 +715,7 @@
 		rc = -EINVAL;
 		break;
 	}
-	if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
-		dprintk(VIDC_WARN,
-			"Failed to scale clocks. Power might be impacted\n");
-	}
+	msm_comm_scale_clocks_and_bus(inst);
 
 	if (rc)
 		dprintk(VIDC_ERR,
@@ -1371,10 +1365,7 @@
 			dprintk(VIDC_WARN,
 				"Failed to set frame rate %d\n", rc);
 		}
-		if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
-			dprintk(VIDC_WARN,
-				"Failed to scale clocks\n");
-		}
+		msm_comm_scale_clocks_and_bus(inst);
 	}
 exit:
 	return rc;
@@ -1578,6 +1569,7 @@
 				 b->m.planes[i].m.userptr;
 			buffer_info.extradata_size = 0;
 			buffer_info.extradata_addr = 0;
+			buffer_info.response_required = false;
 			rc = vidc_hal_session_release_buffers(
 				(void *)inst->session, &buffer_info);
 			if (rc)
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index cda0ea8..46a88c2 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -64,7 +64,6 @@
 };
 
 static const u32 bus_table[] = {
-	0,
 	36000,
 	110400,
 	244800,
@@ -77,12 +76,11 @@
 {
 	int num_rows = sizeof(bus_table)/(sizeof(u32));
 	int i;
-	if (!load)
-		return 0;
 	for (i = 0; i < num_rows; i++) {
 		if (load <= bus_table[i])
 			break;
 	}
+	i++;
 	dprintk(VIDC_DBG, "Required bus = %d\n", i);
 	return i;
 }
@@ -122,37 +120,60 @@
 			break;
 		ret = table[i].freq;
 	}
-	dprintk(VIDC_INFO, "Required clock rate = %lu\n", ret);
+	dprintk(VIDC_DBG, "Required clock rate = %lu\n", ret);
 	return ret;
 }
 
-int msm_comm_scale_bus(struct msm_vidc_core *core, enum session_type type)
+static int msm_comm_scale_bus(struct msm_vidc_core *core,
+	enum session_type type, enum mem_type mtype)
 {
 	int load;
 	int rc = 0;
+	u32 handle = 0;
 	if (!core || type >= MSM_VIDC_MAX_DEVICES) {
 		dprintk(VIDC_ERR, "Invalid args: %p, %d\n", core, type);
 		return -EINVAL;
 	}
 	load = msm_comm_get_load(core, type);
-	rc = msm_bus_scale_client_update_request(
-			core->resources.bus_info.ddr_handle[type],
-			get_bus_vector(load));
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
-		goto fail_scale_bus;
+	if (mtype & DDR_MEM)
+		handle = core->resources.bus_info.ddr_handle[type];
+	if (mtype & OCMEM_MEM)
+		handle = core->resources.bus_info.ocmem_handle[type];
+	if (handle) {
+		rc = msm_bus_scale_client_update_request(
+				handle, get_bus_vector(load));
+		if (rc)
+			dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
+	} else {
+		dprintk(VIDC_ERR, "Failed to scale bus, mtype: %d\n",
+				mtype);
+		rc = -EINVAL;
 	}
-	rc = msm_bus_scale_client_update_request(
-			core->resources.bus_info.ocmem_handle[type],
-			get_bus_vector(load));
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
-		goto fail_scale_bus;
-	}
-fail_scale_bus:
 	return rc;
 }
 
+static void msm_comm_unvote_buses(struct msm_vidc_core *core,
+	enum mem_type mtype)
+{
+	int i;
+	for (i = 0; i < MSM_VIDC_MAX_DEVICES; i++) {
+		if ((mtype & DDR_MEM) &&
+			msm_bus_scale_client_update_request(
+				core->resources.bus_info.ddr_handle[i],
+				0)) {
+			dprintk(VIDC_WARN,
+				"Failed to unvote for DDR accesses\n");
+		}
+		if ((mtype & OCMEM_MEM) &&
+			msm_bus_scale_client_update_request(
+				core->resources.bus_info.ocmem_handle[i],
+				0)) {
+			dprintk(VIDC_WARN,
+				"Failed to unvote for OCMEM accesses\n");
+		}
+	}
+}
+
 static int protect_cp_mem(struct msm_vidc_core *core)
 {
 	struct tzbsp_memprot memprot;
@@ -333,6 +354,48 @@
 	}
 }
 
+static void handle_session_release_buf_done(enum command_response cmd,
+	void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct internal_buf *buf;
+	struct list_head *ptr, *next;
+	struct hal_buffer_info *buffer;
+	u32 address, buf_found = false;
+
+	if (!response || !response->data) {
+		dprintk(VIDC_ERR, "Invalid release_buf_done response\n");
+		return;
+	}
+
+	inst = (struct msm_vidc_inst *)response->session_id;
+	buffer = (struct hal_buffer_info *) response->data;
+	address = (u32) buffer->buffer_addr;
+
+	list_for_each_safe(ptr, next, &inst->internalbufs) {
+		buf = list_entry(ptr, struct internal_buf, list);
+		if (address == buf->handle->device_addr) {
+			dprintk(VIDC_DBG, "releasing scratch: 0x%x",
+					(u32) buf->handle->device_addr);
+					buf_found = true;
+		}
+	}
+
+	list_for_each_safe(ptr, next, &inst->persistbufs) {
+		buf = list_entry(ptr, struct internal_buf, list);
+		if (address == (u32) buf->handle->device_addr) {
+			dprintk(VIDC_DBG, "releasing persist: 0x%x",
+					(u32) buf->handle->device_addr);
+			buf_found = true;
+		}
+	}
+
+	if (!buf_found)
+		dprintk(VIDC_ERR, "invalid buffer received from firmware");
+	complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+}
+
 static void handle_sys_release_res_done(
 	enum command_response cmd, void *data)
 {
@@ -589,33 +652,28 @@
 	struct v4l2_event dqevent;
 	unsigned long flags;
 	if (response) {
-		inst = (struct msm_vidc_inst *)response->session_id;
-		dprintk(VIDC_WARN,
-				"Sys error received for session %p\n", inst);
-		if (inst) {
-			core = inst->core;
-			if (core) {
-				spin_lock_irqsave(&core->lock, flags);
-				core->state = VIDC_CORE_INVALID;
-				spin_unlock_irqrestore(&core->lock, flags);
-				dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
-				dqevent.id = 0;
-				list_for_each_entry(inst, &core->instances,
+		core = get_vidc_core(response->device_id);
+		dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
+		if (core) {
+			spin_lock_irqsave(&core->lock, flags);
+			core->state = VIDC_CORE_INVALID;
+			spin_unlock_irqrestore(&core->lock, flags);
+			dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+			dqevent.id = 0;
+			list_for_each_entry(inst, &core->instances,
 					list) {
-					if (inst) {
-						v4l2_event_queue_fh(
-							&inst->event_handler,
-								&dqevent);
-						spin_lock_irqsave(&inst->lock,
-							flags);
-						inst->state =
-							MSM_VIDC_CORE_INVALID;
-						spin_unlock_irqrestore(
-							&inst->lock, flags);
-					}
-				}
-			wake_up(&inst->kernel_event_queue);
+				v4l2_event_queue_fh(&inst->event_handler,
+						&dqevent);
+
+				spin_lock_irqsave(&inst->lock, flags);
+				inst->state = MSM_VIDC_CORE_INVALID;
+				spin_unlock_irqrestore(&inst->lock, flags);
+
+				wake_up(&inst->kernel_event_queue);
 			}
+		} else {
+			dprintk(VIDC_ERR,
+				"Got SYS_ERR but unable to identify core");
 		}
 	} else {
 		dprintk(VIDC_ERR,
@@ -876,13 +934,16 @@
 	case SESSION_ERROR:
 		handle_session_error(cmd, data);
 		break;
+	case SESSION_RELEASE_BUFFER_DONE:
+		handle_session_release_buf_done(cmd, data);
+		break;
 	default:
 		dprintk(VIDC_ERR, "response unhandled\n");
 		break;
 	}
 }
 
-int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type)
+static int msm_comm_scale_clocks(struct msm_vidc_core *core)
 {
 	int num_mbs_per_sec;
 	int rc = 0;
@@ -896,14 +957,8 @@
 	rc = clk_set_rate(core->resources.clock[VCODEC_CLK].clk,
 			get_clock_rate(&core->resources.clock[VCODEC_CLK],
 				num_mbs_per_sec));
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
-		goto fail_clk_set_rate;
-	}
-	rc = msm_comm_scale_bus(core, type);
 	if (rc)
-		dprintk(VIDC_ERR, "Failed to scale bus bandwidth\n");
-fail_clk_set_rate:
+		dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
 	return rc;
 }
 
@@ -949,6 +1004,28 @@
 	}
 }
 
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core = inst->core;
+	if (!inst) {
+		dprintk(VIDC_WARN, "Invalid params\n");
+		return;
+	}
+	if (msm_comm_scale_clocks(core)) {
+		dprintk(VIDC_WARN,
+		"Failed to scale clocks. Performance might be impacted\n");
+	}
+	if (msm_comm_scale_bus(core, inst->session_type, DDR_MEM)) {
+		dprintk(VIDC_WARN,
+		"Failed to scale DDR bus. Performance might be impacted\n");
+	}
+	if (core->resources.ocmem.buf) {
+		if (msm_comm_scale_bus(core, inst->session_type, OCMEM_MEM))
+			dprintk(VIDC_WARN,
+			"Failed to scale OCMEM bus. Performance might be impacted\n");
+	}
+}
+
 static int msm_comm_load_fw(struct msm_vidc_core *core)
 {
 	int rc = 0;
@@ -956,25 +1033,28 @@
 		dprintk(VIDC_ERR, "Invalid paramter: %p\n", core);
 		return -EINVAL;
 	}
-
 	if (!core->resources.fw.cookie)
 		core->resources.fw.cookie = subsystem_get("venus");
 
 	if (IS_ERR_OR_NULL(core->resources.fw.cookie)) {
 		dprintk(VIDC_ERR, "Failed to download firmware\n");
 		rc = -ENOMEM;
-		goto fail_subsystem_get;
+		goto fail_load_fw;
 	}
+	/*Clocks can be enabled only after pil_get since
+	 * gdsc is turned-on in pil_get*/
 	rc = msm_comm_enable_clks(core);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
 		goto fail_enable_clks;
 	}
+
 	rc = protect_cp_mem(core);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to protect memory\n");
 		goto fail_iommu_attach;
 	}
+
 	rc = msm_comm_iommu_attach(core);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to attach iommu");
@@ -986,7 +1066,7 @@
 fail_enable_clks:
 	subsystem_put(core->resources.fw.cookie);
 	core->resources.fw.cookie = NULL;
-fail_subsystem_get:
+fail_load_fw:
 	return rc;
 }
 
@@ -1189,16 +1269,24 @@
 				core->id, core->state);
 		goto core_already_inited;
 	}
-	rc = msm_comm_scale_clocks(core, inst->session_type);
+
+	rc = msm_comm_scale_bus(core, inst->session_type, DDR_MEM);
 	if (rc) {
-		dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
-		goto fail_load_fw;
+		dprintk(VIDC_ERR, "Failed to scale DDR bus: %d\n", rc);
+		goto fail_scale_bus;
 	}
+
 	rc = msm_comm_load_fw(core);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to load video firmware\n");
 		goto fail_load_fw;
 	}
+	rc = msm_comm_scale_clocks(core);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to scale clocks: %d\n", rc);
+		goto fail_core_init;
+	}
+
 	init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
 	rc = vidc_hal_core_init(core->device,
 		core->resources.io_map[NS_MAP].domain);
@@ -1216,6 +1304,8 @@
 fail_core_init:
 	msm_comm_unload_fw(core);
 fail_load_fw:
+	msm_comm_unvote_buses(core, DDR_MEM);
+fail_scale_bus:
 	mutex_unlock(&core->sync_lock);
 	return rc;
 }
@@ -1231,10 +1321,7 @@
 				core->id, core->state);
 		goto core_already_uninited;
 	}
-	if (msm_comm_scale_clocks(core, inst->session_type)) {
-		dprintk(VIDC_WARN, "Failed to scale clocks while closing\n");
-		dprintk(VIDC_INFO, "Power might be impacted\n");
-	}
+	msm_comm_scale_clocks_and_bus(inst);
 	if (list_empty(&core->instances)) {
 		msm_comm_unset_ocmem(core);
 		msm_comm_free_ocmem(core);
@@ -1249,6 +1336,7 @@
 		core->state = VIDC_CORE_UNINIT;
 		spin_unlock_irqrestore(&core->lock, flags);
 		msm_comm_unload_fw(core);
+		msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
 	}
 core_already_uninited:
 	change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
@@ -1367,11 +1455,18 @@
 		goto exit;
 	}
 	ocmem_sz = get_ocmem_requirement(inst->prop.height, inst->prop.width);
-	rc = msm_comm_alloc_ocmem(inst->core, ocmem_sz);
-	if (rc)
-		dprintk(VIDC_WARN,
+	rc = msm_comm_scale_bus(inst->core, inst->session_type, OCMEM_MEM);
+	if (!rc) {
+		rc = msm_comm_alloc_ocmem(inst->core, ocmem_sz);
+		if (rc) {
+			dprintk(VIDC_WARN,
 			"Failed to allocate OCMEM. Performance will be impacted\n");
-
+			msm_comm_unvote_buses(inst->core, OCMEM_MEM);
+		}
+	} else {
+		dprintk(VIDC_WARN,
+		"Failed to vote for OCMEM BW. Performance will be impacted\n");
+	}
 	rc = vidc_hal_session_load_res((void *) inst->session);
 	if (rc) {
 		dprintk(VIDC_ERR,
@@ -1790,6 +1885,10 @@
 			buffer_info.align_device_addr = handle->device_addr;
 			if (inst->state != MSM_VIDC_CORE_INVALID &&
 					core->state != VIDC_CORE_INVALID) {
+				buffer_info.response_required = true;
+				init_completion(
+				   &inst->completions[SESSION_MSG_INDEX
+				   (SESSION_RELEASE_BUFFER_DONE)]);
 				rc = vidc_hal_session_release_buffers(
 						(void *) inst->session,
 							&buffer_info);
@@ -1798,6 +1897,10 @@
 						"Rel scrtch buf fail:0x%x, %d",
 						buffer_info.align_device_addr,
 						buffer_info.buffer_size);
+				spin_unlock_irqrestore(&inst->lock, flags);
+				rc = wait_for_sess_signal_receipt(inst,
+					SESSION_RELEASE_BUFFER_DONE);
+				spin_lock_irqsave(&inst->lock, flags);
 			}
 			list_del(&buf->list);
 			spin_unlock_irqrestore(&inst->lock, flags);
@@ -1842,6 +1945,10 @@
 			buffer_info.align_device_addr = handle->device_addr;
 			if (inst->state != MSM_VIDC_CORE_INVALID &&
 					core->state != VIDC_CORE_INVALID) {
+				buffer_info.response_required = true;
+				init_completion(
+				   &inst->completions[SESSION_MSG_INDEX
+				   (SESSION_RELEASE_BUFFER_DONE)]);
 				rc = vidc_hal_session_release_buffers(
 						(void *) inst->session,
 							&buffer_info);
@@ -1850,6 +1957,10 @@
 						"Rel prst buf fail:0x%x, %d",
 						buffer_info.align_device_addr,
 						buffer_info.buffer_size);
+				spin_unlock_irqrestore(&inst->lock, flags);
+				rc = wait_for_sess_signal_receipt(inst,
+					SESSION_RELEASE_BUFFER_DONE);
+				spin_lock_irqsave(&inst->lock, flags);
 			}
 			list_del(&buf->list);
 			spin_unlock_irqrestore(&inst->lock, flags);
@@ -1932,6 +2043,8 @@
 			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr = handle->device_addr;
+			dprintk(VIDC_DBG, "Scratch buffer address: %x",
+					buffer_info.align_device_addr);
 			rc = vidc_hal_session_set_buffers(
 					(void *) inst->session,	&buffer_info);
 			if (rc) {
@@ -2003,6 +2116,8 @@
 			buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr = handle->device_addr;
+			dprintk(VIDC_DBG, "Persist buffer address: %x",
+					buffer_info.align_device_addr);
 			rc = vidc_hal_session_set_buffers(
 				(void *) inst->session, &buffer_info);
 			if (rc) {
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 28bec97..916a3ca 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -32,7 +32,7 @@
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
 int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
 int msm_comm_qbuf(struct vb2_buffer *vb);
-int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type);
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
 int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
 int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst);
 int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index e9295a6..b274d13 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -134,6 +134,11 @@
 	u32 freq;
 };
 
+enum mem_type {
+	DDR_MEM = 0x1,
+	OCMEM_MEM = 0x2,
+};
+
 struct core_clock {
 	char name[MAX_NAME_LENGTH];
 	struct clk *clk;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index e449821..207bfe4 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -1954,6 +1954,7 @@
 		pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
 			((buffer_info->num_buffers - 1) * sizeof(u32));
 	}
+	pkt->response_req = buffer_info->response_required;
 	buffer = get_hfi_buffer(buffer_info->buffer_type);
 	if (buffer)
 		pkt->buffer_type = buffer;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.h b/drivers/media/video/msm_vidc/vidc_hal.h
index 57d685b..c8a7d43 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.h
+++ b/drivers/media/video/msm_vidc/vidc_hal.h
@@ -271,6 +271,8 @@
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013)
 #define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA	\
 	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014)
+#define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015)
 
 #define HFI_PROPERTY_CONFIG_VDEC_OX_START				\
 	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000)
@@ -479,6 +481,7 @@
 	u32 input_tag;
 	u8 *packet_buffer;
 	u8 *extra_data_buffer;
+	u32 rgData[0];
 };
 
 struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet {
@@ -497,6 +500,7 @@
 	u32 input_tag;
 	u8 *packet_buffer;
 	u8 *extra_data_buffer;
+	u32 rgData[0];
 };
 
 struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet {
@@ -505,6 +509,7 @@
 	u32 filled_len;
 	u32 offset;
 	u8 *packet_buffer2;
+	u32 rgData[0];
 };
 
 struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet {
@@ -513,6 +518,7 @@
 	u32 filled_len;
 	u32 offset;
 	u8 *packet_buffer3;
+	u32 rgData[0];
 };
 
 struct hfi_cmd_session_fill_buffer_packet {
@@ -526,6 +532,7 @@
 	u32 output_tag;
 	u8 *packet_buffer;
 	u8 *extra_data_buffer;
+	u32 rgData[0];
 };
 
 struct hfi_cmd_session_flush_packet {
@@ -659,6 +666,7 @@
 	u32 input_tag;
 	u8 *packet_buffer;
 	u8 *extra_data_buffer;
+	u32 rgData[0];
 };
 
 struct hfi_msg_session_fill_buffer_done_compressed_packet {
@@ -680,6 +688,7 @@
 	u32 picture_type;
 	u8 *packet_buffer;
 	u8 *extra_data_buffer;
+	u32 rgData[0];
 };
 
 struct hfi_msg_session_fbd_uncompressed_plane0_packet {
@@ -708,6 +717,7 @@
 	u32 picture_type;
 	u8 *packet_buffer;
 	u8 *extra_data_buffer;
+	u32 rgData[0];
 };
 
 struct hfi_msg_session_fill_buffer_done_uncompressed_plane1_packet {
@@ -716,6 +726,7 @@
 	u32 filled_len;
 	u32 offset;
 	u8 *packet_buffer2;
+	u32 rgData[0];
 };
 
 struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet {
@@ -724,6 +735,7 @@
 	u32 filled_len;
 	u32 offset;
 	u8 *packet_buffer3;
+	u32 rgData[0];
 };
 
 struct hfi_msg_session_parse_sequence_header_done_packet {
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 9d20a31..3b83424 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -777,6 +777,12 @@
 	u32 align_device_addr;
 	u32 extradata_size;
 	u32 extradata_addr;
+	u32 response_required;
+};
+
+struct hal_buffer_info {
+	u32 buffer_addr;
+	u32 extra_data_addr;
 };
 
 struct vidc_frame_plane_config {
diff --git a/drivers/media/video/msm_vidc/vidc_hal_helper.h b/drivers/media/video/msm_vidc/vidc_hal_helper.h
index 9412eed..9f805d7 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_helper.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_helper.h
@@ -224,6 +224,8 @@
 	(HFI_PROPERTY_PARAM_COMMON_START + 0x00D)
 #define  HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED            \
 	(HFI_PROPERTY_PARAM_COMMON_START + 0x00E)
+#define HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT \
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00F)
 
 #define HFI_PROPERTY_CONFIG_COMMON_START				\
 	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000)
@@ -632,6 +634,15 @@
 	u32 aspect_width;
 	u32 aspect_height;
 };
+#define HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM  (0)
+#define HFI_MVC_BUFFER_LAYOUT_SIDEBYSIDE  (1)
+#define HFI_MVC_BUFFER_LAYOUT_SEQ         (2)
+struct hfi_mvc_buffer_lauout_descp_type {
+	u32    layout_type;
+	u32    bright_view_first;
+	u32    ngap;
+};
+
 
 #define HFI_CMD_SYS_COMMON_START			\
 (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + HFI_CMD_START_OFFSET \
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 200f5d3..3bedb92 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -154,11 +154,14 @@
 	cmd_done.device_id = device->device_id;
 	device->callback(SYS_ERROR, &cmd_done);
 }
-static void hal_process_session_error(struct hal_device *device)
+static void hal_process_session_error(struct hal_device *device,
+		struct hfi_msg_event_notify_packet *pkt)
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
 	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
 	cmd_done.device_id = device->device_id;
+	cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
+		session_id;
 	device->callback(SESSION_ERROR, &cmd_done);
 }
 static void hal_process_event_notify(struct hal_device *device,
@@ -179,7 +182,7 @@
 		break;
 	case HFI_EVENT_SESSION_ERROR:
 		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR");
-		hal_process_session_error(device);
+		hal_process_session_error(device, pkt);
 		break;
 	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
 		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED");
@@ -530,7 +533,7 @@
 
 	dprintk(VIDC_DBG, "RECEIVED:SESSION_ETB_DONE");
 
-	if (!pkt || pkt->size !=
+	if (!pkt || pkt->size <
 		sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
 		dprintk(VIDC_ERR, "hal_process_session_etb_done:bad_pkt_size");
 		return;
@@ -576,7 +579,7 @@
 		msg_hdr;
 		if (sizeof(struct
 			hfi_msg_session_fill_buffer_done_compressed_packet)
-			!= pkt->size) {
+			> pkt->size) {
 			dprintk(VIDC_ERR,
 				"hal_process_session_ftb_done: bad_pkt_size");
 			return;
@@ -729,6 +732,31 @@
 	device->callback(SESSION_RELEASE_RESOURCE_DONE, &cmd_done);
 }
 
+static void hal_process_session_rel_buf_done(struct hal_device *device,
+	struct hfi_msg_session_release_buffers_done_packet *pkt)
+{
+	struct msm_vidc_cb_cmd_done cmd_done;
+	if (!pkt || pkt->size !=
+		sizeof(struct
+			   hfi_msg_session_release_buffers_done_packet)) {
+		dprintk(VIDC_ERR, "bad packet/packet size: %d", pkt->size);
+		return;
+	}
+	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+	cmd_done.device_id = device->device_id;
+	cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done);
+	cmd_done.session_id =
+		((struct hal_session *) pkt->session_id)->session_id;
+	cmd_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+	if (pkt->rg_buffer_info) {
+		cmd_done.data = (void *) &pkt->rg_buffer_info;
+		cmd_done.size = sizeof(struct hfi_buffer_info);
+	} else {
+		dprintk(VIDC_ERR, "invalid payload in rel_buff_done\n");
+	}
+	device->callback(SESSION_RELEASE_BUFFER_DONE, &cmd_done);
+}
+
 static void hal_process_session_end_done(struct hal_device *device,
 	struct hfi_msg_sys_session_end_done_packet *pkt)
 {
@@ -867,6 +895,11 @@
 			hfi_msg_session_get_sequence_header_done_packet
 			 *) msg_hdr);
 		break;
+	case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE:
+		hal_process_session_rel_buf_done(device, (struct
+			hfi_msg_session_release_buffers_done_packet
+			*) msg_hdr);
+		break;
 	default:
 		dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
 		break;
diff --git a/drivers/media/video/msm_wfd/enc-mfc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
index 45532a9..21fc719 100644
--- a/drivers/media/video/msm_wfd/enc-mfc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -40,6 +40,7 @@
 	int secure;
 	struct mem_region unqueued_op_bufs;
 	bool streaming;
+	enum venc_framerate_modes framerate_mode;
 };
 
 struct venc {
@@ -301,6 +302,8 @@
 	inst->cbdata = vmops->cbdata;
 	inst->secure = vmops->secure;
 	inst->streaming = false;
+	inst->framerate_mode = VENC_MODE_VFR;
+
 	if (vmops->secure) {
 		WFD_MSG_ERR("OPENING SECURE SESSION\n");
 		flags |= VCD_CP_SESSION;
@@ -1123,6 +1126,14 @@
 	return rc;
 }
 
+static long venc_set_framerate_mode(struct v4l2_subdev *sd,
+				void *arg)
+{
+	struct venc_inst *inst = sd->dev_priv;
+	inst->framerate_mode = *(enum venc_framerate_modes *)arg;
+	return 0;
+}
+
 static long venc_set_qp_value(struct video_client_ctx *client_ctx,
 		__s32 frametype, __s32 qp)
 {
@@ -1400,6 +1411,51 @@
 	return rc;
 }
 
+static long venc_set_vui_timing_info(struct video_client_ctx *client_ctx,
+			struct venc_inst *inst, __s32 flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_vui_timing_info_enable vui_timing_info_enable;
+
+	if (!client_ctx)
+		return -EINVAL;
+	if (inst->framerate_mode == VENC_MODE_VFR) {
+		WFD_MSG_ERR("VUI timing info not suported in VFR mode ");
+		return -EINVAL;
+	}
+	vcd_property_hdr.prop_id = VCD_I_ENABLE_VUI_TIMING_INFO;
+	vcd_property_hdr.sz =
+			sizeof(struct vcd_property_vui_timing_info_enable);
+	vui_timing_info_enable.vui_timing_info = flag;
+	return vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vui_timing_info_enable);
+}
+
+static long venc_get_vui_timing_info(struct video_client_ctx *client_ctx,
+			__s32 *flag)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_vui_timing_info_enable vui_timing_info_enable;
+	int rc = 0;
+
+	if (!client_ctx || !flag)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_ENABLE_VUI_TIMING_INFO;
+	vcd_property_hdr.sz =
+			sizeof(struct vcd_property_vui_timing_info_enable);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vui_timing_info_enable);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Failed getting property for VUI timing info");
+		return rc;
+	}
+
+	*flag = vui_timing_info_enable.vui_timing_info;
+	return rc;
+}
+
 static long venc_set_header_mode(struct video_client_ctx *client_ctx,
 		__s32 mode)
 {
@@ -2285,6 +2341,9 @@
 	case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
 		rc = venc_set_avc_delimiter(client_ctx, ctrl->value);
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+		rc = venc_set_vui_timing_info(client_ctx, inst, ctrl->value);
+		break;
 	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
 		rc = venc_set_entropy_mode(client_ctx, ctrl->value);
 		break;
@@ -2359,6 +2418,9 @@
 	case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
 		rc = venc_get_avc_delimiter(client_ctx, &ctrl->value);
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+		rc = venc_get_vui_timing_info(client_ctx, &ctrl->value);
+		break;
 	default:
 		WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
 		rc = -ENOTSUPP;
@@ -2503,6 +2565,9 @@
 	case ENC_MUNMAP:
 		rc = venc_munmap(sd, arg);
 		break;
+	case SET_FRAMERATE_MODE:
+		rc = venc_set_framerate_mode(sd, arg);
+		break;
 	default:
 		rc = -1;
 		break;
diff --git a/drivers/media/video/msm_wfd/enc-subdev.h b/drivers/media/video/msm_wfd/enc-subdev.h
index c6c854e..25373e4 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.h
+++ b/drivers/media/video/msm_wfd/enc-subdev.h
@@ -20,6 +20,11 @@
 #include <media/videobuf2-core.h>
 #define VENC_MAGIC_IOCTL 'V'
 
+enum venc_framerate_modes {
+	VENC_MODE_CFR,
+	VENC_MODE_VFR,
+};
+
 struct mem_region {
 	struct list_head list;
 	u8 *kvaddr;
@@ -101,6 +106,7 @@
 #define ENCODE_FLUSH _IO('V', 24)
 #define ENC_MMAP _IOWR('V', 25, struct mem_region_map *)
 #define ENC_MUNMAP _IOWR('V', 26, struct mem_region_map *)
+#define SET_FRAMERATE_MODE _IO('V', 27)
 
 extern int venc_init(struct v4l2_subdev *sd, u32 val);
 extern int venc_load_fw(struct v4l2_subdev *sd);
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 5f67a96..99dc0d0 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -240,6 +240,7 @@
 	int rc;
 	unsigned long flags;
 	struct mdp_buf_info mdp_buf = {0};
+	struct mem_region_map mmap_context = {0};
 	spin_lock_irqsave(&inst->inst_lock, flags);
 	if (inst->input_bufs_allocated) {
 		spin_unlock_irqrestore(&inst->inst_lock, flags);
@@ -249,7 +250,6 @@
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
 
 	for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
-		struct mem_region_map mmap_context = {0};
 		mpair = kzalloc(sizeof(*mpair), GFP_KERNEL);
 		enc_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
 		mdp_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
@@ -278,6 +278,10 @@
 
 		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 				SET_INPUT_BUFFER, (void *)enc_mregion);
+		if (rc) {
+			WFD_MSG_ERR("Setting enc input buffer failed\n");
+			goto set_input_fail;
+		}
 
 		/* map the buffer from encoder to mdp */
 		mdp_mregion->kvaddr = enc_mregion->kvaddr;
@@ -301,7 +305,7 @@
 			mdp_mregion->kvaddr = NULL;
 			mdp_mregion->paddr = NULL;
 			mdp_mregion->ion_handle = NULL;
-			goto alloc_fail;
+			goto mdp_mmap_fail;
 		}
 
 		mdp_buf.inst = inst->mdp_inst;
@@ -314,34 +318,58 @@
 				((int)mdp_mregion->paddr + mdp_mregion->size),
 				mdp_mregion->kvaddr);
 
-		INIT_LIST_HEAD(&mpair->list);
-		mpair->enc = enc_mregion;
-		mpair->mdp = mdp_mregion;
-		list_add_tail(&mpair->list, &inst->input_mem_list);
-
 		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
 				MDP_Q_BUFFER, (void *)&mdp_buf);
 		if (rc) {
 			WFD_MSG_ERR("Unable to queue the"
 					" buffer to mdp\n");
-			break;
+			goto mdp_q_fail;
 		} else {
 			wfd_stats_update(&inst->stats,
 					WFD_STAT_EVENT_MDP_QUEUE);
 		}
+
+		INIT_LIST_HEAD(&mpair->list);
+		mpair->enc = enc_mregion;
+		mpair->mdp = mdp_mregion;
+		list_add_tail(&mpair->list, &inst->input_mem_list);
+
 	}
+
 	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
 			ALLOC_RECON_BUFFERS, NULL);
 	if (rc) {
 		WFD_MSG_ERR("Failed to allocate recon buffers\n");
-		goto alloc_fail;
+		goto recon_alloc_fail;
 	}
 	return rc;
 
+	/*
+	 * Clean up only the buffer that we failed in setting up.
+	 * Caller will clean up the rest by calling free_input_buffers()
+	 */
+mdp_q_fail:
+	memset(&mmap_context, 0, sizeof(mmap_context));
+	mmap_context.mregion = mdp_mregion;
+	mmap_context.ion_client = wfd_dev->ion_client;
+	mmap_context.cookie = inst->mdp_inst;
+	v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+			MDP_MUNMAP, (void *)&mmap_context);
+mdp_mmap_fail:
+	v4l2_subdev_call(&wfd_dev->enc_sdev,
+			core, ioctl, FREE_INPUT_BUFFER,
+			(void *)enc_mregion);
+set_input_fail:
+	memset(&mmap_context, 0, sizeof(mmap_context));
+	mmap_context.ion_client = wfd_dev->ion_client;
+	mmap_context.mregion = enc_mregion;
+	v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			ENC_MUNMAP, &mmap_context);
 alloc_fail:
 	kfree(mpair);
 	kfree(enc_mregion);
 	kfree(mdp_mregion);
+recon_alloc_fail:
 	return rc;
 }
 void wfd_free_input_buffers(struct wfd_device *wfd_dev,
@@ -1047,7 +1075,8 @@
 	struct v4l2_qcom_frameskip frameskip;
 	int64_t frame_interval, max_frame_interval;
 	void *extendedmode = NULL;
-	enum vsg_modes mode = VSG_MODE_VFR;
+	enum vsg_modes vsg_mode = VSG_MODE_VFR;
+	enum venc_framerate_modes venc_mode = VENC_MODE_VFR;
 
 
 	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1069,6 +1098,7 @@
 			rc = -EINVAL;
 			goto set_parm_fail;
 		}
+		venc_mode = VENC_MODE_CFR;
 		frame_interval =
 			a->parm.capture.timeperframe.numerator * NSEC_PER_SEC /
 			a->parm.capture.timeperframe.denominator;
@@ -1097,7 +1127,7 @@
 			goto set_parm_fail;
 
 		max_frame_interval = (int64_t)frameskip.maxframeinterval;
-		mode = VSG_MODE_VFR;
+		vsg_mode = VSG_MODE_VFR;
 
 		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
 				ioctl, VSG_SET_MAX_FRAME_INTERVAL,
@@ -1107,19 +1137,23 @@
 			goto set_parm_fail;
 
 		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
-				ioctl, VSG_SET_MODE, &mode);
+				ioctl, VSG_SET_MODE, &vsg_mode);
 
 		if (rc)
 			goto set_parm_fail;
 	} else {
-		mode = VSG_MODE_CFR;
+		vsg_mode = VSG_MODE_CFR;
 		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
-				ioctl, VSG_SET_MODE, &mode);
+				ioctl, VSG_SET_MODE, &vsg_mode);
 
 		if (rc)
 			goto set_parm_fail;
 	}
 
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+			ioctl, SET_FRAMERATE_MODE,
+			&venc_mode);
+
 set_parm_fail:
 	return rc;
 }
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index f009e06..5b76c35 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -568,6 +568,17 @@
 	return 0;
 }
 
+void free_ion_on_q_bufs(struct vb2_queue *vq)
+{
+	struct vcap_client_data *c_data = vb2_get_drv_priv(vq);
+	struct vb2_buffer *vb;
+
+	if (!vq->streaming) {
+		list_for_each_entry(vb, &vq->queued_list, queued_entry)
+			free_ion_handle_work(c_data, vb);
+	}
+}
+
 /* VC Videobuf operations */
 static void wait_prepare(struct vb2_queue *q)
 {
@@ -1874,6 +1885,10 @@
 	}
 	v4l2_fh_del(&c_data->vfh);
 	v4l2_fh_exit(&c_data->vfh);
+	free_ion_on_q_bufs(&c_data->vp_out_vidq);
+	free_ion_on_q_bufs(&c_data->vp_in_vidq);
+	free_ion_on_q_bufs(&c_data->vc_vidq);
+
 	vb2_queue_release(&c_data->vp_out_vidq);
 	vb2_queue_release(&c_data->vp_in_vidq);
 	vb2_queue_release(&c_data->vc_vidq);
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index f310524..eebaab9 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -35,6 +35,8 @@
 #include <mach/sps.h>            /* BAM stuff */
 #include <mach/gpio.h>
 #include <linux/wakelock.h>      /* Locking functions */
+#include <linux/timer.h>         /* Timer services */
+#include <linux/jiffies.h>       /* Jiffies counter */
 #include <mach/dma.h>
 #include <mach/msm_tspp.h>
 #include <linux/debugfs.h>
@@ -49,11 +51,24 @@
 #define TSPP_NUM_PRIORITIES            16
 #define TSPP_NUM_KEYS                  8
 #define INVALID_CHANNEL                0xFFFFFFFF
-#define TSPP_SPS_DESCRIPTOR_COUNT      128
+
+/*
+ * BAM descriptor FIFO size (in number of descriptors).
+ * Max number of descriptors allowed by SPS which is 8K-1.
+ * Restrict it to half of this to save DMA memory.
+ */
+#define TSPP_SPS_DESCRIPTOR_COUNT      (4 * 1024 - 1)
 #define TSPP_PACKET_LENGTH             188
 #define TSPP_MIN_BUFFER_SIZE           (TSPP_PACKET_LENGTH)
-#define TSPP_MAX_BUFFER_SIZE           (32 * 1024)
-#define TSPP_NUM_BUFFERS               64
+
+/* Max descriptor buffer size allowed by SPS */
+#define TSPP_MAX_BUFFER_SIZE           (32 * 1024 - 1)
+
+/*
+ * Max allowed TSPP buffers/descriptors.
+ * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
+ */
+#define TSPP_NUM_BUFFERS               (TSPP_SPS_DESCRIPTOR_COUNT - 1)
 #define TSPP_TSIF_DEFAULT_TIME_LIMIT   60
 #define SPS_DESCRIPTOR_SIZE            8
 #define MIN_ACCEPTABLE_BUFFER_COUNT    2
@@ -307,6 +322,8 @@
 #define CONTEXT_UNSPEC_LENGTH					BIT(11)
 #define CONTEXT_GET_CONT_COUNT(_a)			((_a >> 12) & 0xF)
 
+#define MSEC_TO_JIFFIES(msec)			((msec) * HZ / 1000)
+
 struct tspp_pipe_performance_regs {
 	u32 tsp_total;
 	u32 ps_duplicate_tsp;
@@ -379,7 +396,8 @@
 	enum tspp_mode mode;
 	tspp_notifier *notifier; /* used only with kernel api */
 	void *notify_data;       /* data to be passed with the notifier */
-	u32 notify_timer;        /* notification for partially filled buffers */
+	u32 expiration_period_ms; /* notification on partially filled buffers */
+	struct timer_list expiration_timer;
 	tspp_memfree *memfree;   /* user defined memory free function */
 	void *user_info; /* user cookie passed to memory alloc/free function */
 };
@@ -539,6 +557,14 @@
 	tasklet_schedule(&pdev->tlet);
 }
 
+static void tspp_expiration_timer(unsigned long data)
+{
+	struct tspp_device *pdev = (struct tspp_device *)data;
+
+	if (pdev)
+		tasklet_schedule(&pdev->tlet);
+}
+
 /*** tasklet ***/
 static void tspp_sps_complete_tlet(unsigned long data)
 {
@@ -553,9 +579,14 @@
 	for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
 		complete = 0;
 		channel = &device->channels[i];
+
 		if (!channel->used || !channel->waiting)
 			continue;
 
+		/* stop the expiration timer */
+		if (channel->expiration_period_ms)
+			del_timer(&channel->expiration_timer);
+
 		/* get completions */
 		while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
 			if (sps_get_iovec(channel->pipe, &iovec) != 0) {
@@ -593,6 +624,13 @@
 				channel->notifier(channel->id,
 					channel->notify_data);
 		}
+
+		/* restart expiration timer */
+		if (channel->expiration_period_ms)
+			mod_timer(&channel->expiration_timer,
+				jiffies +
+				MSEC_TO_JIFFIES(
+					channel->expiration_period_ms));
 	}
 
 	spin_unlock_irqrestore(&device->spinlock, flags);
@@ -897,7 +935,7 @@
 
 	/* generate interrupt according to requested frequency */
 	if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
-		flags = SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOB;
+		flags = SPS_IOVEC_FLAG_INT;
 
 	/* start the transfer */
 	rc = sps_transfer_one(channel->pipe,
@@ -1034,7 +1072,7 @@
 	channel->mode = TSPP_MODE_DISABLED;
 	channel->notifier = NULL;
 	channel->notify_data = NULL;
-	channel->notify_timer = 0;
+	channel->expiration_period_ms = 0;
 	channel->memfree = NULL;
 	channel->user_info = NULL;
 	init_waitqueue_head(&channel->in_queue);
@@ -1394,10 +1432,11 @@
 		SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
 		SPS_O_STREAMING | /* streaming mode */
 		SPS_O_DESC_DONE | /* interrupt on end of descriptor */
-		SPS_O_ACK_TRANSFERS; /* must use sps_get_iovec() */
+		SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
+		SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
 	config->src_pipe_index = channel->id;
 	config->desc.size =
-		(TSPP_SPS_DESCRIPTOR_COUNT + 1) * SPS_DESCRIPTOR_SIZE;
+		TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
 	config->desc.base = dma_alloc_coherent(NULL,
 						config->desc.size,
 						&config->desc.phys_base,
@@ -1428,6 +1467,11 @@
 		goto err_event;
 	}
 
+	init_timer(&channel->expiration_timer);
+	channel->expiration_timer.function = tspp_expiration_timer;
+	channel->expiration_timer.data = (unsigned long)pdev;
+	channel->expiration_timer.expires = 0xffffffffL;
+
 	rc = pm_runtime_get(&pdev->pdev->dev);
 	if (rc < 0) {
 		dev_err(&pdev->pdev->dev,
@@ -1482,9 +1526,12 @@
 	if (!channel->used)
 		return 0;
 
+	if (channel->expiration_period_ms)
+		del_timer(&channel->expiration_timer);
+
 	channel->notifier = NULL;
 	channel->notify_data = NULL;
-	channel->notify_timer = 0;
+	channel->expiration_period_ms = 0;
 
 	config = &channel->config;
 	pdev = channel->pdev;
@@ -1833,7 +1880,8 @@
 	channel = &pdev->channels[channel_id];
 	channel->notifier = pNotify;
 	channel->notify_data = userdata;
-	channel->notify_timer = timer_ms;
+	channel->expiration_period_ms = timer_ms;
+
 	return 0;
 }
 EXPORT_SYMBOL(tspp_register_notification);
@@ -2113,6 +2161,13 @@
 	channel->read = channel->data;
 	channel->locked = channel->data;
 
+	/* Now that buffers are scheduled to HW, kick data expiration timer */
+	if (channel->expiration_period_ms)
+		mod_timer(&channel->expiration_timer,
+			jiffies +
+			MSEC_TO_JIFFIES(
+				channel->expiration_period_ms));
+
 	return 0;
 }
 EXPORT_SYMBOL(tspp_allocate_buffers);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 8810b46..ae68060 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -298,13 +298,33 @@
 {
 	int value;
 	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+	struct mmc_card *card = md->queue.card;
+	int ret = count;
+
+	if (!card) {
+		ret = -EINVAL;
+		goto exit;
+	}
 
 	sscanf(buf, "%d", &value);
-	if (value >= 0)
-		md->queue.num_wr_reqs_to_start_packing = value;
 
+	if (value >= 0) {
+		md->queue.num_wr_reqs_to_start_packing =
+		    min_t(int, value, (int)card->ext_csd.max_packed_writes);
+
+		pr_debug("%s: trigger to pack: new value = %d",
+			mmc_hostname(card->host),
+			md->queue.num_wr_reqs_to_start_packing);
+	} else {
+		pr_err("%s: value %d is not valid. old value remains = %d",
+			mmc_hostname(card->host), value,
+			md->queue.num_wr_reqs_to_start_packing);
+		ret = -EINVAL;
+	}
+
+exit:
 	mmc_blk_put(md);
-	return count;
+	return ret;
 }
 
 static ssize_t
@@ -317,13 +337,13 @@
 	int ret;
 
 	if (!card)
-		return -EINVAL;
-
-	min_sectors_to_check_bkops_status =
-		card->bkops_info.min_sectors_to_queue_delayed_work;
-
-	ret = snprintf(buf, PAGE_SIZE, "%d\n",
-		       min_sectors_to_check_bkops_status);
+		ret = -EINVAL;
+	else {
+	    min_sectors_to_check_bkops_status =
+		    card->bkops_info.min_sectors_to_queue_delayed_work;
+	    ret = snprintf(buf, PAGE_SIZE, "%d\n",
+			   min_sectors_to_check_bkops_status);
+	}
 
 	mmc_blk_put(md);
 	return ret;
@@ -1409,6 +1429,10 @@
 	if (!(host->caps2 & MMC_CAP2_PACKED_WR))
 		return;
 
+	/* Support for the write packing on eMMC 4.5 or later */
+	if (mq->card->ext_csd.rev <= 5)
+		return;
+
 	/*
 	 * In case the packing control is not supported by the host, it should
 	 * not have an effect on the write packing. Therefore we have to enable
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 8897f18a..8eb787d 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -210,7 +210,9 @@
 	mq->mqrq_cur = mqrq_cur;
 	mq->mqrq_prev = mqrq_prev;
 	mq->queue->queuedata = mq;
-	mq->num_wr_reqs_to_start_packing = DEFAULT_NUM_REQS_TO_START_PACK;
+	mq->num_wr_reqs_to_start_packing =
+		min_t(int, (int)card->ext_csd.max_packed_writes,
+		     DEFAULT_NUM_REQS_TO_START_PACK);
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 48516b6..f91ba89 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -29,6 +29,7 @@
 #include <linux/wakelock.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -44,6 +45,8 @@
 #include "sd_ops.h"
 #include "sdio_ops.h"
 
+static void mmc_clk_scaling(struct mmc_host *host, bool from_wq);
+
 /*
  * Background operations can take a long time, depending on the housekeeping
  * operations the card has to perform.
@@ -171,6 +174,10 @@
 #ifdef CONFIG_MMC_PERF_PROFILING
 	ktime_t diff;
 #endif
+	if (host->card && host->clk_scaling.enable)
+		host->clk_scaling.busy_time_us +=
+			ktime_to_us(ktime_sub(ktime_get(),
+					host->clk_scaling.start_busy));
 
 	if (err && cmd->retries && mmc_host_is_spi(host)) {
 		if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
@@ -300,6 +307,19 @@
 	}
 	mmc_host_clk_hold(host);
 	led_trigger_event(host->led, LED_FULL);
+
+	if (host->card && host->clk_scaling.enable) {
+		/*
+		 * Check if we need to scale the clocks. Clocks
+		 * will be scaled up immediately if necessary
+		 * conditions are satisfied. Scaling down the
+		 * frequency will be done after current thread
+		 * releases host.
+		 */
+		mmc_clk_scaling(host, false);
+		host->clk_scaling.start_busy = ktime_get();
+	}
+
 	host->ops->request(host, mrq);
 }
 
@@ -2286,6 +2306,289 @@
 }
 EXPORT_SYMBOL(mmc_hw_reset_check);
 
+/**
+ * mmc_reset_clk_scale_stats() - reset clock scaling statistics
+ * @host: pointer to mmc host structure
+ */
+void mmc_reset_clk_scale_stats(struct mmc_host *host)
+{
+	host->clk_scaling.busy_time_us = 0;
+	host->clk_scaling.window_time = jiffies;
+}
+EXPORT_SYMBOL_GPL(mmc_reset_clk_scale_stats);
+
+/**
+ * mmc_get_max_frequency() - get max. frequency supported
+ * @host: pointer to mmc host structure
+ *
+ * Returns max. frequency supported by card/host. If the
+ * timing mode is SDR50/SDR104/HS200/DDR50 return appropriate
+ * max. frequency in these modes else, use the current frequency.
+ * Also, allow host drivers to overwrite the frequency in case
+ * they support "get_max_frequency" host ops.
+ */
+unsigned long mmc_get_max_frequency(struct mmc_host *host)
+{
+	unsigned long freq;
+
+	if (host->ops && host->ops->get_max_frequency) {
+		freq = host->ops->get_max_frequency(host);
+		goto out;
+	}
+
+	switch (host->ios.timing) {
+	case MMC_TIMING_UHS_SDR50:
+		freq = UHS_SDR50_MAX_DTR;
+		break;
+	case MMC_TIMING_UHS_SDR104:
+		freq = UHS_SDR104_MAX_DTR;
+		break;
+	case MMC_TIMING_MMC_HS200:
+		freq = MMC_HS200_MAX_DTR;
+		break;
+	case MMC_TIMING_UHS_DDR50:
+		freq = UHS_DDR50_MAX_DTR;
+		break;
+	default:
+		mmc_host_clk_hold(host);
+		freq = host->ios.clock;
+		mmc_host_clk_release(host);
+		break;
+	}
+
+out:
+	return freq;
+}
+EXPORT_SYMBOL_GPL(mmc_get_max_frequency);
+
+/**
+ * mmc_get_min_frequency() - get min. frequency supported
+ * @host: pointer to mmc host structure
+ *
+ * Returns min. frequency supported by card/host which doesn't impair
+ * performance for most usecases. If the timing mode is SDR50/SDR104/HS200
+ * return 50MHz value. If timing mode is DDR50 return 25MHz so that
+ * throughput would be equivalent to SDR50/SDR104 in 50MHz. Also, allow
+ * host drivers to overwrite the frequency in case they support
+ * "get_min_frequency" host ops.
+ */
+static unsigned long mmc_get_min_frequency(struct mmc_host *host)
+{
+	unsigned long freq;
+
+	if (host->ops && host->ops->get_min_frequency) {
+		freq = host->ops->get_min_frequency(host);
+		goto out;
+	}
+
+	switch (host->ios.timing) {
+	case MMC_TIMING_UHS_SDR50:
+	case MMC_TIMING_UHS_SDR104:
+		freq = UHS_SDR25_MAX_DTR;
+		break;
+	case MMC_TIMING_MMC_HS200:
+		freq = MMC_HIGH_52_MAX_DTR;
+		break;
+	case MMC_TIMING_UHS_DDR50:
+		freq = UHS_DDR50_MAX_DTR / 2;
+		break;
+	default:
+		mmc_host_clk_hold(host);
+		freq = host->ios.clock;
+		mmc_host_clk_release(host);
+		break;
+	}
+
+out:
+	return freq;
+}
+
+/*
+ * Scale down clocks to minimum frequency supported.
+ * The delayed work re-arms itself in case it cannot
+ * claim the host.
+ */
+static void mmc_clk_scale_work(struct work_struct *work)
+{
+	struct mmc_host *host = container_of(work, struct mmc_host,
+					      clk_scaling.work.work);
+
+	if (!host->card || !host->bus_ops ||
+			!host->bus_ops->change_bus_speed ||
+			!host->clk_scaling.enable || !host->ios.clock)
+		goto out;
+
+	if (!mmc_try_claim_host(host)) {
+		/* retry after a timer tick */
+		queue_delayed_work(system_nrt_wq, &host->clk_scaling.work, 1);
+		goto out;
+	}
+
+	mmc_clk_scaling(host, true);
+	mmc_release_host(host);
+out:
+	return;
+}
+
+
+/**
+ * mmc_clk_scaling() - clock scaling decision algorithm
+ * @host:	pointer to mmc host structure
+ * @from_wq:	variable that specifies the context in which
+ *		mmc_clk_scaling() is called.
+ *
+ * Calculate load percentage based on host busy time
+ * and total sampling interval and decide clock scaling
+ * based on scale up/down thresholds.
+ * If load is greater than up threshold increase the
+ * frequency to maximum as supported by host. Else,
+ * if load is less than down threshold, scale down the
+ * frequency to minimum supported by the host. Otherwise,
+ * retain current frequency and do nothing.
+ */
+static void mmc_clk_scaling(struct mmc_host *host, bool from_wq)
+{
+	int err = 0;
+	struct mmc_card *card = host->card;
+	unsigned long total_time_ms = 0;
+	unsigned long busy_time_ms = 0;
+	unsigned long freq;
+	unsigned int up_threshold = host->clk_scaling.up_threshold;
+	unsigned int down_threshold = host->clk_scaling.down_threshold;
+	bool queue_scale_down_work = false;
+
+	if (!card || !host->bus_ops || !host->bus_ops->change_bus_speed) {
+		pr_err("%s: %s: invalid entry\n", mmc_hostname(host), __func__);
+		goto out;
+	}
+
+	/* Check if the clocks are already gated. */
+	if (!host->ios.clock)
+		goto out;
+
+	if (time_is_after_jiffies(host->clk_scaling.window_time +
+			msecs_to_jiffies(host->clk_scaling.polling_delay_ms)))
+		goto out;
+
+	/* handle time wrap */
+	total_time_ms = jiffies_to_msecs((long)jiffies -
+			(long)host->clk_scaling.window_time);
+
+	/* Check if we re-enter during clock switching */
+	if (unlikely(host->clk_scaling.in_progress))
+		goto out;
+
+	host->clk_scaling.in_progress = true;
+
+	busy_time_ms = host->clk_scaling.busy_time_us / USEC_PER_MSEC;
+
+	freq = host->clk_scaling.curr_freq;
+
+	/*
+	 * Note that the max. and min. frequency should be based
+	 * on the timing modes that the card and host handshake
+	 * during initialization.
+	 */
+	if ((busy_time_ms * 100 > total_time_ms * up_threshold)) {
+		freq = mmc_get_max_frequency(host);
+	} else if ((busy_time_ms * 100 < total_time_ms * down_threshold)) {
+		if (!from_wq)
+			queue_scale_down_work = true;
+		freq = mmc_get_min_frequency(host);
+	}
+
+	if (freq != host->clk_scaling.curr_freq) {
+		if (!queue_scale_down_work) {
+			if (!from_wq)
+				cancel_delayed_work_sync(
+						&host->clk_scaling.work);
+			err = host->bus_ops->change_bus_speed(host, &freq);
+			if (!err)
+				host->clk_scaling.curr_freq = freq;
+			else
+				pr_err("%s: %s: failed (%d) at freq=%lu\n",
+					mmc_hostname(host), __func__, err,
+					freq);
+		} else {
+			/*
+			 * We hold claim host while queueing the scale down
+			 * work, so delay atleast one timer tick to release
+			 * host and re-claim while scaling down the clocks.
+			 */
+			queue_delayed_work(system_nrt_wq,
+					&host->clk_scaling.work, 1);
+			host->clk_scaling.in_progress = false;
+			goto out;
+		}
+	}
+
+	mmc_reset_clk_scale_stats(host);
+	host->clk_scaling.in_progress = false;
+out:
+	return;
+}
+
+/**
+ * mmc_disable_clk_scaling() - Disable clock scaling
+ * @host: pointer to mmc host structure
+ *
+ * Disables clock scaling temporarily by setting enable
+ * property to false. To disable completely, one also
+ * need to set 'initialized' variable to false.
+ */
+void mmc_disable_clk_scaling(struct mmc_host *host)
+{
+	cancel_delayed_work_sync(&host->clk_scaling.work);
+	host->clk_scaling.enable = false;
+}
+EXPORT_SYMBOL_GPL(mmc_disable_clk_scaling);
+
+/**
+ * mmc_can_scale_clk() - Check if clock scaling is initialized
+ * @host: pointer to mmc host structure
+ */
+bool mmc_can_scale_clk(struct mmc_host *host)
+{
+	return host->clk_scaling.initialized;
+}
+EXPORT_SYMBOL_GPL(mmc_can_scale_clk);
+
+/**
+ * mmc_init_clk_scaling() - Initialize clock scaling
+ * @host: pointer to mmc host structure
+ *
+ * Initialize clock scaling for supported hosts.
+ * It is assumed that the caller ensure clock is
+ * running at maximum possible frequency before
+ * calling this function.
+ */
+void mmc_init_clk_scaling(struct mmc_host *host)
+{
+	if (!host->card || !(host->caps2 & MMC_CAP2_CLK_SCALE))
+		return;
+
+	INIT_DELAYED_WORK(&host->clk_scaling.work, mmc_clk_scale_work);
+	host->clk_scaling.curr_freq = mmc_get_max_frequency(host);
+	mmc_reset_clk_scale_stats(host);
+	host->clk_scaling.enable = true;
+	host->clk_scaling.initialized = true;
+	pr_debug("%s: clk scaling enabled\n", mmc_hostname(host));
+}
+EXPORT_SYMBOL_GPL(mmc_init_clk_scaling);
+
+/**
+ * mmc_exit_clk_scaling() - Disable clock scaling
+ * @host: pointer to mmc host structure
+ *
+ * Disable clock scaling permanently.
+ */
+void mmc_exit_clk_scaling(struct mmc_host *host)
+{
+	cancel_delayed_work_sync(&host->clk_scaling.work);
+	memset(&host->clk_scaling, 0, sizeof(host->clk_scaling));
+}
+EXPORT_SYMBOL_GPL(mmc_exit_clk_scaling);
+
 static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
 {
 	host->f_init = freq;
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index de87e82..c85f5aa 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -81,5 +81,11 @@
 void mmc_add_card_debugfs(struct mmc_card *card);
 void mmc_remove_card_debugfs(struct mmc_card *card);
 
+extern void mmc_disable_clk_scaling(struct mmc_host *host);
+extern bool mmc_can_scale_clk(struct mmc_host *host);
+extern void mmc_init_clk_scaling(struct mmc_host *host);
+extern void mmc_exit_clk_scaling(struct mmc_host *host);
+extern void mmc_reset_clk_scale_stats(struct mmc_host *host);
+extern unsigned long mmc_get_max_frequency(struct mmc_host *host);
 #endif
 
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 850872d..d30f10f 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -163,6 +163,9 @@
 	if (host->clk_gated) {
 		spin_unlock_irqrestore(&host->clk_lock, flags);
 		mmc_ungate_clock(host);
+
+		/* Reset clock scaling stats as host is out of idle */
+		mmc_reset_clk_scale_stats(host);
 		spin_lock_irqsave(&host->clk_lock, flags);
 		pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
 	}
@@ -446,6 +449,10 @@
 #endif
 	mmc_host_clk_sysfs_init(host);
 
+	host->clk_scaling.up_threshold = 35;
+	host->clk_scaling.down_threshold = 5;
+	host->clk_scaling.polling_delay_ms = 100;
+
 	err = sysfs_create_group(&host->parent->kobj, &dev_attr_grp);
 	if (err)
 		pr_err("%s: failed to create sysfs group with err %d\n",
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a98ed3d..d3dc133 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1460,6 +1460,7 @@
 
 	mmc_claim_host(host);
 	host->card = NULL;
+	mmc_exit_clk_scaling(host);
 	mmc_release_host(host);
 }
 
@@ -1510,6 +1511,12 @@
 	BUG_ON(!host);
 	BUG_ON(!host->card);
 
+	/*
+	 * Disable clock scaling before suspend and enable it after resume so
+	 * as to avoid clock scaling decisions kicking in during this window.
+	 */
+	mmc_disable_clk_scaling(host);
+
 	mmc_claim_host(host);
 	if (mmc_can_poweroff_notify(host->card))
 		err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
@@ -1540,6 +1547,13 @@
 	err = mmc_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);
 
+	/*
+	 * We have done full initialization of the card,
+	 * reset the clk scale stats and current frequency.
+	 */
+	if (mmc_can_scale_clk(host))
+		mmc_init_clk_scaling(host);
+
 	return err;
 }
 
@@ -1547,11 +1561,17 @@
 {
 	int ret;
 
+	/* Disable clk scaling to avoid switching frequencies intermittently */
+	mmc_disable_clk_scaling(host);
+
 	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 	mmc_claim_host(host);
 	ret = mmc_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);
 
+	if (mmc_can_scale_clk(host))
+		mmc_init_clk_scaling(host);
+
 	return ret;
 }
 
@@ -1686,6 +1706,10 @@
 	if (err)
 		goto remove_card;
 
+	/* Initialize clock scaling only for high frequency modes */
+	if (mmc_card_hs200(host->card) || mmc_card_ddr_mode(host->card))
+		mmc_init_clk_scaling(host);
+
 	return 0;
 
 remove_card:
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 8661929..318d590 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1121,6 +1121,7 @@
 
 	mmc_claim_host(host);
 	host->card = NULL;
+	mmc_exit_clk_scaling(host);
 	mmc_release_host(host);
 }
 
@@ -1187,6 +1188,12 @@
 	BUG_ON(!host);
 	BUG_ON(!host->card);
 
+	/*
+	 * Disable clock scaling before suspend and enable it after resume so
+	 * as to avoid clock scaling decisions kicking in during this window.
+	 */
+	mmc_disable_clk_scaling(host);
+
 	mmc_claim_host(host);
 	if (!mmc_host_is_spi(host))
 		mmc_deselect_cards(host);
@@ -1235,6 +1242,13 @@
 #endif
 	mmc_release_host(host);
 
+	/*
+	 * We have done full initialization of the card,
+	 * reset the clk scale stats and current frequency.
+	 */
+	if (mmc_can_scale_clk(host))
+		mmc_init_clk_scaling(host);
+
 	return err;
 }
 
@@ -1242,11 +1256,17 @@
 {
 	int ret;
 
+	/* Disable clk scaling to avoid switching frequencies intermittently */
+	mmc_disable_clk_scaling(host);
+
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	ret = mmc_sd_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);
 
+	if (mmc_can_scale_clk(host))
+		mmc_init_clk_scaling(host);
+
 	return ret;
 }
 
@@ -1385,6 +1405,10 @@
 	if (err)
 		goto remove_card;
 
+	/* Initialize clock scaling only for high frequency modes */
+	if (mmc_card_uhs(host->card))
+		mmc_init_clk_scaling(host);
+
 	return 0;
 
 remove_card:
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 81a4ba0..4e76f61 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -162,10 +162,7 @@
 			if (ret)
 				goto out;
 
-			if (card->host->caps &
-				(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
-				 MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
-				 MMC_CAP_UHS_DDR50)) {
+			if (mmc_host_uhs(card->host)) {
 				if (data & SDIO_UHS_DDR50)
 					card->sw_caps.sd3_bus_mode
 						|= SD_MODE_UHS_DDR50;
@@ -480,8 +477,7 @@
 	 * If the host doesn't support any of the UHS-I modes, fallback on
 	 * default speed.
 	 */
-	if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
-	    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
+	if (!mmc_host_uhs(card->host))
 		return 0;
 
 	bus_speed = SDIO_SPEED_SDR12;
@@ -491,23 +487,27 @@
 			bus_speed = SDIO_SPEED_SDR104;
 			timing = MMC_TIMING_UHS_SDR104;
 			card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+			card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
 	} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
 		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
 			bus_speed = SDIO_SPEED_DDR50;
 			timing = MMC_TIMING_UHS_DDR50;
 			card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+			card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
 		    SD_MODE_UHS_SDR50)) {
 			bus_speed = SDIO_SPEED_SDR50;
 			timing = MMC_TIMING_UHS_SDR50;
 			card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+			card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
 		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
 			bus_speed = SDIO_SPEED_SDR25;
 			timing = MMC_TIMING_UHS_SDR25;
 			card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+			card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
 		    MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
@@ -515,6 +515,7 @@
 			bus_speed = SDIO_SPEED_SDR12;
 			timing = MMC_TIMING_UHS_SDR12;
 			card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+			card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
 	}
 
 	err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
@@ -653,11 +654,7 @@
 	 * systems that claim 1.8v signalling in fact do not support
 	 * it.
 	 */
-	if ((ocr & R4_18V_PRESENT) &&
-		(host->caps &
-			(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
-			 MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
-			 MMC_CAP_UHS_DDR50))) {
+	if ((ocr & R4_18V_PRESENT) && mmc_host_uhs(host)) {
 		err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
 				true);
 		if (err) {
@@ -964,10 +961,12 @@
 	mmc_claim_host(host);
 
 	/* No need to reinitialize powered-resumed nonremovable cards */
-	if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
+	if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
+		sdio_reset(host);
+		mmc_go_idle(host);
 		err = mmc_sdio_init_card(host, host->ocr, host->card,
 					mmc_card_keep_power(host));
-	else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
+	} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
 		/* We may have switched to 1-bit mode during suspend */
 		err = sdio_enable_4bit_bus(host->card);
 		if (err > 0) {
@@ -1054,6 +1053,10 @@
 		goto out;
 	}
 
+	if (mmc_host_uhs(host))
+		/* to query card if 1.8V signalling is supported */
+		host->ocr |= R4_18V_PRESENT;
+
 	ret = mmc_sdio_init_card(host, host->ocr, host->card,
 				mmc_card_keep_power(host));
 	if (!ret && host->sdio_irqs)
@@ -1119,6 +1122,10 @@
 	/*
 	 * Detect and init the card.
 	 */
+	if (mmc_host_uhs(host))
+		/* to query card if 1.8V signalling is supported */
+		host->ocr |= R4_18V_PRESENT;
+
 	err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
 	if (err) {
 		if (err == -EAGAIN) {
@@ -1236,79 +1243,6 @@
 
 int sdio_reset_comm(struct mmc_card *card)
 {
-	struct mmc_host *host = card->host;
-	u32 ocr;
-	int err;
-
-	printk("%s():\n", __func__);
-	mmc_claim_host(host);
-
-	mmc_go_idle(host);
-
-	mmc_set_clock(host, host->f_min);
-
-	err = mmc_send_io_op_cond(host, 0, &ocr);
-	if (err)
-		goto err;
-
-	host->ocr = mmc_select_voltage(host, ocr);
-	if (!host->ocr) {
-		err = -EINVAL;
-		goto err;
-	}
-
-	err = mmc_send_io_op_cond(host, host->ocr, &ocr);
-	if (err)
-		goto err;
-
-	if (mmc_host_is_spi(host)) {
-		err = mmc_spi_set_crc(host, use_spi_crc);
-		if (err)
-			goto err;
-	}
-
-	if (!mmc_host_is_spi(host)) {
-		err = mmc_send_relative_addr(host, &card->rca);
-		if (err)
-			goto err;
-		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
-	}
-	if (!mmc_host_is_spi(host)) {
-		err = mmc_select_card(card);
-		if (err)
-			goto err;
-	}
-
-	/*
-	 * Switch to high-speed (if supported).
-	 */
-	err = sdio_enable_hs(card);
-	if (err > 0)
-		mmc_sd_go_highspeed(card);
-	else if (err)
-		goto err;
-
-	/*
-	 * Change to the card's maximum speed.
-	 */
-	mmc_set_clock(host, mmc_sdio_get_max_clock(card));
-
-	err = sdio_enable_4bit_bus(card);
-	if (err > 0) {
-		if (host->caps & MMC_CAP_8_BIT_DATA)
-			mmc_set_bus_width(host, MMC_BUS_WIDTH_8);
-		else if (host->caps & MMC_CAP_4_BIT_DATA)
-			mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
-	}
-	else if (err)
-		goto err;
-
-	mmc_release_host(host);
-	return 0;
-err:
-	printk("%s: Error resetting SDIO communications (%d)\n",
-	       mmc_hostname(host), err);
-	mmc_release_host(host);
-	return err;
+	return mmc_power_restore_host(card->host);
 }
 EXPORT_SYMBOL(sdio_reset_comm);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 4f7d4c3..c8b47b9 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -162,6 +162,7 @@
 static int msmsdcc_runtime_resume(struct device *dev);
 static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
 		u32 **out_array, int *len, int size);
+static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode);
 
 static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
 {
@@ -1201,8 +1202,9 @@
 		*c |= MCI_CSPM_DATCMD;
 
 	/* Check if AUTO CMD19/CMD21 is required or not? */
-	if (host->tuning_needed &&
-		(host->en_auto_cmd19 || host->en_auto_cmd21)) {
+	if (host->tuning_needed && (cmd->mrq->data &&
+	    (cmd->mrq->data->flags & MMC_DATA_READ)) &&
+	    (host->en_auto_cmd19 || host->en_auto_cmd21)) {
 		/*
 		 * For open ended block read operation (without CMD23),
 		 * AUTO_CMD19/AUTO_CMD21 bit should be set while sending
@@ -1216,7 +1218,8 @@
 				MMC_READ_MULTIPLE_BLOCK) ||
 			(!host->curr.mrq->sbc &&
 			(cmd->opcode == MMC_READ_SINGLE_BLOCK ||
-			cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
+			cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+			cmd->opcode == SD_IO_RW_EXTENDED))) {
 			msmsdcc_enable_cdr_cm_sdc4_dll(host);
 			if (host->en_auto_cmd19 &&
 			    host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
@@ -1416,6 +1419,10 @@
 			else
 				data->error = -ETIMEDOUT;
 		}
+		/* In case of DATA CRC/timeout error, execute tuning again */
+		if (host->tuning_needed && !host->tuning_in_progress)
+			host->tuning_done = false;
+
 	} else if (status & MCI_RXOVERRUN) {
 		pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
 		data->error = -EIO;
@@ -1768,6 +1775,8 @@
 		msmsdcc_dump_sdcc_state(host);
 		/* Execute full tuning in case of CRC errors */
 		host->saved_tuning_phase = INVALID_TUNING_PHASE;
+		if (host->tuning_needed)
+			host->tuning_done = false;
 		cmd->error = -EILSEQ;
 	}
 
@@ -1864,9 +1873,10 @@
 				 */
 				wake_lock(&host->sdio_wlock);
 			} else {
-				if (mmc->card && !mmc_card_sdio(mmc->card)) {
-					WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
-					     mmc_hostname(mmc));
+				if (!mmc->card || (mmc->card &&
+				    !mmc_card_sdio(mmc->card))) {
+					pr_warning("%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
+					   mmc_hostname(mmc));
 					ret = 1;
 					break;
 				}
@@ -1898,9 +1908,10 @@
 #endif
 
 		if (status & MCI_SDIOINTROPE) {
-			if (mmc->card && !mmc_card_sdio(mmc->card)) {
-				WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
-					mmc_hostname(mmc));
+			if (!mmc->card || (mmc->card &&
+			    !mmc_card_sdio(mmc->card))) {
+				pr_warning("%s: SDIO interrupt (SDIOINTROPE) received for non-SDIO card\n",
+					   mmc_hostname(mmc));
 				ret = 1;
 				break;
 			}
@@ -2147,6 +2158,22 @@
 		}
 	}
 
+	/*
+	 * Check if DLL retuning is required? If yes, perform it here before
+	 * starting new request.
+	 */
+	if (host->tuning_needed && !host->tuning_in_progress &&
+	    !host->tuning_done) {
+		pr_debug("%s: %s: execute_tuning for timing mode = %d\n",
+			 mmc_hostname(mmc), __func__, host->mmc->ios.timing);
+		if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
+			msmsdcc_execute_tuning(mmc,
+					       MMC_SEND_TUNING_BLOCK);
+		else if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
+			msmsdcc_execute_tuning(mmc,
+					       MMC_SEND_TUNING_BLOCK_HS200);
+	}
+
 	spin_lock_irqsave(&host->lock, flags);
 
 	if (host->eject) {
@@ -3343,10 +3370,24 @@
 		/* Card clock frequency must be > 100MHz to enable tuning */
 		clk |= (4 << 14);
 		host->tuning_needed = 1;
-	} else if (ios->timing == MMC_TIMING_UHS_DDR50) {
-		clk |= (3 << 14);
 	} else {
-		clk |= (2 << 14); /* feedback clock */
+		if (ios->timing == MMC_TIMING_UHS_DDR50)
+			clk |= (3 << 14);
+		else
+			clk |= (2 << 14); /* feedback clock */
+
+		host->tuning_done = false;
+		if (atomic_read(&host->clks_on)) {
+			/* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
+			writel_relaxed((readl_relaxed(host->base +
+					MCI_DLL_CONFIG) | MCI_DLL_RST),
+					host->base + MCI_DLL_CONFIG);
+
+			/* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
+			writel_relaxed((readl_relaxed(host->base +
+					MCI_DLL_CONFIG) | MCI_DLL_PDN),
+					host->base + MCI_DLL_CONFIG);
+		}
 	}
 
 	/* Select free running MCLK as input clock of cm_dll_sdc4 */
@@ -4181,6 +4222,8 @@
 out:
 	spin_lock_irqsave(&host->lock, flags);
 	host->tuning_in_progress = 0;
+	if (!rc)
+		host->tuning_done = true;
 	spin_unlock_irqrestore(&host->lock, flags);
 exit:
 	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index bb1b211..500b5fb 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 tuning_done;
 	bool en_auto_cmd19;
 	bool en_auto_cmd21;
 	bool sdio_gpio_lpm;
diff --git a/drivers/net/ethernet/msm/msm_rmnet.c b/drivers/net/ethernet/msm/msm_rmnet.c
index 4af2d8c..cc9ed74 100644
--- a/drivers/net/ethernet/msm/msm_rmnet.c
+++ b/drivers/net/ethernet/msm/msm_rmnet.c
@@ -94,6 +94,7 @@
 	struct sk_buff *skb;
 	spinlock_t lock;
 	struct tasklet_struct tsklt;
+	struct tasklet_struct rx_tasklet;
 	u32 operation_mode;    /* IOCTL specified mode (protocol, QoS header) */
 	struct platform_driver pdrv;
 	struct completion complete;
@@ -257,7 +258,6 @@
 }
 
 static void smd_net_data_handler(unsigned long arg);
-static DECLARE_TASKLET(smd_net_data_tasklet, smd_net_data_handler, 0);
 
 /* Called in soft-irq context */
 static void smd_net_data_handler(unsigned long arg)
@@ -280,8 +280,8 @@
 			pr_err("[%s] rmnet_recv() cannot allocate skb\n",
 			       dev->name);
 			/* out of memory, reschedule a later attempt */
-			smd_net_data_tasklet.data = (unsigned long)dev;
-			tasklet_schedule(&smd_net_data_tasklet);
+			p->rx_tasklet.data = (unsigned long)dev;
+			tasklet_schedule(&p->rx_tasklet);
 			break;
 		} else {
 			skb->dev = dev;
@@ -449,8 +449,8 @@
 
 		if (smd_read_avail(p->ch) &&
 			(smd_read_avail(p->ch) >= smd_cur_packet_size(p->ch))) {
-			smd_net_data_tasklet.data = (unsigned long) _dev;
-			tasklet_schedule(&smd_net_data_tasklet);
+			p->rx_tasklet.data = (unsigned long) _dev;
+			tasklet_schedule(&p->rx_tasklet);
 		}
 		break;
 
@@ -788,6 +788,8 @@
 		spin_lock_init(&p->lock);
 		tasklet_init(&p->tsklt, _rmnet_resume_flow,
 				(unsigned long)dev);
+		tasklet_init(&p->rx_tasklet, smd_net_data_handler,
+				(unsigned long)dev);
 		wake_lock_init(&p->wake_lock, WAKE_LOCK_SUSPEND, ch_name[n]);
 #ifdef CONFIG_MSM_RMNET_DEBUG
 		p->timeout_us = timeout_us;
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 75cc086..872a9b5 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -12,11 +12,7 @@
 
 config SPS
 	bool "SPS support"
-	depends on (HAS_IOMEM && (ARCH_MSM8960 || ARCH_MSM8X60 \
-			|| ARCH_APQ8064 || ARCH_MSM9615 \
-			|| ARCH_MSM9625 || ARCH_MSM8974))
 	select GENERIC_ALLOCATOR
-	default n
 	help
 	  The SPS (Smart Peripheral Switch) is a DMA engine.
 	  It can move data in the following modes:
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index f671ece..a3bbb73 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -1005,6 +1005,8 @@
 	no_queue = ((options & SPS_O_NO_Q));
 	ack_xfers = ((options & SPS_O_ACK_TRANSFERS));
 
+	pipe->hybrid = options & SPS_O_HYBRID;
+
 	/* Create interrupt source mask */
 	mask = 0;
 	for (n = 0; n < ARRAY_SIZE(opt_event_table); n++) {
@@ -1773,7 +1775,7 @@
 	}
 
 	/* If pipe is polled and queue is enabled, perform polling operation */
-	if (pipe->polled && !pipe->sys.no_queue)
+	if ((pipe->polled || pipe->hybrid) && !pipe->sys.no_queue)
 		pipe_handler_eot(dev, pipe);
 
 	/* Is there a completed descriptor? */
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index 6004b75..84d2b97 100644
--- a/drivers/platform/msm/sps/sps_bam.h
+++ b/drivers/platform/msm/sps/sps_bam.h
@@ -170,6 +170,7 @@
 	u32 pipe_index_mask;
 	u32 irq_mask;
 	int polled;
+	int hybrid;
 	u32 irq_gen_addr;
 	enum sps_mode mode;
 	u32 num_descs; /* Size (number of elements) of descriptor FIFO */
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 703aca9..2eddb9d 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -55,6 +55,9 @@
 #define TEMP_IAVG_STORAGE	0x105
 #define TEMP_IAVG_STORAGE_USE_MASK	0x0F
 
+#define PON_CNTRL_6		0x018
+#define WD_BIT			BIT(7)
+
 enum pmic_bms_interrupts {
 	PM8921_BMS_SBI_WRITE_OK,
 	PM8921_BMS_CC_THR,
@@ -151,6 +154,9 @@
 	struct power_supply	*batt_psy;
 	bool			low_voltage_wake_lock_held;
 	struct wake_lock	low_voltage_wake_lock;
+	int			soc_calc_period;
+	int			normal_voltage_calc_ms;
+	int			low_voltage_calc_ms;
 };
 
 /*
@@ -627,17 +633,17 @@
 	return 0;
 }
 
-#define MBG_TRANSIENT_ERROR_RAW 51
-static void adjust_pon_ocv_raw(struct pm8921_bms_chip *chip,
-				struct pm8921_soc_params *raw)
+#define MBG_TRANSIENT_ERROR_UV 15000
+static void adjust_pon_ocv(struct pm8921_bms_chip *chip, int *uv)
 {
-	/* in 8921 parts the PON ocv is taken when the MBG is not settled.
+	/*
+	 * In 8921 parts the PON ocv is taken when the MBG is not settled.
 	 * decrease the pon ocv by 15mV raw value to account for it
 	 * Since a 1/3rd  of vbatt is supplied to the adc the raw value
 	 * needs to be adjusted by 5mV worth bits
 	 */
-	if (raw->last_good_ocv_raw >= MBG_TRANSIENT_ERROR_RAW)
-		raw->last_good_ocv_raw -= MBG_TRANSIENT_ERROR_RAW;
+	if (*uv >= MBG_TRANSIENT_ERROR_UV)
+		*uv -= MBG_TRANSIENT_ERROR_UV;
 }
 
 #define SEL_ALT_OREG_BIT  BIT(2)
@@ -660,10 +666,71 @@
 	return compensated_ocv;
 }
 
+#define RESET_CC_BIT BIT(3)
+static int reset_cc(struct pm8921_bms_chip *chip)
+{
+	int rc;
+
+	rc = pm_bms_masked_write(chip, BMS_TEST1, RESET_CC_BIT, RESET_CC_BIT);
+	if (rc < 0) {
+		pr_err("err setting cc reset rc = %d\n", rc);
+		return rc;
+	}
+
+	/* sleep 100uS for the coulomb counter to reset */
+	udelay(100);
+
+	rc = pm_bms_masked_write(chip, BMS_TEST1, RESET_CC_BIT, 0);
+	if (rc < 0)
+		pr_err("err clearing cc reset rc = %d\n", rc);
+	return rc;
+}
+
+static int estimate_ocv(struct pm8921_bms_chip *chip)
+{
+	int ibat_ua, vbat_uv, ocv_est_uv;
+	int rc;
+
+	int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
+
+	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+							&ibat_ua,
+							&vbat_uv);
+	if (rc) {
+		pr_err("simultaneous failed rc = %d\n", rc);
+		return rc;
+	}
+
+	ocv_est_uv = vbat_uv + (ibat_ua * rbatt_mohm) / 1000;
+	pr_debug("estimated pon ocv = %d\n", ocv_est_uv);
+	return ocv_est_uv;
+}
+
+static bool is_warm_restart(struct pm8921_bms_chip *chip)
+{
+	u8 reg;
+	int rc;
+
+	rc = pm8xxx_readb(chip->dev->parent, PON_CNTRL_6, &reg);
+	if (rc) {
+		pr_err("err reading pon 6 rc = %d\n", rc);
+		return false;
+	}
+	return reg & WD_BIT;
+}
+/*
+ * This reflects what should the CC readings should be for
+ * a 5mAh discharge. This value is dependent on
+ * CC_RESOLUTION_N, CC_RESOLUTION_D, CC_READING_TICKS
+ * and rsense
+ */
+#define CC_RAW_5MAH	0x00110000
+#define MIN_OCV_UV	2000000
 static int read_soc_params_raw(struct pm8921_bms_chip *chip,
 				struct pm8921_soc_params *raw)
 {
 	int usb_chg;
+	int est_ocv_uv;
 
 	mutex_lock(&chip->bms_output_lock);
 	pm_bms_lock_output_data(chip);
@@ -679,12 +746,40 @@
 
 	if (chip->prev_last_good_ocv_raw == 0) {
 		chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
-		adjust_pon_ocv_raw(chip, raw);
+
 		convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
+		adjust_pon_ocv(chip, &raw->last_good_ocv_uv);
 		raw->last_good_ocv_uv = ocv_ir_compensation(chip,
 						raw->last_good_ocv_uv);
 		chip->last_ocv_uv = raw->last_good_ocv_uv;
+
+		if (is_warm_restart(chip)
+			|| raw->cc > CC_RAW_5MAH
+			|| (raw->last_good_ocv_uv < MIN_OCV_UV
+			&& raw->cc > 0)) {
+			/*
+			 * The CC value is higher than 5mAh.
+			 * The phone started without going through a pon
+			 * sequence
+			 * OR
+			 * The ocv was very small and there was no
+			 * charging in the bootloader
+			 * - reset the CC and take an ocv again
+			 */
+			pr_debug("cc_raw = 0x%x may be > 5mAh(0x%x)\n",
+				       raw->cc,	CC_RAW_5MAH);
+			pr_debug("ocv_uv = %d ocv_raw = 0x%x may be < 2V\n",
+				       chip->last_ocv_uv,
+				       raw->last_good_ocv_raw);
+			est_ocv_uv = estimate_ocv(chip);
+			if (est_ocv_uv > 0) {
+				raw->last_good_ocv_uv = est_ocv_uv;
+				chip->last_ocv_uv = est_ocv_uv;
+				reset_cc(chip);
+				raw->cc = 0;
+			}
+		}
 		pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
 	} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
 		chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
@@ -1370,6 +1465,7 @@
 		pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
 		wake_lock(&chip->low_voltage_wake_lock);
 		chip->low_voltage_wake_lock_held = 1;
+		chip->soc_calc_period = chip->low_voltage_calc_ms;
 	}
 
 	if (vbat_uv > (chip->v_cutoff + 20) * 1000
@@ -1377,6 +1473,7 @@
 		pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
 		chip->low_voltage_wake_lock_held = 0;
 		wake_unlock(&chip->low_voltage_wake_lock);
+		chip->soc_calc_period = chip->normal_voltage_calc_ms;
 	}
 }
 
@@ -1811,7 +1908,6 @@
 	return calculated_soc;
 }
 
-#define CALCULATE_SOC_MS	20000
 static void calculate_soc_work(struct work_struct *work)
 {
 	struct pm8921_bms_chip *chip = container_of(work,
@@ -1841,7 +1937,7 @@
 
 	schedule_delayed_work(&chip->calculate_soc_delayed_work,
 			round_jiffies_relative(msecs_to_jiffies
-			(CALCULATE_SOC_MS)));
+			(chip->soc_calc_period)));
 }
 
 static int report_state_of_charge(struct pm8921_bms_chip *chip)
@@ -2686,7 +2782,9 @@
 	int ret = 0;
 	struct pm8921_soc_params raw;
 
+	mutex_lock(&the_chip->bms_output_lock);
 	read_soc_params_raw(the_chip, &raw);
+	mutex_unlock(&the_chip->bms_output_lock);
 
 	*val = 0;
 
@@ -2907,6 +3005,12 @@
 	chip->end_percent = -EINVAL;
 	chip->shutdown_soc_valid_limit = pdata->shutdown_soc_valid_limit;
 	chip->adjust_soc_low_threshold = pdata->adjust_soc_low_threshold;
+
+	chip->normal_voltage_calc_ms = pdata->normal_voltage_calc_ms;
+	chip->low_voltage_calc_ms = pdata->low_voltage_calc_ms;
+
+	chip->soc_calc_period = pdata->normal_voltage_calc_ms;
+
 	if (chip->adjust_soc_low_threshold >= 45)
 		chip->adjust_soc_low_threshold = 45;
 
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 3995cf7..20b3fc6 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -260,11 +260,9 @@
 	struct dentry			*dent;
 	struct bms_notify		bms_notify;
 	int				*usb_trim_table;
-	bool				keep_btm_on_suspend;
 	bool				ext_charging;
 	bool				ext_charge_done;
 	bool				iusb_fine_res;
-	bool				dc_unplug_check;
 	bool				disable_hw_clock_switching;
 	DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
 	struct work_struct		battery_id_valid_work;
@@ -307,8 +305,6 @@
 
 static struct pm8921_chg_chip *the_chip;
 
-static struct pm8xxx_adc_arb_btm_param btm_config;
-
 static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
 							u8 mask, u8 val)
 {
@@ -1431,15 +1427,6 @@
 	case POWER_SUPPLY_PROP_PRESENT:
 	case POWER_SUPPLY_PROP_ONLINE:
 		val->intval = 0;
-		if (charging_disabled)
-			return 0;
-
-		/*
-		 * if drawing any current from usb is disabled behave
-		 * as if no usb cable is connected
-		 */
-		if (pm_is_chg_charge_dis(the_chip))
-			return 0;
 
 		/* USB charging */
 		if (usb_target_ma < USB_WALL_THRESHOLD_MA)
@@ -1473,7 +1460,7 @@
 	POWER_SUPPLY_PROP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_TEMP,
-	POWER_SUPPLY_PROP_ENERGY_FULL,
+	POWER_SUPPLY_PROP_CHARGE_FULL,
 	POWER_SUPPLY_PROP_CHARGE_NOW,
 };
 
@@ -1759,8 +1746,8 @@
 	case POWER_SUPPLY_PROP_TEMP:
 		val->intval = get_prop_batt_temp(chip);
 		break;
-	case POWER_SUPPLY_PROP_ENERGY_FULL:
-		val->intval = get_prop_batt_fcc(chip) * 1000;
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		val->intval = get_prop_batt_fcc(chip);
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_NOW:
 		val->intval = get_prop_batt_charge_now(chip);
@@ -1812,6 +1799,12 @@
 		return;
 	}
 
+	if (usb_max_current && mA > usb_max_current) {
+		pr_debug("restricting usb current to %d instead of %d\n",
+					usb_max_current, mA);
+		mA = usb_max_current;
+	}
+
 	if (mA <= 2) {
 		usb_chg_current = 0;
 		rc = pm_chg_iusbmax_set(the_chip, 0);
@@ -1905,22 +1898,6 @@
 }
 EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
 
-int pm8921_charger_enable(bool enable)
-{
-	int rc;
-
-	if (!the_chip) {
-		pr_err("called before init\n");
-		return -EINVAL;
-	}
-	enable = !!enable;
-	rc = pm_chg_auto_enable(the_chip, enable);
-	if (rc)
-		pr_err("Failed rc=%d\n", rc);
-	return rc;
-}
-EXPORT_SYMBOL(pm8921_charger_enable);
-
 int pm8921_is_usb_chg_plugged_in(void)
 {
 	if (!the_chip) {
@@ -2312,7 +2289,10 @@
 		pr_warn("%s. battery temperature not ok.\n", __func__);
 		return;
 	}
-	pm8921_disable_source_current(true); /* Force BATFET=ON */
+
+	/* Force BATFET=ON */
+	pm8921_disable_source_current(true);
+
 	vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
 	if (vbat_ov) {
 		pr_warn("%s. battery over voltage.\n", __func__);
@@ -2322,16 +2302,17 @@
 	schedule_delayed_work(&chip->unplug_check_work,
 	round_jiffies_relative(msecs_to_jiffies
 		(UNPLUG_CHECK_WAIT_PERIOD_MS)));
-	pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
 
 	power_supply_set_online(chip->ext_psy, dc_present);
 	power_supply_set_charge_type(chip->ext_psy,
 					POWER_SUPPLY_CHARGE_TYPE_FAST);
-	power_supply_changed(&chip->dc_psy);
 	chip->ext_charging = true;
 	chip->ext_charge_done = false;
 	bms_notify_check(chip);
-	/* Start BMS */
+	/*
+	 * since we wont get a fastchg irq from external charger
+	 * use eoc worker to detect end of charging
+	 */
 	schedule_delayed_work(&chip->eoc_work, delay);
 	wake_lock(&chip->eoc_wake_lock);
 	/* Update battery charging LEDs and user space battery info */
@@ -2568,15 +2549,25 @@
 	struct pm8921_chg_chip *chip = container_of(dwork,
 			struct pm8921_chg_chip, vin_collapse_check_work);
 
-	/* AICL only for wall-chargers */
-	if (is_usb_chg_plugged_in(chip) &&
-		usb_target_ma > USB_WALL_THRESHOLD_MA) {
+	/*
+	 * AICL only for wall-chargers. If the charger appears to be plugged
+	 * back in now, the corresponding unplug must have been because of we
+	 * were trying to draw more current than the charger can support. In
+	 * such a case reset usb current to 500mA and decrease the target.
+	 * The AICL algorithm will step up the current from 500mA to target
+	 */
+	if (is_usb_chg_plugged_in(chip)
+		&& usb_target_ma > USB_WALL_THRESHOLD_MA) {
 		/* decrease usb_target_ma */
 		decrease_usb_ma_value(&usb_target_ma);
 		/* reset here, increase in unplug_check_worker */
 		__pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
 		pr_debug("usb_now=%d, usb_target = %d\n",
 				USB_WALL_THRESHOLD_MA, usb_target_ma);
+		if (!delayed_work_pending(&chip->unplug_check_work))
+			schedule_delayed_work(&chip->unplug_check_work,
+				      round_jiffies_relative(msecs_to_jiffies
+						(UNPLUG_CHECK_WAIT_PERIOD_MS)));
 	} else {
 		handle_usb_insertion_removal(chip);
 	}
@@ -2801,12 +2792,6 @@
 		}
 	} else if (active_path & DC_ACTIVE_BIT) {
 		pr_debug("DC charger active\n");
-		/*
-		 * Some board designs are not prone to reverse boost on DC
-		 * charging path
-		 */
-		if (!chip->dc_unplug_check)
-			return;
 	} else {
 		/* No charger active */
 		if (!(is_usb_chg_plugged_in(chip)
@@ -3079,20 +3064,33 @@
 	struct pm8921_chg_chip *chip = data;
 	int dc_present;
 
+	pm_chg_failed_clear(chip, 1);
 	dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
-	if (chip->ext_psy)
-		power_supply_set_online(chip->ext_psy, dc_present);
-	chip->dc_present = dc_present;
-	if (dc_present)
-		handle_start_ext_chg(chip);
-	else
-		handle_stop_ext_chg(chip);
 
-	if (!chip->ext_psy) {
+	if (chip->dc_present ^ dc_present)
+		pm8921_bms_calibrate_hkadc();
+
+	if (dc_present)
+		pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
+	else
+		pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
+
+	chip->dc_present = dc_present;
+
+	if (chip->ext_psy) {
+		if (dc_present)
+			handle_start_ext_chg(chip);
+		else
+			handle_stop_ext_chg(chip);
+	} else {
+		if (dc_present)
+			schedule_delayed_work(&chip->unplug_check_work,
+				round_jiffies_relative(msecs_to_jiffies
+					(UNPLUG_CHECK_WAIT_PERIOD_MS)));
 		power_supply_changed(&chip->dc_psy);
-		power_supply_changed(&chip->batt_psy);
 	}
 
+	power_supply_changed(&chip->batt_psy);
 	return IRQ_HANDLED;
 }
 
@@ -3243,6 +3241,79 @@
 			- the_chip->resume_voltage_delta);
 }
 
+static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
+{
+	unsigned int chg_current = chip->max_bat_chg_current;
+
+	if (chip->is_bat_cool)
+		chg_current = min(chg_current, chip->cool_bat_chg_current);
+
+	if (chip->is_bat_warm)
+		chg_current = min(chg_current, chip->warm_bat_chg_current);
+
+	if (thermal_mitigation != 0 && chip->thermal_mitigation)
+		chg_current = min(chg_current,
+				chip->thermal_mitigation[thermal_mitigation]);
+
+	pm_chg_ibatmax_set(the_chip, chg_current);
+}
+
+#define TEMP_HYSTERISIS_DECIDEGC 20
+static void battery_cool(bool enter)
+{
+	pr_debug("enter = %d\n", enter);
+	if (enter == the_chip->is_bat_cool)
+		return;
+	the_chip->is_bat_cool = enter;
+	if (enter)
+		pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
+	else
+		pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
+	set_appropriate_battery_current(the_chip);
+	set_appropriate_vbatdet(the_chip);
+}
+
+static void battery_warm(bool enter)
+{
+	pr_debug("enter = %d\n", enter);
+	if (enter == the_chip->is_bat_warm)
+		return;
+	the_chip->is_bat_warm = enter;
+	if (enter)
+		pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
+	else
+		pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
+
+	set_appropriate_battery_current(the_chip);
+	set_appropriate_vbatdet(the_chip);
+}
+
+static void check_temp_thresholds(struct pm8921_chg_chip *chip)
+{
+	int temp = 0;
+
+	temp = get_prop_batt_temp(chip);
+	pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
+			temp, chip->warm_temp_dc,
+			chip->cool_temp_dc);
+
+	if (chip->warm_temp_dc != INT_MIN) {
+		if (chip->is_bat_warm
+			&& temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
+			battery_warm(false);
+		else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
+			battery_warm(true);
+	}
+
+	if (chip->cool_temp_dc != INT_MIN) {
+		if (chip->is_bat_cool
+			&& temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
+			battery_cool(false);
+		else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
+			battery_cool(true);
+	}
+}
+
 enum {
 	CHG_IN_PROGRESS,
 	CHG_NOT_IN_PROGRESS,
@@ -3418,6 +3489,7 @@
 		/* declare end of charging by invoking chgdone interrupt */
 		chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
 	} else {
+		check_temp_thresholds(chip);
 		adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
 		pr_debug("EOC count = %d\n", count);
 		schedule_delayed_work(&chip->eoc_work,
@@ -3432,100 +3504,6 @@
 	set_appropriate_vbatdet(chip);
 }
 
-static void btm_configure_work(struct work_struct *work)
-{
-	int rc;
-
-	rc = pm8xxx_adc_btm_configure(&btm_config);
-	if (rc)
-		pr_err("failed to configure btm rc=%d", rc);
-}
-
-DECLARE_WORK(btm_config_work, btm_configure_work);
-
-static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
-{
-	unsigned int chg_current = chip->max_bat_chg_current;
-
-	if (chip->is_bat_cool)
-		chg_current = min(chg_current, chip->cool_bat_chg_current);
-
-	if (chip->is_bat_warm)
-		chg_current = min(chg_current, chip->warm_bat_chg_current);
-
-	if (thermal_mitigation != 0 && chip->thermal_mitigation)
-		chg_current = min(chg_current,
-				chip->thermal_mitigation[thermal_mitigation]);
-
-	pm_chg_ibatmax_set(the_chip, chg_current);
-}
-
-#define TEMP_HYSTERISIS_DEGC 2
-static void battery_cool(bool enter)
-{
-	pr_debug("enter = %d\n", enter);
-	if (enter == the_chip->is_bat_cool)
-		return;
-	the_chip->is_bat_cool = enter;
-	if (enter) {
-		btm_config.low_thr_temp =
-			the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
-		pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
-	} else {
-		btm_config.low_thr_temp = the_chip->cool_temp_dc;
-		pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
-	}
-	set_appropriate_battery_current(the_chip);
-	set_appropriate_vbatdet(the_chip);
-	schedule_work(&btm_config_work);
-}
-
-static void battery_warm(bool enter)
-{
-	pr_debug("enter = %d\n", enter);
-	if (enter == the_chip->is_bat_warm)
-		return;
-	the_chip->is_bat_warm = enter;
-	if (enter) {
-		btm_config.high_thr_temp =
-			the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
-		pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
-	} else {
-		btm_config.high_thr_temp = the_chip->warm_temp_dc;
-		pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
-	}
-	set_appropriate_battery_current(the_chip);
-	set_appropriate_vbatdet(the_chip);
-	schedule_work(&btm_config_work);
-}
-
-static int configure_btm(struct pm8921_chg_chip *chip)
-{
-	int rc;
-
-	if (chip->warm_temp_dc != INT_MIN)
-		btm_config.btm_warm_fn = battery_warm;
-	else
-		btm_config.btm_warm_fn = NULL;
-
-	if (chip->cool_temp_dc != INT_MIN)
-		btm_config.btm_cool_fn = battery_cool;
-	else
-		btm_config.btm_cool_fn = NULL;
-
-	btm_config.low_thr_temp = chip->cool_temp_dc;
-	btm_config.high_thr_temp = chip->warm_temp_dc;
-	btm_config.interval = chip->temp_check_period;
-	rc = pm8xxx_adc_btm_configure(&btm_config);
-	if (rc)
-		pr_err("failed to configure btm rc = %d\n", rc);
-	rc = pm8xxx_adc_btm_start();
-	if (rc)
-		pr_err("failed to start btm rc = %d\n", rc);
-
-	return rc;
-}
-
 /**
  * set_disable_status_param -
  *
@@ -4435,19 +4413,8 @@
 
 static int pm8921_charger_resume(struct device *dev)
 {
-	int rc;
 	struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
 
-	if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
-		&& !(chip->keep_btm_on_suspend)) {
-		rc = pm8xxx_adc_btm_configure(&btm_config);
-		if (rc)
-			pr_err("couldn't reconfigure btm rc=%d\n", rc);
-
-		rc = pm8xxx_adc_btm_start();
-		if (rc)
-			pr_err("couldn't restart btm rc=%d\n", rc);
-	}
 	if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
 		disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
 		pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
@@ -4460,13 +4427,6 @@
 	int rc;
 	struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
 
-	if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
-		&& !(chip->keep_btm_on_suspend)) {
-		rc = pm8xxx_adc_btm_end();
-		if (rc)
-			pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
-	}
-
 	if (is_usb_chg_plugged_in(chip)) {
 		pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
 		enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
@@ -4524,13 +4484,13 @@
 		chip->warm_temp_dc = INT_MIN;
 
 	chip->temp_check_period = pdata->temp_check_period;
-	chip->dc_unplug_check = pdata->dc_unplug_check;
 	chip->max_bat_chg_current = pdata->max_bat_chg_current;
+	/* Assign to corresponding module parameter */
+	usb_max_current = pdata->usb_max_current;
 	chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
 	chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
 	chip->cool_bat_voltage = pdata->cool_bat_voltage;
 	chip->warm_bat_voltage = pdata->warm_bat_voltage;
-	chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
 	chip->trkl_voltage = pdata->trkl_voltage;
 	chip->weak_voltage = pdata->weak_voltage;
 	chip->trkl_current = pdata->trkl_current;
@@ -4621,20 +4581,8 @@
 
 	enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
-	enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
-	/*
-	 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
-	 * care for jeita compliance
-	 */
-	if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
-		rc = configure_btm(chip);
-		if (rc) {
-			pr_err("couldn't register with btm rc=%d\n", rc);
-			goto free_irq;
-		}
-	}
 
 	rc = pm8921_charger_configure_batt_alarm(chip);
 	if (rc) {
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 1955ff4..6623d81 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -176,7 +176,8 @@
 	int				soc_at_cv;
 	int				prev_chg_soc;
 	int				calculated_soc;
-	int				last_vbat_read_uv;
+	int				prev_voltage_based_soc;
+	bool				use_voltage_soc;
 };
 
 static struct of_device_id qpnp_bms_match_table[] = {
@@ -196,37 +197,6 @@
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 };
 
-static bool use_voltage_soc;
-
-/* module params */
-static int bms_param_set_bool(const char *val, const struct kernel_param *kp)
-{
-	int rc;
-	struct power_supply *bms_psy;
-
-	rc = param_set_bool(val, kp);
-	if (rc) {
-		pr_err("failed to set %s, rc = %d\n", kp->name, rc);
-		return rc;
-	}
-
-	bms_psy = power_supply_get_by_name("bms");
-
-	if (bms_psy)
-		power_supply_changed(bms_psy);
-	else
-		pr_debug("%s changed but bms has not been initialized yet\n",
-				kp->name);
-
-	return 0;
-}
-
-static struct kernel_param_ops bms_param_ops = {
-	.set = bms_param_set_bool,
-	.get = param_get_bool,
-};
-
-module_param_cb(use_voltage_soc, &bms_param_ops, &use_voltage_soc, 0644);
 
 static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
 			u16 base, int count)
@@ -370,6 +340,10 @@
 	s64 result_uv;
 
 	pr_debug("adjusting_uv = %lld\n", uv);
+	if (gain == 0) {
+		pr_debug("gain is %d, not adjusting\n", gain);
+		return uv;
+	}
 	pr_debug("adjusting by factor: %lld/%hu = %lld%%\n",
 			QPNP_ADC_GAIN_NV, gain,
 			div_s64(QPNP_ADC_GAIN_NV * 100LL, (s64)gain));
@@ -1381,12 +1355,12 @@
 	}
 
 	chip->calculated_soc = new_calculated_soc;
-	pr_debug("Set calculated SOC = %d\n", chip->calculated_soc);
+	pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
 	chip->first_time_calc_soc = 0;
 	return chip->calculated_soc;
 }
 
-static void read_vbat(struct qpnp_bms_chip *chip)
+static int read_vbat(struct qpnp_bms_chip *chip)
 {
 	int rc;
 	struct qpnp_vadc_result result;
@@ -1395,9 +1369,35 @@
 	if (rc) {
 		pr_err("error reading vadc VBAT_SNS = %d, rc = %d\n",
 					VBAT_SNS, rc);
-		return;
+		return rc;
 	}
-	chip->last_vbat_read_uv = (int)result.physical;
+	pr_debug("read %duv from vadc\n", (int)result.physical);
+	return (int)result.physical;
+}
+
+static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip)
+{
+	int voltage_range_uv, voltage_remaining_uv, voltage_based_soc;
+	int vbat_uv;
+
+	vbat_uv = read_vbat(chip);
+
+	voltage_range_uv = chip->max_voltage_uv - chip->v_cutoff_uv;
+	voltage_remaining_uv = vbat_uv - chip->v_cutoff_uv;
+	voltage_based_soc = voltage_remaining_uv * 100 / voltage_range_uv;
+
+	voltage_based_soc = clamp(voltage_based_soc, 0, 100);
+
+	if (chip->prev_voltage_based_soc != voltage_based_soc
+				&& chip->bms_psy.name != NULL) {
+		power_supply_changed(&chip->bms_psy);
+		pr_debug("power supply changed\n");
+	}
+	chip->prev_voltage_based_soc = voltage_based_soc;
+
+	pr_debug("vbat used = %duv\n", vbat_uv);
+	pr_debug("Calculated voltage based soc = %d\n", voltage_based_soc);
+	return voltage_based_soc;
 }
 
 static void calculate_soc_work(struct work_struct *work)
@@ -1409,22 +1409,25 @@
 	struct qpnp_vadc_result result;
 	struct raw_soc_params raw;
 
-	read_vbat(chip);
-
-	rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
-	if (rc) {
-		pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
-					LR_MUX1_BATT_THERM, rc);
-		return;
-	}
-	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+	if (chip->use_voltage_soc) {
+		soc = calculate_soc_from_voltage(chip);
+	} else {
+		rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+		if (rc) {
+			pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
+						LR_MUX1_BATT_THERM, rc);
+			return;
+		}
+		pr_debug("batt_temp phy = %lld meas = 0x%llx\n",
+						result.physical,
 						result.measurement);
-	batt_temp = (int)result.physical;
+		batt_temp = (int)result.physical;
 
-	mutex_lock(&chip->last_ocv_uv_mutex);
-	read_soc_params_raw(chip, &raw);
-	soc = calculate_state_of_charge(chip, &raw, batt_temp);
-	mutex_unlock(&chip->last_ocv_uv_mutex);
+		mutex_lock(&chip->last_ocv_uv_mutex);
+		read_soc_params_raw(chip, &raw);
+		soc = calculate_state_of_charge(chip, &raw, batt_temp);
+		mutex_unlock(&chip->last_ocv_uv_mutex);
+	}
 
 	if (soc < chip->low_soc_calc_threshold)
 		schedule_delayed_work(&chip->calculate_soc_delayed_work,
@@ -1514,7 +1517,14 @@
 static int bms_fake_battery = -EINVAL;
 module_param(bms_fake_battery, int, 0644);
 
-static int report_state_of_charge(struct qpnp_bms_chip *chip)
+static int report_voltage_based_soc(struct qpnp_bms_chip *chip)
+{
+	pr_debug("Reported voltage based soc = %d\n",
+			chip->prev_voltage_based_soc);
+	return chip->prev_voltage_based_soc;
+}
+
+static int report_cc_based_soc(struct qpnp_bms_chip *chip)
 {
 	int soc;
 	int delta_time_us;
@@ -1523,11 +1533,6 @@
 	int batt_temp;
 	int rc;
 
-	if (bms_fake_battery != -EINVAL) {
-		pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
-		return bms_fake_battery;
-	}
-
 	soc = chip->calculated_soc;
 
 	rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
@@ -1598,27 +1603,21 @@
 	return chip->last_soc;
 }
 
-static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip)
+static int report_state_of_charge(struct qpnp_bms_chip *chip)
 {
-	int voltage_range_uv, voltage_remaining_uv, voltage_based_soc;
-
-	if (chip->last_vbat_read_uv < 0)
-		read_vbat(chip);
-
-	voltage_range_uv = chip->max_voltage_uv - chip->v_cutoff_uv;
-	voltage_remaining_uv = chip->last_vbat_read_uv - chip->v_cutoff_uv;
-	voltage_based_soc = voltage_remaining_uv * 100 / voltage_range_uv;
-
-	return clamp(voltage_based_soc, 0, 100);
+	if (bms_fake_battery != -EINVAL) {
+		pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
+		return bms_fake_battery;
+	} else if (chip->use_voltage_soc)
+		return report_voltage_based_soc(chip);
+	else
+		return report_cc_based_soc(chip);
 }
 
 /* Returns capacity as a SoC percentage between 0 and 100 */
 static int get_prop_bms_capacity(struct qpnp_bms_chip *chip)
 {
-	if (use_voltage_soc)
-		return calculate_soc_from_voltage(chip);
-	else
-		return report_state_of_charge(chip);
+	return report_state_of_charge(chip);
 }
 
 /* Returns instantaneous current in uA */
@@ -1873,7 +1872,7 @@
 	chip->ignore_shutdown_soc = of_property_read_bool(
 			chip->spmi->dev.of_node,
 			"qcom,bms-ignore-shutdown-soc");
-	use_voltage_soc = of_property_read_bool(chip->spmi->dev.of_node,
+	chip->use_voltage_soc = of_property_read_bool(chip->spmi->dev.of_node,
 			"qcom,bms-use-voltage-soc");
 
 	if (chip->adjust_soc_low_threshold >= 45)
@@ -1889,7 +1888,7 @@
 			chip->adjust_soc_high_threshold, chip->chg_term_ua,
 			chip->batt_type);
 	pr_debug("ignore_shutdown_soc:%d, use_voltage_soc:%d\n",
-			chip->ignore_shutdown_soc, use_voltage_soc);
+			chip->ignore_shutdown_soc, chip->use_voltage_soc);
 
 	return 0;
 }
@@ -1902,7 +1901,6 @@
 	chip->soc_at_cv = -EINVAL;
 	chip->calculated_soc = -EINVAL;
 	chip->last_soc = -EINVAL;
-	chip->last_vbat_read_uv = -EINVAL;
 	chip->last_soc_est = -EINVAL;
 	chip->first_time_calc_soc = 1;
 	chip->first_time_calc_uuc = 1;
@@ -1950,6 +1948,18 @@
 		goto error_read;
 	}
 
+	rc = qpnp_vadc_is_ready();
+	if (rc) {
+		pr_info("vadc not ready: %d, deferring probe\n", rc);
+		goto error_read;
+	}
+
+	rc = qpnp_iadc_is_ready();
+	if (rc) {
+		pr_info("iadc not ready: %d, deferring probe\n", rc);
+		goto error_read;
+	}
+
 	rc = set_battery_data(chip);
 	if (rc) {
 		pr_err("Bad battery data %d\n", rc);
@@ -1996,7 +2006,7 @@
 	vbatt = 0;
 	get_battery_voltage(&vbatt);
 
-	pr_info("OK battery_capacity_at_boot=%d vbatt = %d\n",
+	pr_debug("OK battery_capacity_at_boot=%d vbatt = %d\n",
 				get_prop_bms_capacity(chip),
 				vbatt);
 	pr_info("probe success\n");
diff --git a/drivers/power/smb137c-charger.c b/drivers/power/smb137c-charger.c
index 9cdf5b5..fc3277f 100644
--- a/drivers/power/smb137c-charger.c
+++ b/drivers/power/smb137c-charger.c
@@ -31,6 +31,7 @@
 	bool			charging_enabled;
 	bool			otg_mode_enabled;
 	bool			charging_allowed;
+	bool			usb_suspend_enabled;
 };
 
 struct input_current_config {
@@ -130,6 +131,9 @@
 
 #define VAR_FUNC_REG			0x0C
 #define VAR_FUNC_USB_MODE_MASK		0x80
+#define VAR_FUNC_USB_SUSPEND_CTRL_MASK	0x20
+#define VAR_FUNC_USB_SUSPEND_CTRL_REG	0x00
+#define VAR_FUNC_USB_SUSPEND_CTRL_PIN	0x20
 #define VAR_FUNC_BMD_MASK		0x0C
 #define VAR_FUNC_BMD_DISABLED		0x00
 #define VAR_FUNC_BMD_ALGO_PERIODIC	0x04
@@ -146,6 +150,9 @@
 #define CMD_A_OTG_MASK			0x10
 #define CMD_A_OTG_ENABLED		0x10
 #define CMD_A_OTG_DISABLED		0x00
+#define CMD_A_USB_SUSPEND_MASK		0x04
+#define CMD_A_USB_SUSPEND_DISABLED	0x00
+#define CMD_A_USB_SUSPEND_ENABLED	0x04
 #define CMD_A_CHARGING_MASK		0x02
 #define CMD_A_CHARGING_ENABLED		0x00
 #define CMD_A_CHARGING_DISABLED		0x02
@@ -257,17 +264,16 @@
 
 	chip->charging_allowed = true;
 
-	if (chip->input_current_limit_ua > 0
-	    && chip->charge_current_limit_ua > 0) {
-		if (!chip->charging_enabled)
-			rc = smb137c_masked_write_reg(chip, CMD_A_REG,
-				CMD_A_CHARGING_MASK, CMD_A_CHARGING_ENABLED);
-		chip->charging_enabled = true;
-
+	if (!chip->charging_enabled && chip->charge_current_limit_ua > 0) {
+		rc = smb137c_masked_write_reg(chip, CMD_A_REG,
+			CMD_A_CHARGING_MASK, CMD_A_CHARGING_ENABLED);
 		if (!rc)
-			dev_dbg(&chip->client->dev, "%s\n", __func__);
+			chip->charging_enabled = true;
 	}
 
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s\n", __func__);
+
 	return rc;
 }
 
@@ -280,10 +286,10 @@
 	if (chip->charging_enabled) {
 		rc = smb137c_masked_write_reg(chip, CMD_A_REG,
 			CMD_A_CHARGING_MASK, CMD_A_CHARGING_DISABLED);
+		if (!rc)
+			chip->charging_enabled = false;
 	}
 
-	chip->charging_enabled = false;
-
 	if (!rc)
 		dev_dbg(&chip->client->dev, "%s\n", __func__);
 
@@ -297,7 +303,8 @@
 	if (!chip->otg_mode_enabled) {
 		rc = smb137c_masked_write_reg(chip, CMD_A_REG, CMD_A_OTG_MASK,
 					CMD_A_OTG_ENABLED);
-		chip->otg_mode_enabled = true;
+		if (!rc)
+			chip->otg_mode_enabled = true;
 	}
 
 	if (!rc)
@@ -313,7 +320,42 @@
 	if (chip->otg_mode_enabled) {
 		rc = smb137c_masked_write_reg(chip, CMD_A_REG, CMD_A_OTG_MASK,
 					CMD_A_OTG_DISABLED);
-		chip->otg_mode_enabled = false;
+		if (!rc)
+			chip->otg_mode_enabled = false;
+	}
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s\n", __func__);
+
+	return rc;
+}
+
+static int smb137c_enable_usb_suspend(struct smb137c_chip *chip)
+{
+	int rc = 0;
+
+	if (!chip->usb_suspend_enabled) {
+		rc = smb137c_masked_write_reg(chip, CMD_A_REG,
+			CMD_A_USB_SUSPEND_MASK, CMD_A_USB_SUSPEND_ENABLED);
+		if (!rc)
+			chip->usb_suspend_enabled = true;
+	}
+
+	if (!rc)
+		dev_dbg(&chip->client->dev, "%s\n", __func__);
+
+	return rc;
+}
+
+static int smb137c_disable_usb_suspend(struct smb137c_chip *chip)
+{
+	int rc = 0;
+
+	if (chip->input_current_limit_ua > 0 && chip->usb_suspend_enabled) {
+		rc = smb137c_masked_write_reg(chip, CMD_A_REG,
+			CMD_A_USB_SUSPEND_MASK, CMD_A_USB_SUSPEND_DISABLED);
+		if (!rc)
+			chip->usb_suspend_enabled = false;
 	}
 
 	if (!rc)
@@ -371,13 +413,11 @@
 			chip->input_current_limit_ua = config->current_limit_ua;
 		}
 
-		if (chip->charging_allowed)
-			rc = smb137c_enable_charging(chip);
+		rc = smb137c_disable_usb_suspend(chip);
 	} else {
-		/* Current limit is below all set points so disable charging. */
 		chip->input_current_limit_ua = 0;
 
-		rc = smb137c_disable_charging(chip);
+		rc = smb137c_enable_usb_suspend(chip);
 	}
 
 	if (!rc)
@@ -993,7 +1033,7 @@
 	struct smb137c_chip *chip = container_of(psy, struct smb137c_chip, psy);
 	union power_supply_propval prop = {0,};
 	int scope = POWER_SUPPLY_SCOPE_DEVICE;
-	int current_limit = USB_MIN_CURRENT_UA;
+	int current_limit = 0;
 	int online = 0;
 	int rc;
 
@@ -1037,7 +1077,8 @@
 		/* USB offline */
 		smb137c_disable_charging(chip);
 		smb137c_disable_otg_mode(chip);
-		smb137c_set_usb_input_current_limit(chip, USB_MIN_CURRENT_UA);
+		smb137c_set_usb_input_current_limit(chip,
+			min(current_limit, USB_MIN_CURRENT_UA));
 	}
 
 	dev_dbg(&chip->client->dev, "%s: end\n", __func__);
@@ -1086,6 +1127,14 @@
 	val = CTRL_A_AUTO_RECHARGE_ENABLED | CTRL_A_THERM_MONITOR_ENABLED;
 	mask = CTRL_A_AUTO_RECHARGE_MASK | CTRL_A_THERM_MONITOR_MASK;
 	rc = smb137c_masked_write_reg(chip, CTRL_A_REG, mask, val);
+	if (rc)
+		return rc;
+
+	/* Use register value instead of pin to control USB suspend. */
+	rc = smb137c_masked_write_reg(chip, VAR_FUNC_REG,
+		VAR_FUNC_USB_SUSPEND_CTRL_MASK, VAR_FUNC_USB_SUSPEND_CTRL_REG);
+	if (rc)
+		return rc;
 
 	return rc;
 }
diff --git a/drivers/regulator/onsemi-ncp6335d.c b/drivers/regulator/onsemi-ncp6335d.c
index a0c90f0..4574862 100644
--- a/drivers/regulator/onsemi-ncp6335d.c
+++ b/drivers/regulator/onsemi-ncp6335d.c
@@ -369,8 +369,16 @@
 	.remove = __devexit_p(ncp6335d_regulator_remove),
 	.id_table = ncp6335d_id,
 };
+static int __init ncp6335d_regulator_init(void)
+{
+	return i2c_add_driver(&ncp6335d_regulator_driver);
+}
+subsys_initcall(ncp6335d_regulator_init);
 
-module_i2c_driver(ncp6335d_regulator_driver);
-
+static void __exit ncp6335d_regulator_exit(void)
+{
+	i2c_del_driver(&ncp6335d_regulator_driver);
+}
+module_exit(ncp6335d_regulator_exit);
 MODULE_DESCRIPTION("OnSemi-NCP6335D regulator driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 0497a32..dba02f8 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -288,6 +288,18 @@
 	return spi_op & SPI_OP_STATE_VALID;
 }
 
+static inline void msm_spi_udelay(unsigned long delay_usecs)
+{
+	/*
+	 * For smaller values of delay, context switch time
+	 * would negate the usage of usleep
+	 */
+	if (delay_usecs > 20)
+		usleep_range(delay_usecs, delay_usecs);
+	else if (delay_usecs)
+		udelay(delay_usecs);
+}
+
 static inline int msm_spi_wait_valid(struct msm_spi *dd)
 {
 	unsigned long delay = 0;
@@ -321,14 +333,7 @@
 			} else
 				return 0;
 		}
-		/*
-		 * For smaller values of delay, context switch time
-		 * would negate the usage of usleep
-		 */
-		if (delay > 20)
-			usleep(delay);
-		else if (delay)
-			udelay(delay);
+		msm_spi_udelay(delay);
 	}
 	return 0;
 }
@@ -1412,6 +1417,7 @@
 		}
 	} while (msm_spi_dm_send_next(dd));
 
+	msm_spi_udelay(dd->cur_transfer->delay_usecs);
 transfer_end:
 	msm_spi_dma_unmap_buffers(dd);
 	dd->mode = SPI_MODE_NONE;
@@ -1504,6 +1510,8 @@
 	int xfrs_grped = 0;
 	int cs_num;
 	int rc;
+	bool xfer_delay = false;
+	struct spi_transfer *tr;
 
 	dd->write_xfr_cnt = dd->read_xfr_cnt = 0;
 	cs_num = dd->cur_msg->spi->chip_select;
@@ -1521,8 +1529,21 @@
 		dd->cs_gpios[cs_num].valid = 1;
 	}
 
-	if (dd->qup_ver) {
-		write_force_cs(dd, 0);
+	list_for_each_entry(tr,
+				&dd->cur_msg->transfers,
+				transfer_list) {
+		if (tr->delay_usecs) {
+			dev_info(dd->dev, "SPI slave requests delay per txn :%d",
+					tr->delay_usecs);
+			xfer_delay = true;
+			break;
+		}
+	}
+
+	/* Don't combine xfers if delay is needed after every xfer */
+	if (dd->qup_ver || xfer_delay) {
+		if (dd->qup_ver)
+			write_force_cs(dd, 0);
 		list_for_each_entry(dd->cur_transfer,
 				&dd->cur_msg->transfers,
 				transfer_list) {
@@ -1534,9 +1555,10 @@
 						struct spi_transfer,
 						transfer_list);
 
-				if (t->cs_change == nxt->cs_change)
+				if (dd->qup_ver &&
+					t->cs_change == nxt->cs_change)
 					write_force_cs(dd, 1);
-				else
+				else if (dd->qup_ver)
 					write_force_cs(dd, 0);
 			}
 
@@ -2658,7 +2680,8 @@
 err_probe_reg_master:
 err_probe_irq:
 err_probe_state:
-	dd->dma_teardown(dd);
+	if (dd->dma_teardown)
+		dd->dma_teardown(dd);
 err_probe_dma:
 err_probe_gsbi:
 	if (pclk_enabled)
@@ -2741,7 +2764,8 @@
 	spi_debugfs_exit(dd);
 	sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
 
-	dd->dma_teardown(dd);
+	if (dd->dma_teardown)
+		dd->dma_teardown(dd);
 	clk_put(dd->clk);
 	clk_put(dd->pclk);
 	destroy_workqueue(dd->workqueue);
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index e6f5bf5..5e7ab9f 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -848,8 +848,7 @@
 	},
 };
 
-#define UART_NR	ARRAY_SIZE(msm_uart_ports)
-
+#define UART_NR 256
 static inline struct uart_port * get_port_from_line(unsigned int line)
 {
 	return &msm_uart_ports[line].uart;
@@ -1002,9 +1001,7 @@
 	struct resource *resource;
 	struct uart_port *port;
 	int irq;
-#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
 	struct msm_serial_platform_data *pdata = pdev->dev.platform_data;
-#endif
 
 	if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
 		return -ENXIO;
@@ -1057,6 +1054,8 @@
 #endif
 
 	pm_runtime_enable(port->dev);
+	if (pdata != NULL && pdata->userid && pdata->userid <= UART_NR)
+		port->line = pdata->userid;
 	return uart_add_one_port(&msm_uart_driver, port);
 }
 
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 494ec49..55ff980 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1357,8 +1357,14 @@
 {
 	struct usb_device	*udev = to_usb_device(dev);
 
-	if (udev->bus->skip_resume && udev->state == USB_STATE_SUSPENDED)
-		return 0;
+	if (udev->bus->skip_resume) {
+		if (udev->state == USB_STATE_SUSPENDED) {
+			return 0;
+		} else {
+			dev_err(dev, "abort suspend\n");
+			return -EBUSY;
+		}
+	}
 
 	unbind_no_pm_drivers_interfaces(udev);
 
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index d4a30f1..be4eff7 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -56,7 +56,7 @@
 #define dump_register(nm)				\
 {							\
 	.name	= __stringify(nm),			\
-	.offset	= DWC3_ ##nm,				\
+	.offset	= DWC3_ ##nm - DWC3_GLOBALS_REGS_START,	\
 }
 
 static const struct debugfs_reg32 dwc3_regs[] = {
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index 8f68234..aca2af3 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/ratelimit.h>
 
 #include <mach/usbdiag.h>
 
@@ -427,6 +428,7 @@
 	struct diag_context *ctxt = ch->priv_usb;
 	unsigned long flags;
 	struct usb_request *req;
+	static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
 
 	if (!ctxt)
 		return -ENODEV;
@@ -456,7 +458,9 @@
 		spin_lock_irqsave(&ctxt->lock, flags);
 		list_add_tail(&req->list, &ctxt->read_pool);
 		spin_unlock_irqrestore(&ctxt->lock, flags);
-		ERROR(ctxt->cdev, "%s: cannot queue"
+		/* 1 error message for every 10 sec */
+		if (__ratelimit(&rl))
+			ERROR(ctxt->cdev, "%s: cannot queue"
 				" read request\n", __func__);
 		return -EIO;
 	}
@@ -483,6 +487,7 @@
 	struct diag_context *ctxt = ch->priv_usb;
 	unsigned long flags;
 	struct usb_request *req = NULL;
+	static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
 
 	if (!ctxt)
 		return -ENODEV;
@@ -512,7 +517,9 @@
 		spin_lock_irqsave(&ctxt->lock, flags);
 		list_add_tail(&req->list, &ctxt->write_pool);
 		spin_unlock_irqrestore(&ctxt->lock, flags);
-		ERROR(ctxt->cdev, "%s: cannot queue"
+		/* 1 error message for every 10 sec */
+		if (__ratelimit(&rl))
+			ERROR(ctxt->cdev, "%s: cannot queue"
 				" read request\n", __func__);
 		return -EIO;
 	}
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 8c22f8e..7d12598 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1886,7 +1886,8 @@
 	 * when remote wakeup is received or interface driver
 	 * start I/O.
 	 */
-	if (!atomic_read(&mehci->pm_usage_cnt))
+	if (!atomic_read(&mehci->pm_usage_cnt) &&
+			pm_runtime_suspended(dev))
 		return 0;
 
 	ret = msm_hsic_resume(mehci);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c6fe765..dde9312 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -485,6 +485,9 @@
 	ret = msm_otg_phy_clk_reset(motg);
 	if (ret)
 		return ret;
+	/* 10 usec delay is required according to spec */
+	if (IS_ERR(motg->phy_reset_clk))
+		usleep_range(10, 12);
 	ret = msm_otg_link_clk_reset(motg, 0);
 	if (ret)
 		return ret;
@@ -771,10 +774,12 @@
 	if (aca_enabled())
 		return 0;
 
-	if (atomic_read(&motg->in_lpm) == suspend &&
-		!atomic_read(&motg->suspend_work_pending))
-		return 0;
-
+	/*
+	 * UDC and HCD call usb_phy_set_suspend() to enter/exit LPM
+	 * during bus suspend/resume.  Update the relevant state
+	 * machine inputs and trigger LPM entry/exit.  Checking
+	 * in_lpm flag would avoid unnecessary work scheduling.
+	 */
 	if (suspend) {
 		switch (phy->state) {
 		case OTG_STATE_A_WAIT_BCON:
@@ -784,16 +789,18 @@
 		case OTG_STATE_A_HOST:
 			pr_debug("host bus suspend\n");
 			clear_bit(A_BUS_REQ, &motg->inputs);
-			queue_work(system_nrt_wq, &motg->sm_work);
+			if (!atomic_read(&motg->in_lpm))
+				queue_work(system_nrt_wq, &motg->sm_work);
 			break;
 		case OTG_STATE_B_PERIPHERAL:
 			pr_debug("peripheral bus suspend\n");
 			if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
 				break;
 			set_bit(A_BUS_SUSPEND, &motg->inputs);
-			atomic_set(&motg->suspend_work_pending, 1);
-			queue_delayed_work(system_nrt_wq, &motg->suspend_work,
-				USB_SUSPEND_DELAY_TIME);
+			if (!atomic_read(&motg->in_lpm))
+				queue_delayed_work(system_nrt_wq,
+					&motg->suspend_work,
+					USB_SUSPEND_DELAY_TIME);
 			break;
 
 		default:
@@ -801,20 +808,29 @@
 		}
 	} else {
 		switch (phy->state) {
+		case OTG_STATE_A_WAIT_BCON:
+			/* Remote wakeup or resume */
+			set_bit(A_BUS_REQ, &motg->inputs);
+			/* ensure hardware is not in low power mode */
+			if (atomic_read(&motg->in_lpm))
+				pm_runtime_resume(phy->dev);
+			break;
 		case OTG_STATE_A_SUSPEND:
 			/* Remote wakeup or resume */
 			set_bit(A_BUS_REQ, &motg->inputs);
 			phy->state = OTG_STATE_A_HOST;
 
 			/* ensure hardware is not in low power mode */
-			pm_runtime_resume(phy->dev);
+			if (atomic_read(&motg->in_lpm))
+				pm_runtime_resume(phy->dev);
 			break;
 		case OTG_STATE_B_PERIPHERAL:
 			pr_debug("peripheral bus resume\n");
 			if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
 				break;
 			clear_bit(A_BUS_SUSPEND, &motg->inputs);
-			queue_work(system_nrt_wq, &motg->sm_work);
+			if (atomic_read(&motg->in_lpm))
+				queue_work(system_nrt_wq, &motg->sm_work);
 			break;
 		default:
 			break;
@@ -2945,8 +2961,10 @@
 {
 	struct msm_otg *motg =
 		container_of(w, struct msm_otg, suspend_work.work);
-	atomic_set(&motg->suspend_work_pending, 0);
-	msm_otg_sm_work(&motg->sm_work);
+
+	/* This work is only for device bus suspend */
+	if (test_bit(A_BUS_SUSPEND, &motg->inputs))
+		msm_otg_sm_work(&motg->sm_work);
 }
 
 static irqreturn_t msm_otg_irq(int irq, void *data)
@@ -3475,6 +3493,21 @@
 	return 0;
 }
 
+static int otg_power_property_is_writeable_usb(struct power_supply *psy,
+						enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+	case POWER_SUPPLY_PROP_ONLINE:
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		return 1;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static char *otg_pm_power_supplied_to[] = {
 	"battery",
 };
@@ -4055,6 +4088,8 @@
 	motg->usb_psy.num_properties = ARRAY_SIZE(otg_pm_power_props_usb);
 	motg->usb_psy.get_property = otg_power_get_property_usb;
 	motg->usb_psy.set_property = otg_power_set_property_usb;
+	motg->usb_psy.property_is_writeable
+		= otg_power_property_is_writeable_usb;
 
 	if (!pm8921_charger_register_vbus_sn(NULL)) {
 		/* if pm8921 use legacy implementation */
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 6edc9f2..67ef8bf 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -28,6 +28,8 @@
 extern char *mmss_cc_base;	/* mutimedia sub system clock control */
 extern spinlock_t dsi_clk_lock;
 extern u32 mdp_max_clk;
+extern u32 dbg_force_ov0_blt;
+extern u32 dbg_force_ov1_blt;
 
 #define MDP4_OVERLAYPROC0_BASE	0x10000
 #define MDP4_OVERLAYPROC1_BASE	0x18000
@@ -94,11 +96,6 @@
 #define MDP4_PANEL_WRITEBACK		BIT(6)
 
 enum {
-	OVERLAY_MODE_NONE,
-	OVERLAY_MODE_BLT
-};
-
-enum {
 	OVERLAY_REFRESH_ON_DEMAND,
 	OVERLAY_REFRESH_VSYNC,
 	OVERLAY_REFRESH_VSYNC_HALF,
@@ -449,7 +446,6 @@
 void mdp4_intr_clear_set(ulong clear, ulong set);
 void mdp4_dma_p_cfg(void);
 unsigned is_mdp4_hw_reset(void);
-void mdp4_overlay_cfg_init(void);
 void mdp4_hw_init(void);
 void mdp4_isr_read(int);
 void mdp4_clear_lcdc(void);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 59565c1..f4332dd 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -53,7 +53,6 @@
 	uint32 flush[MDP4_MIXER_MAX];
 	struct iommu_free_list iommu_free[MDP4_MIXER_MAX];
 	uint32 cs_controller;
-	uint32 hw_version;
 	uint32 panel_3d;
 	uint32 panel_mode;
 	uint32 mixer0_played;
@@ -253,7 +252,7 @@
 		pipe->pipe_ndx, plane);
 	if (ion_map_iommu(display_iclient, *srcp_ihdl,
 		DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K, 0, start,
-		len, 0, ION_IOMMU_UNMAP_DELAYED)) {
+		len, 0, 0)) {
 		ion_free(display_iclient, *srcp_ihdl);
 		pr_err("ion_map_iommu() failed\n");
 		return -EINVAL;
@@ -354,23 +353,9 @@
 	return ctrl->panel_mode;
 }
 
-void mdp4_overlay_cfg_init(void)
-{
-	if (ctrl->hw_version == 0) {
-		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-		ctrl->hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */
-		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-	}
-
-	if (ctrl->hw_version >= 0x0402030b) {
-		/* MDP_LAYERMIXER_IN_CFG_UPDATE_METHOD */
-		outpdw(MDP_BASE + 0x100fc, 0x01);
-	}
-}
-
 int mdp4_overlay_borderfill_supported(void)
 {
-	return (ctrl->hw_version >= 0x0402030b);
+	return (mdp_rev >= MDP_REV_42);
 }
 
 void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv)
@@ -2895,8 +2880,9 @@
 				perf_req->mdp_bw);
 			perf_cur->mdp_bw = perf_req->mdp_bw;
 		}
-		if (mfd->panel_info.pdest == DISPLAY_1 &&
-		    perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) {
+		if ((mfd->panel_info.pdest == DISPLAY_1 &&
+		     perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) ||
+		    dbg_force_ov0_blt) {
 			if (mfd->panel_info.type == LCDC_PANEL ||
 			    mfd->panel_info.type == LVDS_PANEL)
 				mdp4_lcdc_overlay_blt_start(mfd);
@@ -2906,17 +2892,18 @@
 				mdp4_dsi_cmd_blt_start(mfd);
 			else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
 				mdp4_mddi_blt_start(mfd);
-			pr_info("%s mixer0 start blt [%d] from %d to %d.\n",
+			pr_debug("%s mixer0 start blt [%d] from %d to %d.\n",
 				__func__,
 				flag,
 				perf_cur->use_ov0_blt,
 				perf_req->use_ov0_blt);
 			perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
 		}
-		if (mfd->panel_info.pdest == DISPLAY_2 &&
-		    perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) {
+		if ((mfd->panel_info.pdest == DISPLAY_2 &&
+		     perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) ||
+		    dbg_force_ov1_blt) {
 			mdp4_dtv_overlay_blt_start(mfd);
-			pr_info("%s mixer1 start blt [%d] from %d to %d.\n",
+			pr_debug("%s mixer1 start blt [%d] from %d to %d.\n",
 				__func__,
 				flag,
 				perf_cur->use_ov1_blt,
@@ -2945,8 +2932,9 @@
 				 perf_req->mdp_bw);
 			perf_cur->mdp_bw = perf_req->mdp_bw;
 		}
-		if (mfd->panel_info.pdest == DISPLAY_1 &&
-		    !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) {
+		if ((mfd->panel_info.pdest == DISPLAY_1 &&
+		     !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) ||
+		    dbg_force_ov0_blt) {
 			if (mfd->panel_info.type == LCDC_PANEL ||
 			    mfd->panel_info.type == LVDS_PANEL)
 				mdp4_lcdc_overlay_blt_stop(mfd);
@@ -2956,17 +2944,18 @@
 				mdp4_dsi_cmd_blt_stop(mfd);
 			else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
 				mdp4_mddi_blt_stop(mfd);
-			pr_info("%s mixer0 stop blt [%d] from %d to %d.\n",
+			pr_debug("%s mixer0 stop blt [%d] from %d to %d.\n",
 				__func__,
 				flag,
 				perf_cur->use_ov0_blt,
 				perf_req->use_ov0_blt);
 			perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
 		}
-		if (mfd->panel_info.pdest == DISPLAY_2 &&
-		    !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) {
+		if ((mfd->panel_info.pdest == DISPLAY_2 &&
+		     !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) ||
+		    dbg_force_ov1_blt) {
 			mdp4_dtv_overlay_blt_stop(mfd);
-			pr_info("%s mixer1 stop blt [%d] from %d to %d.\n",
+			pr_debug("%s mixer1 stop blt [%d] from %d to %d.\n",
 				__func__,
 				flag,
 				perf_cur->use_ov1_blt,
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 239d9f5..450f1de 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -56,7 +56,8 @@
 	int wait_vsync_cnt;
 	int blt_change;
 	int blt_free;
-	int blt_ctrl;
+	u32 blt_ctrl;
+	u32 blt_mode;
 	int sysfs_created;
 	struct mutex update_lock;
 	struct completion ov_comp;
@@ -197,18 +198,6 @@
 	}
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 
-	if (vctrl->blt_change) {
-		pipe = vctrl->base_pipe;
-		spin_lock_irqsave(&vctrl->spin_lock, flags);
-		INIT_COMPLETION(vctrl->dmap_comp);
-		INIT_COMPLETION(vctrl->ov_comp);
-		vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
-		spin_unlock_irqrestore(&vctrl->spin_lock, flags);
-		mdp4_dsi_video_wait4dmap(0);
-		if (pipe->ov_blt_addr)
-			mdp4_dsi_video_wait4ov(0);
-	}
-
 	pipe = vp->plist;
 
 	for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
@@ -498,7 +487,6 @@
 
 	vctrl = &vsync_ctrl_db[cndx];
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-	pinfo = &mfd->panel_info;
 
 	if (!mfd)
 		return -ENODEV;
@@ -508,7 +496,9 @@
 
 	vctrl->mfd = mfd;
 	vctrl->dev = mfd->fbi->dev;
+	pinfo = &mfd->panel_info;
 	vctrl->blt_ctrl = pinfo->lcd.blt_ctrl;
+	vctrl->blt_mode = pinfo->lcd.blt_mode;
 
 	/* mdp clock on */
 	mdp_clk_ctrl(1);
@@ -551,6 +541,7 @@
 		mfd->cont_splash_done = 1;
 		mdp4_dsi_video_wait4dmap_done(0);
 		MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
+		dsi_video_enabled = 0;
 		mipi_dsi_controller_cfg(0);
 		/* Clks are enabled in probe.
 		   Disabling clocks now */
@@ -940,20 +931,8 @@
 	if (vctrl->blt_change) {
 		mdp4_overlayproc_cfg(pipe);
 		mdp4_overlay_dmap_xy(pipe);
-		if (pipe->ov_blt_addr) {
-			mdp4_dsi_video_blt_ov_update(pipe);
-			pipe->ov_cnt++;
-			/* Prefill one frame */
-			vsync_irq_enable(INTR_OVERLAY0_DONE,
-						MDP_OVERLAY0_TERM);
-			/* kickoff overlay0 engine */
-			mdp4_stat.kickoff_ov0++;
-			vctrl->ov_koff++;	/* make up for prefill */
-			outpdw(MDP_BASE + 0x0004, 0);
-		}
 		vctrl->blt_change = 0;
 	}
-
 	complete_all(&vctrl->dmap_comp);
 	mdp4_overlay_dma_commit(cndx);
 	spin_unlock(&vctrl->spin_lock);
@@ -997,19 +976,43 @@
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
 	long long vtime;
+	u32 mode, ctrl;
 
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
 
-	mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+	mode = (dbg_force_ov0_blt & 0x0f) ?
+		(dbg_force_ov0_blt & 0x0f) : vctrl->blt_mode;
+	ctrl = (dbg_force_ov0_blt >> 4) ?
+		(dbg_force_ov0_blt >> 4) : vctrl->blt_ctrl;
 
-	if (mfd->ov0_wb_buf->write_addr == 0) {
-		pr_info("%s: no blt_base assigned\n", __func__);
+	pr_debug("%s: mode=%d, enable=%d ov_blt_addr=%x\n",
+		 __func__, mode, enable, (int)pipe->ov_blt_addr);
+
+	if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF) &&
+	    !pipe->ov_blt_addr)
 		return;
+	else if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_ON) &&
+	    pipe->ov_blt_addr)
+		return;
+	else if (enable && pipe->ov_blt_addr)
+		return;
+	else if (!enable && !pipe->ov_blt_addr)
+		return;
+
+	if (pipe->ov_blt_addr == 0) {
+		mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+		if (mfd->ov0_wb_buf->write_addr == 0) {
+			pr_warning("%s: no blt_base assigned\n", __func__);
+			return;
+		}
 	}
 
+	pr_debug("%s: mode=%d, enable=%d ov_blt_addr=%x\n",
+		 __func__, mode, enable, (int)pipe->ov_blt_addr);
+
 	spin_lock_irqsave(&vctrl->spin_lock, flag);
-	if (enable && pipe->ov_blt_addr == 0) {
+	if (pipe->ov_blt_addr == 0) {
 		pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr;
 		pipe->dma_blt_addr = mfd->ov0_wb_buf->read_addr;
 		pipe->ov_cnt = 0;
@@ -1018,36 +1021,38 @@
 		vctrl->ov_done = 0;
 		vctrl->blt_free = 0;
 		mdp4_stat.blt_dsi_video++;
-		vctrl->blt_change++;
-	} else if (enable == 0 && pipe->ov_blt_addr) {
+	} else {
 		pipe->ov_blt_addr = 0;
 		pipe->dma_blt_addr =  0;
 		vctrl->blt_free = 4;	/* 4 commits to free wb buf */
-		vctrl->blt_change++;
-	}
-
-	pr_info("%s: changed=%d enable=%d ov_blt_addr=%x\n", __func__,
-		vctrl->blt_change, enable, (int)pipe->ov_blt_addr);
-
-	if (!vctrl->blt_change) {
-		spin_unlock_irqrestore(&vctrl->spin_lock, flag);
-		return;
 	}
 	spin_unlock_irqrestore(&vctrl->spin_lock, flag);
 
-	if (vctrl->blt_ctrl == BLT_SWITCH_TG_OFF) {
-		int tg_enabled;
-
-		vctrl->blt_change = 0;
-		tg_enabled = inpdw(MDP_BASE + DSI_VIDEO_BASE) & 0x01;
-		if (tg_enabled) {
+	if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_ON) {
+		spin_lock_irqsave(&vctrl->spin_lock, flag);
+		if (!dsi_video_enabled) {
+			pr_debug("%s: blt switched not in ISR dsi_video_enabled=%d\n",
+				__func__, dsi_video_enabled);
+			mdp4_overlayproc_cfg(pipe);
+			mdp4_overlay_dmap_xy(pipe);
+		} else {
+			pr_debug("%s: blt switched in ISR dsi_video_enabled=%d\n",
+				__func__, dsi_video_enabled);
+			vctrl->blt_change++;
+		}
+		spin_unlock_irqrestore(&vctrl->spin_lock, flag);
+		if (dsi_video_enabled)
+			mdp4_dsi_video_wait4dmap_done(0);
+	} else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_OFF) {
+		pr_debug("%s: blt switched by turning TG off\n", __func__);
+		if (dsi_video_enabled) {
 			mdp4_dsi_video_wait4vsync(0, &vtime);
 			MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
 			mdp4_dsi_video_wait4dmap_done(0);
 		}
 		mdp4_overlayproc_cfg(pipe);
 		mdp4_overlay_dmap_xy(pipe);
-		if (tg_enabled) {
+		if (dsi_video_enabled) {
 			/*
 			* need wait for more than 1 ms to
 			* make sure dsi lanes' fifo is empty and
@@ -1058,7 +1063,15 @@
 			mipi_dsi_sw_reset();
 			MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 1);
 		}
-	}
+	} else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_POLL) {
+		pr_debug("%s: blt switched by polling mdp status\n", __func__);
+		if (dsi_video_enabled)
+			while (inpdw(MDP_BASE + 0x0018) & 0x05)
+				cpu_relax();
+		mdp4_overlayproc_cfg(pipe);
+		mdp4_overlay_dmap_xy(pipe);
+	} else
+		pr_err("%s: ctrl=%d is not supported\n", __func__, ctrl);
 }
 
 void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd,
@@ -1125,4 +1138,3 @@
 	mdp4_overlay_mdp_perf_upd(mfd, 0);
 	mutex_unlock(&mfd->dma->ov_mutex);
 }
-
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 1de5d6e..7de2e2a 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -66,6 +66,9 @@
 	int dmae_wait_cnt;
 	int wait_vsync_cnt;
 	int blt_change;
+	int blt_ctrl;
+	int blt_mode;
+	int blt_free;
 	int sysfs_created;
 	struct mutex update_lock;
 	struct completion ov_comp;
@@ -159,6 +162,7 @@
 }
 
 static void mdp4_dtv_blt_ov_update(struct mdp4_overlay_pipe *pipe);
+static void mdp4_dtv_wait4ov(int cndx);
 static void mdp4_dtv_wait4dmae(int cndx);
 
 int mdp4_dtv_pipe_commit(int cndx, int wait)
@@ -191,6 +195,13 @@
 	vctrl->update_ndx++;
 	vctrl->update_ndx &= 0x01;
 	vp->update_cnt = 0;	/* reset */
+
+	if (vctrl->blt_free) {
+		vctrl->blt_free--;
+		if (vctrl->blt_free == 0)
+			mdp4_free_writeback_buf(vctrl->mfd, mixer);
+	}
+
 	mutex_unlock(&vctrl->update_lock);
 
 	pipe = vp->plist;
@@ -220,6 +231,7 @@
 	if (pipe->ov_blt_addr) {
 		mdp4_dtv_blt_ov_update(pipe);
 		pipe->blt_ov_done++;
+		INIT_COMPLETION(vctrl->ov_comp);
 		vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM);
 		mb();
 		pipe->blt_ov_koff++;
@@ -234,9 +246,12 @@
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 	mdp4_stat.overlay_commit[pipe->mixer_num]++;
 
-	if (wait)
-		mdp4_dtv_wait4dmae(cndx);
-
+	if (wait) {
+		if (pipe->ov_blt_addr)
+			mdp4_dtv_wait4ov(cndx);
+		else
+			mdp4_dtv_wait4dmae(cndx);
+	}
 	return cnt;
 }
 
@@ -296,6 +311,23 @@
 	*vtime = ktime_to_ns(vctrl->vsync_time);
 }
 
+static void mdp4_dtv_wait4ov(int cndx)
+{
+	struct vsycn_ctrl *vctrl;
+
+	if (cndx >= MAX_CONTROLLER) {
+		pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+		return;
+	}
+
+	vctrl = &vsync_ctrl_db[cndx];
+
+	if (atomic_read(&vctrl->suspend) > 0)
+		return;
+
+	wait_for_completion(&vctrl->ov_comp);
+}
+
 static void mdp4_dtv_wait4dmae(int cndx)
 {
 	struct vsycn_ctrl *vctrl;
@@ -367,6 +399,28 @@
 	return ret;
 }
 
+static void mdp4_dtv_wait4dmae_done(int cndx)
+{
+	unsigned long flags;
+	struct vsycn_ctrl *vctrl;
+
+	if (cndx >= MAX_CONTROLLER) {
+		pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+		return;
+	}
+
+	vctrl = &vsync_ctrl_db[cndx];
+
+	if (atomic_read(&vctrl->suspend) > 0)
+		return;
+
+	spin_lock_irqsave(&vctrl->spin_lock, flags);
+	INIT_COMPLETION(vctrl->dmae_comp);
+	vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
+	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+	mdp4_dtv_wait4dmae(cndx);
+}
+
 void mdp4_dtv_vsync_init(int cndx)
 {
 	struct vsycn_ctrl *vctrl;
@@ -554,6 +608,7 @@
 
 	/* enable DTV block */
 	MDP_OUTP(MDP_BASE + DTV_BASE, 1);
+	dtv_enabled = 1;
 
 	return 0;
 }
@@ -568,6 +623,7 @@
 		return -EINVAL;
 
 	MDP_OUTP(MDP_BASE + DTV_BASE, 0);
+	dtv_enabled = 0;
 
 	return 0;
 }
@@ -578,6 +634,7 @@
 	int ret = 0;
 	int cndx = 0;
 	struct vsycn_ctrl *vctrl;
+	struct msm_panel_info *pinfo;
 
 	vctrl = &vsync_ctrl_db[cndx];
 
@@ -589,7 +646,12 @@
 	if (mfd->key != MFD_KEY)
 		return -EINVAL;
 
+	vctrl->mfd = mfd;
 	vctrl->dev = mfd->fbi->dev;
+	pinfo = &mfd->panel_info;
+
+	vctrl->blt_ctrl = pinfo->lcd.blt_ctrl;
+	vctrl->blt_mode = pinfo->lcd.blt_mode;
 
 	mdp_footswitch_ctrl(TRUE);
 	/* Mdp clock enable */
@@ -673,7 +735,7 @@
 
 	if (vctrl->vsync_irq_enabled) {
 		vctrl->vsync_irq_enabled = 0;
-		vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+		vsync_irq_disable(INTR_EXTERNAL_VSYNC, MDP_EXTER_VSYNC_TERM);
 	}
 
 	undx =  vctrl->update_ndx;
@@ -748,11 +810,6 @@
 	MDP_OUTP(MDP_BASE + 0xb0008, addr);
 }
 
-void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd)
-{
-
-}
-
 static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd,
 		int32 ptype, struct vsycn_ctrl *vctrl)
 {
@@ -940,18 +997,8 @@
 
 	spin_lock(&vctrl->spin_lock);
 	if (vctrl->blt_change) {
-		if (pipe->ov_blt_addr) {
-			mdp4_overlayproc_cfg(pipe);
-			mdp4_overlay_dmae_xy(pipe);
-			mdp4_dtv_blt_ov_update(pipe);
-			pipe->blt_ov_done++;
-
-			/* Prefill one frame */
-			vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM);
-			/* kickoff overlay1 engine */
-			mdp4_stat.kickoff_ov1++;
-			outpdw(MDP_BASE + 0x0008, 0);
-		}
+		mdp4_overlayproc_cfg(pipe);
+		mdp4_overlay_dmae_xy(pipe);
 		vctrl->blt_change = 0;
 	}
 
@@ -986,6 +1033,7 @@
 	}
 
 	mdp4_dtv_blt_dmae_update(pipe);
+	complete_all(&vctrl->ov_comp);
 	pipe->blt_dmap_done++;
 	vsync_irq_disable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM);
 	spin_unlock(&vctrl->spin_lock);
@@ -1039,63 +1087,100 @@
 static void mdp4_dtv_do_blt(struct msm_fb_data_type *mfd, int enable)
 {
 	unsigned long flag;
-	int data;
 	int cndx = 0;
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
+	u32 mode, ctrl;
 
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
 
-	mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
+	mode = (dbg_force_ov1_blt & 0x0f) ?
+		(dbg_force_ov1_blt & 0x0f) : vctrl->blt_mode;
+	ctrl = (dbg_force_ov1_blt >> 4) ?
+		(dbg_force_ov1_blt >> 4) : vctrl->blt_ctrl;
 
-	if (!mfd->ov1_wb_buf->write_addr) {
-		pr_info("%s: ctrl=%d blt_base NOT assigned\n", __func__, cndx);
+	pr_debug("%s: mode=%d, ctrl = %d, enable=%d ov_blt_addr=%x\n",
+		 __func__, mode, ctrl, enable, (int)pipe->ov_blt_addr);
+
+	if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF) &&
+	    !pipe->ov_blt_addr)
 		return;
+	else if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_ON) &&
+	    pipe->ov_blt_addr)
+		return;
+	else if (enable && pipe->ov_blt_addr)
+		return;
+	else if (!enable && !pipe->ov_blt_addr)
+		return;
+
+	if (pipe->ov_blt_addr == 0) {
+		mdp4_allocate_writeback_buf(vctrl->mfd, MDP4_MIXER1);
+		if (!vctrl->mfd->ov1_wb_buf->write_addr) {
+			pr_warning("%s: ctrl=%d blt_base NOT assigned\n",
+				__func__, cndx);
+			return;
+		}
 	}
 
+	pr_debug("%s: mode=%d, ctrl=%d, enable=%d ov_blt_addr=%x\n",
+		 __func__, mode, ctrl, enable, (int)pipe->ov_blt_addr);
+
 	spin_lock_irqsave(&vctrl->spin_lock, flag);
 	if (enable && pipe->ov_blt_addr == 0) {
-		pipe->ov_blt_addr = mfd->ov1_wb_buf->write_addr;
-		pipe->dma_blt_addr = mfd->ov1_wb_buf->read_addr;
+		pipe->ov_blt_addr = vctrl->mfd->ov1_wb_buf->write_addr;
+		pipe->dma_blt_addr = vctrl->mfd->ov1_wb_buf->read_addr;
 		pipe->blt_cnt = 0;
 		pipe->ov_cnt = 0;
 		pipe->blt_dmap_done = 0;
 		pipe->blt_ov_koff = 0;
 		pipe->blt_ov_done = 0;
 		mdp4_stat.blt_dtv++;
-		vctrl->blt_change++;
+		vctrl->blt_free = 0;
 	} else if (enable == 0 && pipe->ov_blt_addr) {
 		pipe->ov_blt_addr = 0;
 		pipe->dma_blt_addr = 0;
-		vctrl->blt_change++;
+		vctrl->blt_free = 4;
 	}
-
-	pr_info("%s: enable=%d change=%d blt_addr=%x\n", __func__,
-		enable, vctrl->blt_change, (int)pipe->ov_blt_addr);
-
-	if (!vctrl->blt_change) {
-		spin_unlock_irqrestore(&vctrl->spin_lock, flag);
-		return;
-	}
-
-	atomic_set(&vctrl->suspend, 1);
 	spin_unlock_irqrestore(&vctrl->spin_lock, flag);
 
-	data = inpdw(MDP_BASE + DTV_BASE);
-	data &= 0x01;
-	if (data)       /* timing generator enabled */
-		mdp4_dtv_wait4dmae(0);
+	if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_ON) {
+		spin_lock_irqsave(&vctrl->spin_lock, flag);
+		if (!dtv_enabled) {
+			pr_debug("%s: blt switched not in isr dtv_enabled=%d\n",
+				 __func__, dtv_enabled);
+			mdp4_overlayproc_cfg(pipe);
+			mdp4_overlay_dmae_xy(pipe);
+		} else {
+			pr_debug("%s: blt switched in ISR dtv_enabled=%d\n",
+				__func__, dtv_enabled);
+			vctrl->blt_change++;
 
-	if (pipe->ov_blt_addr == 0) {
-		MDP_OUTP(MDP_BASE + DTV_BASE, 0);       /* stop dtv */
-		msleep(20);
+		}
+		spin_unlock_irqrestore(&vctrl->spin_lock, flag);
+		if (dtv_enabled)
+			mdp4_dtv_wait4dmae_done(0);
+	} else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_OFF) {
+		pr_debug("%s: dtv blt switched by turning TG off\n",
+			 __func__);
+		if (dtv_enabled) {
+			mdp4_dtv_wait4dmae_done(0);
+			MDP_OUTP(MDP_BASE + DTV_BASE, 0);
+			msleep(20);
+		}
 		mdp4_overlayproc_cfg(pipe);
 		mdp4_overlay_dmae_xy(pipe);
-		MDP_OUTP(MDP_BASE + DTV_BASE, 1);       /* start dtv */
-	}
-
-	atomic_set(&vctrl->suspend, 0);
+		if (dtv_enabled)
+			MDP_OUTP(MDP_BASE + DTV_BASE, 1);
+	} else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_POLL) {
+		pr_debug("%s: dtv blt change by polling status\n",
+			__func__);
+		while (inpdw(MDP_BASE + 0x0018) & 0x12)
+			cpu_relax();
+		mdp4_overlayproc_cfg(pipe);
+		mdp4_overlay_dmae_xy(pipe);
+	} else
+		pr_err("%s: ctrl=%d is not supported\n", __func__, ctrl);
 }
 
 void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index ee9ca3c..b6c2634 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -454,8 +454,6 @@
 	clk_rate = mdp_get_core_clk();
 	mdp4_fetch_cfg(clk_rate);
 
-	mdp4_overlay_cfg_init();
-
 	/* Mark hardware as initialized. Only revisions > v2.1 have a register
 	 * for tracking core reset status. */
 	if (mdp_hw_revision > MDP4_REVISION_V2_1)
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 54f5ef5..767375d 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -1029,6 +1029,135 @@
 	.write = dbg_reg_write,
 };
 
+u32 dbg_force_ov0_blt;
+u32 dbg_force_ov1_blt;
+
+static ssize_t dbg_force_ov0_blt_read(
+	struct file *file,
+	char __user *buff,
+	size_t count,
+	loff_t *ppos) {
+	int len;
+
+	if (*ppos)
+		return 0;
+
+	len = snprintf(debug_buf, sizeof(debug_buf),
+		       "%d\n", dbg_force_ov0_blt);
+
+	if (len < 0)
+		return 0;
+
+	if (copy_to_user(buff, debug_buf, len))
+		return -EFAULT;
+
+	*ppos += len;
+
+	return len;
+}
+
+static ssize_t dbg_force_ov0_blt_write(
+	struct file *file,
+	const char __user *buff,
+	size_t count,
+	loff_t *ppos)
+{
+	u32 cnt;
+
+	if (count >= sizeof(debug_buf))
+		return -EFAULT;
+
+	if (copy_from_user(debug_buf, buff, count))
+		return -EFAULT;
+
+	debug_buf[count] = 0;	/* end of string */
+
+	cnt = sscanf(debug_buf, "%x", &dbg_force_ov0_blt);
+
+	pr_info("%s: dbg_force_ov0_blt = %x\n",
+		__func__, dbg_force_ov0_blt);
+
+	if ((dbg_force_ov0_blt & 0x0f) > 2)
+		pr_err("%s: invalid dbg_force_ov0_blt = %d\n",
+			__func__, dbg_force_ov0_blt);
+
+	if ((dbg_force_ov0_blt >> 4) > 2)
+		pr_err("%s: invalid dbg_force_ov0_blt = %d\n",
+			__func__, dbg_force_ov0_blt);
+
+	return count;
+}
+
+static const struct file_operations dbg_force_ov0_blt_fops = {
+	.open = dbg_open,
+	.release = dbg_release,
+	.read = dbg_force_ov0_blt_read,
+	.write = dbg_force_ov0_blt_write,
+};
+
+static ssize_t dbg_force_ov1_blt_read(
+	struct file *file,
+	char __user *buff,
+	size_t count,
+	loff_t *ppos) {
+	int len;
+
+	if (*ppos)
+		return 0;
+
+	len = snprintf(debug_buf, sizeof(debug_buf),
+		       "%x\n", dbg_force_ov1_blt);
+
+	if (len < 0)
+		return 0;
+
+	if (copy_to_user(buff, debug_buf, len))
+		return -EFAULT;
+
+	*ppos += len;
+
+	return len;
+}
+
+static ssize_t dbg_force_ov1_blt_write(
+	struct file *file,
+	const char __user *buff,
+	size_t count,
+	loff_t *ppos)
+{
+	u32 cnt;
+
+	if (count >= sizeof(debug_buf))
+		return -EFAULT;
+
+	if (copy_from_user(debug_buf, buff, count))
+		return -EFAULT;
+
+	debug_buf[count] = 0;	/* end of string */
+
+	cnt = sscanf(debug_buf, "%x", &dbg_force_ov1_blt);
+
+	pr_info("%s: dbg_force_ov1_blt = %x\n",
+		__func__, dbg_force_ov1_blt);
+
+	if ((dbg_force_ov1_blt & 0x0f) > 2)
+		pr_err("%s: invalid dbg_force_ov1_blt = %x\n",
+			__func__, dbg_force_ov1_blt);
+
+	if ((dbg_force_ov1_blt >> 4) > 2)
+		pr_err("%s: invalid dbg_force_ov1_blt = %d\n",
+			__func__, dbg_force_ov1_blt);
+
+	return count;
+}
+
+static const struct file_operations dbg_force_ov1_blt_fops = {
+	.open = dbg_open,
+	.release = dbg_release,
+	.read = dbg_force_ov1_blt_read,
+	.write = dbg_force_ov1_blt_write,
+};
+
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
 static uint32 hdmi_offset;
 static uint32 hdmi_count;
@@ -1249,6 +1378,22 @@
 	}
 #endif
 
+	if (debugfs_create_file("force_ov0_blt", 0644, dent, 0,
+				&dbg_force_ov0_blt_fops)
+			== NULL) {
+		pr_err("%s(%d): debugfs_create_file: debug fail\n",
+			__FILE__, __LINE__);
+		return -EFAULT;
+	}
+
+	if (debugfs_create_file("force_ov1_blt", 0644, dent, 0,
+				&dbg_force_ov1_blt_fops)
+			== NULL) {
+		pr_err("%s(%d): debugfs_create_file: debug fail\n",
+			__FILE__, __LINE__);
+		return -EFAULT;
+	}
+
 	dent = debugfs_create_dir("mddi", NULL);
 
 	if (IS_ERR(dent)) {
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index b760388..5e57de6 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -64,6 +64,9 @@
 	u32 fb_imgType;
 	u32 dst_format;
 	int vsync_pending;
+	ktime_t vsync_time;
+	struct completion vsync_comp;
+	spinlock_t vsync_lock;
 
 	int hw_refresh;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 9508846..052d78c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 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
@@ -13,8 +13,6 @@
 
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
-#include <linux/workqueue.h>
-
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 
@@ -39,7 +37,6 @@
 
 #define MAX_SESSIONS 3
 struct mdss_mdp_video_ctx {
-	u32 ctl_num;
 	u32 pp_num;
 	u8 ref_cnt;
 
@@ -47,11 +44,9 @@
 	struct completion pp_comp;
 	struct completion vsync_comp;
 
-	struct mutex vsync_lock;
-	struct work_struct vsync_work;
+	atomic_t vsync_ref;
+	spinlock_t vsync_lock;
 	mdp_vsync_handler_t vsync_handler;
-	void *vsync_ptr;
-	ktime_t vsync_time;
 };
 
 struct mdss_mdp_video_ctx mdss_mdp_video_ctx_list[MAX_SESSIONS];
@@ -157,43 +152,43 @@
 	return 0;
 }
 
-static void send_vsync_work(struct work_struct *work)
-{
-	struct mdss_mdp_video_ctx *ctx;
 
-	ctx = container_of(work, typeof(*ctx), vsync_work);
-	mutex_lock(&ctx->vsync_lock);
-	if (ctx->vsync_handler)
-		ctx->vsync_handler(ctx->vsync_ptr, ctx->vsync_time);
-	mutex_unlock(&ctx->vsync_lock);
+static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+
+	if (atomic_inc_return(&ctx->vsync_ref) == 1)
+		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+}
+
+static inline void video_vsync_irq_disable(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+
+	if (atomic_dec_return(&ctx->vsync_ref) == 0)
+		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
 }
 
 static int mdss_mdp_video_set_vsync_handler(struct mdss_mdp_ctl *ctl,
 		mdp_vsync_handler_t vsync_handler)
 {
 	struct mdss_mdp_video_ctx *ctx;
+	unsigned long flags;
 
 	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
 	if (!ctx) {
 		pr_err("invalid ctx for ctl=%d\n", ctl->num);
 		return -ENODEV;
 	}
-	if (mutex_lock_interruptible(&ctx->vsync_lock))
-		return -EINTR;
 
-	if (vsync_handler && !ctx->timegen_en) {
-		ctx->vsync_time = ktime_get();
-		schedule_work(&ctx->vsync_work);
-	}
-
+	spin_lock_irqsave(&ctx->vsync_lock, flags);
 	if (!ctx->vsync_handler && vsync_handler)
-		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+		video_vsync_irq_enable(ctl);
 	else if (ctx->vsync_handler && !vsync_handler)
-		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+		video_vsync_irq_disable(ctl);
 
 	ctx->vsync_handler = vsync_handler;
-	ctx->vsync_ptr = ctl;
-	mutex_unlock(&ctx->vsync_lock);
+	spin_unlock_irqrestore(&ctx->vsync_lock, flags);
 
 	return 0;
 }
@@ -229,8 +224,7 @@
 		WARN(rc, "intf %d timegen off error (%d)\n", ctl->intf_num, rc);
 	}
 
-	if (ctx->vsync_handler)
-		mdss_mdp_video_set_vsync_handler(ctl, NULL);
+	mdss_mdp_video_set_vsync_handler(ctl, NULL);
 
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
 				   NULL, NULL);
@@ -244,9 +238,9 @@
 
 static void mdss_mdp_video_pp_intr_done(void *arg)
 {
-	struct mdss_mdp_video_ctx *ctx;
+	struct mdss_mdp_ctl *ctl = arg;
+	struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
 
-	ctx = (struct mdss_mdp_video_ctx *) arg;
 	if (!ctx) {
 		pr_err("invalid ctx\n");
 		return;
@@ -259,20 +253,24 @@
 
 static void mdss_mdp_video_vsync_intr_done(void *arg)
 {
-	struct mdss_mdp_video_ctx *ctx;
+	struct mdss_mdp_ctl *ctl = arg;
+	struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+	ktime_t vsync_time;
 
-	ctx = (struct mdss_mdp_video_ctx *) arg;
 	if (!ctx) {
 		pr_err("invalid ctx\n");
 		return;
 	}
-	ctx->vsync_time = ktime_get();
 
-	pr_debug("intr ctl=%d\n", ctx->ctl_num);
+	vsync_time = ktime_get();
+
+	pr_debug("intr ctl=%d\n", ctl->num);
 
 	complete(&ctx->vsync_comp);
+	spin_lock(&ctx->vsync_lock);
 	if (ctx->vsync_handler)
-		schedule_work(&ctx->vsync_work);
+		ctx->vsync_handler(ctl, vsync_time);
+	spin_unlock(&ctx->vsync_lock);
 }
 
 static int mdss_mdp_video_prepare(struct mdss_mdp_ctl *ctl, void *arg)
@@ -309,11 +307,7 @@
 		return -ENODEV;
 	}
 	INIT_COMPLETION(ctx->vsync_comp);
-
-	if (mutex_lock_interruptible(&ctx->vsync_lock))
-		return -EINTR;
-	if (!ctx->vsync_handler)
-		mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+	video_vsync_irq_enable(ctl);
 
 	if (!ctx->timegen_en) {
 		int off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
@@ -335,9 +329,8 @@
 		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_ON, NULL);
 		WARN(rc, "intf %d timegen on error (%d)\n", ctl->intf_num, rc);
 	}
-	if (!ctx->vsync_handler)
-		mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
-	mutex_unlock(&ctx->vsync_lock);
+
+	video_vsync_irq_disable(ctl);
 
 	return 0;
 }
@@ -376,17 +369,16 @@
 		return -ENOMEM;
 	}
 	ctl->priv_data = ctx;
-	ctx->ctl_num = ctl->num;
 	ctx->pp_num = mixer->num;
 	init_completion(&ctx->pp_comp);
 	init_completion(&ctx->vsync_comp);
+	spin_lock_init(&ctx->vsync_lock);
+	atomic_set(&ctx->vsync_ref, 0);
 
-	INIT_WORK(&ctx->vsync_work, send_vsync_work);
-	mutex_init(&ctx->vsync_lock);
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
-				   mdss_mdp_video_vsync_intr_done, ctx);
+				   mdss_mdp_video_vsync_intr_done, ctl);
 	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
-				   mdss_mdp_video_pp_intr_done, ctx);
+				   mdss_mdp_video_pp_intr_done, ctl);
 
 	itp.width = pinfo->xres + pinfo->lcdc.xres_pad;
 	itp.height = pinfo->yres + pinfo->lcdc.yres_pad;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index f537c39..9c62ea2 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -26,6 +26,7 @@
 #include "mdss_mdp.h"
 #include "mdss_mdp_rotator.h"
 
+#define VSYNC_PERIOD 16
 #define CHECK_BOUNDS(offset, size, max_size) \
 	(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
 
@@ -837,30 +838,27 @@
 		mdss_mdp_overlay_kickoff(mfd->ctl);
 }
 
+/* function is called in irq context should have minimum processing */
 static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
 {
-	struct device *dev;
-	char buf[64];
-	char *envp[2];
-
-	if (!ctl || !ctl->mfd || !ctl->mfd->fbi) {
+	struct msm_fb_data_type *mfd = ctl->mfd;
+	if (!mfd) {
 		pr_warn("Invalid handle for vsync\n");
 		return;
 	}
 
-	dev = ctl->mfd->fbi->dev;
+	pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
 
-	snprintf(buf, sizeof(buf), "VSYNC=%llu", ktime_to_ns(t));
-	envp[0] = buf;
-	envp[1] = NULL;
-	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
-
-	pr_debug("sent vsync on ctl=%d ts=%llu\n", ctl->num, ktime_to_ns(t));
+	spin_lock(&mfd->vsync_lock);
+	mfd->vsync_time = t;
+	complete(&mfd->vsync_comp);
+	spin_unlock(&mfd->vsync_lock);
 }
 
 int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
 {
 	struct mdss_mdp_ctl *ctl = mfd->ctl;
+	unsigned long flags;
 	int rc;
 
 	if (!ctl)
@@ -868,13 +866,23 @@
 	if (!ctl->set_vsync_handler)
 		return -ENOTSUPP;
 
-	pr_debug("vsync en=%d\n", en);
-
 	if (!ctl->power_on) {
+		pr_debug("fb%d vsync pending first update en=%d\n",
+				mfd->index, en);
 		mfd->vsync_pending = en;
 		return 0;
 	}
 
+	pr_debug("fb%d vsync en=%d\n", mfd->index, en);
+
+	spin_lock_irqsave(&mfd->vsync_lock, flags);
+	INIT_COMPLETION(mfd->vsync_comp);
+	if (en && ctl->play_cnt == 0) {
+		mfd->vsync_time = ktime_get();
+		complete(&mfd->vsync_comp);
+	}
+	spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (en)
 		rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
@@ -885,6 +893,47 @@
 	return rc;
 }
 
+static ssize_t mdss_mdp_vsync_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	unsigned long flags;
+	u64 vsync_ticks;
+	int ret;
+
+	if (!mfd->ctl || !mfd->ctl->power_on)
+		return 0;
+
+	ret = wait_for_completion_interruptible_timeout(&mfd->vsync_comp,
+			msecs_to_jiffies(VSYNC_PERIOD * 5));
+	if (ret <= 0) {
+		pr_warn("vsync wait on fb%d interrupted (%d)\n",
+			mfd->index, ret);
+		return -EBUSY;
+	}
+
+	spin_lock_irqsave(&mfd->vsync_lock, flags);
+	vsync_ticks = ktime_to_ns(mfd->vsync_time);
+	spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+
+	pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
+	ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
+
+	return ret;
+}
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
+
+static struct attribute *vsync_fs_attrs[] = {
+	&dev_attr_vsync_event.attr,
+	NULL,
+};
+
+static struct attribute_group vsync_fs_attr_group = {
+	.attrs = vsync_fs_attrs,
+};
+
 static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
 				     struct fb_cursor *cursor)
 {
@@ -1154,6 +1203,9 @@
 
 int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
 {
+	struct device *dev = mfd->fbi->dev;
+	int rc;
+
 	mfd->on_fnc = mdss_mdp_overlay_on;
 	mfd->off_fnc = mdss_mdp_overlay_off;
 	mfd->hw_refresh = true;
@@ -1168,7 +1220,18 @@
 
 	INIT_LIST_HEAD(&mfd->pipes_used);
 	INIT_LIST_HEAD(&mfd->pipes_cleanup);
+	init_completion(&mfd->vsync_comp);
+	spin_lock_init(&mfd->vsync_lock);
 	mutex_init(&mfd->ov_lock);
 
-	return 0;
+	rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
+	if (rc) {
+		pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
+		return rc;
+	}
+
+	kobject_uevent(&dev->kobj, KOBJ_ADD);
+	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
+
+	return rc;
 }
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index bdd4f3bb..505928e 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -71,6 +71,7 @@
 	__u32 hw_vsync_mode;
 	__u32 vsync_notifier_period;
 	__u32 blt_ctrl;
+	__u32 blt_mode;
 	__u32 rev;
 };
 
@@ -204,6 +205,18 @@
 	int (*clk_func) (int enable);
 };
 
+enum {
+	MDP4_OVERLAY_BLT_SWITCH_TG_OFF,
+	MDP4_OVERLAY_BLT_SWITCH_TG_ON,
+	MDP4_OVERLAY_BLT_SWITCH_POLL
+};
+
+enum {
+	MDP4_OVERLAY_MODE_BLT_CTRL,
+	MDP4_OVERLAY_MODE_BLT_ALWAYS_ON,
+	MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF
+};
+
 /*===========================================================================
   FUNCTIONS PROTOTYPES
 ============================================================================*/
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 2a850d8..7a1d521 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -293,6 +293,7 @@
 	struct vcd_property_slice_delivery_info slice_delivery_info;
 	struct ddl_batch_frame_data batch_frame;
 	u32 avc_delimiter_enable;
+	u32 vui_timinginfo_enable;
 };
 struct ddl_decoder_data {
 	struct ddl_codec_data_hdr  hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 2c41ab4..78f96c8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -1259,7 +1259,8 @@
 				output_vcd_frm->flags |=
 					VCD_FRAME_FLAG_DATACORRUPT;
 		}
-		if (decoder->codec.codec != VCD_CODEC_H264)
+		if (decoder->codec.codec != VCD_CODEC_H264 ||
+			decoder->codec.codec != VCD_CODEC_MPEG2)
 			output_vcd_frm->flags &= ~VCD_FRAME_FLAG_DATACORRUPT;
 		output_vcd_frm->ip_frm_tag = dec_disp_info->tag_top;
 		vidc_sm_get_picture_times(&ddl->shared_mem
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 d6558c3..332497f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1061,6 +1061,20 @@
 		}
 		break;
 	}
+	case VCD_I_ENABLE_VUI_TIMING_INFO:
+	{
+		struct vcd_property_vui_timing_info_enable *vui_timing_enable =
+			(struct vcd_property_vui_timing_info_enable *)
+				property_value;
+		if (sizeof(struct vcd_property_vui_timing_info_enable) ==
+			property_hdr->sz &&
+			encoder->codec.codec == VCD_CODEC_H264) {
+			encoder->vui_timinginfo_enable =
+			vui_timing_enable->vui_timing_info;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
+	}
 	default:
 		DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
 		vcd_status = VCD_ERR_ILLEGAL_OP;
@@ -1553,6 +1567,15 @@
 			vcd_status = VCD_S_SUCCESS;
 		}
 		break;
+	case VCD_I_ENABLE_VUI_TIMING_INFO:
+		if (sizeof(struct vcd_property_vui_timing_info_enable) ==
+			property_hdr->sz) {
+			((struct vcd_property_vui_timing_info_enable *)
+				property_value)->vui_timing_info =
+					encoder->vui_timinginfo_enable;
+			vcd_status = VCD_S_SUCCESS;
+		}
+		break;
 	default:
 		vcd_status = VCD_ERR_ILLEGAL_OP;
 		break;
@@ -1715,6 +1738,7 @@
 	encoder->slice_delivery_info.num_slices = 0;
 	encoder->slice_delivery_info.num_slices_enc = 0;
 	encoder->avc_delimiter_enable = 0;
+	encoder->vui_timinginfo_enable = 0;
 }
 
 static void ddl_set_default_enc_profile(struct ddl_encoder_data *encoder)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 40dc2aa..de3fc4f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -83,6 +83,8 @@
 #define VIDC_SM_ENC_EXT_CTRL_ADDR                    0x0028
 #define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_BMSK    0xffff0000
 #define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_SHFT    16
+#define VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK     0x00004000
+#define VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_SHFT     14
 #define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK    0x00000800
 #define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT    11
 #define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK  0x80
@@ -176,6 +178,13 @@
 #define VIDC_SM_ENC_NUM_OF_SLICE_COMP_ADDR                        0x01d0
 #define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_BMSK                  0xffffffff
 #define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_SHFT                  0
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_ADDR                        0x01dc
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_VALUE_BMSK                  0xffffffff
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_VALUE_SHFT                  0
+#define VIDC_SM_ENC_TIME_SCALE_ADDR                               0x01e0
+#define VIDC_SM_ENC_TIME_SCALE_VALUE_BMSK                         0xffffffff
+#define VIDC_SM_ENC_TIME_SCALE_VALUE_SHFT                         0
+
 
 #define VIDC_SM_ALLOCATED_LUMA_DPB_SIZE_ADDR               0x0064
 #define VIDC_SM_ALLOCATED_CHROMA_DPB_SIZE_ADDR             0x0068
@@ -449,7 +458,8 @@
 	enum VIDC_SM_frame_skip frame_skip_mode,
 	u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
 	u32 sps_pps_control, u32 closed_gop_enable,
-	u32 au_delim_enable)
+	u32 au_delim_enable,
+	u32 vui_timing_info_enable)
 {
 	u32 enc_ctrl;
 	enc_ctrl = VIDC_SETFIELD((hec_enable) ? 1 : 0,
@@ -475,7 +485,10 @@
 			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK) |
 			VIDC_SETFIELD((au_delim_enable) ? 1 : 0,
 			VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT,
-			VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK);
+			VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK) |
+			VIDC_SETFIELD((vui_timing_info_enable) ? 1 : 0,
+			VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_SHFT,
+			VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK);
 
 	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
 }
@@ -962,20 +975,12 @@
 		(codec == VCD_CODEC_DIVX_4) ||
 		(codec == VCD_CODEC_DIVX_5) ||
 		(codec == VCD_CODEC_DIVX_6) ||
-		(codec == VCD_CODEC_XVID) ||
-		(codec == VCD_CODEC_MPEG2)) {
+		(codec == VCD_CODEC_XVID)) {
 
-		if (codec == VCD_CODEC_MPEG2) {
-			aspect_ratio_info->aspect_ratio =
-				VIDC_GETFIELD(aspect_ratio,
-				VIDC_SM_MPEG2_ASPECT_RATIO_INFO_BMSK,
-				VIDC_SM_MPEG2_ASPECT_RATIO_INFO_SHFT);
-		} else {
-			aspect_ratio_info->aspect_ratio =
-				VIDC_GETFIELD(aspect_ratio,
-				VIDC_SM_MPEG4_ASPECT_RATIO_INFO_BMSK,
-				VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT);
-		}
+		aspect_ratio_info->aspect_ratio =
+			VIDC_GETFIELD(aspect_ratio,
+			VIDC_SM_MPEG4_ASPECT_RATIO_INFO_BMSK,
+			VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT);
 
 		switch (aspect_ratio_info->aspect_ratio) {
 		case 1:
@@ -1016,7 +1021,38 @@
 			aspect_ratio_info->par_height   = 1;
 			break;
 		}
+	} else if (codec == VCD_CODEC_MPEG2) {
+
+		aspect_ratio_info->aspect_ratio =
+			VIDC_GETFIELD(aspect_ratio,
+			VIDC_SM_MPEG2_ASPECT_RATIO_INFO_BMSK,
+			VIDC_SM_MPEG2_ASPECT_RATIO_INFO_SHFT);
+
+		switch (aspect_ratio_info->aspect_ratio) {
+		case 1:
+			aspect_ratio_info->par_width    = 1;
+			aspect_ratio_info->par_height   = 1;
+			break;
+		case 2:
+			aspect_ratio_info->par_width    = 4;
+			aspect_ratio_info->par_height   = 3;
+			break;
+		case 3:
+			aspect_ratio_info->par_width    = 16;
+			aspect_ratio_info->par_height   = 9;
+			break;
+		case 4:
+			aspect_ratio_info->par_width    = 221;
+			aspect_ratio_info->par_height   = 100;
+			break;
+		default:
+			DDL_MSG_LOW("Incorrect Aspect Ratio.");
+			aspect_ratio_info->par_width    = 1;
+			aspect_ratio_info->par_height   = 1;
+			break;
+		}
 	}
+
 }
 
 void vidc_sm_set_encoder_slice_batch_int_ctrl(struct ddl_buf_addr *shared_mem,
@@ -1139,3 +1175,15 @@
 			VIDC_SM_MP2_DATA_DUMP_BUFFER_SIZE_ADDR,
 			mp2datadumpsize);
 }
+
+void vidc_sm_set_h264_encoder_timing_info(struct ddl_buf_addr *shared_mem,
+	u32 num_units_in_tick, u32 time_scale)
+{
+	DDL_MEM_WRITE_32(shared_mem,
+			VIDC_SM_ENC_NUM_UNITS_IN_TICK_ADDR,
+			num_units_in_tick);
+
+	DDL_MEM_WRITE_32(shared_mem,
+			VIDC_SM_ENC_TIME_SCALE_ADDR,
+			time_scale);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index c4d577b..2eef99d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -106,7 +106,7 @@
 	struct ddl_buf_addr *shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip  frame_skip_mode, u32 seq_hdr_in_band,
 	u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
-	u32 closed_gop_enable, u32 au_delim_enable);
+	u32 closed_gop_enable, u32 au_delim_enable, u32 vui_timing_info_enable);
 void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
 	u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
 void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
@@ -198,6 +198,8 @@
 void vidc_sm_set_mp2datadump_enable(struct ddl_buf_addr *shared_mem,
 	struct ddl_mp2_datadumpenabletype *ddl_mp2_datadump_enable);
 void vidc_sm_set_mp2datadumpbuffer(struct ddl_buf_addr *shared_mem,
-		u32 mp2datadumpaddr, u32 mp2datadumpsize);
+	u32 mp2datadumpaddr, u32 mp2datadumpsize);
+void vidc_sm_set_h264_encoder_timing_info(struct ddl_buf_addr *shared_mem,
+	u32 num_units_in_tick, u32 time_scale);
 
 #endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
index bbde7ae..6817101 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
@@ -62,7 +62,8 @@
 #define DDL_GET_ALIGNED_VITUAL(x)   ((x).align_virtual_addr)
 #define DDL_KILO_BYTE(x)   ((x)*1024)
 #define DDL_MEGA_BYTE(x)   ((x)*1024*1024)
-#define DDL_FRAMERATE_SCALE(x)            ((x) * 1000)
+#define DDL_FRAMERATE_SCALE_FACTOR      (1000)
+#define DDL_FRAMERATE_SCALE(x)          ((x) * DDL_FRAMERATE_SCALE_FACTOR)
 
 #define DDL_MIN(x, y)  ((x < y) ? x : y)
 #define DDL_MAX(x, y)  ((x > y) ? x : y)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 5eed305..76972ca 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -370,6 +370,15 @@
 				(u32)(DDL_FRAMERATE_SCALE(encoder->\
 				frame_rate.fps_numerator) /
 				encoder->frame_rate.fps_denominator));
+			if (encoder->vui_timinginfo_enable &&
+				encoder->frame_rate.fps_denominator) {
+				vidc_sm_set_h264_encoder_timing_info(
+					&ddl->shared_mem[ddl->command_channel],
+					DDL_FRAMERATE_SCALE_FACTOR,
+					(u32)(DDL_FRAMERATE_SCALE(encoder->\
+					frame_rate.fps_numerator) / encoder->\
+					frame_rate.fps_denominator) << 1);
+			}
 			encoder->dynamic_prop_change &=
 				~(DDL_ENC_CHANGE_FRAMERATE);
 		}
@@ -596,7 +605,14 @@
 		[ddl->command_channel], hdr_ext_control,
 		r_cframe_skip, false, 0,
 		h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
-		encoder->closed_gop, encoder->avc_delimiter_enable);
+		encoder->closed_gop, encoder->avc_delimiter_enable,
+		encoder->vui_timinginfo_enable);
+	if (encoder->vui_timinginfo_enable) {
+		vidc_sm_set_h264_encoder_timing_info(
+			&ddl->shared_mem[ddl->command_channel],
+			DDL_FRAMERATE_SCALE_FACTOR,
+			scaled_frame_rate << 1);
+	}
 	vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
 		[ddl->command_channel],
 		encoder->target_bit_rate.target_bitrate);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd.h b/drivers/video/msm/vidc/common/vcd/vcd.h
index 8f44a56..a22adeb 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd.h
@@ -398,4 +398,8 @@
 u32 vcd_update_decoder_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl);
 
 u32 vcd_set_perf_turbo_level(struct vcd_clnt_ctxt *cctxt);
+
+struct vcd_transc *vcd_get_first_in_use_trans_for_clnt(
+	struct vcd_clnt_ctxt *cctxt);
+
 #endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index b84ae44..a4c44f3 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -1684,7 +1684,7 @@
 void vcd_send_frame_done_in_eos(struct vcd_clnt_ctxt *cctxt,
 	 struct vcd_frame_data *input_frame, u32 valid_opbuf)
 {
-	VCD_MSG_LOW("vcd_send_frame_done_in_eos:");
+	VCD_MSG_HIGH("vcd_send_frame_done_in_eos:");
 
 	if (!input_frame->virtual && !valid_opbuf) {
 		VCD_MSG_MED("Sending NULL output with EOS");
@@ -1804,12 +1804,41 @@
 	}
 }
 
+struct vcd_transc *vcd_get_first_in_use_trans_for_clnt(
+	struct vcd_clnt_ctxt *cctxt)
+{
+	u32 i;
+	struct vcd_dev_ctxt *dev_ctxt;
+	VCD_MSG_HIGH("%s: ", __func__);
+	dev_ctxt = cctxt->dev_ctxt;
+	if (!dev_ctxt->trans_tbl) {
+		VCD_MSG_ERROR("%s: Null trans_tbl", __func__);
+		return NULL;
+	}
+	i = 0;
+	while (i < dev_ctxt->trans_tbl_size) {
+		if ((cctxt == dev_ctxt->trans_tbl[i].cctxt) &&
+			(dev_ctxt->trans_tbl[i].in_use)) {
+			VCD_MSG_MED("%s: found transc = 0x%p",
+				__func__, &dev_ctxt->trans_tbl[i]);
+			break;
+		}
+		i++;
+	}
+	if (i == dev_ctxt->trans_tbl_size) {
+		VCD_MSG_ERROR("%s: in_use transction not found",
+			__func__);
+		return NULL;
+	} else
+		return &dev_ctxt->trans_tbl[i];
+}
+
 u32 vcd_handle_recvd_eos(
 	struct vcd_clnt_ctxt *cctxt,
 	 struct vcd_frame_data *input_frame, u32 *pb_eos_handled)
 {
 	u32 rc;
-
+	struct vcd_transc *transc;
 	VCD_MSG_LOW("vcd_handle_recvd_eos:");
 
 	*pb_eos_handled = false;
@@ -1827,13 +1856,21 @@
 		*pb_eos_handled = true;
 	else if (cctxt->decoding && !input_frame->virtual)
 		cctxt->sched_clnt_hdl->tkns++;
-	else if (!cctxt->decoding) {
-		vcd_send_frame_done_in_eos(cctxt, input_frame, false);
-		if (cctxt->status.mask & VCD_EOS_WAIT_OP_BUF) {
-			vcd_do_client_state_transition(cctxt,
-				VCD_CLIENT_STATE_EOS,
-				CLIENT_STATE_EVENT_NUMBER
-				(encode_frame));
+	else if (!cctxt->decoding && !cctxt->status.frame_delayed) {
+		if (!cctxt->status.frame_submitted) {
+			vcd_send_frame_done_in_eos(cctxt, input_frame, false);
+			if (cctxt->status.mask & VCD_EOS_WAIT_OP_BUF)
+				vcd_do_client_state_transition(cctxt,
+					VCD_CLIENT_STATE_EOS,
+					CLIENT_STATE_EVENT_NUMBER
+					(encode_frame));
+		} else {
+			transc = vcd_get_first_in_use_trans_for_clnt(cctxt);
+			if (transc) {
+				transc->flags |= VCD_FRAME_FLAG_EOS;
+				VCD_MSG_HIGH("%s: Add EOS flag to transc",
+				       __func__);
+			}
 		}
 		*pb_eos_handled = true;
 	}
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 98cce5b..29546b7 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -445,4 +445,5 @@
 header-y += genlock.h
 header-y += msm_audio_amrwb.h
 header-y += coresight-stm.h
-header-y += ci-bridge-spi.h
\ No newline at end of file
+header-y += ci-bridge-spi.h
+header-y += msm_audio_amrwbplus.h
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 211327f..3a29f20 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -33,12 +33,14 @@
  * @ION_HEAP_TYPE_CP:	 memory allocated from a prereserved
  *				carveout heap, allocations are physically
  *				contiguous. Used for content protection.
+ * @ION_HEAP_TYPE_DMA:          memory allocated via DMA API
  * @ION_HEAP_END:		helper for iterating over heaps
  */
 enum ion_heap_type {
 	ION_HEAP_TYPE_SYSTEM,
 	ION_HEAP_TYPE_SYSTEM_CONTIG,
 	ION_HEAP_TYPE_CARVEOUT,
+	ION_HEAP_TYPE_DMA,
 	ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
 				 are at the end of this enum */
 	ION_NUM_HEAPS,
@@ -47,6 +49,7 @@
 #define ION_HEAP_SYSTEM_MASK		(1 << ION_HEAP_TYPE_SYSTEM)
 #define ION_HEAP_SYSTEM_CONTIG_MASK	(1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
 #define ION_HEAP_CARVEOUT_MASK		(1 << ION_HEAP_TYPE_CARVEOUT)
+#define ION_HEAP_TYPE_DMA_MASK         (1 << ION_HEAP_TYPE_DMA)
 
 /**
  * heap flags - the lower 16 bits are used by core ion, the upper 16
@@ -84,6 +87,7 @@
  * @memory_type:Memory type used for the heap
  * @has_outer_cache:    set to 1 if outer cache is used, 0 otherwise.
  * @extra_data:	Extra data specific to each heap type
+ * @priv:	heap private data
  */
 struct ion_platform_heap {
 	enum ion_heap_type type;
@@ -94,6 +98,7 @@
 	enum ion_memory_types memory_type;
 	unsigned int has_outer_cache;
 	void *extra_data;
+	void *priv;
 };
 
 /**
@@ -115,7 +120,7 @@
 	int (*request_region)(void *);
 	int (*release_region)(void *);
 	void *(*setup_region)(void);
-	struct ion_platform_heap heaps[];
+	struct ion_platform_heap *heaps;
 };
 
 #ifdef CONFIG_ION
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 82ec57d..6db6204 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -37,6 +37,10 @@
  *			is considered empty(mV)
  * @enable_fcc_learning:	if set the driver will learn full charge
  *				capacity of the battery upon end of charge
+ * @normal_voltage_calc_ms:	The period of soc calculation in ms when battery
+ *				voltage higher than cutoff voltage
+ * @low_voltage_calc_ms:	The period of soc calculation in ms when battery
+ *				voltage is near cutoff voltage
  */
 struct pm8921_bms_platform_data {
 	struct pm8xxx_bms_core_data	bms_cdata;
@@ -51,6 +55,8 @@
 	int				ignore_shutdown_soc;
 	int				adjust_soc_low_threshold;
 	int				chg_term_ua;
+	int				normal_voltage_calc_ms;
+	int				low_voltage_calc_ms;
 };
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 4ad55f4..ae2c3d8 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -89,6 +89,7 @@
  *			area
  * @max_bat_chg_current:	Max charge current of the battery in mA
  *				Usually 70% of full charge capacity
+ * @usb_max_current:		Maximum USB current in mA
  * @cool_bat_chg_current:	chg current (mA) when the battery is cool
  * @warm_bat_chg_current:	chg current (mA)  when the battery is warm
  * @cool_bat_voltage:		chg voltage (mV) when the battery is cool
@@ -96,10 +97,6 @@
  * @get_batt_capacity_percent:
  *			a board specific function to return battery
  *			capacity. If null - a default one will be used
- * @dc_unplug_check:	enables the reverse boosting fix for the DC_IN line
- *			however, this should only be enabled for devices which
- *			control the DC OVP FETs otherwise this option should
- *			remain disabled
  * @has_dc_supply:	report DC online if this bit is set in board file
  * @trkl_voltage:	the trkl voltage in (mV) below which hw controlled
  *			 trkl charging happens with linear charger
@@ -144,6 +141,7 @@
 	int				warm_temp;
 	unsigned int			temp_check_period;
 	unsigned int			max_bat_chg_current;
+	unsigned int			usb_max_current;
 	unsigned int			cool_bat_chg_current;
 	unsigned int			warm_bat_chg_current;
 	unsigned int			cool_bat_voltage;
@@ -152,7 +150,6 @@
 	int64_t				batt_id_min;
 	int64_t				batt_id_max;
 	bool				keep_btm_on_suspend;
-	bool				dc_unplug_check;
 	bool				has_dc_supply;
 	int				trkl_voltage;
 	int				weak_voltage;
@@ -178,15 +175,6 @@
 void pm8921_charger_vbus_draw(unsigned int mA);
 int pm8921_charger_register_vbus_sn(void (*callback)(int));
 void pm8921_charger_unregister_vbus_sn(void (*callback)(int));
-/**
- * pm8921_charger_enable -
- *
- * @enable: 1 means enable charging, 0 means disable
- *
- * Enable/Disable battery charging current, the device will still draw current
- * from the charging source
- */
-int pm8921_charger_enable(bool enable);
 
 /**
  * pm8921_is_usb_chg_plugged_in - is usb plugged in
@@ -312,10 +300,6 @@
 static inline void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
 {
 }
-static inline int pm8921_charger_enable(bool enable)
-{
-	return -ENXIO;
-}
 static inline int pm8921_is_usb_chg_plugged_in(void)
 {
 	return -ENXIO;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index f435221..6c43ec7 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -138,6 +138,8 @@
 	void	(*enable_preset_value)(struct mmc_host *host, bool enable);
 	int	(*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
 	void	(*hw_reset)(struct mmc_host *host);
+	unsigned long (*get_max_frequency)(struct mmc_host *host);
+	unsigned long (*get_min_frequency)(struct mmc_host *host);
 };
 
 struct mmc_card;
@@ -250,6 +252,7 @@
 
 #define MMC_CAP2_SANITIZE	(1 << 13)		/* Support Sanitize */
 #define MMC_CAP2_INIT_BKOPS	    (1 << 15)	/* Need to set BKOPS_EN */
+#define MMC_CAP2_CLK_SCALE	(1 << 16)	/* Allow dynamic clk scaling */
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
 	int			clk_requests;	/* internal reference counter */
@@ -353,6 +356,19 @@
 #endif
 
 	struct mmc_ios saved_ios;
+	struct {
+		unsigned long	busy_time_us;
+		unsigned long	window_time;
+		unsigned long	curr_freq;
+		unsigned long	polling_delay_ms;
+		unsigned int	up_threshold;
+		unsigned int	down_threshold;
+		ktime_t		start_busy;
+		bool		enable;
+		bool		initialized;
+		bool		in_progress;
+		struct delayed_work work;
+	} clk_scaling;
 	unsigned long		private[0] ____cacheline_aligned;
 };
 
@@ -468,6 +484,14 @@
 	return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
 }
 
+static inline int mmc_host_uhs(struct mmc_host *host)
+{
+	return host->caps &
+		(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+		 MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+		 MMC_CAP_UHS_DDR50);
+}
+
 #ifdef CONFIG_MMC_CLKGATE
 void mmc_host_clk_hold(struct mmc_host *host);
 void mmc_host_clk_release(struct mmc_host *host);
diff --git a/include/linux/msm_audio_amrwbplus.h b/include/linux/msm_audio_amrwbplus.h
new file mode 100644
index 0000000..aa17117
--- /dev/null
+++ b/include/linux/msm_audio_amrwbplus.h
@@ -0,0 +1,18 @@
+#ifndef __MSM_AUDIO_AMR_WB_PLUS_H
+#define __MSM_AUDIO_AMR_WB_PLUS_H
+
+#define AUDIO_GET_AMRWBPLUS_CONFIG_V2  _IOR(AUDIO_IOCTL_MAGIC, \
+	(AUDIO_MAX_COMMON_IOCTL_NUM+2), struct msm_audio_amrwbplus_config_v2)
+#define AUDIO_SET_AMRWBPLUS_CONFIG_V2  _IOW(AUDIO_IOCTL_MAGIC, \
+	(AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_amrwbplus_config_v2)
+
+struct msm_audio_amrwbplus_config_v2 {
+	unsigned int size_bytes;
+	unsigned int version;
+	unsigned int num_channels;
+	unsigned int amr_band_mode;
+	unsigned int amr_dtx_mode;
+	unsigned int amr_frame_fmt;
+	unsigned int amr_lsf_idx;
+};
+#endif /* __MSM_AUDIO_AMR_WB_PLUS_H */
diff --git a/include/linux/msm_ipc.h b/include/linux/msm_ipc.h
index 44fa8eb..7b6bf41 100644
--- a/include/linux/msm_ipc.h
+++ b/include/linux/msm_ipc.h
@@ -45,6 +45,14 @@
 	unsigned char reserved;
 };
 
+struct config_sec_rules_args {
+	int num_group_info;
+	uint32_t service_id;
+	uint32_t instance_id;
+	unsigned reserved;
+	gid_t group_id[0];
+};
+
 #define IPC_ROUTER_IOCTL_MAGIC (0xC3)
 
 #define IPC_ROUTER_IOCTL_GET_VERSION \
@@ -62,6 +70,9 @@
 #define IPC_ROUTER_IOCTL_BIND_CONTROL_PORT \
 	_IOR(IPC_ROUTER_IOCTL_MAGIC, 4, unsigned int)
 
+#define IPC_ROUTER_IOCTL_CONFIG_SEC_RULES \
+	_IOR(IPC_ROUTER_IOCTL_MAGIC, 5, struct config_sec_rules_args)
+
 struct msm_ipc_server_info {
 	uint32_t node_id;
 	uint32_t port_id;
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 6912087..4e62b4f 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -1,6 +1,13 @@
 #ifndef _MSM_KGSL_H
 #define _MSM_KGSL_H
 
+/*
+ * The KGSL version has proven not to be very useful in userspace if features
+ * are cherry picked into other trees out of order so it is frozen as of 3.14.
+ * It is left here for backwards compatabilty and as a reminder that
+ * software releases are never linear. Also, I like pie.
+ */
+
 #define KGSL_VERSION_MAJOR        3
 #define KGSL_VERSION_MINOR        14
 
@@ -16,13 +23,25 @@
 
 #define KGSL_CONTEXT_INVALID 0xffffffff
 
-/* Memory allocayion flags */
-#define KGSL_MEMFLAGS_GPUREADONLY	0x01000000
+/* --- Memory allocation flags --- */
 
+/* General allocation hints */
+#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000
+#define KGSL_MEMFLAGS_USE_CPU_MAP 0x10000000
+
+/* Memory caching hints */
+#define KGSL_CACHEMODE_MASK 0x0C000000
+#define KGSL_CACHEMODE_SHIFT 26
+
+#define KGSL_CACHEMODE_WRITECOMBINE 0
+#define KGSL_CACHEMODE_UNCACHED 1
+#define KGSL_CACHEMODE_WRITETHROUGH 2
+#define KGSL_CACHEMODE_WRITEBACK 3
+
+/* Memory types for which allocations are made */
 #define KGSL_MEMTYPE_MASK		0x0000FF00
 #define KGSL_MEMTYPE_SHIFT		8
 
-/* Memory types for which allocations are made */
 #define KGSL_MEMTYPE_OBJECTANY			0
 #define KGSL_MEMTYPE_FRAMEBUFFER		1
 #define KGSL_MEMTYPE_RENDERBUFFER		2
@@ -53,7 +72,8 @@
 #define KGSL_MEMALIGN_MASK		0x00FF0000
 #define KGSL_MEMALIGN_SHIFT		16
 
-/* generic flag values */
+/* --- generic KGSL flag values --- */
+
 #define KGSL_FLAGS_NORMALMODE  0x00000000
 #define KGSL_FLAGS_SAFEMODE    0x00000001
 #define KGSL_FLAGS_INITIALIZED0 0x00000002
@@ -419,6 +439,14 @@
 #define IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC \
 	_IOWR(KGSL_IOC_TYPE, 0x23, struct kgsl_sharedmem_from_vmalloc)
 
+/*
+ * This is being deprecated in favor of IOCTL_KGSL_GPUMEM_CACHE_SYNC which
+ * supports both directions (flush and invalidate). This code will still
+ * work, but by definition it will do a flush of the cache which might not be
+ * what you want to have happen on a buffer following a GPU operation.  It is
+ * safer to go with IOCTL_KGSL_GPUMEM_CACHE_SYNC
+ */
+
 #define IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE \
 	_IOW(KGSL_IOC_TYPE, 0x24, struct kgsl_sharedmem_free)
 
@@ -511,6 +539,115 @@
 #define IOCTL_KGSL_TIMESTAMP_EVENT \
 	_IOWR(KGSL_IOC_TYPE, 0x33, struct kgsl_timestamp_event)
 
+/**
+ * struct kgsl_gpumem_alloc_id - argument to IOCTL_KGSL_GPUMEM_ALLOC_ID
+ * @id: returned id value for this allocation.
+ * @flags: mask of KGSL_MEM* values requested and actual flags on return.
+ * @size: requested size of the allocation and actual size on return.
+ * @mmapsize: returned size to pass to mmap() which may be larger than 'size'
+ * @gpuaddr: returned GPU address for the allocation
+ *
+ * Allocate memory for access by the GPU. The flags and size fields are echoed
+ * back by the kernel, so that the caller can know if the request was
+ * adjusted.
+ *
+ * Supported flags:
+ * KGSL_MEMFLAGS_GPUREADONLY: the GPU will be unable to write to the buffer
+ * KGSL_MEMTYPE*: usage hint for debugging aid
+ * KGSL_MEMALIGN*: alignment hint, may be ignored or adjusted by the kernel.
+ * KGSL_MEMFLAGS_USE_CPU_MAP: If set on call and return, the returned GPU
+ * address will be 0. Calling mmap() will set the GPU address.
+ */
+struct kgsl_gpumem_alloc_id {
+	unsigned int id;
+	unsigned int flags;
+	unsigned int size;
+	unsigned int mmapsize;
+	unsigned long gpuaddr;
+/* private: reserved for future use*/
+	unsigned int __pad[2];
+};
+
+#define IOCTL_KGSL_GPUMEM_ALLOC_ID \
+	_IOWR(KGSL_IOC_TYPE, 0x34, struct kgsl_gpumem_alloc_id)
+
+/**
+ * struct kgsl_gpumem_free_id - argument to IOCTL_KGSL_GPUMEM_FREE_ID
+ * @id: GPU allocation id to free
+ *
+ * Free an allocation by id, in case a GPU address has not been assigned or
+ * is unknown. Freeing an allocation by id with this ioctl or by GPU address
+ * with IOCTL_KGSL_SHAREDMEM_FREE are equivalent.
+ */
+struct kgsl_gpumem_free_id {
+	unsigned int id;
+/* private: reserved for future use*/
+	unsigned int __pad;
+};
+
+#define IOCTL_KGSL_GPUMEM_FREE_ID \
+	_IOWR(KGSL_IOC_TYPE, 0x35, struct kgsl_gpumem_free_id)
+
+/**
+ * struct kgsl_gpumem_get_info - argument to IOCTL_KGSL_GPUMEM_GET_INFO
+ * @gpuaddr: GPU address to query. Also set on return.
+ * @id: GPU allocation id to query. Also set on return.
+ * @flags: returned mask of KGSL_MEM* values.
+ * @size: returned size of the allocation.
+ * @mmapsize: returned size to pass mmap(), which may be larger than 'size'
+ * @useraddr: returned address of the userspace mapping for this buffer
+ *
+ * This ioctl allows querying of all user visible attributes of an existing
+ * allocation, by either the GPU address or the id returned by a previous
+ * call to IOCTL_KGSL_GPUMEM_ALLOC_ID. Legacy allocation ioctls may not
+ * return all attributes so this ioctl can be used to look them up if needed.
+ *
+ */
+struct kgsl_gpumem_get_info {
+	unsigned long gpuaddr;
+	unsigned int id;
+	unsigned int flags;
+	unsigned int size;
+	unsigned int mmapsize;
+	unsigned long useraddr;
+/* private: reserved for future use*/
+	unsigned int __pad[4];
+};
+
+#define IOCTL_KGSL_GPUMEM_GET_INFO\
+	_IOWR(KGSL_IOC_TYPE, 0x36, struct kgsl_gpumem_get_info)
+
+/**
+ * struct kgsl_gpumem_sync_cache - argument to IOCTL_KGSL_GPUMEM_SYNC_CACHE
+ * @gpuaddr: GPU address of the buffer to sync.
+ * @id: id of the buffer to sync. Either gpuaddr or id is sufficient.
+ * @op: a mask of KGSL_GPUMEM_CACHE_* values
+ *
+ * Sync the L2 cache for memory headed to and from the GPU - this replaces
+ * KGSL_SHAREDMEM_FLUSH_CACHE since it can handle cache management for both
+ * directions
+ *
+ */
+struct kgsl_gpumem_sync_cache {
+	unsigned int gpuaddr;
+	unsigned int id;
+	unsigned int op;
+/* private: reserved for future use*/
+	unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define KGSL_GPUMEM_CACHE_CLEAN (1 << 0)
+#define KGSL_GPUMEM_CACHE_TO_GPU KGSL_GPUMEM_CACHE_CLEAN
+
+#define KGSL_GPUMEM_CACHE_INV (1 << 1)
+#define KGSL_GPUMEM_CACHE_FROM_GPU KGSL_GPUMEM_CACHE_INV
+
+#define KGSL_GPUMEM_CACHE_FLUSH \
+	(KGSL_GPUMEM_CACHE_CLEAN | KGSL_GPUMEM_CACHE_INV)
+
+#define IOCTL_KGSL_GPUMEM_SYNC_CACHE \
+	_IOW(KGSL_IOC_TYPE, 0x37, struct kgsl_gpumem_sync_cache)
+
 #ifdef __KERNEL__
 #ifdef CONFIG_MSM_KGSL_DRM
 int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 077ccfc..fc34b22 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -402,8 +402,11 @@
 };
 
 /**
- * enum qpnp_adc_meas_timer - Selects the measurement interval time.
+ * enum qpnp_adc_meas_timer_1 - Selects the measurement interval time.
  *		If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * The timer period is used by the USB_ID. Do not set a polling rate
+ * greater than 1 second on PMIC 2.0. The max polling rate on the PMIC 2.0
+ * appears to be limited to 1 second.
  * %ADC_MEAS_INTERVAL_0MS : 0ms
  * %ADC_MEAS_INTERVAL_1P0MS : 1ms
  * %ADC_MEAS_INTERVAL_2P0MS : 2ms
@@ -421,24 +424,126 @@
  * %ADC_MEAS_INTERVAL_8S : 8seconds
  * %ADC_MEAS_INTERVAL_16S: 16seconds
  */
-enum qpnp_adc_meas_timer {
-	ADC_MEAS_INTERVAL_0MS = 0,
-	ADC_MEAS_INTERVAL_1P0MS,
-	ADC_MEAS_INTERVAL_2P0MS,
-	ADC_MEAS_INTERVAL_3P9MS,
-	ADC_MEAS_INTERVAL_7P8MS,
-	ADC_MEAS_INTERVAL_15P6MS,
-	ADC_MEAS_INTERVAL_31P3MS,
-	ADC_MEAS_INTERVAL_62P5MS,
-	ADC_MEAS_INTERVAL_125MS,
-	ADC_MEAS_INTERVAL_250MS,
-	ADC_MEAS_INTERVAL_500MS,
-	ADC_MEAS_INTERVAL_1S,
-	ADC_MEAS_INTERVAL_2S,
-	ADC_MEAS_INTERVAL_4S,
-	ADC_MEAS_INTERVAL_8S,
-	ADC_MEAS_INTERVAL_16S,
-	ADC_MEAS_INTERVAL_NONE,
+enum qpnp_adc_meas_timer_1 {
+	ADC_MEAS1_INTERVAL_0MS = 0,
+	ADC_MEAS1_INTERVAL_1P0MS,
+	ADC_MEAS1_INTERVAL_2P0MS,
+	ADC_MEAS1_INTERVAL_3P9MS,
+	ADC_MEAS1_INTERVAL_7P8MS,
+	ADC_MEAS1_INTERVAL_15P6MS,
+	ADC_MEAS1_INTERVAL_31P3MS,
+	ADC_MEAS1_INTERVAL_62P5MS,
+	ADC_MEAS1_INTERVAL_125MS,
+	ADC_MEAS1_INTERVAL_250MS,
+	ADC_MEAS1_INTERVAL_500MS,
+	ADC_MEAS1_INTERVAL_1S,
+	ADC_MEAS1_INTERVAL_2S,
+	ADC_MEAS1_INTERVAL_4S,
+	ADC_MEAS1_INTERVAL_8S,
+	ADC_MEAS1_INTERVAL_16S,
+	ADC_MEAS1_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer_2 - Selects the measurement interval time.
+ *		If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * The timer period is used by the batt_therm. Do not set a polling rate
+ * greater than 1 second on PMIC 2.0. The max polling rate on the PMIC 2.0
+ * appears to be limited to 1 second.
+ * %ADC_MEAS_INTERVAL_0MS : 0ms
+ * %ADC_MEAS_INTERVAL_100MS : 100ms
+ * %ADC_MEAS_INTERVAL_200MS : 200ms
+ * %ADC_MEAS_INTERVAL_300MS : 300ms
+ * %ADC_MEAS_INTERVAL_400MS : 400ms
+ * %ADC_MEAS_INTERVAL_500MS : 500ms
+ * %ADC_MEAS_INTERVAL_600MS : 600ms
+ * %ADC_MEAS_INTERVAL_700MS : 700ms
+ * %ADC_MEAS_INTERVAL_800MS : 800ms
+ * %ADC_MEAS_INTERVAL_900MS : 900ms
+ * %ADC_MEAS_INTERVAL_1S: 1seconds
+ * %ADC_MEAS_INTERVAL_1P1S: 1.1seconds
+ * %ADC_MEAS_INTERVAL_1P2S: 1.2seconds
+ * %ADC_MEAS_INTERVAL_1P3S: 1.3seconds
+ * %ADC_MEAS_INTERVAL_1P4S: 1.4seconds
+ * %ADC_MEAS_INTERVAL_1P5S: 1.5seconds
+ */
+enum qpnp_adc_meas_timer_2 {
+	ADC_MEAS2_INTERVAL_0MS = 0,
+	ADC_MEAS2_INTERVAL_100MS,
+	ADC_MEAS2_INTERVAL_200MS,
+	ADC_MEAS2_INTERVAL_300MS,
+	ADC_MEAS2_INTERVAL_400MS,
+	ADC_MEAS2_INTERVAL_500MS,
+	ADC_MEAS2_INTERVAL_600MS,
+	ADC_MEAS2_INTERVAL_700MS,
+	ADC_MEAS2_INTERVAL_800MS,
+	ADC_MEAS2_INTERVAL_900MS,
+	ADC_MEAS2_INTERVAL_1S,
+	ADC_MEAS2_INTERVAL_1P1S,
+	ADC_MEAS2_INTERVAL_1P2S,
+	ADC_MEAS2_INTERVAL_1P3S,
+	ADC_MEAS2_INTERVAL_1P4S,
+	ADC_MEAS2_INTERVAL_1P5S,
+	ADC_MEAS2_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer_3 - Selects the measurement interval time.
+ *		If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * Do not set a polling rate greater than 1 second on PMIC 2.0.
+ * The max polling rate on the PMIC 2.0 appears to be limited to 1 second.
+ * %ADC_MEAS_INTERVAL_0MS : 0ms
+ * %ADC_MEAS_INTERVAL_1S : 1seconds
+ * %ADC_MEAS_INTERVAL_2S : 2seconds
+ * %ADC_MEAS_INTERVAL_3S : 3seconds
+ * %ADC_MEAS_INTERVAL_4S : 4seconds
+ * %ADC_MEAS_INTERVAL_5S : 5seconds
+ * %ADC_MEAS_INTERVAL_6S: 6seconds
+ * %ADC_MEAS_INTERVAL_7S : 7seconds
+ * %ADC_MEAS_INTERVAL_8S : 8seconds
+ * %ADC_MEAS_INTERVAL_9S : 9seconds
+ * %ADC_MEAS_INTERVAL_10S : 10seconds
+ * %ADC_MEAS_INTERVAL_11S : 11seconds
+ * %ADC_MEAS_INTERVAL_12S : 12seconds
+ * %ADC_MEAS_INTERVAL_13S : 13seconds
+ * %ADC_MEAS_INTERVAL_14S : 14seconds
+ * %ADC_MEAS_INTERVAL_15S : 15seconds
+ */
+enum qpnp_adc_meas_timer_3 {
+	ADC_MEAS3_INTERVAL_0S = 0,
+	ADC_MEAS3_INTERVAL_1S,
+	ADC_MEAS3_INTERVAL_2S,
+	ADC_MEAS3_INTERVAL_3S,
+	ADC_MEAS3_INTERVAL_4S,
+	ADC_MEAS3_INTERVAL_5S,
+	ADC_MEAS3_INTERVAL_6S,
+	ADC_MEAS3_INTERVAL_7S,
+	ADC_MEAS3_INTERVAL_8S,
+	ADC_MEAS3_INTERVAL_9S,
+	ADC_MEAS3_INTERVAL_10S,
+	ADC_MEAS3_INTERVAL_11S,
+	ADC_MEAS3_INTERVAL_12S,
+	ADC_MEAS3_INTERVAL_13S,
+	ADC_MEAS3_INTERVAL_14S,
+	ADC_MEAS3_INTERVAL_15S,
+	ADC_MEAS3_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer_select - Selects the timer for which
+ *	the appropriate polling frequency is set.
+ * %ADC_MEAS_TIMER_SELECT1 - Select this timer if the client is USB_ID.
+ * %ADC_MEAS_TIMER_SELECT2 - Select this timer if the client is batt_therm.
+ * %ADC_MEAS_TIMER_SELECT3 - The timer is added only for completion. It is
+ *	not used by kernel space clients and user space clients cannot set
+ *	the polling frequency. The driver will set a appropriate polling
+ *	frequency to measure the user space clients from qpnp_adc_meas_timer_3.
+ */
+enum qpnp_adc_meas_timer_select {
+	ADC_MEAS_TIMER_SELECT1 = 0,
+	ADC_MEAS_TIMER_SELECT2,
+	ADC_MEAS_TIMER_SELECT3,
+	ADC_MEAS_TIMER_NUM,
 };
 
 /**
@@ -455,6 +560,134 @@
 };
 
 /**
+ * Channel selection registers for each of the 5 configurable measurements
+ * Channels allotment is fixed for the given channels below.
+ * The USB_ID and BATT_THERM channels are used only by the kernel space
+ * USB and Battery drivers.
+ * The other 3 channels are configurable for use by userspace clients.
+ * USB_ID uses QPNP_ADC_TM_M0_ADC_CH_SEL_CTL
+ * BATT_TEMP uses QPNP_ADC_TM_M1_ADC_CH_SEL_CTL
+ * PA_THERM1 uses QPNP_ADC_TM_M2_ADC_CH_SEL_CTL
+ * PA_THERM2 uses QPNP_ADC_TM_M3_ADC_CH_SEL_CTL
+ * EMMC_THERM uses QPNP_ADC_TM_M4_ADC_CH_SEL_CTL
+ */
+enum qpnp_adc_tm_channel_select	{
+	QPNP_ADC_TM_M0_ADC_CH_SEL_CTL = 0x48,
+	QPNP_ADC_TM_M1_ADC_CH_SEL_CTL = 0x68,
+	QPNP_ADC_TM_M2_ADC_CH_SEL_CTL = 0x70,
+	QPNP_ADC_TM_M3_ADC_CH_SEL_CTL = 0x78,
+	QPNP_ADC_TM_M4_ADC_CH_SEL_CTL = 0x80,
+	QPNP_ADC_TM_CH_SELECT_NONE
+};
+
+/**
+ * struct qpnp_adc_tm_config - Represent ADC Thermal Monitor configuration.
+ * @channel: ADC channel for which thermal monitoring is requested.
+ * @adc_code: The pre-calibrated digital output of a given ADC releative to the
+ *		ADC reference.
+ * @high_thr_temp: Temperature at which high threshold notification is required.
+ * @low_thr_temp: Temperature at which low threshold notification is required.
+ * @low_thr_voltage : Low threshold voltage ADC code used for reverse
+ *			calibration.
+ * @high_thr_voltage: High threshold voltage ADC code used for reverse
+ *			calibration.
+ */
+struct qpnp_adc_tm_config {
+	int	channel;
+	int	adc_code;
+	int	high_thr_temp;
+	int	low_thr_temp;
+	int64_t	high_thr_voltage;
+	int64_t	low_thr_voltage;
+};
+
+/**
+ * enum qpnp_adc_tm_trip_type - Type for setting high/low temperature/voltage.
+ * %ADC_TM_TRIP_HIGH_WARM: Setting high temperature. Note that high temperature
+ *			corresponds to low voltage. Driver handles this case
+ *			appropriately to set high/low thresholds for voltage.
+ *			threshold.
+ * %ADC_TM_TRIP_LOW_COOL: Setting low temperature.
+ */
+enum qpnp_adc_tm_trip_type {
+	ADC_TM_TRIP_HIGH_WARM = 0,
+	ADC_TM_TRIP_LOW_COOL,
+	ADC_TM_TRIP_NUM,
+};
+
+/**
+ * enum qpnp_tm_state - This lets the client know whether the threshold
+ *		that was crossed was high/low.
+ * %ADC_TM_HIGH_STATE: Client is notified of crossing the requested high
+ *			threshold.
+ * %ADC_TM_LOW_STATE: Client is notified of crossing the requested low
+ *			threshold.
+ */
+enum qpnp_tm_state {
+	ADC_TM_HIGH_STATE = 0,
+	ADC_TM_LOW_STATE,
+	ADC_TM_STATE_NUM,
+};
+
+/**
+ * enum qpnp_state_request - Request to enable/disable the corresponding
+ *			high/low voltage/temperature thresholds.
+ * %ADC_TM_HIGH_THR_ENABLE: Enable high voltage/temperature threshold.
+ * %ADC_TM_LOW_THR_ENABLE: Enable low voltage/temperature threshold.
+ * %ADC_TM_HIGH_LOW_THR_ENABLE: Enable high and low voltage/temperature
+ *				threshold.
+ * %ADC_TM_HIGH_THR_DISABLE: Disable high voltage/temperature threshold.
+ * %ADC_TM_LOW_THR_DISABLE: Disable low voltage/temperature threshold.
+ * %ADC_TM_HIGH_THR_DISABLE: Disable high and low voltage/temperature
+ *				threshold.
+ */
+enum qpnp_state_request {
+	ADC_TM_HIGH_THR_ENABLE = 0,
+	ADC_TM_LOW_THR_ENABLE,
+	ADC_TM_HIGH_LOW_THR_ENABLE,
+	ADC_TM_HIGH_THR_DISABLE,
+	ADC_TM_LOW_THR_DISABLE,
+	ADC_TM_HIGH_LOW_THR_DISABLE,
+	ADC_TM_THR_NUM,
+};
+
+/**
+ * struct qpnp_adc_tm_usbid_param - Represent USB_ID threshold
+ *				monitoring configuration.
+ * @high_thr: High voltage threshold for which notification is requested.
+ * @low_thr: Low voltage threshold for which notification is requested.
+ * @state_request: Enable/disable the corresponding high and low voltage
+ *		thresholds.
+ * @timer_interval: Select polling rate from qpnp_adc_meas_timer_1 type.
+ * @threshold_notification: Notification callback once threshold are crossed.
+ */
+struct qpnp_adc_tm_usbid_param {
+	int32_t					high_thr;
+	int32_t					low_thr;
+	enum qpnp_state_request			state_request;
+	enum qpnp_adc_meas_timer_1		timer_interval;
+	void	(*threshold_notification) (enum qpnp_tm_state state);
+};
+
+/**
+ * struct qpnp_adc_tm_btm_param - Represent Battery temperature threshold
+ *				monitoring configuration.
+ * @high_temp: High temperature threshold for which notification is requested.
+ * @low_temp: Low temperature threshold for which notification is requested.
+ * @state_request: Enable/disable the corresponding high and low temperature
+ *		thresholds.
+ * @timer_interval: Select polling rate from qpnp_adc_meas_timer_2 type.
+ * @threshold_notification: Notification callback once threshold are crossed.
+ */
+struct qpnp_adc_tm_btm_param {
+	int32_t					high_temp;
+	int32_t					low_temp;
+	enum qpnp_state_request			state_request;
+	enum qpnp_adc_meas_timer_2		timer_interval;
+	void	(*threshold_notification) (enum qpnp_tm_state state);
+};
+
+/**
  * struct qpnp_vadc_linear_graph - Represent ADC characteristics.
  * @dy: Numerator slope to calculate the gain.
  * @dx: Denominator slope to calculate the gain.
@@ -541,7 +774,7 @@
 };
 
 /**
- * struct qpnp_adc_amux - AMUX properties for individual channel
+ * struct qpnp_vadc_amux - AMUX properties for individual channel
  * @name: Channel string name.
  * @channel_num: Channel in integer used from qpnp_adc_channels.
  * @chan_path_prescaling: Channel scaling performed on the input signal.
@@ -624,7 +857,7 @@
  * @adc_prop - ADC properties specific to the ADC peripheral.
  * @amux_prop - AMUX properties representing the ADC peripheral.
  * @adc_channels - ADC channel properties for the ADC peripheral.
- * @adc_irq - IRQ number that is mapped to the ADC peripheral.
+ * @adc_irq_eoc - End of Conversion IRQ.
  * @adc_lock - ADC lock for access to the peripheral.
  * @adc_rslt_completion - ADC result notification after interrupt
  *			  is received.
@@ -637,7 +870,7 @@
 	struct qpnp_adc_properties	*adc_prop;
 	struct qpnp_adc_amux_properties	*amux_prop;
 	struct qpnp_vadc_amux		*adc_channels;
-	int				adc_irq;
+	int				adc_irq_eoc;
 	struct mutex			adc_lock;
 	struct completion		adc_rslt_completion;
 	struct qpnp_iadc_calib		calib;
@@ -828,6 +1061,70 @@
  *		has not occured.
  */
 int32_t qpnp_vadc_is_ready(void);
+/**
+ * qpnp_adc_tm_scaler() - Performs reverse calibration.
+ * @config:	Thermal monitoring configuration.
+ * @adc_prop:	adc properties of the qpnp adc such as bit resolution and
+ *		reference voltage.
+ * @chan_prop:	Individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ */
+static inline int32_t qpnp_adc_tm_scaler(struct qpnp_adc_tm_config *tm_config,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop)
+{ return -ENXIO; }
+/**
+ * qpnp_get_vadc_gain_and_offset() - Obtains the VADC gain and offset
+ *		for absolute and ratiometric calibration.
+ * @param:	The result in which the ADC offset and gain values are stored.
+ * @type:	The calibration type whether client needs the absolute or
+ *		ratiometric gain and offset values.
+ */
+int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
+			enum qpnp_adc_calib_type calib_type);
+/**
+ * qpnp_adc_btm_scaler() - Performs reverse calibration on the low/high
+ *		temperature threshold values passed by the client.
+ *		The function maps the temperature to voltage and applies
+ *		ratiometric calibration on the voltage values.
+ * @param:	The input parameters that contain the low/high temperature
+ *		values.
+ * @low_threshold: The low threshold value that needs to be updated with
+ *		the above calibrated voltage value.
+ * @high_threshold: The low threshold value that needs to be updated with
+ *		the above calibrated voltage value.
+ */
+int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
+		uint32_t *low_threshold, uint32_t *high_threshold);
+/**
+ * qpnp_adc_tm_scale_therm_voltage_pu2() - Performs reverse calibration
+ *		and convert given temperature to voltage on supported
+ *		thermistor channels using 100k pull-up.
+ * @param:	The input temperature values.
+ */
+int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param);
+/**
+ * qpnp_adc_tm_scale_therm_voltage_pu2() - Performs reverse calibration
+ *		and converts the given ADC code to temperature for
+ *		thermistor channels using 100k pull-up.
+ * @reg:	The input ADC code.
+ * @result:	The physical measurement temperature on the thermistor.
+ */
+int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result);
+/**
+ * qpnp_adc_usb_scaler() - Performs reverse calibration on the low/high
+ *		voltage threshold values passed by the client.
+ *		The function applies ratiometric calibration on the
+ *		voltage values.
+ * @param:	The input parameters that contain the low/high voltage
+ *		threshold values.
+ * @low_threshold: The low threshold value that needs to be updated with
+ *		the above calibrated voltage value.
+ * @high_threshold: The low threshold value that needs to be updated with
+ *		the above calibrated voltage value.
+ */
+int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_usbid_param *param,
+		uint32_t *low_threshold, uint32_t *high_threshold);
 #else
 static inline int32_t qpnp_vadc_read(uint32_t channel,
 				struct qpnp_vadc_result *result)
@@ -874,6 +1171,29 @@
 { return -ENXIO; }
 static inline int32_t qpnp_vadc_is_ready(void)
 { 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)
+{ return -ENXIO; }
+static inline int32_t qpnp_get_vadc_gain_and_offset(
+			struct qpnp_vadc_linear_graph *param,
+			enum qpnp_adc_calib_type calib_type)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_usb_scaler(
+		struct qpnp_adc_tm_usbid_param *param,
+		uint32_t *low_threshold, uint32_t *high_threshold)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_btm_scaler(
+		struct qpnp_adc_tm_btm_param *param,
+		uint32_t *low_threshold, uint32_t *high_threshold)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_scale_therm_voltage_pu2(
+				struct qpnp_adc_tm_config *param)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_scale_voltage_therm_pu2(
+				uint32_t reg, int64_t *result)
+{ return -ENXIO; }
 #endif
 
 /* Public API */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index d6fbc64..5b7820d 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -333,7 +333,6 @@
 	bool sm_work_pending;
 	atomic_t pm_suspended;
 	atomic_t in_lpm;
-	atomic_t suspend_work_pending;
 	int async_int;
 	unsigned cur_power;
 	struct delayed_work chg_work;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b1f534d..e5e0bb4 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1833,6 +1833,12 @@
 	V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM,
 	V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
 };
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
+enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
+};
 
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 180b38d..545dcd2 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -56,6 +56,8 @@
 #define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
 #define VCD_I_SET_TURBO_CLK (VCD_START_BASE + 0x29)
 #define VCD_I_ENABLE_DELIMITER_FLAG (VCD_START_BASE + 0x2A)
+#define VCD_I_ENABLE_VUI_TIMING_INFO (VCD_START_BASE + 0x2B)
+
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
@@ -378,4 +380,8 @@
 	u32 avc_delimiter_enable_flag;
 };
 
+struct vcd_property_vui_timing_info_enable {
+	u32 vui_timing_info;
+};
+
 #endif
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 84d9b42..369cf45 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -38,8 +38,8 @@
 };
 
 enum hal_vcap_polar {
-	HAL_VCAP_POLAR_NEG = 0,
-	HAL_VCAP_POLAR_POS,
+	HAL_VCAP_POLAR_POS = 0,
+	HAL_VCAP_POLAR_NEG,
 };
 
 enum hal_vcap_color {
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 14ccf3e..3bf514f 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -247,6 +247,11 @@
 	bdaddr_t	bdaddr;
 } __packed;
 
+#define MGMT_OP_CANCEL_RESOLVE_NAME	0x0024
+struct mgmt_cp_cancel_resolve_name {
+	bdaddr_t bdaddr;
+} __packed;
+
 #define MGMT_OP_LE_READ_WHITE_LIST_SIZE	0xE000
 
 #define MGMT_OP_LE_CLEAR_WHITE_LIST	0xE001
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 4376ece..3dd0ccd 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -712,8 +712,8 @@
 #define AFE_PORT_ID_PRIMARY_MI2S_TX         0x1001
 #define AFE_PORT_ID_SECONDARY_MI2S_RX       0x1002
 #define AFE_PORT_ID_SECONDARY_MI2S_TX       0x1003
-#define AFE_PORT_IDERTIARY_MI2S_RX        0x1004
-#define AFE_PORT_IDERTIARY_MI2S_TX        0x1005
+#define AFE_PORT_ID_TERTIARY_MI2S_RX        0x1004
+#define AFE_PORT_ID_TERTIARY_MI2S_TX        0x1005
 #define AFE_PORT_ID_QUATERNARY_MI2S_RX      0x1006
 #define AFE_PORT_ID_QUATERNARY_MI2S_TX      0x1007
 #define AUDIO_PORT_ID_I2S_RX				0x1008
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
index 6c60318..4ecd435 100644
--- a/include/sound/msm-dai-q6-v2.h
+++ b/include/sound/msm-dai-q6-v2.h
@@ -20,10 +20,11 @@
 #define MSM_MI2S_SD3 (1 << 3)
 #define MSM_MI2S_CAP_RX 0
 #define MSM_MI2S_CAP_TX 1
+
 #define MSM_PRIM_MI2S 0
 #define MSM_SEC_MI2S  1
 #define MSM_TERT_MI2S 2
-#define MSM_QUAD_MI2S 3
+#define MSM_QUAT_MI2S  3
 
 struct msm_dai_auxpcm_pdata {
 	const char *clk;
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index cb2f3d7..9c43d09 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -16,13 +16,13 @@
 #define ADM_PATH_PLAYBACK 0x1
 #define ADM_PATH_LIVE_REC 0x2
 #define ADM_PATH_NONLIVE_REC 0x3
+#include <sound/q6afe-v2.h>
 #include <sound/q6audio-v2.h>
 
-#define Q6_AFE_MAX_PORTS 32
 
 /* multiple copp per stream. */
 struct route_payload {
-	unsigned int copp_ids[Q6_AFE_MAX_PORTS];
+	unsigned int copp_ids[AFE_MAX_PORTS];
 	unsigned short num_copps;
 	unsigned int session_id;
 };
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 1324f8a..444b432 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -71,6 +71,8 @@
 	IDX_INT_FM_TX = 29,
 	IDX_RT_PROXY_PORT_001_RX = 30,
 	IDX_RT_PROXY_PORT_001_TX = 31,
+	IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 32,
+	IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 33,
 	AFE_MAX_PORTS
 };
 
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 28eb7ea..493801a 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1956,6 +1956,38 @@
 	return err;
 }
 
+static int cancel_resolve_name(struct sock *sk, u16 index, unsigned char *data,
+								u16 len)
+{
+	struct mgmt_cp_cancel_resolve_name *mgmt_cp = (void *) data;
+	struct hci_cp_remote_name_req_cancel hci_cp;
+	struct hci_dev *hdev;
+	int err;
+
+	BT_DBG("");
+
+	if (len != sizeof(*mgmt_cp))
+		return cmd_status(sk, index, MGMT_OP_CANCEL_RESOLVE_NAME,
+								EINVAL);
+
+	hdev = hci_dev_get(index);
+	if (!hdev)
+		return cmd_status(sk, index, MGMT_OP_CANCEL_RESOLVE_NAME,
+								ENODEV);
+
+	hci_dev_lock_bh(hdev);
+
+	memset(&hci_cp, 0, sizeof(hci_cp));
+	bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
+	err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(hci_cp),
+								&hci_cp);
+
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+
+	return err;
+}
+
 static int set_connection_params(struct sock *sk, u16 index,
 				unsigned char *data, u16 len)
 {
@@ -2189,10 +2221,11 @@
 	struct mgmt_mode cp = {0};
 	int err = -1;
 
-	BT_DBG("");
-
 	hdev = hci_dev_get(index);
 
+	if (hdev)
+		BT_DBG("disco_state: %d", hdev->disco_state);
+
 	if (!hdev || !lmp_le_capable(hdev)) {
 
 		mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
@@ -2200,6 +2233,8 @@
 
 		mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
 
+		hdev->disco_state = SCAN_IDLE;
+
 		if (hdev)
 			goto done;
 		else
@@ -2315,6 +2350,7 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
 
+	BT_DBG("disco_state: %d", hdev->disco_state);
 	hci_dev_lock_bh(hdev);
 
 	if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
@@ -2395,6 +2431,8 @@
 	if (!hdev)
 		return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
 
+	BT_DBG("disco_state: %d", hdev->disco_state);
+
 	hci_dev_lock_bh(hdev);
 
 	state = hdev->disco_state;
@@ -2659,6 +2697,9 @@
 	case MGMT_OP_RESOLVE_NAME:
 		err = resolve_name(sk, index, buf + sizeof(*hdr), len);
 		break;
+	case MGMT_OP_CANCEL_RESOLVE_NAME:
+		err = cancel_resolve_name(sk, index, buf + sizeof(*hdr), len);
+		break;
 	case MGMT_OP_SET_CONNECTION_PARAMS:
 		err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
 		break;
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 04afd89..b7a3656 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -256,6 +256,7 @@
 static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
 {
 	unsigned long flags;
+	bool prev, curr;
 	int err;
 
 	if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
@@ -270,6 +271,8 @@
 		rfkill->ops->query(rfkill, rfkill->data);
 
 	spin_lock_irqsave(&rfkill->lock, flags);
+	prev = rfkill->state & RFKILL_BLOCK_SW;
+
 	if (rfkill->state & RFKILL_BLOCK_SW)
 		rfkill->state |= RFKILL_BLOCK_SW_PREV;
 	else
@@ -299,10 +302,15 @@
 	}
 	rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL;
 	rfkill->state &= ~RFKILL_BLOCK_SW_PREV;
+	curr = rfkill->state & RFKILL_BLOCK_SW;
+
 	spin_unlock_irqrestore(&rfkill->lock, flags);
 
 	rfkill_led_trigger_event(rfkill);
-	rfkill_event(rfkill);
+
+	if (prev != curr)
+		rfkill_event(rfkill);
+
 }
 
 #ifdef CONFIG_RFKILL_INPUT
diff --git a/scripts/build-all.py b/scripts/build-all.py
index 296d9ad..7f37841 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -35,6 +35,7 @@
 import subprocess
 import os
 import os.path
+import re
 import shutil
 import sys
 
@@ -83,12 +84,15 @@
 def scan_configs():
     """Get the full list of defconfigs appropriate for this tree."""
     names = {}
-    for n in glob.glob('arch/arm/configs/[fm]sm[0-9-]*_defconfig'):
-        names[os.path.basename(n)[:-10]] = n
-    for n in glob.glob('arch/arm/configs/qsd*_defconfig'):
-        names[os.path.basename(n)[:-10]] = n
-    for n in glob.glob('arch/arm/configs/apq*_defconfig'):
-        names[os.path.basename(n)[:-10]] = n
+    arch_pats = (
+        r'[fm]sm[0-9]*_defconfig',
+        r'apq*_defconfig',
+        r'qsd*_defconfig',
+        r'omap2*_defconfig',
+        )
+    for p in arch_pats:
+        for n in glob.glob('arch/arm/configs/' + p):
+            names[os.path.basename(n)[:-10]] = n
     return names
 
 class Builder:
@@ -142,23 +146,41 @@
     savedefconfig = '%s/defconfig' % dest_dir
     shutil.copyfile(defconfig, dotconfig)
 
+    staging_dir = 'install_staging'
+    modi_dir = '%s' % staging_dir
+    hdri_dir = '%s/usr' % staging_dir
+    shutil.rmtree(os.path.join(dest_dir, staging_dir), ignore_errors=True)
+
     devnull = open('/dev/null', 'r')
     subprocess.check_call(['make', 'O=%s' % dest_dir,
         '%s_defconfig' % target], env=make_env, stdin=devnull)
     devnull.close()
 
     if not all_options.updateconfigs:
-        build = Builder(log_name)
-
-        result = build.run(['make', 'O=%s' % dest_dir] + make_command)
-
-        if result != 0:
-            if all_options.keep_going:
-                failed_targets.append(target)
-                fail_or_error = error
+        # Build targets can be dependent upon the completion of previous
+        # build targets, so build them one at a time.
+        cmd_line = ['make',
+            'INSTALL_HDR_PATH=%s' % hdri_dir,
+            'INSTALL_MOD_PATH=%s' % modi_dir,
+            'O=%s' % dest_dir]
+        build_targets = []
+        for c in make_command:
+            if re.match(r'^-{1,2}\w', c):
+                cmd_line.append(c)
             else:
-                fail_or_error = fail
-            fail_or_error("Failed to build %s, see %s" % (target, build.logname))
+                build_targets.append(c)
+        for t in build_targets:
+            build = Builder(log_name)
+
+            result = build.run(cmd_line + [t])
+            if result != 0:
+                if all_options.keep_going:
+                    failed_targets.append(target)
+                    fail_or_error = error
+                else:
+                    fail_or_error = fail
+                fail_or_error("Failed to build %s, see %s" %
+                              (target, build.logname))
 
     # Copy the defconfig back.
     if all_options.configs or all_options.updateconfigs:
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index fd9d825..3fc3f32 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1212,6 +1212,42 @@
 	return 0;
 }
 
+static void sitar_enable_classg(struct snd_soc_codec *codec,
+	bool enable)
+{
+
+	if (enable) {
+		snd_soc_update_bits(codec,
+			SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x00);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x00);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
+
+	} else {
+		snd_soc_update_bits(codec,
+			SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10, 0x10);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x07, 0x03);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
+		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
+	}
+}
+
+static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
+{
+	u8 hph_reg_val = 0;
+	hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
+
+	return (hph_reg_val & 0x30) ? true : false;
+}
+
+static bool sitar_is_line_pa_on(struct snd_soc_codec *codec)
+{
+	u8 line_reg_val = 0;
+	line_reg_val = snd_soc_read(codec, SITAR_A_RX_LINE_CNP_EN);
+
+	return (line_reg_val & 0x03) ? true : false;
+}
+
 static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
@@ -1235,6 +1271,15 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		if (sitar_is_hph_pa_on(codec)) {
+			snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
+				0x20, 0x00);
+			sitar_enable_classg(codec, false);
+		} else {
+			snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
+				0x20, 0x20);
+			sitar_enable_classg(codec, true);
+		}
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
@@ -1243,6 +1288,11 @@
 		usleep_range(32000, 32000);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		if (sitar_is_hph_pa_on(codec))
+			sitar_enable_classg(codec, true);
+		else
+			sitar_enable_classg(codec, false);
+
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
 		break;
 	}
@@ -1585,14 +1635,6 @@
 	return rc;
 }
 
-static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
-{
-	u8 hph_reg_val = 0;
-	hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
-
-	return (hph_reg_val & 0x30) ? true : false;
-}
-
 static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
 {
 	u8 hph_reg_val = 0;
@@ -1947,6 +1989,11 @@
 			SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
 		}
 
+		if (sitar_is_line_pa_on(codec))
+			sitar_enable_classg(codec, false);
+		else
+			sitar_enable_classg(codec, true);
+
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
@@ -1979,6 +2026,11 @@
 				w->name);
 		usleep_range(10000, 10000);
 
+		if (sitar_is_line_pa_on(codec))
+			sitar_enable_classg(codec, true);
+		else
+			sitar_enable_classg(codec, false);
+
 		break;
 	}
 	return 0;
@@ -2033,24 +2085,21 @@
 	pr_debug("%s %d\n", __func__, event);
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
-			0x00);
 		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
 			0x01);
 		snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
 		usleep_range(200, 200);
-		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
-			0x10);
-		usleep_range(20, 20);
-		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
-		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
 		snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
+		/*
+		 * This delay is for the class G controller to settle down
+		 * after turn OFF. The delay is as per the hardware spec for
+		 * the codec
+		 */
+		usleep_range(20, 20);
 		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
 			0x00);
-		snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
 		break;
 	}
 	return 0;
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 76cd625..7190ae9 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -1024,6 +1024,9 @@
 	}
 	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
 	err = tabla_hs_detect(codec, &mbhc_cfg);
+	msm_gpiomux_install(
+			msm9615_audio_prim_i2s_codec_configs,
+			ARRAY_SIZE(msm9615_audio_prim_i2s_codec_configs));
 	return err;
 }
 
@@ -1617,6 +1620,7 @@
 	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
 
 	if (hs_detect_use_gpio) {
+		pr_debug("%s: GPIO Headset detection enabled\n", __func__);
 		mbhc_cfg.gpio = PM8018_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
 		mbhc_cfg.gpio_irq = JACK_DETECT_INT;
 	}
@@ -2428,6 +2432,8 @@
 	sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
 	secpcm_portslc_virt_addr = ioremap(SEC_PCM_PORT_SLC_ADDR, 4);
 
+	hs_detect_use_gpio = true;
+
 	return ret;
 }
 module_init(mdm9615_audio_init);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 58205e9..37a4234 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/qpnp/clkdiv.h>
+#include <linux/regulator/consumer.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -30,9 +31,6 @@
 
 #define DRV_NAME "msm8974-asoc-taiko"
 
-#define PM8921_GPIO_BASE		NR_GPIO_IRQS
-#define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
-
 #define MSM8974_SPK_ON 1
 #define MSM8974_SPK_OFF 0
 
@@ -42,10 +40,10 @@
 #define BTSCO_RATE_8KHZ 8000
 #define BTSCO_RATE_16KHZ 16000
 
-#define BOTTOM_SPK_AMP_POS	0x1
-#define BOTTOM_SPK_AMP_NEG	0x2
-#define TOP_SPK_AMP_POS		0x4
-#define TOP_SPK_AMP_NEG		0x8
+#define LO_1_SPK_AMP	0x1
+#define LO_3_SPK_AMP	0x2
+#define LO_2_SPK_AMP	0x4
+#define LO_4_SPK_AMP	0x8
 
 #define GPIO_AUX_PCM_DOUT 43
 #define GPIO_AUX_PCM_DIN 44
@@ -56,6 +54,9 @@
 #define WCD9XXX_MBHC_DEF_RLOADS 5
 #define TAIKO_EXT_CLK_RATE 9600000
 
+/* It takes about 13ms for Class-D PAs to ramp-up */
+#define EXT_CLASS_D_EN_DELAY 13000
+
 void *def_taiko_mbhc_cal(void);
 static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
 					bool dapm);
@@ -89,11 +90,11 @@
 	SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
 };
 
-static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
-static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
-static int msm_spk_control;
-static int msm_ext_bottom_spk_pamp;
-static int msm_ext_top_spk_pamp;
+static struct platform_device *spdev;
+static struct regulator *ext_spk_amp_regulator;
+static int ext_spk_amp_gpio = -1;
+static int msm8974_spk_control = 1;
+static int msm8974_ext_spk_pamp;
 static int msm_slim_0_rx_ch = 1;
 static int msm_slim_0_tx_ch = 1;
 
@@ -105,103 +106,70 @@
 static int clk_users;
 static atomic_t auxpcm_rsc_ref;
 
-static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
+static int msm8974_liquid_ext_spk_power_amp_init(void)
 {
 	int ret = 0;
 
-	struct pm_gpio param = {
-		.direction      = PM_GPIO_DIR_OUT,
-		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
-		.output_value   = 1,
-		.pull      = PM_GPIO_PULL_NO,
-		.vin_sel	= PM_GPIO_VIN_S4,
-		.out_strength   = PM_GPIO_STRENGTH_MED,
-		.
-			function       = PM_GPIO_FUNC_NORMAL,
-	};
-
-	if (spk_amp_gpio == bottom_spk_pamp_gpio) {
-
-		ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+	ext_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+		"qcom,ext-spk-amp-gpio", 0);
+	if (ext_spk_amp_gpio >= 0) {
+		ret = gpio_request(ext_spk_amp_gpio, "ext_spk_amp_gpio");
 		if (ret) {
-			pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
-				__func__, bottom_spk_pamp_gpio);
-			return;
+			pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n",
+				__func__);
+			return -EINVAL;
 		}
-		ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
-		if (ret)
-			pr_err("%s: Failed to configure Bottom Spk Ampl gpio %u\n",
-				__func__, bottom_spk_pamp_gpio);
-		else {
-			pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
-			gpio_direction_output(bottom_spk_pamp_gpio, 1);
-		}
+		gpio_direction_output(ext_spk_amp_gpio, 0);
 
-	} else if (spk_amp_gpio == top_spk_pamp_gpio) {
+		if (ext_spk_amp_regulator == NULL) {
+			ext_spk_amp_regulator = regulator_get(&spdev->dev,
+									"qcom,ext-spk-amp");
 
-		ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
-		if (ret) {
-			pr_err("%s: Error requesting GPIO %d\n", __func__,
-				top_spk_pamp_gpio);
-			return;
+			if (IS_ERR(ext_spk_amp_regulator)) {
+				pr_err("%s: Cannot get regulator %s.\n",
+					__func__, "qcom,ext-spk-amp");
+
+				gpio_free(ext_spk_amp_gpio);
+				return PTR_ERR(ext_spk_amp_regulator);
+			}
 		}
-		ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
-		if (ret)
-			pr_err("%s: Failed to configure Top Spk Ampl gpio %u\n",
-				__func__, top_spk_pamp_gpio);
-		else {
-			pr_debug("%s: enable Top spkr amp gpio\n", __func__);
-			gpio_direction_output(top_spk_pamp_gpio, 1);
-		}
-	} else {
-		pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO. gpio = %u\n",
-			__func__, spk_amp_gpio);
-		return;
 	}
+
+	return 0;
 }
 
-static void msm_ext_spk_power_amp_on(u32 spk)
+static void msm8974_liquid_ext_spk_power_amp_enable(u32 on)
 {
-	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+	if (on)
+		regulator_enable(ext_spk_amp_regulator);
+	else
+		regulator_disable(ext_spk_amp_regulator);
 
-		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
-			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+	gpio_direction_output(ext_spk_amp_gpio, on);
+	usleep_range(EXT_CLASS_D_EN_DELAY, EXT_CLASS_D_EN_DELAY);
+	pr_debug("%s: %s external speaker PAs.\n", __func__,
+			on ? "Enable" : "Disable");
+}
 
-			pr_debug("%s() External Bottom Speaker Ampl already turned on. spk = 0x%08x\n",
+static void msm8974_ext_spk_power_amp_on(u32 spk)
+{
+	if (spk & (LO_1_SPK_AMP |
+					  LO_3_SPK_AMP |
+					  LO_2_SPK_AMP |
+					  LO_4_SPK_AMP)) {
+
+		pr_debug("%s() External Left/Right Speakers already turned on. spk = 0x%08x\n",
 						__func__, spk);
-			return;
-		}
 
-		msm_ext_bottom_spk_pamp |= spk;
+		msm8974_ext_spk_pamp |= spk;
 
-		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
-			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+		if ((msm8974_ext_spk_pamp & LO_1_SPK_AMP) &&
+			(msm8974_ext_spk_pamp & LO_3_SPK_AMP) &&
+			(msm8974_ext_spk_pamp & LO_2_SPK_AMP) &&
+			(msm8974_ext_spk_pamp & LO_4_SPK_AMP)) {
 
-			msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
-			pr_debug("%s: slepping 4 ms after turning on external Bottom Speaker Ampl\n",
-							__func__);
-			usleep_range(4000, 4000);
-		}
-
-	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
-
-		if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
-			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
-
-			pr_debug("%s() External Top Speaker Ampl already turned on. spk = 0x%08x\n",
-						__func__, spk);
-			return;
-		}
-
-		msm_ext_top_spk_pamp |= spk;
-
-		if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
-			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
-
-			msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
-			pr_debug("%s: sleeping 4 ms after turning on external Top Speaker Ampl\n",
-						__func__);
-			usleep_range(4000, 4000);
+			if (ext_spk_amp_gpio >= 0)
+				msm8974_liquid_ext_spk_power_amp_enable(1);
 		}
 	} else  {
 
@@ -211,35 +179,22 @@
 	}
 }
 
-static void msm_ext_spk_power_amp_off(u32 spk)
+static void msm8974_ext_spk_power_amp_off(u32 spk)
 {
-	if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+	if (spk & (LO_1_SPK_AMP |
+					  LO_3_SPK_AMP |
+					  LO_2_SPK_AMP |
+					  LO_4_SPK_AMP)) {
 
-		if (!msm_ext_bottom_spk_pamp)
-			return;
+		pr_debug("%s Left and right speakers case spk = 0x%08x",
+				  __func__, spk);
 
-		gpio_direction_output(bottom_spk_pamp_gpio, 0);
-		gpio_free(bottom_spk_pamp_gpio);
-		msm_ext_bottom_spk_pamp = 0;
+		if (!msm8974_ext_spk_pamp) {
+			if (ext_spk_amp_gpio >= 0)
+				msm8974_liquid_ext_spk_power_amp_enable(0);
+			msm8974_ext_spk_pamp = 0;
+		}
 
-		pr_debug("%s: sleeping 4 ms after turning off external Bottom Speaker Ampl\n",
-					__func__);
-
-		usleep_range(4000, 4000);
-
-	} else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
-
-		if (!msm_ext_top_spk_pamp)
-			return;
-
-		gpio_direction_output(top_spk_pamp_gpio, 0);
-		gpio_free(top_spk_pamp_gpio);
-		msm_ext_top_spk_pamp = 0;
-
-		pr_debug("%s: sleeping 4 ms after turning off external Top Spkaker Ampl\n",
-					__func__);
-
-		usleep_range(4000, 4000);
 	} else  {
 
 		pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
@@ -248,87 +203,89 @@
 	}
 }
 
-static void msm_ext_control(struct snd_soc_codec *codec)
+static void msm8974_ext_control(struct snd_soc_codec *codec)
 {
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 
 	mutex_lock(&dapm->codec->mutex);
 
-	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
-	if (msm_spk_control == MSM8974_SPK_ON) {
-		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
-		snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
-		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
-		snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+	pr_debug("%s: msm8974_spk_control = %d", __func__, msm8974_spk_control);
+	if (msm8974_spk_control == MSM8974_SPK_ON) {
+		snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+		snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+		snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+		snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
 	} else {
-		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
-		snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
-		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
-		snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+		snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
+		snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp");
+		snd_soc_dapm_disable_pin(dapm, "Lineout_2 amp");
+		snd_soc_dapm_disable_pin(dapm, "Lineout_4 amp");
 	}
 
 	snd_soc_dapm_sync(dapm);
 	mutex_unlock(&dapm->codec->mutex);
 }
 
-static int msm_get_spk(struct snd_kcontrol *kcontrol,
+static int msm8974_get_spk(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_value *ucontrol)
 {
-	pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
-	ucontrol->value.integer.value[0] = msm_spk_control;
+	pr_debug("%s: msm8974_spk_control = %d", __func__, msm8974_spk_control);
+	ucontrol->value.integer.value[0] = msm8974_spk_control;
 	return 0;
 }
 
-static int msm_set_spk(struct snd_kcontrol *kcontrol,
+static int msm8974_set_spk(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 
 	pr_debug("%s()\n", __func__);
-	if (msm_spk_control == ucontrol->value.integer.value[0])
+	if (msm8974_spk_control == ucontrol->value.integer.value[0])
 		return 0;
 
-	msm_spk_control = ucontrol->value.integer.value[0];
-	msm_ext_control(codec);
+	msm8974_spk_control = ucontrol->value.integer.value[0];
+	msm8974_ext_control(codec);
 	return 1;
 }
 
-static int msm_spkramp_event(struct snd_soc_dapm_widget *w,
+
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
 			     struct snd_kcontrol *k, int event)
 {
-	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+	pr_debug("%s()\n", __func__);
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
-		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
-			msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
-		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
-			msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
-		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
-			msm_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
-		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
-			msm_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+		if (!strncmp(w->name, "Lineout_1 amp", 14))
+			msm8974_ext_spk_power_amp_on(LO_1_SPK_AMP);
+		else if (!strncmp(w->name, "Lineout_3 amp", 14))
+			msm8974_ext_spk_power_amp_on(LO_3_SPK_AMP);
+		else if (!strncmp(w->name, "Lineout_2 amp", 14))
+			msm8974_ext_spk_power_amp_on(LO_2_SPK_AMP);
+		else if  (!strncmp(w->name, "Lineout_4 amp", 14))
+			msm8974_ext_spk_power_amp_on(LO_4_SPK_AMP);
 		else {
 			pr_err("%s() Invalid Speaker Widget = %s\n",
 					__func__, w->name);
 			return -EINVAL;
 		}
-
 	} else {
-		if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
-			msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
-		else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
-			msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
-		else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
-			msm_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
-		else if  (!strncmp(w->name, "Ext Spk Top Neg", 15))
-			msm_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+		if (!strncmp(w->name, "Lineout_1 amp", 14))
+			msm8974_ext_spk_power_amp_off(LO_1_SPK_AMP);
+		else if (!strncmp(w->name, "Lineout_3 amp", 14))
+			msm8974_ext_spk_power_amp_off(LO_3_SPK_AMP);
+		else if (!strncmp(w->name, "Lineout_2 amp", 14))
+			msm8974_ext_spk_power_amp_off(LO_2_SPK_AMP);
+		else if  (!strncmp(w->name, "Lineout_4 amp", 14))
+			msm8974_ext_spk_power_amp_off(LO_4_SPK_AMP);
 		else {
 			pr_err("%s() Invalid Speaker Widget = %s\n",
 					__func__, w->name);
 			return -EINVAL;
 		}
 	}
+
 	return 0;
+
 }
 
 static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
@@ -397,11 +354,11 @@
 	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
 	msm8974_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm_spkramp_event),
-	SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Lineout_1 amp", msm_ext_spkramp_event),
+	SND_SOC_DAPM_SPK("Lineout_3 amp", msm_ext_spkramp_event),
 
-	SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm_spkramp_event),
-	SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm_spkramp_event),
+	SND_SOC_DAPM_SPK("Lineout_2 amp", msm_ext_spkramp_event),
+	SND_SOC_DAPM_SPK("Lineout_4 amp", msm_ext_spkramp_event),
 
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -693,8 +650,8 @@
 };
 
 static const struct snd_kcontrol_new msm_snd_controls[] = {
-	SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm_get_spk,
-		     msm_set_spk),
+	SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm8974_get_spk,
+		     msm8974_set_spk),
 	SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
 		     msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
 	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
@@ -723,11 +680,6 @@
 
 	pr_info("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
 
-	if (machine_is_msm8960_liquid()) {
-		top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
-		bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
-	}
-
 	rtd->pmdown_time = 0;
 
 	err = snd_soc_add_codec_controls(codec, msm_snd_controls,
@@ -735,13 +687,21 @@
 	if (err < 0)
 		return err;
 
+	err = msm8974_liquid_ext_spk_power_amp_init();
+	if (err) {
+		pr_err("%s: LiQUID 8974 CLASS_D PAs init failed (%d)\n",
+			__func__, err);
+		return err;
+	}
+
 	snd_soc_dapm_new_controls(dapm, msm8974_dapm_widgets,
 				ARRAY_SIZE(msm8974_dapm_widgets));
 
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
-	snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+	snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+	snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+	snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+	snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
 
 	snd_soc_dapm_sync(dapm);
 
@@ -1458,9 +1418,13 @@
 			ret);
 		goto err;
 	}
+
 	mutex_init(&cdc_mclk_mutex);
 	atomic_set(&auxpcm_rsc_ref, 0);
 
+	spdev = pdev;
+	ext_spk_amp_regulator = NULL;
+
 	return 0;
 err:
 	devm_kfree(&pdev->dev, pdata);
@@ -1472,7 +1436,13 @@
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
 	struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
 
+	if (ext_spk_amp_regulator)
+		regulator_put(ext_spk_amp_regulator);
+
 	gpio_free(pdata->mclk_gpio);
+	if (ext_spk_amp_gpio >= 0)
+		gpio_free(ext_spk_amp_gpio);
+
 	snd_soc_unregister_card(card);
 
 	return 0;
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 00394aa..119e017 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -853,24 +853,15 @@
 		} else if (channel_mode == 4) {
 			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
 			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
-			open.dev_channel_mapping[2] = PCM_CHANNEL_RB;
-			open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
+			open.dev_channel_mapping[2] = PCM_CHANNEL_LS;
+			open.dev_channel_mapping[3] = PCM_CHANNEL_RS;
 		} else if (channel_mode == 6) {
-			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
-			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
-			open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
-			open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
-			open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
-			open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
-		} else if (channel_mode == 8) {
-			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
-			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
-			open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
-			open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
-			open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
-			open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
-			open.dev_channel_mapping[6] = PCM_CHANNEL_FLC;
-			open.dev_channel_mapping[7] = PCM_CHANNEL_FRC;
+			open.dev_channel_mapping[0] = PCM_CHANNEL_FC;
+			open.dev_channel_mapping[1] = PCM_CHANNEL_FL;
+			open.dev_channel_mapping[2] = PCM_CHANNEL_FR;
+			open.dev_channel_mapping[3] = PCM_CHANNEL_LS;
+			open.dev_channel_mapping[4] = PCM_CHANNEL_RS;
+			open.dev_channel_mapping[5] = PCM_CHANNEL_LFE;
 		} else {
 			pr_err("%s invalid num_chan %d\n", __func__,
 					channel_mode);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index cde5b02..52e481a 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1152,7 +1152,9 @@
 	enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_dts_enc_cfg);
 	enc_cfg.enc_blk.cfg.dts.sample_rate = sample_rate;
 	enc_cfg.enc_blk.cfg.dts.num_channels = channels;
-	if (channels == 2) {
+	if (channels == 1) {
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FC;
+	} else if (channels == 2) {
 		enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FL;
 		enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FR;
 		enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = 0;
@@ -1167,12 +1169,12 @@
 		enc_cfg.enc_blk.cfg.dts.channel_mapping[4] = 0;
 		enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = 0;
 	} else if (channels == 6) {
-		enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FL;
-		enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FR;
-		enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = PCM_CHANNEL_LFE;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FC;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FL;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = PCM_CHANNEL_FR;
 		enc_cfg.enc_blk.cfg.dts.channel_mapping[3] = PCM_CHANNEL_LS;
 		enc_cfg.enc_blk.cfg.dts.channel_mapping[4] = PCM_CHANNEL_RS;
-		enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = PCM_CHANNEL_FC;
+		enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = PCM_CHANNEL_LFE;
 	}
 	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
 	if (rc < 0) {
@@ -1765,6 +1767,9 @@
 	case FORMAT_AMRWB:
 		open.write_format = AMRWB_FS;
 		break;
+	case FORMAT_AMR_WB_PLUS:
+		open.write_format = AMR_WB_PLUS;
+		break;
 	case FORMAT_V13K:
 		open.write_format = V13K_FS;
 		break;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 621d24b..a307bcc 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1310,6 +1310,16 @@
 		switch (mi2s_id) {
 		case MSM_PRIM_MI2S:
 			*port_id = MI2S_RX;
+			break;
+		case MSM_SEC_MI2S:
+			*port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
+			break;
+		case MSM_TERT_MI2S:
+			*port_id = AFE_PORT_ID_TERTIARY_MI2S_RX;
+			break;
+		case MSM_QUAT_MI2S:
+			*port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
+			break;
 		break;
 		default:
 			ret = -1;
@@ -1320,7 +1330,16 @@
 		switch (mi2s_id) {
 		case MSM_PRIM_MI2S:
 			*port_id = MI2S_TX;
-		break;
+			break;
+		case MSM_SEC_MI2S:
+			*port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+			break;
+		case MSM_TERT_MI2S:
+			*port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+			break;
+		case MSM_QUAT_MI2S:
+			*port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+			break;
 		default:
 			ret = -1;
 		break;
@@ -1330,7 +1349,7 @@
 		ret = -1;
 	break;
 	}
-	pr_debug("%s: port_id = %x\n", __func__, *port_id);
+	pr_debug("%s: port_id = %#x\n", __func__, *port_id);
 	return ret;
 }
 
@@ -1346,15 +1365,17 @@
 	u16 port_id = 0;
 	int rc = 0;
 
-	dev_dbg(dai->dev, "%s: device name %s dai id %x,port id = %x\n",
-		__func__, dai->name, dai->id, port_id);
-
 	if (msm_mi2s_get_port_id(dai->id, substream->stream,
 				 &port_id) != 0) {
-		dev_err(dai->dev, "%s: Invalid Port ID\n", __func__);
+		dev_err(dai->dev, "%s: Invalid Port ID %#x\n",
+				__func__, port_id);
 		return -EINVAL;
 	}
 
+	dev_dbg(dai->dev, "%s: dai id %d, afe port id = %x\n"
+		"dai_data->channels = %u sample_rate = %u\n", __func__,
+		dai->id, port_id, dai_data->channels, dai_data->rate);
+
 	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
 		/* PORT START should be set if prepare called
 		 * in active state.
@@ -1382,6 +1403,8 @@
 		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
 		&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
 	struct msm_dai_q6_dai_data *dai_data = &mi2s_dai_config->mi2s_dai_data;
+	struct afe_param_id_i2s_cfg *i2s = &dai_data->port_config.i2s;
+
 
 	dai_data->channels = params_channels(params);
 	switch (dai_data->channels) {
@@ -1451,13 +1474,19 @@
 		mi2s_dai_data->bitwidth_constraint.list = &dai_data->bitwidth;
 	}
 
-	pr_debug("%s: dai_data->channels = %d, line = %d\n"
-		 ",mono_stereo =%x sample rate = %x\n", __func__,
-		 dai_data->channels, dai_data->port_config.i2s.channel_mode,
-		 dai_data->port_config.i2s.mono_stereo, dai_data->rate);
+	dev_dbg(dai->dev, "%s: dai id %d dai_data->channels = %d\n"
+		"sample_rate = %u i2s_cfg_minor_version = %#x\n"
+		"bit_width = %hu  channel_mode = %#x mono_stereo = %#x\n"
+		"ws_src = %#x sample_rate = %u data_format = %#x\n"
+		"reserved = %u\n", __func__, dai->id, dai_data->channels,
+		dai_data->rate, i2s->i2s_cfg_minor_version, i2s->bit_width,
+		i2s->channel_mode, i2s->mono_stereo, i2s->ws_src,
+		i2s->sample_rate, i2s->data_format, i2s->reserved);
+
 	return 0;
+
 error_invalid_data:
-	pr_debug("%s: dai_data->channels = %d, line = %d\n", __func__,
+	pr_debug("%s: dai_data->channels = %d channel_mode = %d\n", __func__,
 		 dai_data->channels, dai_data->port_config.i2s.channel_mode);
 	return -EINVAL;
 }
@@ -1507,11 +1536,12 @@
 
 	if (msm_mi2s_get_port_id(dai->id, substream->stream,
 				 &port_id) != 0) {
-		dev_err(dai->dev, "%s: Invalid Port ID\n", __func__);
+		dev_err(dai->dev, "%s: Invalid Port ID %#x\n",
+				__func__, port_id);
 	}
 
-	dev_dbg(dai->dev, "%s: device name %s port id = %x\n",
-		__func__, dai->name, port_id);
+	dev_dbg(dai->dev, "%s: closing afe port id = %x\n",
+			__func__, port_id);
 
 	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
 		rc = afe_close(port_id);
@@ -1714,20 +1744,21 @@
 	if (rc) {
 		dev_err(&pdev->dev,
 			"%s: missing %x in dt node\n", __func__, mi2s_intf);
-	return rc;
+		return rc;
 	}
 
-	if (mi2s_intf > MSM_QUAD_MI2S) {
-		dev_err(&pdev->dev, "%s: Invalid MI2S ID from Device Tree\n",
-			 __func__);
-		return -EINVAL;
+	dev_dbg(&pdev->dev, "dev name %s dev id %x\n", dev_name(&pdev->dev),
+			     mi2s_intf);
+
+	if (mi2s_intf < MSM_PRIM_MI2S || mi2s_intf > MSM_QUAT_MI2S) {
+		dev_err(&pdev->dev,
+			"%s: Invalid MI2S ID %u from Device Tree\n",
+			__func__, mi2s_intf);
+		return -ENXIO;
 	}
 
-	if (mi2s_intf == MSM_PRIM_MI2S) {
-		dev_set_name(&pdev->dev, "%s.%d", "msm-dai-q6-mi2s",
-			     MSM_PRIM_MI2S);
-		pdev->id = MSM_PRIM_MI2S;
-	}
+	dev_set_name(&pdev->dev, "%s.%d", "msm-dai-q6-mi2s", mi2s_intf);
+	pdev->id = mi2s_intf;
 
 	mi2s_pdata = kzalloc(sizeof(struct msm_mi2s_pdata), GFP_KERNEL);
 	if (!mi2s_pdata) {
@@ -1736,9 +1767,6 @@
 		goto rtn;
 	}
 
-	dev_dbg(&pdev->dev, "dev name %s dev id %x\n", dev_name(&pdev->dev),
-		pdev->id);
-
 	rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-mi2s-rx-lines",
 				  &rx_line);
 	if (rc) {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 2e0c229..17c18dd 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -142,6 +142,8 @@
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
 	{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
+	{ AFE_PORT_ID_QUATERNARY_MI2S_RX, 0, 0, 0, 0, 0},
+	{ AFE_PORT_ID_QUATERNARY_MI2S_TX, 0, 0, 0, 0, 0},
 };
 
 
@@ -943,6 +945,21 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX ,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_HDMI_RX,
 	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -1043,6 +1060,9 @@
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
 	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
@@ -1623,8 +1643,13 @@
 	SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0),
 	SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback",
+						0, 0, 0, 0),
+
 	SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("MI2S_TX", "MI2S Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture",
+						0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback",
 				0, 0, 0 , 0),
@@ -1684,6 +1709,9 @@
 	hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	mi2s_rx_mixer_controls, ARRAY_SIZE(mi2s_rx_mixer_controls)),
+	SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+				quaternary_mi2s_rx_mixer_controls,
+				ARRAY_SIZE(quaternary_mi2s_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
@@ -1827,9 +1855,16 @@
 	{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
 	{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
 
+	{"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"QUAT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+	{"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+	{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
+
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
 	{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
+	{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
 	{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
 	{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
@@ -2006,8 +2041,11 @@
 	{"BE_OUT", NULL, "SLIMBUS_4_RX"},
 	{"BE_OUT", NULL, "HDMI"},
 	{"BE_OUT", NULL, "MI2S_RX"},
+	{"BE_OUT", NULL, "QUAT_MI2S_RX"},
+
 	{"PRI_I2S_TX", NULL, "BE_IN"},
 	{"MI2S_TX", NULL, "BE_IN"},
+	{"QUAT_MI2S_TX", NULL, "BE_IN"},
 	{"SLIMBUS_0_TX", NULL, "BE_IN" },
 	{"SLIMBUS_1_TX", NULL, "BE_IN" },
 	{"SLIMBUS_3_TX", NULL, "BE_IN" },
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 261c359..be646ed 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -33,6 +33,8 @@
 
 #define LPASS_BE_MI2S_RX "MI2S_RX"
 #define LPASS_BE_MI2S_TX "MI2S_TX"
+#define LPASS_BE_QUAT_MI2S_RX "QUAT_MI2S_RX"
+#define LPASS_BE_QUAT_MI2S_TX "QUAT_MI2S_TX"
 #define LPASS_BE_STUB_RX "STUB_RX"
 #define LPASS_BE_STUB_TX "STUB_TX"
 #define LPASS_BE_SLIMBUS_1_RX "SLIMBUS_1_RX"
@@ -95,6 +97,8 @@
 	MSM_BACKEND_DAI_EXTPROC_RX,
 	MSM_BACKEND_DAI_EXTPROC_TX,
 	MSM_BACKEND_DAI_EXTPROC_EC_TX,
+	MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+	MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
 	MSM_BACKEND_DAI_MAX,
 };
 
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index cc69123..7267a82 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -34,11 +34,11 @@
 
 struct adm_ctl {
 	void *apr;
-	atomic_t copp_id[Q6_AFE_MAX_PORTS];
-	atomic_t copp_cnt[Q6_AFE_MAX_PORTS];
-	atomic_t copp_stat[Q6_AFE_MAX_PORTS];
-	u32      mem_map_handle[Q6_AFE_MAX_PORTS];
-	wait_queue_head_t wait[Q6_AFE_MAX_PORTS];
+	atomic_t copp_id[AFE_MAX_PORTS];
+	atomic_t copp_cnt[AFE_MAX_PORTS];
+	atomic_t copp_stat[AFE_MAX_PORTS];
+	u32      mem_map_handle[AFE_MAX_PORTS];
+	wait_queue_head_t wait[AFE_MAX_PORTS];
 };
 
 static struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
@@ -81,7 +81,7 @@
 				this_adm.apr);
 		if (this_adm.apr) {
 			apr_reset(this_adm.apr);
-			for (i = 0; i < Q6_AFE_MAX_PORTS; i++) {
+			for (i = 0; i < AFE_MAX_PORTS; i++) {
 				atomic_set(&this_adm.copp_id[i],
 							RESET_COPP_ID);
 				atomic_set(&this_adm.copp_cnt[i], 0);
@@ -107,7 +107,7 @@
 	adm_callback_debug_print(data);
 	if (data->payload_size) {
 		index = q6audio_get_port_index(data->token);
-		if (index < 0 || index >= Q6_AFE_MAX_PORTS) {
+		if (index < 0 || index >= AFE_MAX_PORTS) {
 			pr_err("%s: invalid port idx %d token %d\n",
 					__func__, index, data->token);
 			return 0;
@@ -219,15 +219,15 @@
 	struct adm_cmd_set_pp_params_v5	adm_params;
 	int index = afe_get_port_index(port_id);
 	if (index < 0 || index >= AFE_MAX_PORTS) {
-		pr_err("%s: invalid port idx %d portid %d\n",
+		pr_err("%s: invalid port idx %d portid %#x\n",
 				__func__, index, port_id);
 		return 0;
 	}
 
-	pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
+	pr_debug("%s: Port id %#x, index %d\n", __func__, port_id, index);
 
 	if (!aud_cal || aud_cal->cal_size == 0) {
-		pr_debug("%s: No ADM cal to send for port_id = %d!\n",
+		pr_debug("%s: No ADM cal to send for port_id = %#x!\n",
 			__func__, port_id);
 		result = -EINVAL;
 		goto done;
@@ -257,7 +257,7 @@
 		adm_params.payload_size);
 	result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_params);
 	if (result < 0) {
-		pr_err("%s: Set params failed port = %d payload = 0x%x\n",
+		pr_err("%s: Set params failed port = %#x payload = 0x%x\n",
 			__func__, port_id, aud_cal->cal_paddr);
 		result = -EINVAL;
 		goto done;
@@ -267,7 +267,7 @@
 		atomic_read(&this_adm.copp_stat[index]),
 		msecs_to_jiffies(TIMEOUT_MS));
 	if (!result) {
-		pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
+		pr_err("%s: Set params timed out port = %#x, payload = 0x%x\n",
 			__func__, port_id, aud_cal->cal_paddr);
 		result = -EINVAL;
 		goto done;
@@ -317,10 +317,10 @@
 	}
 
 	if (!send_adm_cal_block(port_id, &aud_cal))
-		pr_debug("%s: Audproc cal sent for port id: %d, path %d\n",
+		pr_debug("%s: Audproc cal sent for port id: %#x, path %d\n",
 			__func__, port_id, acdb_path);
 	else
-		pr_debug("%s: Audproc cal not sent for port id: %d, path %d\n",
+		pr_debug("%s: Audproc cal not sent for port id: %#x, path %d\n",
 			__func__, port_id, acdb_path);
 
 	pr_debug("%s: Sending audvol cal\n", __func__);
@@ -351,10 +351,10 @@
 	}
 
 	if (!send_adm_cal_block(port_id, &aud_cal))
-		pr_debug("%s: Audvol cal sent for port id: %d, path %d\n",
+		pr_debug("%s: Audvol cal sent for port id: %#x, path %d\n",
 			__func__, port_id, acdb_path);
 	else
-		pr_debug("%s: Audvol cal not sent for port id: %d, path %d\n",
+		pr_debug("%s: Audvol cal not sent for port id: %#x, path %d\n",
 			__func__, port_id, acdb_path);
 }
 
@@ -384,7 +384,7 @@
 		rtac_set_adm_handle(this_adm.apr);
 	}
 	index = afe_get_port_index(port_id);
-	pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+	pr_debug("%s: Port ID %#x, index %d\n", __func__, port_id, index);
 
 	cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -405,7 +405,7 @@
 	atomic_set(&this_adm.copp_stat[index], 0);
 	ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
 	if (ret < 0) {
-		pr_err("%s:ADM enable for port %d failed\n",
+		pr_err("%s:ADM enable for port %#x failed\n",
 					__func__, port_id);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -415,7 +415,7 @@
 		atomic_read(&this_adm.copp_stat[index]),
 		msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
-		pr_err("%s ADM connect AFE failed for port %d\n", __func__,
+		pr_err("%s ADM connect AFE failed for port %#x\n", __func__,
 							port_id);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -435,18 +435,18 @@
 	int index;
 	int tmp_port = q6audio_get_port_id(port_id);
 
-	pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
+	pr_debug("%s: port %#x path:%d rate:%d mode:%d\n", __func__,
 				port_id, path, rate, channel_mode);
 
 	port_id = q6audio_convert_virtual_to_portid(port_id);
 
 	if (q6audio_validate_port(port_id) < 0) {
-		pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+		pr_err("%s port idi[%#x] is invalid\n", __func__, port_id);
 		return -ENODEV;
 	}
 
 	index = q6audio_get_port_index(port_id);
-	pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+	pr_debug("%s: Port ID %#x, index %d\n", __func__, port_id, index);
 
 	if (this_adm.apr == NULL) {
 		this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
@@ -543,15 +543,15 @@
 			return -EINVAL;
 		}
 
-		pr_debug("%s: port_id=%d rate=%d"
-			"topology_id=0x%X\n", __func__,	open.endpoint_id_1, \
-				  open.sample_rate, open.topology_id);
+		pr_debug("%s: port_id=%#x rate=%d topology_id=0x%X\n",
+			__func__, open.endpoint_id_1, open.sample_rate,
+			open.topology_id);
 
 		atomic_set(&this_adm.copp_stat[index], 0);
 
 		ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
 		if (ret < 0) {
-			pr_err("%s:ADM enable for port %d for[%d] failed\n",
+			pr_err("%s:ADM enable for port %#x for[%d] failed\n",
 						__func__, tmp_port, port_id);
 			ret = -EINVAL;
 			goto fail_cmd;
@@ -561,7 +561,7 @@
 			atomic_read(&this_adm.copp_stat[index]),
 			msecs_to_jiffies(TIMEOUT_MS));
 		if (!ret) {
-			pr_err("%s ADM open failed for port %d"
+			pr_err("%s ADM open failed for port %#x"
 			"for [%d]\n", __func__, tmp_port, port_id);
 			ret = -EINVAL;
 			goto fail_cmd;
@@ -599,7 +599,7 @@
 
 	/* Assumes port_ids have already been validated during adm_open */
 	int index = q6audio_get_port_index(copp_id);
-	if (index < 0 || index >= Q6_AFE_MAX_PORTS) {
+	if (index < 0 || index >= AFE_MAX_PORTS) {
 		pr_err("%s: invalid port idx %d token %d\n",
 					__func__, index, copp_id);
 		return 0;
@@ -615,7 +615,7 @@
 	}
 	route = (struct adm_cmd_matrix_map_routings_v5 *)matrix_map;
 
-	pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0] :%d coppid[%d]\n",
+	pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0]:%#x coppid[%d]\n",
 		 __func__, session_id, path, num_copps, port_id[0], copp_id);
 
 	route->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -658,10 +658,10 @@
 		tmp = q6audio_get_port_index(port_id[i]);
 
 
-		if (tmp >= 0 && tmp < Q6_AFE_MAX_PORTS)
+		if (tmp >= 0 && tmp < AFE_MAX_PORTS)
 			copps_list[i] =
 					atomic_read(&this_adm.copp_id[tmp]);
-		pr_debug("%s: port_id[%d]: %d, index: %d act coppid[0x%x]\n",
+		pr_debug("%s: port_id[%#x]: %d, index: %d act coppid[0x%x]\n",
 			__func__, i, port_id[i], tmp,
 			atomic_read(&this_adm.copp_id[tmp]));
 	}
@@ -669,7 +669,7 @@
 
 	ret = apr_send_pkt(this_adm.apr, (uint32_t *)matrix_map);
 	if (ret < 0) {
-		pr_err("%s: ADM routing for port %d failed\n",
+		pr_err("%s: ADM routing for port %#x failed\n",
 					__func__, port_id[0]);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -678,7 +678,7 @@
 				atomic_read(&this_adm.copp_stat[index]),
 				msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
-		pr_err("%s: ADM cmd Route failed for port %d\n",
+		pr_err("%s: ADM cmd Route failed for port %#x\n",
 					__func__, port_id[0]);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -724,7 +724,7 @@
 	port_id = q6audio_convert_virtual_to_portid(port_id);
 
 	if (q6audio_validate_port(port_id) < 0) {
-		pr_err("%s port id[%d] is invalid\n", __func__, port_id);
+		pr_err("%s port id[%#x] is invalid\n", __func__, port_id);
 		return -ENODEV;
 	}
 
@@ -864,10 +864,10 @@
 	if (q6audio_validate_port(port_id) < 0)
 		return -EINVAL;
 
-	pr_debug("%s port_id=%d index %d\n", __func__, port_id, index);
+	pr_debug("%s port_id=%#x index %d\n", __func__, port_id, index);
 
 	if (!(atomic_read(&this_adm.copp_cnt[index]))) {
-		pr_err("%s: copp count for port[%d]is 0\n", __func__, port_id);
+		pr_err("%s: copp count for port[%#x]is 0\n", __func__, port_id);
 
 		goto fail_cmd;
 	}
@@ -890,7 +890,7 @@
 		atomic_set(&this_adm.copp_stat[index], 0);
 
 
-		pr_debug("%s:coppid %d portid=%d index=%d coppcnt=%d\n",
+		pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
 				__func__,
 				atomic_read(&this_adm.copp_id[index]),
 				port_id, index,
@@ -907,7 +907,7 @@
 				atomic_read(&this_adm.copp_stat[index]),
 				msecs_to_jiffies(TIMEOUT_MS));
 		if (!ret) {
-			pr_err("%s: ADM cmd Route failed for port %d\n",
+			pr_err("%s: ADM cmd Route failed for port %#x\n",
 						__func__, port_id);
 			ret = -EINVAL;
 			goto fail_cmd;
@@ -925,7 +925,7 @@
 	int i = 0;
 	this_adm.apr = NULL;
 
-	for (i = 0; i < Q6_AFE_MAX_PORTS; i++) {
+	for (i = 0; i < AFE_MAX_PORTS; i++) {
 		atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
 		atomic_set(&this_adm.copp_cnt[i], 0);
 		atomic_set(&this_adm.copp_stat[i], 0);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 8d8ff5d..de9841a 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -165,6 +165,7 @@
 	case INT_FM_RX:
 	case VOICE_PLAYBACK_TX:
 	case RT_PROXY_PORT_001_RX:
+	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
 		ret = MSM_AFE_PORT_TYPE_RX;
 		break;
 
@@ -183,12 +184,13 @@
 	case VOICE_RECORD_RX:
 	case INT_BT_SCO_TX:
 	case RT_PROXY_PORT_001_TX:
+	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
 		ret = MSM_AFE_PORT_TYPE_TX;
 		break;
 
 	default:
 		WARN_ON(1);
-		pr_err("%s: invalid port id %d\n", __func__, port_id);
+		pr_err("%s: invalid port id %#x\n", __func__, port_id);
 		ret = -EINVAL;
 	}
 
@@ -283,10 +285,10 @@
 		(port_id == RT_PROXY_DAI_001_TX))
 		port_id = VIRTUAL_ID_TO_PORTID(port_id);
 
-	pr_debug("%s: port id: %d\n", __func__, port_id);
+	pr_debug("%s: port id: %#x\n", __func__, port_id);
 	index = q6audio_get_port_index(port_id);
 	if (q6audio_validate_port(port_id) < 0) {
-		pr_err("%s: port id: %d\n", __func__, port_id);
+		pr_err("%s: port id: %#x\n", __func__, port_id);
 		return -EINVAL;
 	}
 
@@ -295,7 +297,7 @@
 		return ret;
 
 	if (q6audio_validate_port(port_id) < 0) {
-		pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+		pr_err("%s: Failed : Invalid Port id = %#x\n", __func__,
 				port_id);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -321,6 +323,12 @@
 	case SECONDARY_I2S_TX:
 	case MI2S_RX:
 	case MI2S_TX:
+	case AFE_PORT_ID_SECONDARY_MI2S_RX:
+	case AFE_PORT_ID_SECONDARY_MI2S_TX:
+	case AFE_PORT_ID_TERTIARY_MI2S_RX:
+	case AFE_PORT_ID_TERTIARY_MI2S_TX:
+	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
 		cfg_type = AFE_PARAM_ID_I2S_CONFIG;
 		break;
 	case HDMI_RX:
@@ -370,7 +378,7 @@
 	atomic_set(&this_afe.status, 0);
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
 	if (ret < 0) {
-		pr_err("%s: AFE enable for port %d failed\n", __func__,
+		pr_err("%s: AFE enable for port %#x failed\n", __func__,
 				port_id);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -407,7 +415,7 @@
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
 
 	if (IS_ERR_VALUE(ret)) {
-		pr_err("%s: AFE enable for port %d failed\n", __func__,
+		pr_err("%s: AFE enable for port %#x failed\n", __func__,
 				port_id);
 		ret = -EINVAL;
 		goto fail_cmd;
@@ -468,7 +476,10 @@
 	case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
 	case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
 	case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
-
+	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+		return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
+	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+		return IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX;
 	default: return -EINVAL;
 	}
 }
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 8c524fa..033cb8e 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -48,7 +48,10 @@
 	case INT_FM_TX: return IDX_INT_FM_TX;
 	case RT_PROXY_PORT_001_RX: return IDX_RT_PROXY_PORT_001_RX;
 	case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
-
+	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+		return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
+	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+		return IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX;
 	default: return -EINVAL;
 	}
 }
@@ -82,6 +85,10 @@
 	case INT_FM_TX: return AFE_PORT_ID_INTERNAL_FM_TX;
 	case RT_PROXY_PORT_001_RX: return AFE_PORT_ID_RT_PROXY_PORT_001_RX;
 	case RT_PROXY_PORT_001_TX: return AFE_PORT_ID_RT_PROXY_PORT_001_TX;
+	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+			     return AFE_PORT_ID_QUATERNARY_MI2S_RX;
+	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+			     return AFE_PORT_ID_QUATERNARY_MI2S_TX;
 
 	default: return -EINVAL;
 	}
@@ -138,6 +145,8 @@
 	case INT_FM_TX:
 	case RT_PROXY_PORT_001_RX:
 	case RT_PROXY_PORT_001_TX:
+	case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+	case AFE_PORT_ID_QUATERNARY_MI2S_TX:
 	{
 		ret = 0;
 		break;