Merge "qup_i2c: Add runtime PM support to I2C QUP controller"
diff --git a/Documentation/ABI/testing/sysfs-kernel-iommu_groups b/Documentation/ABI/testing/sysfs-kernel-iommu_groups
new file mode 100644
index 0000000..9b31556
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-kernel-iommu_groups
@@ -0,0 +1,14 @@
+What:		/sys/kernel/iommu_groups/
+Date:		May 2012
+KernelVersion:	v3.5
+Contact:	Alex Williamson <alex.williamson@redhat.com>
+Description:	/sys/kernel/iommu_groups/ contains a number of sub-
+		directories, each representing an IOMMU group.  The
+		name of the sub-directory matches the iommu_group_id()
+		for the group, which is an integer value.  Within each
+		subdirectory is another directory named "devices" with
+		links to the sysfs devices contained in this group.
+		The group directory also optionally contains a "name"
+		file if the IOMMU driver has chosen to register a more
+		common name for the group.
+Users:
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/arm/msm/dcvs-core-info.txt b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
index b7dd427..f8152cfb 100644
--- a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
+++ b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
@@ -37,9 +37,9 @@
 - qcom,algo-ss-win-size-max-us:		sets maximum steady state window size.
 - qcom,algo-ss-util-pct:		sets target CPU utilization during
 					steady-state.
-- qcom,algo-ss-iobusy-conv:		specifies how wait time (i/o busy time)
-					is incorporated into the steady-state
-					algorithm.
+- qcom,algo-ss-no-corr-below-freq:	specifies frequency below which DCVS
+					will not attempt to correlate busy or
+					idle information from different CPUs
 
 - qcom,energy-active-coeff-a:	sets active power equation coefficient a.
 - qcom,energy-active-coeff-b:	sets active power equation coefficient b.
@@ -89,7 +89,7 @@
 			qcom,algo-ss-win-size-min-us = <1000000>;
 			qcom,algo-ss-win-size-max-us = <1000000>;
 			qcom,algo-ss-util-pct = <95>;
-			qcom,algo-ss-iobusy-conv = <100>;
+			qcom,algo-ss-no-corr-below-freq = <0>;
 
 			qcom,energy-active-coeff-a = <2492>;
 			qcom,energy-active-coeff-b = <0>;
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
index 7f2a21b..ccb3465 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
@@ -23,6 +23,7 @@
 - qcom,resource-type: The type of the LPM resource.
    MSM_LPM_RPM_RS_TYPE    = 0
    MSM_LPM_LOCAL_RS_TYPE  = 1
+- qcom,init-value: Initialization value of the LPM resource.
 
 
 Optional Nodes:
@@ -41,5 +42,6 @@
                         qcom,type = <0x62706d73>;   /* "smpb" */
                         qcom,id = <0x02>;
                         qcom,key = <0x6e726f63>;   /* "corn" */
+			qcom,init-value= <5>;   /* Active Corner*/
                 };
 
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 8bb8a76..3e309e4 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -4,7 +4,8 @@
 Each SATA controller should have its own node.
 
 Required properties:
-- compatible        : compatible list, contains "calxeda,hb-ahci" or "snps,spear-ahci"
+- compatible        : compatible list, contains "calxeda,hb-ahci" or
+		      "snps,spear-ahci" or "qcom,msm-ahci"
 - interrupts        : <interrupt mapping for SATA IRQ>
 - reg               : <registers mapping>
 
diff --git a/Documentation/devicetree/bindings/dma/sps/sps.txt b/Documentation/devicetree/bindings/dma/sps/sps.txt
new file mode 100644
index 0000000..094acb1
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/sps/sps.txt
@@ -0,0 +1,27 @@
+SPS (Smart Peripheral Switch) may be used as a DMA engine to move data
+in either the Peripheral-to-Peripheral (a.k.a. BAM-to-BAM) mode or the
+Peripheral-to-Memory (a.k.a. BAM-System) mode. SPS includes BAM (Bus
+Access Module) hardware block, BAM DMA peripheral, and pipe memory.
+
+Required property:
+  - compatible: should be "qcom,msm_sps"
+
+Optional properties:
+  - reg: offset and size of the register set in the memory map
+  - interrupts: IRQ line
+  - qcom,device-type: specify the device configuration of BAM DMA and
+    pipe memory. Can be one of
+        1 - With BAM DMA and without pipe memory
+        2 - With BAM DMA and with pipe memory
+        3 - Without BAM DMA and without pipe memory
+
+Example:
+
+	qcom,sps@f9980000 {
+		compatible = "qcom,msm_sps";
+		reg = <0xf9984000 0x15000>,
+		      <0xf9999000 0xb000>,
+		      <0xfe803000 0x4800>;
+		interrupts = <0 94 0>;
+		qcom,device-type = <2>;
+	};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-msm.txt b/Documentation/devicetree/bindings/gpio/gpio-msm.txt
index 359d700..a5d50fd 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-msm.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-msm.txt
@@ -9,6 +9,7 @@
 - gpio-controller : Marks the device node as a GPIO controller.
 - #interrupt-cells : Should be 2.
 - interrupt-controller: Mark the device node as an interrupt controller
+- interrupts : Specify the TLMM summary interrupt number
 
 Example:
 
@@ -19,6 +20,7 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
+		interrupts = <0 208 0>;
 	};
 
 To specify gpios for a device:
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 9164647..2ea9ba9 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -132,7 +132,7 @@
 			qcom,algo-ss-window-size = <1000000>;
 			qcom,algo-ss-util-pct = <95>;
 			qcom,algo-em-max-util-pct = <97>;
-			qcom,algo-ss-iobusy-conv = <100>;
+			qcom,algo-ss-no-corr-below-freq = <0>;
 
 			qcom,dcvs-freq@0 {
 				reg = <0>;
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index 33d5cc1..fbe8ffa 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -10,7 +10,10 @@
 Required properties:
 - compatible : should be "qcom,qpnp-iadc" for Current ADC driver.
 - reg : offset and length of the PMIC Aribter register map.
+- address-cells : Must be one.
+- size-cells : Must be zero.
 - 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.
@@ -20,6 +23,7 @@
 
 Required properties:
 - label : Channel name used for sysfs entry.
+- reg : AMUX channel number.
 - qcom,channel-num : Channel number associated to the AMUX input.
 - qcom,decimation : Sampling rate to use for the individual channel measurement.
 		    Select from the following unsigned int.
@@ -83,7 +87,10 @@
 	qcom,iadc@3200 {
                         compatible = "qcom,qpnp-iadc";
                         reg = <0x3200 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
                         interrupts = <0 0x36 0>;
+			interrupt-names = "eoc-int-en-set";
                         qcom,adc-bit-resolution = <16>;
                         qcom,adc-vdd-reference = <1800>;
 			qcom,rsense = <1500>;
@@ -91,7 +98,7 @@
 			/* Channel Node */
                         chan@0 = {
                                 label = "rsense";
-                                qcom,channel-num = <0>;
+                                reg = <0>;
                                 qcom,decimation = <0>;
                                 qcom,pre-div-channel-scaling = <20>;
                                 qcom,calibration-type = "fresh";
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index d7d3ec2..bb66e7b 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -10,7 +10,10 @@
 Required properties:
 - compatible : should be "qcom,qpnp-vadc" for Voltage ADC driver.
 - reg : offset and length of the PMIC Aribter register map.
+- address-cells : Must be one.
+- size-cells : Must be zero.
 - 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.
 
@@ -19,7 +22,7 @@
 
 Required properties:
 - label : Channel name used for sysfs entry.
-- qcom,channel-num : Channel number associated to the AMUX input.
+- reg : AMUX channel number.
 - qcom,decimation : Sampling rate to use for the individual channel measurement.
 		    Select from following unsigned int.
 		    0 : 512
@@ -81,14 +84,17 @@
 	qcom,vadc@3100 {
                         compatible = "qcom,qpnp-vadc";
                         reg = <0x3100 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
                         interrupts = <0x0 0x31 0x0>;
+			interrupt-names = "eoc-int-en-set";
                         qcom,adc-bit-resolution = <15>;
                         qcom,adc-vdd-reference = <1800>;
 
 			/* Channel Node */
                         chan@0 {
                                 label = "usb_in";
-                                qcom,channel-num = <0>;
+                                reg = <0>;
                                 qcom,decimation = <0>;
                                 qcom,pre-div-channel-scaling = <20>;
                                 qcom,calibration-type = "absolute";
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
new file mode 100644
index 0000000..d8e7791
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
@@ -0,0 +1,37 @@
+* Qualcomm MSM IOMMU v1
+
+Required properties:
+- compatible : one of:
+	- "qcom,msm-smmu-v1"
+- reg : offset and length of the register set for the device.
+- qcom,glb-offset : Offset for the global register base.
+
+Optional properties:
+- List of sub nodes, one for each of the translation context banks supported.
+  Each sub node has the following required properties:
+
+  - reg : offset and length of the register set for the context bank.
+  - interrupts : should contain the context bank interrupt.
+  - qcom,iommu-ctx-mids : List of machine identifiers associated with this
+    translation context.
+  - label : Name of the context bank
+
+Optional properties:
+  - none
+
+Example:
+
+	qcom,iommu@fd000000 {
+		compatible = "qcom,msm-smmu-v1";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfd890000 0x10000>;
+		qcom,glb-offset = <0xF000>;
+
+		qcom,iommu-ctx@fd000000 {
+			reg = <0xfd000000 0x1000>;
+			interrupts = <0 250 0>;
+			qcom,iommu-ctx-mids = <0 3>;
+			label = "a_label";
+		};
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/mmc/msm_sdcc.txt b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
index 46173a0..b99b716 100644
--- a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
+++ b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
@@ -4,61 +4,74 @@
 SD/MMC/SDIO cards.
 
 Required properties:
-  - compatible : should be "qcom,msm-sdcc"
-  - reg : should contain SDCC, SDCC-DML and BAM register map.
-  - reg-names : indicates various resources passed to driver (via reg proptery) by name.
-  "reg-names" examples are "core_mem", "dml_mem" and "bam_mem"
-  - interrupts : should contain SDCC core interrupt.
-  - interrupt-names : indicates interrupts passed to driver (via interrupts property) by name.
-  "core_irq" is mandatory, "bam_irq" is mandatory only when BAM DMA engine is used,
-  "status_irq" and "sdiowakeup_irq" are optional.
-  - qcom,clk-rates : specifies supported SDCC clock frequencies, Units - Hz.
-  - qcom,sup-voltages: specifies supported voltage ranges for card. Should always be
-			specified in pairs (min, max), Units - mV.
-  - <supply-name>-supply: phandle to the regulator device tree node
-  "supply-name" examples are "vdd", "vdd-io".
+  - compatible: should be "qcom,msm-sdcc"
+  - reg: should contain SDCC (mandatory), SDCC-DML (optional) and BAM
+    (optional) register maps.
+  - reg-names: indicates various resources passed to driver (via reg
+    property) by name. "reg-names" examples are "core_mem", "dml_mem"
+    and "bam_mem". "dml_mem" and "bam_mem" are optional, and the SDCC
+    driver will default to PIO mode when neither are present.
+  - interrupts: should contain SDCC core interrupt.
+  - interrupt-names: indicates interrupts passed to driver (via interrupts
+    property) by name. "core_irq" is mandatory, "bam_irq" is mandatory only
+    when BAM DMA engine is used. "status_irq" and "sdiowakeup_irq" are
+    optional.
+  - qcom,clk-rates: specifies supported SDCC clock frequencies, Units - Hz.
+  - qcom,sup-voltages: specifies supported voltage ranges for card. Should
+    always be specified in pairs (min, max), Units - mV.
+  - <supply-name>-supply: phandle to the regulator device tree node.
+    "supply-name" examples are "vdd", "vdd-io".
 
 Optional Properties:
-	- cell-index - defines slot ID.
-	- qcom,bus-width - defines the bus I/O width that controller supports.
-	- wp-gpios - specify GPIO for write protect switch detection.
-	- cd-gpios - specify GPIO for card detection.
-	- qcom,nonremovable - specifies whether the card in slot is
-				hot pluggable or hard wired.
-	- qcom,disable-cmd23 - disable sending CMD23 to card when controller can't support it.
-	- qcom,bus-speed-mode - specifies supported bus speed modes by host.
-	- qcom,current-limit - specifies max. current the host can drive.
-	- qcom,xpc - specifies if the host can supply more than 150mA for SDXC cards.
-	- qcom,dat1-mpm-int - specifies MPM interrupt number corresponding to DAT1 line of SDCC
-					(used only if slot has dedicated DAT1 MSM pin (not GPIO))
+  - cell-index: defines slot ID.
+  - qcom,bus-width: defines the bus I/O width that controller supports.
+  - wp-gpios: specify GPIO for write protect switch detection.
+  - cd-gpios: specify GPIO for card detection.
+  - qcom,nonremovable: specifies whether the card in slot is hot pluggable
+    or hard wired.
+  - qcom,disable-cmd23: disable sending CMD23 to card when controller
+    can't support it.
+  - qcom,bus-speed-mode: specifies supported bus speed modes by host.
+  - qcom,current-limit: specifies max. current the host can drive.
+  - qcom,xpc: specifies if the host can supply more than 150mA for SDXC
+    cards.
+  - qcom,dat1-mpm-int: specifies MPM interrupt number corresponding to
+    DAT1 line of SDCC (used only if slot has dedicated DAT1 MSM pin
+    (not GPIO))
 
-In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
-	- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
-	- qcom,<supply>-lpm-sup - specifies whether supply can be kept in low power mode (lpm).
-	- qcom,<supply>-voltage-level - specifies voltage levels for supply. Should be
-	specified in pairs (min, max), units uV.
-	- qcom,<supply>-current-level - specifies load levels for supply in lpm or
-	high power mode (hpm). Should be specified in pairs (lpm, hpm), units uA.
+In the following, <supply> can be vdd (flash core voltage) or vdd-io
+(I/O voltage).
+  - qcom,<supply>-always-on: specifies whether supply should be kept "on"
+    always.
+  - qcom,<supply>-lpm-sup: specifies whether supply can be kept in low
+    power mode (lpm).
+  - qcom,<supply>-voltage-level: specifies voltage levels for supply.
+    Should be specified in pairs (min, max), units uV.
+  - qcom,<supply>-current-level: specifies load levels for supply in
+    lpm or high power mode (hpm). Should be specified in pairs (lpm, hpm),
+    units uA.
 
-	- gpios - specifies gpios assigned for sdcc slot.
-	- qcom,gpio-names -  a list of strings that map in order to the list of gpios
-	A slot has either gpios or dedicated tlmm pins as represented below.
-	- qcom,pad-pull-on - Active pull configuration for sdc tlmm pins
-	- qcom,pad-pull-off - Suspend pull configuration for sdc tlmm pins.
-	- qcom,pad-drv-on - Active drive strength configuration for sdc tlmm pins.
-	- qcom,pad-drv-off - Suspend drive strength configuration for sdc tlmm pins.
-	Tlmm pins are specified as <clk cmd data>
+  - gpios: specifies gpios assigned for sdcc slot.
+  - qcom,gpio-names:  a list of strings that map in order to the list
+    of gpios. A slot has either gpios or dedicated tlmm pins as represented
+    below.
+  - qcom,pad-pull-on: Active pull configuration for sdc tlmm pins
+  - qcom,pad-pull-off: Suspend pull configuration for sdc tlmm pins.
+  - qcom,pad-drv-on: Active drive strength configuration for sdc tlmm pins.
+  - qcom,pad-drv-off: Suspend drive strength configuration for sdc tlmm pins.
+    Tlmm pins are specified as <clk cmd data>
 
-	- qcom,bus-bw-vectors-bps - specifies array of throughput values in Bytes/sec. The
-	values in the array are determined according to supported bus speed modes. For example,
-	if host supports SDR12 mode, value is 13631488 Bytes/sec.
-	- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
-	below optional properties:
-		- qcom,msm-bus,name
-		- qcom,msm-bus,num-cases
-		- qcom,msm-bus,active-only
-		- qcom,msm-bus,num-paths
-		- qcom,msm-bus,vectors-KBps
+  - qcom,bus-bw-vectors-bps: specifies array of throughput values in
+    Bytes/sec. The values in the array are determined according to
+    supported bus speed modes. For example, if host supports SDR12 mode,
+    value is 13631488 Bytes/sec.
+  - Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+    below optional properties:
+	- qcom,msm-bus,name
+	- qcom,msm-bus,num-cases
+	- qcom,msm-bus,active-only
+	- qcom,msm-bus,num-paths
+	- qcom,msm-bus,vectors-KBps
 
 Example:
 
@@ -67,6 +80,7 @@
 	cell-index = <1>;
 	compatible = "qcom,msm-sdcc";
 	reg = <0xf9600000 0x800   // SDCC register interface
+	/* To use PIO instead of BAM, skip DML and BAM regs */
 		0xf9600800 0x1800  // DML register interface
 		0xf9602000 0x2000> // BAM register interface
 
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 802716c..5bef9b8 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -14,6 +14,7 @@
 		      "metadata_base" are expected.
 - interrupts:         The modem watchdog interrupt
 - vdd_mss-supply:     Reference to the regulator that supplies the processor.
+- vdd_mx-supply:      Reference to the regulator that supplies the memory rail.
 - qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
 - qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
 		      images and self-authentication is not desired;
@@ -32,6 +33,7 @@
 			    "restart_reg", metadata_base";
 		interrupts = <0 24 1>;
 		vdd_mss-supply = <&pm8841_s3>;
+		vdd_mx-supply = <&pm8841_s1>;
 
 		qcom,is-loadable;
 		qcom,firmware-name = "mba";
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 4d571eb..af8d45c 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -4,24 +4,17 @@
 to the battery. It's main function is to calculate the State of Charge (SOC),
 a 0-100 percentage representing the amount of charge left in the battery.
 
-BMS node
+There are two required peripherals in the BMS driver, both implemented as
+subnodes in the example. These peripherals must not be disabled if the BMS
+device is to enabled:
+- qcom,bms-bms : The main BMS device. Supports battery monitoring controls and
+		sensors.
+- qcom,bms-iadc : The BMS IADC peripheral in the IADC device. This is required
+		to determine whether the BMS is using an internal or external
+		rsense to accumulate the Coulomb Counter and read current.
 
-Required properties:
+Parent node required properties:
 - compatible : should be "qcom,qpnp-bms" for the BM driver.
-- reg : offset and length of the PMIC BMS register map.
-- interrupts : the interrupt mappings for bms.
-		The format should be
-		<slave-id peripheral-id interrupt-number>.
-- interrupt-names : names for the mapped bms interrupt
-		The following interrupts are required:
-		0 : vsense_for_r
-		1 : vsense_avg
-		2 : sw_cc_thr
-		3 : ocv_thr
-		4 : charge_begin
-		5 : good_ocv
-		6 : ocv_for_r
-		7 : cc_thr
 - qcom,bms-r-sense-mohm : sensor resistance in in milli-ohms.
 - qcom,bms-v-cutoff-uv : cutoff voltage where the battery is considered dead in
 			micro-volts.
@@ -56,7 +49,7 @@
 			to the enum defined in
 			include/linux/mfd/pm8xxx/batterydata-lib.h
 
-Optional properties:
+Parent node optional properties:
 - qcom,bms-ignore-shutdown-soc: A boolean that controls whether BMS will
 			try to force the startup SoC to be the same as the
 			shutdown SoC. Defining it will make BMS ignore the
@@ -65,14 +58,51 @@
 			voltage-based SoC instead of a coulomb counter based
 			one. Voltage-based SoC will not guarantee linearity.
 
+All sub node required properties:
+- reg : offset and length of the PMIC peripheral register map.
+
+qcom,bms-bms node required properties:
+- interrupts : the interrupt mappings.
+		The format should be
+		<slave-id peripheral-id interrupt-number>.
+- interrupt-names : names for the mapped bms interrupt
+		The following interrupts are required:
+		0 : vsense_for_r
+		1 : vsense_avg
+		2 : sw_cc_thr
+		3 : ocv_thr
+		4 : charge_begin
+		5 : good_ocv
+		6 : ocv_for_r
+		7 : cc_thr
+
 Example:
-	bms@4000 {
-		#address-cells = <1>;
-		#size-cells = <1>;
+pm8941_bms: qcom,bms {
+	spmi-dev-container;
+	compatible = "qcom,qpnp-bms";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	status = "disabled";
 
-		compatible = "qcom,qpnp-bms";
+	qcom,bms-r-sense-mohm = <2>;
+	qcom,bms-v-cutoff-uv = <3400000>;
+	qcom,bms-max-voltage-uv = <4200000>;
+	qcom,bms-r-conn-mohm = <18>;
+	qcom,bms-shutdown-soc-valid-limit = <20>;
+	qcom,bms-adjust-soc-low-threshold = <25>;
+	qcom,bms-adjust-soc-high-threshold = <45>;
+	qcom,bms-low-soc-calculate-soc-threshold = <15>;
+	qcom,bms-low-soc-calculate-soc-ms = <5000>;
+	qcom,bms-calculate-soc-ms = <20000>;
+	qcom,bms-chg-term-ua = <100000>;
+	qcom,bms-batt-type = <0>;
+
+	qcom,bms-iadc@3800 {
+		reg = <0x3800 0x100>;
+	};
+
+	qcom,bms-bms@4000 {
 		reg = <0x4000 0x100>;
-
 		interrupts =	<0x0 0x40 0x0>,
 				<0x0 0x40 0x1>,
 				<0x0 0x40 0x2>,
@@ -90,18 +120,5 @@
 				  "good_ocv",
 				  "ocv_for_r",
 				  "cc_thr";
-
-		qcom,bms-r-sense-mohm = <10>;
-		qcom,bms-v-cutoff-uv = <3400000>;
-		qcom,bms-max-voltage-uv = <4200000>;
-		qcom,bms-r-conn-mohm = <18>;
-		qcom,bms-shutdown-soc-valid-limit = <20>;
-		qcom,bms-adjust-soc-low-threshold = <25>;
-		qcom,bms-adjust-soc-high-threshold = <45>;
-		qcom,bms-low-soc-calculate-soc-threshold = <15>;
-		qcom,bms-low-soc-calculate-soc-ms = <5000>;
-		qcom,bms-calculate-soc-ms = <20000>;
-		qcom,bms-chg-term-ua = <100000>;
-		qcom,bms-batt-type = <0>;
-		qcom,bms-ignore-shutdown-soc;
 	};
+};
diff --git a/Documentation/devicetree/bindings/qdsp/msm-adsp-sensors.txt b/Documentation/devicetree/bindings/qdsp/msm-adsp-sensors.txt
new file mode 100644
index 0000000..ff0b1ef
--- /dev/null
+++ b/Documentation/devicetree/bindings/qdsp/msm-adsp-sensors.txt
@@ -0,0 +1,19 @@
+* msm-adsp-sensors
+
+Required properties:
+
+ - compatible:	"qcom,msm-adsp-sensors"
+ - qcom,src-id:	Master port id
+ - qcom,dst-id:	Slave port id
+ - qcom,ab:	Arbitrated bandwidth in bytes/s
+ - qcom,ib:	Instantaneous bandwidth in bytes/s
+
+Example:
+
+	qcom,msm-adsp-sensors {
+		compatible = "qcom,msm-adsp-sensors";
+		qcom,src-id = <11>;
+		qcom,dst-id = <604>;
+		qcom,ab = <209715200>;
+		qcom,ib = <471859200>;
+	};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 213da90..8cc509a 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:
@@ -82,6 +87,7 @@
                             BT SCO port ID value from 12288 to 12289
                             RT Proxy port ID values from 224 to 225 and 240 to 241
                             FM Rx and TX port ID values from 12292 to 12293
+                            incall record Rx and TX port ID values from 32771 to 32772
 
 * msm-auxpcm
 
@@ -281,6 +287,16 @@
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <240>;
 		};
+
+		qcom,msm-dai-q6-incall-record-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32771>;
+		};
+
+		qcom,msm-dai-q6-incall-record-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32772>;
+		};
 	};
 
         qcom,msm-auxpcm {
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 090d8db..74c25a0 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -34,7 +34,7 @@
  - qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
  - qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
  - qcom,cdc-micbias4-ext-cap: Boolean. Enable micbias 4 external capacitor mode.
-
+ - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for codec.
  - qcom,cdc-slim-ifd-dev - namme of the codec slim interface device.
  - qcom,cdc-slim-ifd-elemental-addr - codec slimbus slave interface device
 				     enumeration address.
@@ -86,7 +86,7 @@
 	qcom,cdc-micbias2-ext-cap;
 	qcom,cdc-micbias3-ext-cap;
 	qcom,cdc-micbias4-ext-cap;
-
+	qcom,cdc-mclk-clk-rate = <9600000>;
 	qcom,cdc-slim-ifd = "taiko-slim-ifd";
 	qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
 };
@@ -123,6 +123,7 @@
  - qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
  - qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
  - qcom,cdc-micbias4-ext-cap: Boolean. Enable micbias 4 external capacitor mode.
+ - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for codec.
 
 Example:
 i2c@f9925000 {
@@ -180,6 +181,7 @@
 		qcom,cdc-micbias2-cfilt-sel = <0x1>;
 		qcom,cdc-micbias3-cfilt-sel = <0x2>;
 		qcom,cdc-micbias4-cfilt-sel = <0x2>;
+		qcom,cdc-mclk-clk-rate = <12288000>;
 	};
 
 	wcd9xxx_codec@77{
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
new file mode 100644
index 0000000..f1f4e94
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -0,0 +1,120 @@
+Qualcomm's QPNP PMIC thermal monitor ADC driver (VADC_TM)
+
+QPNP PMIC thermal monitoring (TM) provides interface to thermal clients
+to set temperature thresholds and receive notification when the thresholds
+are crossed. A 15 bit ADC is used for measurements. The driver is part
+of the sysfs thermal framework that provides support to read the trip
+points, set threshold for the trip points and enable the trip points.
+Seperate kernel api's are provided to usb_id and batt_therm
+to set thresholds and receive threshold notifications.
+
+VADC_TM node
+
+Required properties:
+- compatible : should be "qcom,qpnp-adc-tm" for thermal ADC driver.
+- reg : offset and length of the PMIC Aribter register map.
+- address-cells : Must be one.
+- size-cells : Must be zero.
+- interrupts : The thermal ADC bank peripheral interrupts for eoc, high and low interrupts.
+- interrupt-names : Should be "eoc-int-en-set", "high-thr-en-set" and "low-thr-en-set".
+- qcom,adc-bit-resolution : Bit resolution of the ADC.
+- qcom,adc-vdd-reference : Voltage reference used by the ADC.
+
+Channel nodes
+NOTE: Atleast one Channel node is required.
+
+Required properties:
+- label : Channel name used for sysfs entry.
+- reg : AMUX channel number.
+- qcom,decimation : Sampling rate to use for the individual channel measurement.
+		    Select from the following unsigned int.
+		    0 : 512
+		    1 : 1K
+		    2 : 2K
+		    3 : 4K
+- qcom,pre-div-channel-scaling : Pre-div used for the channel before the signal is being measured.
+				 Select from the following unsigned int for the corresponding
+				 numerator/denominator pre-div ratio.
+				 0 : pre-div ratio of {1, 1}
+				 1 : pre-div ratio of {1, 3}
+				 2 : pre-div ratio of {1, 4}
+				 3 : pre-div ratio of {1, 6}
+				 4 : pre-div ratio of {1, 20}
+- qcom,calibration-type : Reference voltage to use for channel calibration.
+			  Channel calibration is dependendent on the channel.
+			  Certain channels like XO_THERM, BATT_THERM use ratiometric
+			  calibration. Most other channels fall under absolute calibration.
+			  Select from the following strings.
+			  "absolute" : Uses the 625mv and 1.25V reference channels.
+			  "ratiometric" : Uses the reference Voltage/GND for calibration.
+- qcom,scale-function : Scaling fuction used to convert raw ADC code to units specific to
+			a given channel.
+			Select from the following unsigned int.
+			0 : Default scaling to convert raw adc code to voltage.
+			1 : Conversion to temperature based on btm parameters.
+			2 : Returns result in milli degree's Centigrade.
+			3 : Returns current across 0.1 ohm resistor.
+			4 : Returns XO thermistor voltage in degree's Centigrade.
+- qcom,hw-settle-time : Settling period for the channel before ADC read.
+			Select from the following unsigned int.
+			0 : 0us
+			1 : 100us
+			2 : 200us
+			3 : 300us
+			4 : 400us
+			5 : 500us
+			6 : 600us
+			7 : 700us
+			8 : 800us
+			9 : 900us
+			0xa : 1ms
+			0xb : 2ms
+			0xc : 4ms
+			0xd : 6ms
+			0xe : 8ms
+			0xf : 10ms
+- qcom,fast-avg-setup : Average number of samples to be used for measurement. Fast averaging
+			provides the option to obtain a single measurement from the ADC that
+			is an average of multiple samples. The value selected is 2^(value)
+			Select from
+			0 : 1
+			1 : 2
+			2 : 4
+			3 : 8
+			4 : 16
+			5 : 32
+			6 : 64
+			7 : 128
+			8 : 256
+- qcom,btm-channel-number : There are 5 BTM channels. The BTM channel numbers are statically
+			    allocated to the corresponding channel node.
+
+Example:
+	/* Main Node */
+	qcom,vadc@3400 {
+                        compatible = "qcom,qpnp-adc-tm";
+                        reg = <0x3400 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+                        interrupts = <0x0 0x34 0x0>,
+					<0x0 0x34 0x3>,
+					<0x0 0x34 0x4>;
+			interrupt-names = "eoc-int-en-set",
+					  "high-thr-en-set",
+					  "low-thr-en-set";
+                        qcom,adc-bit-resolution = <15>;
+                        qcom,adc-vdd-reference = <1800>;
+
+			/* Channel Node */
+                        chan@b5 {
+                                label = "pa_therm1";
+				reg = <0xb5>;
+                                qcom,decimation = <0>;
+                                qcom,pre-div-channel-scaling = <0>;
+                                qcom,calibration-type = "absolute";
+                                qcom,scale-function = <2>;
+                                qcom,hw-settle-time = <0>;
+                                qcom,fast-avg-setup = <0>;
+				qcom,btm-channel-number = <0x70>;
+                        };
+	};
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 0e59f69..ffb0c6a 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -9,6 +9,17 @@
 - <supply-name>-supply: handle to the regulator device tree node
   Required "supply-name" is "HSIC_VDDCX" and optionally - "HSIC_GDSC".
 
+Optional properties :
+- hsic,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
+  in Documentation/devicetree/bindings/gpio/gpio.txt.
+  Optional "gpio-name" can be "strobe" and "data".
+- hsic,ignore-cal-pad-config : If present then HSIC CAL PAD configuration
+  using TLMM is not performed.
+- hsic,strobe-pad-offset : Offset of TLMM register for configuring HSIC
+  STROBE GPIO PAD.
+- hsic,data-pad-offset : Offset of TLMM register for configuring HSIC
+  DATA GPIO PAD.
+
 Example MSM HSIC EHCI controller device node :
 	hsic@f9a15000 {
 		compatible = "qcom,hsic-host";
@@ -17,4 +28,47 @@
 		interrupt-names = "core_irq";
 		HSIC_VDDCX-supply = <&pm8019_l12>;
 		HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+		hsic,strobe-gpio = <&msmgpio 144 0x00>;
+		hsic,data-gpio = <&msmgpio 145 0x00>;
+		hsic,ignore-cal-pad-config;
+		hsic,strobe-pad-offset = <0x2050>;
+		hsic,data-pad-offset = <0x2054>;
 	};
+
+SMSC HSIC HUB
+
+Required properties :
+- compatible : should be "qcom,hsic-smsc-hub"
+- smsc,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
+  in Documentation/devicetree/bindings/gpio/gpio.txt.
+  Required "gpio-name" is "reset" and optionally - "refclk", "int".
+- <supply-name>-supply: handle to the regulator device tree node
+  Required "supply-name" is "hub_init" and optionally - "hub_vbus".
+- Sub node for "MSM HSIC EHCI controller".
+  Sub node has the required properties mentioned above.
+
+Example SMSC HSIC HUB :
+	hsic_hub {
+		compatible = "qcom,hsic-smsc-hub";
+		ranges;
+		smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
+		smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
+		smsc,int-gpio = <&msmgpio 50 0x00>;
+		hub_int-supply = <&pm8941_l10>;
+		hub_vbus-supply = <&pm8941_mvs1>;
+
+		hsic@f9a00000 {
+			compatible = "qcom,hsic-host";
+			reg = <0xf9a00000 0x400>;
+			interrupts = <0 136 0>;
+			interrupt-names = "core_irq";
+			HSIC_VDDCX-supply = <&pm8841_s2>;
+			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+			hsic,strobe-gpio = <&msmgpio 144 0x00>;
+			hsic,data-gpio = <&msmgpio 145 0x00>;
+			hsic,ignore-cal-pad-config;
+			hsic,strobe-pad-offset = <0x2050>;
+			hsic,data-pad-offset = <0x2054>;
+		};
+	};
+
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/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 7dde34f..43453d0 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -39,7 +39,7 @@
 
 All attributes are read-only.
 
-	cid			Card Identifaction Register
+	cid			Card Identification Register
 	csd			Card Specific Data Register
 	scr			SD Card Configuration Register (SD only)
 	date			Manufacturing Date (from CID Register)
@@ -51,6 +51,8 @@
 	serial			Product Serial Number (from CID Register)
 	erase_size		Erase group size
 	preferred_erase_size	Preferred erase size
+	raw_rpmb_size_mult	RPMB partition size
+	rel_sectors		Reliable write sector count
 
 Note on Erase Size and Preferred Erase Size:
 
@@ -91,6 +93,11 @@
 
 	"preferred_erase_size" is in bytes.
 
+Note on raw_rpmb_size_mult:
+	"raw_rpmb_size_mult" is a mutliple of 128kB block.
+	RPMB size in byte is calculated by using the following equation:
+	RPMB partition size = 128kB x raw_rpmb_size_mult
+
 SD/MMC/SDIO Clock Gating Attribute
 ==================================
 
@@ -100,3 +107,41 @@
 	clkgate_delay	Tune the clock gating delay with desired value in milliseconds.
 
 echo <desired delay> > /sys/class/mmc_host/mmcX/clkgate_delay
+
+SD/MMC/SDIO Clock Scaling Attributes
+====================================
+
+Read and write accesses are provided to following attributes.
+
+	polling_interval	Measured in milliseconds, this attribute
+				defines how often we need to check the card
+				usage and make decisions on frequency scaling.
+
+	up_threshold		This attribute defines what should be the
+				average card usage between the polling
+				interval for the mmc core to make a decision
+				on whether it should increase the frequency.
+				For example when it is set to '35' it means
+				that between the checking intervals the card
+				needs to be on average more than 35% in use to
+				scale up the frequency. The value should be
+				between 0 - 100 so that it can be compared
+				against load percentage.
+
+	down_threshold		Similar to up_threshold, but on lowering the
+				frequency. For example, when it is set to '2'
+				it means that between the checking intervals
+				the card needs to be on average less than 2%
+				in use to scale down the clocks to minimum
+				frequency. The value should be between 0 - 100
+				so that it can be compared against load
+				percentage.
+
+	enable			Enable clock scaling for hosts (and cards)
+				that support ultrahigh speed modes
+				(SDR104, DDR50, HS200).
+
+echo <desired value> > /sys/class/mmc_host/mmcX/clk_scaling/polling_interval
+echo <desired value> > /sys/class/mmc_host/mmcX/clk_scaling/up_threshold
+echo <desired value> > /sys/class/mmc_host/mmcX/clk_scaling/down_threshold
+echo <desired value> > /sys/class/mmc_host/mmcX/clk_scaling/enable
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 89c7417..53fd3b2 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1889,7 +1889,6 @@
 
 config DONT_MAP_HOLE_AFTER_MEMBANK0
 	def_bool n
-	depends on SPARSEMEM
 
 config ARCH_ENABLE_MEMORY_HOTPLUG
 	def_bool n
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 81b5dc9..2f2603f 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -265,7 +265,12 @@
 KBUILD_IMAGE := zImage
 endif
 
-all:	$(KBUILD_IMAGE)
+# Build the DT binary blobs if we have OF configured
+ifeq ($(CONFIG_USE_OF),y)
+KBUILD_DTBS := dtbs
+endif
+
+all:	$(KBUILD_IMAGE) $(KBUILD_DTBS)
 
 boot := arch/arm/boot
 
@@ -281,10 +286,10 @@
 zinstall uinstall install: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
 
-%.dtb:
+%.dtb: scripts
 	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
 
-dtbs:
+dtbs: scripts
 	$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
 
 # We use MRPROPER_FILES and CLEAN_FILES now
@@ -303,7 +308,7 @@
   echo  '  uImage        - U-Boot wrapped zImage'
   echo  '  bootpImage    - Combined zImage and initial RAM disk' 
   echo  '                  (supply initrd image via make variable INITRD=<path>)'
-  echo  '  dtbs          - Build device tree blobs for enabled boards'
+  echo  '* dtbs          - Build device tree blobs for enabled boards'
   echo  '  install       - Install uncompressed kernel'
   echo  '  zinstall      - Install compressed kernel'
   echo  '  uinstall      - Install U-Boot wrapped compressed kernel'
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 502d34a..0ab0a0c 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -35,10 +35,11 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
+		interrupts = <0 208 0>;
 	};
 
 	timer {
-		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		compatible = "arm,armv7-timer";
 		interrupts = <1 2 0>, <1 3 0>;
 		clock-frequency = <19200000>;
 	};
@@ -270,6 +271,12 @@
 		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
 		qcom,current-limit = <800>;
 	};
+
+	sata: sata@fc580000 {
+		compatible = "qcom,msm-ahci";
+		reg = <0xfc580000 0x17c>;
+		interrupts = <0 243 0>;
+	};
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
new file mode 100644
index 0000000..5a08f51
--- /dev/null
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -0,0 +1,228 @@
+/* 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.
+ */
+
+/ {
+	lpass_iommu: qcom,iommu@fd000000 {
+		compatible = "qcom,msm-smmu-v1";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfd000000 0x10000>;
+		qcom,glb-offset = <0xF000>;
+		label = "lpass_iommu";
+		status = "disabled";
+
+		qcom,iommu-ctx@fd000000 {
+			reg = <0xfd000000 0x1000>;
+			interrupts = <0 250 0>;
+			qcom,iommu-ctx-mids = <0 15>;
+			label = "q6_fw";
+		};
+
+		qcom,iommu-ctx@fd001000 {
+			reg = <0xfd001000 0x1000>;
+			interrupts = <0 250 0>;
+			qcom,iommu-ctx-mids = <1>;
+			label = "audio_shared";
+		};
+
+		qcom,iommu-ctx@fd002000 {
+			reg = <0xfd002000 0x1000>;
+			interrupts = <0 250 0>;
+			qcom,iommu-ctx-mids = <2>;
+			label = "video_shared";
+		};
+
+		qcom,iommu-ctx@fd003000 {
+			reg = <0xfd003000 0x1000>;
+			interrupts = <0 250 0>;
+			qcom,iommu-ctx-mids = <3 4 5 6 7 8 9 10 11 12 13 14>;
+			label = "q6_spare";
+		};
+	};
+
+	copss_iommu: qcom,iommu@fd010000 {
+		compatible = "qcom,msm-smmu-v1";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfd010000 0x10000>;
+		qcom,glb-offset = <0xF000>;
+		label = "copss_iommu";
+		status = "disabled";
+
+		qcom,iommu-ctx@fd010000 {
+			reg = <0xfd010000 0x1000>;
+			interrupts = <0 254 0>;
+			qcom,iommu-ctx-mids = <0>;
+			label = "copss_0";
+		};
+
+		qcom,iommu-ctx@fd011000 {
+			reg = <0xfd011000 0x1000>;
+			interrupts = <0 254 0>;
+			qcom,iommu-ctx-mids = <1>;
+			label = "copss_1";
+		};
+
+		qcom,iommu-ctx@fd012000 {
+			reg = <0xfd012000 0x1000>;
+			interrupts = <0 254 0>;
+			qcom,iommu-ctx-mids = <2>;
+			label = "copss_2";
+		};
+
+		qcom,iommu-ctx@fd013000 {
+			reg = <0xfd013000 0x1000>;
+			interrupts = <0 254 0>;
+			qcom,iommu-ctx-mids = <3>;
+			label = "copss_3";
+		};
+
+		qcom,iommu-ctx@fd014000 {
+			reg = <0xfd014000 0x1000>;
+			interrupts = <0 254 0>;
+			qcom,iommu-ctx-mids = <4>;
+			label = "copss_4";
+		};
+
+		qcom,iommu-ctx@fd015000 {
+			reg = <0xfd015000 0x1000>;
+			interrupts = <0 254 0>;
+			qcom,iommu-ctx-mids = <5>;
+			label = "copss_5";
+		};
+
+		qcom,iommu-ctx@fd016000 {
+			reg = <0xfd016000 0x1000>;
+			interrupts = <0 254 0>;
+			qcom,iommu-ctx-mids = <6>;
+			label = "copss_6";
+		};
+
+		qcom,iommu-ctx@fd017000 {
+			reg = <0xfd017000 0x1000>;
+			interrupts = <0 254 0>;
+			qcom,iommu-ctx-mids = <7>;
+			label = "copss_7";
+		};
+	};
+
+	mdpe_iommu: qcom,iommu@fd860000 {
+		compatible = "qcom,msm-smmu-v1";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfd860000 0x10000>;
+		qcom,glb-offset = <0xF000>;
+		label = "mdpe_iommu";
+		status = "disabled";
+
+		qcom,iommu-ctx@fd860000 {
+			reg = <0xfd860000 0x1000>;
+			interrupts = <0 247 0>;
+			qcom,iommu-ctx-mids = <>;
+			label = "mdpe_0";
+		};
+
+		qcom,iommu-ctx@fd861000 {
+			reg = <0xfd861000 0x1000>;
+			interrupts = <0 247 0>;
+			qcom,iommu-ctx-mids = <>;
+			label = "mdpe_1";
+		};
+	};
+
+	mdps_iommu: qcom,iommu@fd870000 {
+		compatible = "qcom,msm-smmu-v1";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfd870000 0x10000>;
+		qcom,glb-offset = <0xF000>;
+		label = "mdps_iommu";
+		status = "disabled";
+
+		qcom,iommu-ctx@fd870000 {
+			reg = <0xfd870000 0x1000>;
+			interrupts = <0 247 0>;
+			qcom,iommu-ctx-mids = <>;
+			label = "mdps_0";
+		};
+
+		qcom,iommu-ctx@fd871000 {
+			reg = <0xfd871000 0x1000>;
+			interrupts = <0 247 0>;
+			qcom,iommu-ctx-mids = <>;
+			label = "mdps_1";
+		};
+	};
+
+	gfx_iommu: qcom,iommu@fd880000 {
+		compatible = "qcom,msm-smmu-v1";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfd880000 0x10000>;
+		qcom,glb-offset = <0xF000>;
+		label = "gfx_iommu";
+		status = "disabled";
+
+		qcom,iommu-ctx@fd880000 {
+			reg = <0xfd880000 0x1000>;
+			interrupts = <0 241 0>;
+			qcom,iommu-ctx-mids = <0 1 2 3 4 5 6 7 8 9 10 11 12 13
+					       14 15>;
+			label = "gfx3d_user";
+		};
+
+		qcom,iommu-ctx@fd881000 {
+			reg = <0xfd881000 0x1000>;
+			interrupts = <0 241 0>;
+			qcom,iommu-ctx-mids = <16 17 18 19 20 21 22 23 24 25
+					       26 27 28 29 30 31>;
+			label = "gfx3d_priv";
+		};
+
+		qcom,iommu-ctx@fd882000 {
+			reg = <0xfd882000 0x1000>;
+			interrupts = <0 241 0>;
+			qcom,iommu-ctx-mids = <>;
+			label = "gfx3d_spare";
+		};
+	};
+
+	vfe_iommu: qcom,iommu@fd890000 {
+		compatible = "qcom,msm-smmu-v1";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfd890000 0x10000>;
+		qcom,glb-offset = <0xF000>;
+		label = "vfe_iommu";
+		status = "disabled";
+
+		qcom,iommu-ctx@fd890000 {
+			reg = <0xfd890000 0x1000>;
+			interrupts = <0 65 0>;
+			qcom,iommu-ctx-mids = <0>;
+			label = "vfe0";
+		};
+
+		qcom,iommu-ctx@fd891000 {
+			reg = <0xfd891000 0x1000>;
+			interrupts = <0 65 0>;
+			qcom,iommu-ctx-mids = <1>;
+			label = "vfe1";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
index 2105e8a..322e601 100755
--- a/arch/arm/boot/dts/msm-pm8019.dtsi
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -156,13 +156,15 @@
 		pm8019_vadc: vadc@3100 {
 			compatible = "qcom,qpnp-vadc";
 			reg = <0x3100 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			interrupts = <0x0 0x31 0x0>;
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
 
 			chan@8 {
 				label = "die_temp";
-				qcom,channel-num = <8>;
+				reg = <8>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
@@ -173,7 +175,7 @@
 
 			chan@9 {
 				label = "ref_625mv";
-				qcom,channel-num = <9>;
+				reg = <9>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
@@ -182,9 +184,9 @@
 				qcom,fast-avg-setup = <0>;
 			};
 
-			chan@10 {
+			chan@a {
 				label = "ref_1250v";
-				qcom,channel-num = <10>;
+				reg = <0xa>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
new file mode 100644
index 0000000..94db3ea
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -0,0 +1,18 @@
+/* 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.
+ */
+
+&spmi_bus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	interrupt-controller;
+	#interrupt-cells = <3>;
+};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 89d4df8..d5f59de 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -58,32 +58,14 @@
 			};
 		};
 
-		pm8941_bms: bms@4000 {
+		pm8941_bms: qcom,bms {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-bms";
 			#address-cells = <1>;
 			#size-cells = <1>;
 			status = "disabled";
-			compatible = "qcom,qpnp-bms";
-			reg = <0x4000 0x100>;
 
-			interrupts =	<0x0 0x40 0x0>,
-					<0x0 0x40 0x1>,
-					<0x0 0x40 0x2>,
-					<0x0 0x40 0x3>,
-					<0x0 0x40 0x4>,
-					<0x0 0x40 0x5>,
-					<0x0 0x40 0x6>,
-					<0x0 0x40 0x7>;
-
-			interrupt-names = "vsense_for_r",
-					  "vsense_avg",
-					  "sw_cc_thr",
-					  "ocv_thr",
-					  "charge_begin",
-					  "good_ocv",
-					  "ocv_for_r",
-					  "cc_thr";
-
-			qcom,bms-r-sense-mohm = <10>;
+			qcom,bms-r-sense-mohm = <2>;
 			qcom,bms-v-cutoff-uv = <3400000>;
 			qcom,bms-max-voltage-uv = <4200000>;
 			qcom,bms-r-conn-mohm = <18>;
@@ -95,7 +77,31 @@
 			qcom,bms-calculate-soc-ms = <20000>;
 			qcom,bms-chg-term-ua = <100000>;
 			qcom,bms-batt-type = <0>;
-			qcom,bms-use-voltage-soc;
+
+			qcom,bms-iadc@3800 {
+				reg = <0x3800 0x100>;
+			};
+
+			qcom,bms-bms@4000 {
+				reg = <0x4000 0x100>;
+				interrupts =	<0x0 0x40 0x0>,
+						<0x0 0x40 0x1>,
+						<0x0 0x40 0x2>,
+						<0x0 0x40 0x3>,
+						<0x0 0x40 0x4>,
+						<0x0 0x40 0x5>,
+						<0x0 0x40 0x6>,
+						<0x0 0x40 0x7>;
+
+				interrupt-names = "vsense_for_r",
+						  "vsense_avg",
+						  "sw_cc_thr",
+						  "ocv_thr",
+						  "charge_begin",
+						  "good_ocv",
+						  "ocv_for_r",
+						  "cc_thr";
+			};
 		};
 
 		clkdiv@5b00 {
@@ -486,13 +492,16 @@
 		vadc@3100 {
 			compatible = "qcom,qpnp-vadc";
 			reg = <0x3100 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			interrupts = <0x0 0x31 0x0>;
+			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
 
 			chan@0 {
 				label = "usb_in";
-				qcom,channel-num = <0>;
+				reg = <0>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <4>;
 				qcom,calibration-type = "absolute";
@@ -503,7 +512,7 @@
 
 			chan@1 {
 				label = "dc_in";
-				qcom,channel-num = <1>;
+				reg = <1>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <4>;
 				qcom,calibration-type = "absolute";
@@ -514,7 +523,7 @@
 
 			chan@2 {
 				label = "vchg_sns";
-				qcom,channel-num = <2>;
+				reg = <2>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <3>;
 				qcom,calibration-type = "absolute";
@@ -525,7 +534,7 @@
 
 			chan@3 {
 				label = "spare1";
-				qcom,channel-num = <3>;
+				reg = <3>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <6>;
 				qcom,calibration-type = "absolute";
@@ -536,7 +545,7 @@
 
 			chan@4 {
 				label = "spare2";
-				qcom,channel-num = <4>;
+				reg = <4>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <6>;
 				qcom,calibration-type = "absolute";
@@ -547,7 +556,7 @@
 
 			chan@5 {
 				label = "vcoin";
-				qcom,channel-num = <5>;
+				reg = <5>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <1>;
 				qcom,calibration-type = "absolute";
@@ -558,7 +567,7 @@
 
 			chan@6 {
 				label = "vbat_sns";
-				qcom,channel-num = <6>;
+				reg = <6>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <1>;
 				qcom,calibration-type = "absolute";
@@ -569,7 +578,7 @@
 
 			chan@7 {
 				label = "vph_pwr";
-				qcom,channel-num = <7>;
+				reg = <7>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <1>;
 				qcom,calibration-type = "absolute";
@@ -580,7 +589,7 @@
 
 			chan@8 {
 				label = "die_temp";
-				qcom,channel-num = <8>;
+				reg = <8>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
@@ -591,7 +600,7 @@
 
 			chan@9 {
 				label = "ref_625mv";
-				qcom,channel-num = <9>;
+				reg = <9>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
@@ -600,9 +609,9 @@
 				qcom,fast-avg-setup = <0>;
 			};
 
-			chan@10 {
+			chan@a {
 				label = "ref_1250v";
-				qcom,channel-num = <10>;
+				reg = <0xa>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "absolute";
@@ -611,9 +620,9 @@
 				qcom,fast-avg-setup = <0>;
 			};
 
-			chan@48 {
+			chan@30 {
 				label = "batt_therm";
-				qcom,channel-num = <48>;
+				reg = <0x30>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
@@ -622,9 +631,9 @@
 				qcom,fast-avg-setup = <0>;
 			};
 
-			chan@49 {
+			chan@31 {
 				label = "batt_id";
-				qcom,channel-num = <49>;
+				reg = <0x31>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
@@ -633,9 +642,9 @@
 				qcom,fast-avg-setup = <0>;
 			};
 
-			chan@178 {
+			chan@b2 {
 				label = "xo_therm_pu2";
-				qcom,channel-num = <178>;
+				reg = <0xb2>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
@@ -644,9 +653,9 @@
 				qcom,fast-avg-setup = <0>;
 			};
 
-			chan@179 {
+			chan@b3 {
 				label = "msm_therm";
-				qcom,channel-num = <179>;
+				reg = <0xb3>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
@@ -655,9 +664,9 @@
 				qcom,fast-avg-setup = <0>;
 			};
 
-			chan@180 {
+			chan@b4 {
 				label = "emmc_therm";
-				qcom,channel-num = <180>;
+				reg = <0xb4>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
@@ -666,9 +675,9 @@
 				qcom,fast-avg-setup = <0>;
 			};
 
-			chan@181 {
+			chan@b5 {
 				label = "pa_therm1";
-				qcom,channel-num = <181>;
+				reg = <0xb5>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
@@ -677,9 +686,9 @@
 				qcom,fast-avg-setup = <0>;
 			};
 
-			chan@183 {
+			chan@b7 {
 				label = "pa_therm2";
-				qcom,channel-num = <183>;
+				reg = <0xb7>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
@@ -688,9 +697,9 @@
 				qcom,fast-avg-setup = <0>;
 			};
 
-			chan@184 {
+			chan@b8 {
 				label = "quiet_therm";
-				qcom,channel-num = <184>;
+				reg = <0xb8>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <0>;
 				qcom,calibration-type = "ratiometric";
@@ -698,19 +707,33 @@
 				qcom,hw-settle-time = <0>;
 				qcom,fast-avg-setup = <0>;
 			};
+
+			chan@b9 {
+				label = "usb_id";
+				reg = <0xb9>;
+				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>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			interrupts = <0x0 0x36 0x0>;
+			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <16>;
 			qcom,adc-vdd-reference = <1800>;
 			qcom,rsense = <1500>;
 
 			chan@0 {
 				label = "internal_rsense";
-				qcom,channel-num = <0>;
+				reg = <0>;
 				qcom,decimation = <0>;
 				qcom,pre-div-channel-scaling = <1>;
 				qcom,calibration-type = "absolute";
@@ -719,6 +742,82 @@
 				qcom,fast-avg-setup = <0>;
 			};
 		};
+
+		qcom,vadc@3400 {
+			compatible = "qcom,qpnp-adc-tm";
+			reg = <0x3400 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts =	<0x0 0x34 0x0>,
+					<0x0 0x34 0x3>,
+				     <0x0 0x34 0x4>;
+			interrupt-names =	"eoc-int-en-set",
+						"high-thr-en-set",
+						"low-thr-en-set";
+			qcom,adc-bit-resolution = <15>;
+			qcom,adc-vdd-reference = <1800>;
+
+			/* Channel Node */
+			chan@b9 {
+				label = "usb_id";
+				reg = <0xb9>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <2>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,btm-channel-number = <0x48>;
+			};
+
+			chan@30 {
+				label = "batt_therm";
+				reg = <0x30>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <1>;
+				qcom,hw-settle-time = <0xf>;
+				qcom,fast-avg-setup = <0>;
+				qcom,btm-channel-number = <0x68>;
+			};
+
+			chan@b5 {
+				label = "pa_therm1";
+				reg = <0xb5>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <2>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,btm-channel-number = <0x70>;
+			};
+
+			chan@b7 {
+				label = "pa_therm2";
+				reg = <0xb7>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <2>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,btm-channel-number = <0x78>;
+			};
+
+			chan@b4 {
+				label = "emmc_therm";
+				reg = <0xb4>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <2>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,btm-channel-number = <0x80>;
+			};
+		};
 	};
 
 	qcom,pm8941@1 {
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 41ac69d..9a0ec17 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -23,3 +23,54 @@
 		status = "ok";
 	};
 };
+
+&sdcc1 {
+	qcom,vdd-always-on;
+	qcom,vdd-lpm-sup;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <800 500000>;
+
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <250 154000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+	vdd-supply = <&pm8026_l17>;
+	vdd-io-supply = <&pm8026_l6>;
+	qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+	qcom,sup-voltages = <2950 2950>;
+
+	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+	qcom,nonremovable;
+	status = "ok";
+};
+
+&sdcc2 {
+	vdd-supply = <&pm8026_l18>;
+	vdd-io-supply = <&pm8026_l21>;
+	qcom,vdd-voltage-level = <2950000 2950000>;
+	qcom,vdd-current-level = <9000 800000>;
+
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <6 22000>;
+
+	qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+	qcom,pad-drv-on = <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,sup-voltages = <2950 2950>;
+
+	qcom,xpc;
+	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+	qcom,current-limit = <800>;
+
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b900c3f..0edcc0d 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -32,11 +32,13 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
+		gpio-controller;
 		#gpio-cells = <2>;
+		interrupts = <0 208 0>;
 	};
 
 	timer {
-		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		compatible = "arm,armv7-timer";
 		interrupts = <1 2 0 1 3 0>;
 		clock-frequency = <19200000>;
 	};
@@ -55,6 +57,13 @@
 		status = "disabled";
 	};
 
+	qcom,sps@f9984000 {
+		compatible = "qcom,msm_sps";
+		reg = <0xf9984000 0x15000>,
+		      <0xf9999000 0xb000>;
+		interrupts = <0 94 0>;
+	};
+
         usb@f9a55000 {
 		compatible = "qcom,hsusb-otg";
 		reg = <0xf9a55000 0x400>;
@@ -83,6 +92,103 @@
 		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;
+		};
+	};
+
+	sdcc1: qcom,sdcc@f9824000 {
+		cell-index = <1>; /* SDC1 eMMC slot */
+		compatible = "qcom,msm-sdcc";
+
+		reg = <0xf9824000 0x800>,
+			<0xf9824800 0x100>,
+			<0xf9804000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 123 0>, <0 137 0>;
+		interrupt-names = "core_irq", "bam_irq";
+
+		qcom,bus-width = <8>;
+		status = "disabled";
+	};
+
+	sdcc2: qcom,sdcc@f98a4000 {
+		cell-index = <2>; /* SDC2 SD card slot */
+		compatible = "qcom,msm-sdcc";
+
+		reg = <0xf98a4000 0x800>,
+			<0xf98a4800 0x100>,
+			<0xf9884000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 125 0>, <0 220 0>;
+		interrupt-names = "core_irq", "bam_irq";
+
+		qcom,bus-width = <4>;
+		status = "disabled";
+	};
 };
 
 &gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8910.dtsi b/arch/arm/boot/dts/msm8910.dtsi
index 9514e5a..8ad4eda 100644
--- a/arch/arm/boot/dts/msm8910.dtsi
+++ b/arch/arm/boot/dts/msm8910.dtsi
@@ -11,7 +11,9 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "msm-iommu-v1.dtsi"
 /include/ "msm8910-ion.dtsi"
+/include/ "msm-gdsc.dtsi"
 
 / {
 	model = "Qualcomm MSM 8910";
@@ -31,11 +33,13 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
+		gpio-controller;
 		#gpio-cells = <2>;
+		interrupts = <0 208 0>;
 	};
 
 	timer {
-		compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+		compatible = "arm,armv7-timer";
 		interrupts = <1 2 0 1 3 0>;
 		clock-frequency = <19200000>;
 	};
@@ -69,10 +73,12 @@
 	sdcc1: qcom,sdcc@f9824000 {
 		cell-index = <1>; /* SDC1 eMMC slot */
 		compatible = "qcom,msm-sdcc";
-		reg = <0xf9824000 0x800>;
-		reg-names = "core_mem";
-		interrupts = <0 123 0>;
-		interrupt-names = "core_irq";
+		reg = <0xf9824000 0x800>,
+		      <0xf9824800 0x100>,
+		      <0xf9804000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 123 0>, <0 137 0>;
+		interrupt-names = "core_irq", "bam_irq";
 
 		vdd-supply = <&pm8110_l17>;
 		qcom,vdd-always-on;
@@ -101,10 +107,12 @@
 	sdcc2: qcom,sdcc@f98a4000 {
 		cell-index = <2>; /* SDC2 SD card slot */
 		compatible = "qcom,msm-sdcc";
-		reg = <0xf98a4000 0x800>;
-		reg-names = "core_mem";
-		interrupts = <0 125 0>;
-		interrupt-names = "core_irq";
+		reg = <0xf98a4000 0x800>,
+		      <0xf98a4800 0x100>,
+		      <0xf9884000 0x7000>;
+		reg-names = "core_mem", "dml_mem", "bam_mem";
+		interrupts = <0 125 0>, <0 220 0>;
+		interrupt-names = "core_irq", "bam_irq";
 
 		vdd-supply = <&pm8110_l18>;
 		qcom,vdd-voltage-level = <2950000 2950000>;
@@ -127,9 +135,14 @@
 		qcom,current-limit = <800>;
 	};
 
-	qcom,smem@fa00000 {
+	qcom,sps {
+		compatible = "qcom,msm_sps";
+		qcom,device-type = <3>;
+	};
+
+	qcom,smem@d600000 {
 		compatible = "qcom,smem";
-		reg = <0xfa00000 0x200000>,
+		reg = <0xd600000 0x200000>,
 			<0xfa006000 0x1000>,
 			<0xfc428000 0x4000>;
 		reg-names = "smem", "irq-reg-base", "aux-mem1";
@@ -194,6 +207,138 @@
 			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>;
+	};
+
+	spmi_bus: qcom,spmi@fc4c0000 {
+		cell-index = <0>;
+		compatible = "qcom,spmi-pmic-arb";
+		reg = <0xfc4cf000 0x1000>,
+		      <0Xfc4cb000 0x1000>;
+		/* 190,ee0_krait_hlos_spmi_periph_irq */
+		/* 187,channel_0_krait_hlos_trans_done_irq */
+		interrupts = <0 190 0>, <0 187 0>;
+		qcom,not-wakeup;
+		qcom,pmic-arb-ee = <0>;
+		qcom,pmic-arb-channel = <0>;
+		qcom,pmic-arb-ppid-map = <0x001000a0>, /* PM8110 */
+					 <0x005000a2>, /* INTERRUPT */
+					 <0x006000a3>, /* SPMI_0 */
+					 <0x00800000>, /* PON0 */
+					 <0x01000002>, /* SMBB_CHG */
+					 <0x01100003>, /* SMBB_BUCK */
+					 <0x01200004>, /* SMBB_BIF */
+					 <0x01300005>, /* SMBB_USB */
+					 <0x01500006>, /* SMBB_BOOST */
+					 <0x01600007>, /* SMBB_MISC */
+					 <0x0280000a>, /* COINCELL */
+					 <0x02c000a5>, /* MBG */
+					 <0x0310000b>, /* VADC1_LC_USR */
+					 <0x03200041>, /* VADC3_LC_MDM */
+					 <0x0330000c>, /* VADC3_LC_BMS */
+					 <0x0340000d>, /* VADC2_LC_BTM */
+					 <0x0360000e>, /* IADC1_USR */
+					 <0x03700042>, /* IADC2_MDM */
+					 <0x0380000f>, /* IADC2_BMS */
+					 <0x04000010>, /* BMS_1 */
+					 <0x050000a6>, /* SHARED_XO */
+					 <0x051000a7>, /* BB_CLK1 */
+					 <0x054000a8>, /* RF_CLK1 */
+					 <0x055000a9>, /* RF_CLK1 */
+					 <0x05a000ab>, /* SLEEP_CLK */
+					 <0x06000043>, /* RTC_RW */
+					 <0x06100011>, /* RTC_ALARM */
+					 <0x070000ac>, /* PBS_CORE */
+					 <0x071000ad>, /* PBS_CLIENT_1 */
+					 <0x072000ae>, /* PBS_CLIENT_2 */
+					 <0x07300013>, /* PBS_CLIENT_3 */
+					 <0x07400044>, /* PBS_CLIENT_4 */
+					 <0x0a000014>, /* MPP_1 */
+					 <0x0a100015>, /* MPP_2 */
+					 <0x0a200016>, /* MPP_3 */
+					 <0x0a300045>, /* MPP_4 */
+					 <0x0c000046>, /* GPIO_1 */
+					 <0x0c1000f0>, /* GPIO_2 */
+					 <0x0c2000af>, /* GPIO_3 */
+					 <0x0c300047>, /* GPIO_4 */
+					 <0x0fe000b0>, /* TRIM_0 */
+					 <0x110000b1>, /* BUCK_CMN_1 */
+					 <0x11400048>, /* SMPS1 */
+					 <0x115000b2>, /* SMPS_1_PS1 */
+					 <0x116000b3>, /* BUCK_FREQ_1 */
+					 <0x11700017>, /* SMPS2 */
+					 <0x11800018>, /* FTPS1_2 */
+					 <0x11900019>, /* BUCK_FREQ_2 */
+					 <0x11a000b4>, /* SMPS3 */
+					 <0x11b000b5>, /* SMPS_3_PS1 */
+					 <0x11c000b6>, /* BUCK_FREQ_3 */
+					 <0x11d000b7>, /* SMPS4 */
+					 <0x11e000b8>, /* SMPS_4_PS1 */
+					 <0x11f000b9>, /* BUCK_FREQ_4 */
+					 <0x140000ba>, /* LDO_1 */
+					 <0x141000bb>, /* LDO_2 */
+					 <0x142000bc>, /* LDO_3 */
+					 <0x143000bd>, /* LDO_4 */
+					 <0x144000be>, /* LDO_5 */
+					 <0x145000bf>, /* LDO_6 */
+					 <0x146000c0>, /* LDO_7 */
+					 <0x147000c1>, /* LDO_8 */
+					 <0x148000c2>, /* LDO_9 */
+					 <0x149000c3>, /* LDO_10 */
+					 <0x14a000c4>, /* LDO_11 */
+					 <0x14b000c5>, /* LDO_12 */
+					 <0x14c000c6>, /* LDO_13 */
+					 <0x14d000c7>, /* LDO_14 */
+					 <0x14e000c8>, /* LDO_15 */
+					 <0x14f000c9>, /* LDO_16 */
+					 <0x150000ca>, /* LDO_17 */
+					 <0x151000cb>, /* LDO_18 */
+					 <0x152000cc>, /* LDO_19 */
+					 <0x153000cd>, /* LDO_20 */
+					 <0x154000ce>, /* LDO_21 */
+					 <0x155000cf>; /* LDO_22 */
+	};
+
+};
+
+&gdsc_vfe {
+	status = "ok";
+};
+
+&gdsc_oxili_cx {
+	status = "ok";
+};
+
+&lpass_iommu {
+	status = "ok";
+};
+
+&copss_iommu {
+	status = "ok";
+};
+
+&mdpe_iommu {
+	status = "ok";
+};
+
+&mdps_iommu {
+	status = "ok";
+};
+
+&gfx_iommu {
+	status = "ok";
+};
+
+&vfe_iommu {
+	status = "ok";
 };
 
 /include/ "msm8910-regulator.dtsi"
+/include/ "msm-pm8110.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..979876d 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 {
@@ -42,7 +42,6 @@
 			atmel,panel-coords = <0  0 760 1424>;
 			atmel,display-coords = <0 0 720 1280>;
 			atmel,i2c-pull-up;
-			atmel,no-force-update;
 			atmel,cfg_1 {
 				atmel,family-id = <0x82>;
 				atmel,variant-id = <0x19>;
@@ -156,40 +155,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>;
 	};
 };
 
@@ -267,6 +233,44 @@
 	wp-gpios = <&pm8941_gpios 29 0x1>;
 };
 
+&usb3 {
+	qcom,otg-capability;
+};
+
+&pm8941_chg {
+	status = "ok";
+
+	qcom,chg-charging-disabled;
+
+	qcom,chg-chgr@1000 {
+		status = "ok";
+	};
+
+	qcom,chg-buck@1100 {
+		status = "ok";
+	};
+
+	qcom,chg-bat-if@1200 {
+		status = "ok";
+	};
+
+	qcom,chg-usb-chgpth@1300 {
+		status = "ok";
+	};
+
+	qcom,chg-dc-chgpth@1400 {
+		status = "ok";
+	};
+
+	qcom,chg-boost@1500 {
+		status = "ok";
+	};
+
+	qcom,chg-misc@1600 {
+		status = "ok";
+	};
+};
+
 &pm8941_gpios {
 	gpio@c000 { /* GPIO 1 */
 	};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index cf45ceb..6a35f2f 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -42,7 +42,6 @@
 			atmel,panel-coords = <0  0 760 1424>;
 			atmel,display-coords = <0 0 720 1280>;
 			atmel,i2c-pull-up;
-			atmel,no-force-update;
 			atmel,cfg_1 {
 				atmel,family-id = <0x82>;
 				atmel,variant-id = <0x19>;
@@ -172,40 +171,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>;
 	};
 };
 
@@ -286,6 +252,44 @@
 	cd-gpios = <&msmgpio 62 0x1>;
 };
 
+&usb3 {
+	qcom,otg-capability;
+};
+
+&pm8941_chg {
+	status = "ok";
+
+	qcom,chg-charging-disabled;
+
+	qcom,chg-chgr@1000 {
+		status = "ok";
+	};
+
+	qcom,chg-buck@1100 {
+		status = "ok";
+	};
+
+	qcom,chg-bat-if@1200 {
+		status = "ok";
+	};
+
+	qcom,chg-usb-chgpth@1300 {
+		status = "ok";
+	};
+
+	qcom,chg-dc-chgpth@1400 {
+		status = "ok";
+	};
+
+	qcom,chg-boost@1500 {
+		status = "ok";
+	};
+
+	qcom,chg-misc@1600 {
+		status = "ok";
+	};
+};
+
 &pm8941_gpios {
 	gpio@c000 { /* GPIO 1 */
 	};
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 6623568..480a034 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -36,8 +36,8 @@
 		qcom,msm-bus,num-paths = <2>;
 		qcom,msm-bus,vectors-KBps =
 				<26 512 0 0>, <89 604 0 0>,
-				<26 512 0 2000000>, <89 604 0 3000000>,
-				<26 512 0 4000000>, <89 604 0 5000000>,
+				<26 512 0 1600000>, <89 604 0 3000000>,
+				<26 512 0 4000000>, <89 604 0 4500000>,
 				<26 512 0 6400000>, <89 604 0 7600000>;
 
 		/* GDSC oxili regulators */
@@ -108,7 +108,7 @@
 			qcom,algo-ss-win-size-min-us = <1000000>;
 			qcom,algo-ss-win-size-max-us = <1000000>;
 			qcom,algo-ss-util-pct = <95>;
-			qcom,algo-ss-iobusy-conv = <100>;
+			qcom,algo-ss-no-corr-below-freq = <0>;
 
 			qcom,energy-active-coeff-a = <2492>;
 			qcom,energy-active-coeff-b = <0>;
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..9238a1b 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 {
@@ -121,7 +121,6 @@
 			atmel,panel-coords = <0 0 1080 1920>;
 			atmel,display-coords = <0 0 1080 1920>;
 			atmel,i2c-pull-up;
-			atmel,no-force-update;
 			atmel,cfg_1 {
 				atmel,family-id = <0xa2>;
 				atmel,variant-id = <0x00>;
@@ -214,9 +213,64 @@
 
 	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 BIAS3 External",
+			"MIC BIAS1 External", "Digital Mic1",
+			"DMIC2", "MIC BIAS3 External",
+			"MIC BIAS1 External", "Digital Mic2",
+			"DMIC3", "MIC BIAS2 External",
+			"MIC BIAS3 External", "Digital Mic3",
+			"DMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic4",
+			"DMIC5", "MIC BIAS2 External",
+			"MIC BIAS4 External", "Digital Mic5",
+			"DMIC6", "MIC BIAS2 External",
+			"MIC BIAS4 External", "Digital Mic6";
+
 		qcom,ext-spk-amp-supply = <&ext_5v>;
 		qcom,ext-spk-amp-gpio = <&pm8841_mpps 1 0>;
 	};
+
+	hsic_hub {
+		compatible = "qcom,hsic-smsc-hub";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
+		smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
+		smsc,int-gpio = <&msmgpio 50 0x00>;
+		hub_int-supply = <&pm8941_l10>;
+		hub_vbus-supply = <&ext_5v>;
+
+		hsic@f9a00000 {
+			compatible = "qcom,hsic-host";
+			reg = <0xf9a00000 0x400>;
+			interrupts = <0 136 0>;
+			interrupt-names = "core_irq";
+			HSIC_VDDCX-supply = <&pm8841_s2>;
+			HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+			hsic,strobe-gpio = <&msmgpio 144 0x00>;
+			hsic,data-gpio = <&msmgpio 145 0x00>;
+			hsic,ignore-cal-pad-config;
+			hsic,strobe-pad-offset = <0x2050>;
+			hsic,data-pad-offset = <0x2054>;
+		};
+	};
 };
 
 &usb3 {
@@ -266,6 +320,11 @@
 	};
 
 	gpio@c700 { /* GPIO 8 */
+		/* HSIC_HUB-RESET */
+		qcom,mode = <1>;		/* DIG_OUT */
+		qcom,pull = <5>;		/* PULL_NO */
+		qcom,out-strength = <2>;	/* STRENGTH_MED */
+		qcom,master-en = <1>;
 	};
 
 	gpio@c800 { /* GPIO 9 */
@@ -313,6 +372,14 @@
 	};
 
 	gpio@cf00 { /* GPIO 16 */
+		/* HSIC_HUB-INT_N */
+		qcom,mode = <1>;
+		qcom,output-type = <0>;
+		qcom,pull = <5>;
+		qcom,vin-sel = <2>;
+		qcom,out-strength = <3>;
+		qcom,src-sel = <2>;
+		qcom,master-en = <1>;
 	};
 
 	gpio@d000 { /* GPIO 17 */
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 8563996..9fb7d0e 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -42,7 +42,6 @@
 			atmel,panel-coords = <0  0 760 1424>;
 			atmel,display-coords = <0 0 720 1280>;
 			atmel,i2c-pull-up;
-			atmel,no-force-update;
 			atmel,cfg_1 {
 				atmel,family-id = <0x82>;
 				atmel,variant-id = <0x19>;
@@ -156,40 +155,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-pm.dtsi b/arch/arm/boot/dts/msm8974-pm.dtsi
index 52f2a41..b8a977b 100644
--- a/arch/arm/boot/dts/msm8974-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-pm.dtsi
@@ -143,6 +143,7 @@
 			qcom,type = <0x62706d73>;	/* "smpb" */
 			qcom,id = <0x02>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
+			qcom,init-value = <5>;		/* Super Turbo */
 		};
 
 		qcom,lpm-resources@1 {
@@ -152,6 +153,7 @@
 			qcom,type = <0x62706d73>;	/* "smpb" */
 			qcom,id = <0x01>;
 			qcom,key = <0x7675>;		/* "uv" */
+			qcom,init-value = <1050000>;	/* Super Turbo */
 		};
 
 		qcom,lpm-resources@2 {
@@ -161,12 +163,14 @@
 			qcom,type = <0x306b6c63>;	/* "clk0" */
 			qcom,id = <0x00>;
 			qcom,key = <0x62616e45>;	/* "Enab" */
+			qcom,init-value = <1>;		/* On */
 		};
 
 		qcom,lpm-resources@3 {
 			reg = <0x3>;
 			qcom,name = "l2";
 			qcom,resource-type = <1>;
+			qcom,init-value = <2>;		/* Retention */
 		};
 	};
 
@@ -184,10 +188,10 @@
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
 			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
-			qcom,latency-us = <100>;
-			qcom,ss-power = <650>;
-			qcom,energy-overhead = <801>;
-			qcom,time-overhead = <200>;
+			qcom,latency-us = <1>;
+			qcom,ss-power = <784>;
+			qcom,energy-overhead = <190000>;
+			qcom,time-overhead = <100>;
 		};
 
 		qcom,lpm-level@1 {
@@ -199,10 +203,10 @@
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
 			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
-			qcom,latency-us = <1500>;
-			qcom,ss-power = <200>;
-			qcom,energy-overhead = <576000>;
-			qcom,time-overhead = <2000>;
+			qcom,latency-us = <75>;
+			qcom,ss-power = <735>;
+			qcom,energy-overhead = <77341>;
+			qcom,time-overhead = <105>;
 		};
 
 
@@ -215,10 +219,10 @@
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
 			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
-			qcom,latency-us = <2000>;
-			qcom,ss-power = <200>;
-			qcom,energy-overhead = <576000>;
-			qcom,time-overhead = <2000>;
+			qcom,latency-us = <95>;
+			qcom,ss-power = <725>;
+			qcom,energy-overhead = <99500>;
+			qcom,time-overhead = <130>;
 		};
 
 		qcom,lpm-level@3 {
@@ -230,10 +234,10 @@
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
 			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
-			qcom,latency-us = <8500>;
-			qcom,ss-power = <51>;
-			qcom,energy-overhead = <1122000>;
-			qcom,time-overhead = <8500>;
+			qcom,latency-us = <2000>;
+			qcom,ss-power = <138>;
+			qcom,energy-overhead = <1208400>;
+			qcom,time-overhead = <3200>;
 		};
 
 		qcom,lpm-level@4 {
@@ -241,33 +245,18 @@
 			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
 			qcom,xo = <1>;          /* ON */
 			qcom,l2 = <0>;          /* OFF */
-			qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
-			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
-			qcom,vdd-dig-upper-bound = <5>; /* MAX */
-			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
-			qcom,latency-us = <9000>;
-			qcom,ss-power = <51>;
-			qcom,energy-overhead = <1130300>;
-			qcom,time-overhead = <9000>;
-		};
-
-		qcom,lpm-level@5 {
-			reg = <0x5>;
-			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
-			qcom,xo = <1>;          /* ON */
-			qcom,l2 = <0>;          /* OFF */
 			qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
 			qcom,vdd-dig-upper-bound = <3>;  /* ACTIVE */
 			qcom,vdd-dig-lower-bound = <2>;  /* RETENTION HIGH */
-			qcom,latency-us = <10000>;
-			qcom,ss-power = <51>;
-			qcom,energy-overhead = <1130300>;
-			qcom,time-overhead = <10000>;
+			qcom,latency-us = <3000>;
+			qcom,ss-power = <110>;
+			qcom,energy-overhead = <1250300>;
+			qcom,time-overhead = <3500>;
 		};
 
-		qcom,lpm-level@6 {
-			reg = <0x6>;
+		qcom,lpm-level@5 {
+			reg = <0x5>;
 			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
 			qcom,xo = <0>;          /* OFF */
 			qcom,l2 = <1>;          /* GDHS */
@@ -275,14 +264,14 @@
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
 			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
-			qcom,latency-us = <12000>;
-			qcom,ss-power = <14>;
-			qcom,energy-overhead = <2205900>;
-			qcom,time-overhead = <12000>;
+			qcom,latency-us = <3000>;
+			qcom,ss-power = <68>;
+			qcom,energy-overhead = <1350200>;
+			qcom,time-overhead = <4000>;
 		};
 
-		qcom,lpm-level@7 {
-			reg = <0x7>;
+		qcom,lpm-level@6 {
+			reg = <0x6>;
 			qcom,mode = <3>;        /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
 			qcom,xo = <0>;          /* OFF */
 			qcom,l2 = <0>;          /* OFF */
@@ -290,14 +279,14 @@
 			qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
 			qcom,vdd-dig-upper-bound = <5>; /* MAX */
 			qcom,vdd-dig-lower-bound = <3>;  /* ACTIVE */
-			qcom,latency-us = <18000>;
-			qcom,ss-power = <12>;
-			qcom,energy-overhead = <2364250>;
-			qcom,time-overhead = <18000>;
+			qcom,latency-us = <10300>;
+			qcom,ss-power = <63>;
+			qcom,energy-overhead = <2128000>;
+			qcom,time-overhead = <18200>;
 		};
 
-		qcom,lpm-level@8 {
-			reg = <0x8>;
+		qcom,lpm-level@7 {
+			reg = <0x7>;
 			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
 			qcom,xo = <0>;          /* OFF */
 			qcom,l2 = <0>;          /* OFF */
@@ -305,14 +294,14 @@
 			qcom,vdd-mem-lower-bound = <750000>;  /* RETENTION HIGH */
 			qcom,vdd-dig-upper-bound = <3>;  /* ACTIVE */
 			qcom,vdd-dig-lower-bound = <2>;  /* RETIONTION HIGH */
-			qcom,latency-us = <23500>;
+			qcom,latency-us = <18000>;
 			qcom,ss-power = <10>;
-			qcom,energy-overhead = <2667000>;
-			qcom,time-overhead = <23500>;
+			qcom,energy-overhead = <3202600>;
+			qcom,time-overhead = <27000>;
 		};
 
-		qcom,lpm-level@9 {
-			reg = <0x9>;
+		qcom,lpm-level@8 {
+			reg = <0x8>;
 			qcom,mode= <3>;         /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
 			qcom,xo = <0>;          /* OFF */
 			qcom,l2 = <0>;          /* OFF */
@@ -320,10 +309,10 @@
 			qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
 			qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
 			qcom,vdd-dig-lower-bound = <0>; /* RETENTION LOW */
-			qcom,latency-us = <29700>;
-			qcom,ss-power = <5>;
-			qcom,energy-overhead = <2867000>;
-			qcom,time-overhead = <30000>;
+			qcom,latency-us = <20000>;
+			qcom,ss-power = <2>;
+			qcom,energy-overhead = <4252000>;
+			qcom,time-overhead = <32000>;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 3f7e9de..a7a7c88 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -108,9 +108,9 @@
 	rpm-regulator-smpb4 {
 		status = "okay";
 		pm8841_s4: regulator-s4 {
-			regulator-min-microvolt = <900000>;
+			regulator-min-microvolt = <815000>;
 			regulator-max-microvolt = <900000>;
-			qcom,init-voltage = <900000>;
+			qcom,init-voltage = <815000>;
 			status = "okay";
 		};
 	};
@@ -121,9 +121,6 @@
 			regulator-min-microvolt = <1300000>;
 			regulator-max-microvolt = <1300000>;
 			qcom,init-voltage = <1300000>;
-			qcom,init-current = <100>;
-			qcom,system-load = <100000>;
-			regulator-always-on;
 			status = "okay";
 		};
 	};
@@ -136,14 +133,6 @@
 			qcom,init-voltage = <2150000>;
 			status = "okay";
 		};
-		pm8941_s2_ao: regulator-s2-ao {
-			regulator-name = "8941_s2_ao";
-			qcom,set = <1>;
-			regulator-min-microvolt = <2150000>;
-			regulator-max-microvolt = <2150000>;
-			status = "okay";
-			compatible = "qcom,rpm-regulator-smd";
-		};
 	};
 
 	rpm-regulator-smpa3 {
@@ -152,9 +141,6 @@
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,init-voltage = <1800000>;
-			qcom,init-current = <100>;
-			qcom,system-load = <100000>;
-			regulator-always-on;
 			status = "okay";
 		};
 	};
@@ -162,13 +148,9 @@
 	rpm-regulator-ldoa1 {
 		status = "okay";
 		pm8941_l1: regulator-l1 {
-			parent-supply = <&pm8941_s1>;
 			regulator-min-microvolt = <1225000>;
 			regulator-max-microvolt = <1225000>;
 			qcom,init-voltage = <1225000>;
-			qcom,init-current = <10>;
-			qcom,system-load = <10000>;
-			regulator-always-on;
 			status = "okay";
 		};
 	};
@@ -176,7 +158,6 @@
 	rpm-regulator-ldoa2 {
 		status = "okay";
 		pm8941_l2: regulator-l2 {
-			parent-supply = <&pm8941_s3>;
 			regulator-min-microvolt = <1200000>;
 			regulator-max-microvolt = <1200000>;
 			qcom,init-voltage = <1200000>;
@@ -187,7 +168,6 @@
 	rpm-regulator-ldoa3 {
 		status = "okay";
 		pm8941_l3: regulator-l3 {
-			parent-supply = <&pm8941_s1>;
 			regulator-min-microvolt = <1225000>;
 			regulator-max-microvolt = <1225000>;
 			qcom,init-voltage = <1225000>;
@@ -198,7 +178,6 @@
 	rpm-regulator-ldoa4 {
 		status = "okay";
 		pm8941_l4: regulator-l4 {
-			parent-supply = <&pm8941_s1>;
 			regulator-min-microvolt = <1225000>;
 			regulator-max-microvolt = <1225000>;
 			qcom,init-voltage = <1225000>;
@@ -209,7 +188,6 @@
 	rpm-regulator-ldoa5 {
 		status = "okay";
 		pm8941_l5: regulator-l5 {
-			parent-supply = <&pm8941_s2>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,init-voltage = <1800000>;
@@ -220,7 +198,6 @@
 	rpm-regulator-ldoa6 {
 		status = "okay";
 		pm8941_l6: regulator-l6 {
-			parent-supply = <&pm8941_s2>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,init-voltage = <1800000>;
@@ -231,7 +208,6 @@
 	rpm-regulator-ldoa7 {
 		status = "okay";
 		pm8941_l7: regulator-l7 {
-			parent-supply = <&pm8941_s2>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,init-voltage = <1800000>;
@@ -272,7 +248,6 @@
 	rpm-regulator-ldoa11 {
 		status = "okay";
 		pm8941_l11: regulator-l11 {
-			parent-supply = <&pm8941_s1>;
 			regulator-min-microvolt = <1300000>;
 			regulator-max-microvolt = <1300000>;
 			qcom,init-voltage = <1300000>;
@@ -283,14 +258,12 @@
 	rpm-regulator-ldoa12 {
 		status = "okay";
 		pm8941_l12: regulator-l12 {
-			parent-supply = <&pm8941_s2>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			status = "okay";
 		};
 		pm8941_l12_ao: regulator-l12-ao {
 			regulator-name = "8941_l12_ao";
-			parent-supply = <&pm8941_s2_ao>;
 			qcom,set = <1>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
@@ -312,7 +285,6 @@
 	rpm-regulator-ldoa14 {
 		status = "okay";
 		pm8941_l14: regulator-l14 {
-			parent-supply = <&pm8941_s2>;
 			regulator-min-microvolt = <1800000>;
 			regulator-max-microvolt = <1800000>;
 			qcom,init-voltage = <1800000>;
@@ -323,7 +295,6 @@
 	rpm-regulator-ldoa15 {
 		status = "okay";
 		pm8941_l15: regulator-l15 {
-			parent-supply = <&pm8941_s2>;
 			regulator-min-microvolt = <2050000>;
 			regulator-max-microvolt = <2050000>;
 			qcom,init-voltage = <2050000>;
@@ -424,7 +395,6 @@
 	rpm-regulator-vsa1 {
 		status = "okay";
 		pm8941_lvs1: regulator-lvs1 {
-			parent-supply = <&pm8941_s3>;
 			status = "okay";
 		};
 	};
@@ -432,7 +402,6 @@
 	rpm-regulator-vsa2 {
 		status = "okay";
 		pm8941_lvs2: regulator-lvs2 {
-			parent-supply = <&pm8941_s3>;
 			status = "okay";
 		};
 	};
@@ -440,7 +409,6 @@
 	rpm-regulator-vsa3 {
 		status = "okay";
 		pm8941_lvs3: regulator-lvs3 {
-			parent-supply = <&pm8941_s3>;
 			status = "okay";
 		};
 	};
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..9dff62f 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -40,6 +40,7 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
+		interrupts = <0 208 0>;
 	};
 
 	wcd9xxx_intc: wcd9xxx-irq {
@@ -52,7 +53,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 +152,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>;
 	};
 
@@ -187,8 +189,6 @@
 		qcom,vdd-voltage-level = <2950000 2950000>;
 		qcom,vdd-current-level = <9000 800000>;
 
-		qcom,vdd-io-always-on;
-		qcom,vdd-io-lpm-sup;
 		qcom,vdd-io-voltage-level = <1800000 2950000>;
 		qcom,vdd-io-current-level = <6 22000>;
 
@@ -197,7 +197,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 +205,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 +245,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 +291,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";
 	};
 
@@ -403,7 +406,7 @@
 			qcom,cdc-micbias2-cfilt-sel = <0x1>;
 			qcom,cdc-micbias3-cfilt-sel = <0x2>;
 			qcom,cdc-micbias4-cfilt-sel = <0x2>;
-
+			qcom,cdc-mclk-clk-rate = <9600000>;
 			qcom,cdc-slim-ifd = "taiko-slim-ifd";
 			qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
 		};
@@ -416,10 +419,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",
@@ -648,16 +647,11 @@
 		krait1_dig-supply = <&pm8841_s2_corner_ao>;
 		krait2_dig-supply = <&pm8841_s2_corner_ao>;
 		krait3_dig-supply = <&pm8841_s2_corner_ao>;
-		krait0_hfpll_a-supply = <&pm8941_s2_ao>;
-		krait1_hfpll_a-supply = <&pm8941_s2_ao>;
-		krait2_hfpll_a-supply = <&pm8941_s2_ao>;
-		krait3_hfpll_a-supply = <&pm8941_s2_ao>;
-		l2_hfpll_a-supply = <&pm8941_s2_ao>;
-		krait0_hfpll_b-supply = <&pm8941_l12_ao>;
-		krait1_hfpll_b-supply = <&pm8941_l12_ao>;
-		krait2_hfpll_b-supply = <&pm8941_l12_ao>;
-		krait3_hfpll_b-supply = <&pm8941_l12_ao>;
-		l2_hfpll_b-supply = <&pm8941_l12_ao>;
+		krait0_hfpll-supply = <&pm8941_l12_ao>;
+		krait1_hfpll-supply = <&pm8941_l12_ao>;
+		krait2_hfpll-supply = <&pm8941_l12_ao>;
+		krait3_hfpll-supply = <&pm8941_l12_ao>;
+		l2_hfpll-supply = <&pm8941_l12_ao>;
 	};
 
 	usb3: qcom,ssusb@f9200000 {
@@ -825,6 +819,16 @@
 			compatible = "qcom,msm-dai-q6-dev";
 			qcom,msm-dai-q6-dev-id = <240>;
 		};
+
+		qcom,msm-dai-q6-incall-record-rx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32771>;
+		};
+
+		qcom,msm-dai-q6-incall-record-tx {
+			compatible = "qcom,msm-dai-q6-dev";
+			qcom,msm-dai-q6-dev-id = <32772>;
+		};
 	};
 
 	qcom,msm-auxpcm {
@@ -849,6 +853,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";
 	};
@@ -864,6 +878,14 @@
 			<11 604 32506 32506>;
 	};
 
+	qcom,msm-adsp-sensors {
+		compatible = "qcom,msm-adsp-sensors";
+		qcom,src-id = <11>;
+		qcom,dst-id = <604>;
+		qcom,ab = <32505856>;
+		qcom,ib = <32505856>;
+	};
+
 	qcom,mss@fc880000 {
 		compatible = "qcom,pil-q6v5-mss";
 		reg = <0xfc880000 0x100>,
@@ -876,6 +898,7 @@
 
 		interrupts = <0 24 1>;
 		vdd_mss-supply = <&pm8841_s3>;
+		vdd_mx-supply = <&pm8841_s1>;
 
 		qcom,is-loadable;
 		qcom,firmware-name = "mba";
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 2839864..71fcfd6 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -42,6 +42,7 @@
 			qcom,type = <0x616F646C>;       /* "ldoa" */
 			qcom,id = <0x0A>;
 			qcom,key = <0x6e726f63>;	/* "corn" */
+			qcom,init-value = <5>;		/* Super Turbo */
 		};
 
 		qcom,lpm-resources@1 {
@@ -51,6 +52,7 @@
 			qcom,type = <0x616F646C>;       /* "ldoa" */
 			qcom,id = <0x0C>;
 			qcom,key =  <0x7675>;		/* "uv" */
+			qcom,init-value = <1050000>;	/* Super Turbo */
 		};
 
 		qcom,lpm-resources@2 {
@@ -60,6 +62,7 @@
 			qcom,type = <0x306b6c63>;	/* "clk0" */
 			qcom,id = <0x00>;
 			qcom,key = <0x62616e45>;	/* "Enab" */
+			qcom,init-value = <1>;		/* On */
 		};
 	};
 
@@ -174,7 +177,8 @@
 		qcom,ipc-bit-offset = <1>;
 
 		qcom,gic-parent = <&intc>;
-		qcom,gic-map = <41 172>, /* usb2_hsic_async_wakeup_irq */
+		qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<0xff 208>; /* summary_irq_kpss */
 
 		qcom,gpio-parent = <&msmgpio>;
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d1c731e..ddba4c3 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -42,10 +42,11 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
+		interrupts = <0 208 0>;
 	};
 
 	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;
@@ -416,6 +417,7 @@
 			qcom,cdc-micbias2-cfilt-sel = <0x1>;
 			qcom,cdc-micbias3-cfilt-sel = <0x2>;
 			qcom,cdc-micbias4-cfilt-sel = <0x2>;
+			qcom,cdc-mclk-clk-rate = <12288000>;
 		};
 
 		wcd9xxx_codec@77{
@@ -523,6 +525,57 @@
 		compatible = "qcom,pil-q6v5-mss";
 		interrupts = <0 24 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-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			qcom,irq-no-suspend;
+		};
+	};
 };
 
 /include/ "msm-pm8019-rpm-regulator.dtsi"
@@ -530,9 +583,9 @@
 /include/ "msm9625-regulator.dtsi"
 
 &pm8019_vadc {
-	chan@49 {
+	chan@31 {
 		label = "batt_id_therm";
-		qcom,channel-num = <49>;
+		reg = <0x31>;
 		qcom,decimation = <0>;
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
@@ -541,9 +594,9 @@
 		qcom,fast-avg-setup = <0>;
 	};
 
-	chan@51 {
+	chan@33 {
 		label = "pa_therm1";
-		qcom,channel-num = <51>;
+		reg = <0x33>;
 		qcom,decimation = <0>;
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
@@ -552,9 +605,9 @@
 		qcom,fast-avg-setup = <0>;
 	};
 
-	chan@52 {
+	chan@34 {
 		label = "pa_therm2";
-		qcom,channel-num = <52>;
+		reg = <0x34>;
 		qcom,decimation = <0>;
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
@@ -563,9 +616,9 @@
 		qcom,fast-avg-setup = <0>;
 	};
 
-	chan@50 {
+	chan@32 {
 		label = "xo_therm";
-		qcom,channel-num = <50>;
+		reg = <0x32>;
 		qcom,decimation = <0>;
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
@@ -574,9 +627,9 @@
 		qcom,fast-avg-setup = <0>;
 	};
 
-	chan@60 {
+	chan@3c {
 		label = "xo_therm_amux";
-		qcom,channel-num = <60>;
+		reg = <0x3c>;
 		qcom,decimation = <0>;
 		qcom,pre-div-channel-scaling = <0>;
 		qcom,calibration-type = "ratiometric";
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 1dc853b..8a7928b 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -37,6 +37,8 @@
 # CONFIG_MSM_HW3D is not set
 # CONFIG_QSD_AUDIO is not set
 # CONFIG_SURF_FFA_GPIO_KEYPAD is not set
+CONFIG_MSM_SMCMOD=m
+CONFIG_MSM_SCM=y
 CONFIG_MSM_WATCHDOG=y
 CONFIG_MSM_RPC_PMIC=y
 CONFIG_MSM_RPC_USB=y
@@ -142,6 +144,8 @@
 # CONFIG_MFD_PM8XXX_MISC is not set
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_PM8058_XO=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
 # CONFIG_USB_SUPPORT is not set
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index 203d3b7..db2f25d 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -36,6 +36,8 @@
 # CONFIG_MSM_HW3D is not set
 # CONFIG_QSD_AUDIO is not set
 # CONFIG_SURF_FFA_GPIO_KEYPAD is not set
+CONFIG_MSM_SMCMOD=m
+CONFIG_MSM_SCM=y
 CONFIG_MSM_WATCHDOG=y
 CONFIG_MSM_RPC_PMIC=y
 CONFIG_MSM_RPC_USB=y
@@ -141,6 +143,8 @@
 # CONFIG_MFD_PM8XXX_MISC is not set
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_PM8058_XO=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
 # CONFIG_USB_SUPPORT is not set
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index d403cec..27c10d0 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -376,7 +376,7 @@
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_SHIRQ=y
 CONFIG_LOCKUP_DETECTOR=y
-# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index 0e066d9..5964afb 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -369,7 +369,6 @@
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_LOCKUP_DETECTOR=y
-# CONFIG_SCHED_DEBUG is not set
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_SLAB=y
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
index 2dd4b30..28d8f61 100644
--- a/arch/arm/configs/msm8910_defconfig
+++ b/arch/arm/configs/msm8910_defconfig
@@ -47,6 +47,7 @@
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
+CONFIG_SCHED_MC=y
 CONFIG_ARM_ARCH_TIMER=y
 CONFIG_HOTPLUG_CPU=y
 CONFIG_PREEMPT=y
@@ -99,6 +100,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 +129,9 @@
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
@@ -132,6 +139,7 @@
 CONFIG_ANDROID_RAM_CONSOLE=y
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_IOMMU=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
@@ -146,7 +154,7 @@
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index d5e15f1..e5fd0d5 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -100,6 +100,7 @@
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 # CONFIG_SMP_ON_UP is not set
+CONFIG_SCHED_MC=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
@@ -242,6 +243,7 @@
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
 CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_TSPP=m
@@ -466,6 +468,7 @@
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_IOMMU=y
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 386f311..f9d7800 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -105,6 +105,7 @@
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 # CONFIG_SMP_ON_UP is not set
+CONFIG_SCHED_MC=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
@@ -247,6 +248,7 @@
 CONFIG_RFKILL=y
 CONFIG_GENLOCK=y
 CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_CMA=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_TSPP=m
@@ -494,7 +496,7 @@
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_LOCKUP_DETECTOR=y
-# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index f468fe0..263160d 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
@@ -66,6 +67,8 @@
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
 CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_CACHE_ERP=y
 CONFIG_MSM_L1_ERR_PANIC=y
 CONFIG_MSM_L1_ERR_LOG=y
@@ -76,6 +79,7 @@
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 # CONFIG_SMP_ON_UP is not set
+CONFIG_SCHED_MC=y
 CONFIG_ARM_ARCH_TIMER=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
@@ -219,6 +223,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_TI_DRV2667=y
 CONFIG_QSEECOM=y
+CONFIG_USB_HSIC_SMSC_HUB=y
 CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -247,6 +252,7 @@
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_XPAD=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_INPUT_MISC=y
@@ -281,7 +287,9 @@
 CONFIG_SENSORS_QPNP_ADC_CURRENT=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
 CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_WCD9320_CODEC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_STUB=y
@@ -296,6 +304,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
@@ -329,6 +339,9 @@
 CONFIG_SND_SOC_MSM8974=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_MSM_HSIC=y
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
@@ -355,6 +368,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..00e4c8a 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
@@ -65,6 +66,8 @@
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
 CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
 CONFIG_MSM_CACHE_ERP=y
 CONFIG_MSM_L1_ERR_PANIC=y
 CONFIG_MSM_L1_ERR_LOG=y
@@ -78,6 +81,7 @@
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 # CONFIG_SMP_ON_UP is not set
+CONFIG_SCHED_MC=y
 CONFIG_ARM_ARCH_TIMER=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
@@ -221,6 +225,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_TI_DRV2667=y
 CONFIG_QSEECOM=y
+CONFIG_USB_HSIC_SMSC_HUB=y
 CONFIG_SCSI=y
 CONFIG_SCSI_TGT=y
 CONFIG_BLK_DEV_SD=y
@@ -249,6 +254,7 @@
 CONFIG_INPUT_EVBUG=m
 CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_XPAD=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_INPUT_MISC=y
@@ -283,9 +289,11 @@
 CONFIG_SENSORS_QPNP_ADC_CURRENT=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONTIOR=y
 CONFIG_THERMAL_QPNP=y
 CONFIG_WCD9320_CODEC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_REGULATOR_QPNP=y
 CONFIG_MEDIA_SUPPORT=y
@@ -298,6 +306,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
@@ -331,6 +341,9 @@
 CONFIG_SND_SOC_MSM8974=y
 CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_MSM_HSIC=y
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
@@ -357,6 +370,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
@@ -400,7 +415,7 @@
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_LOCKUP_DETECTOR=y
 # CONFIG_DETECT_HUNG_TASK is not set
-# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_KMEMLEAK=y
 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index a052609..06ec01a 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -275,7 +275,7 @@
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 1a8bbfc..a81b8a3 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
@@ -184,7 +185,7 @@
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
-# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/include/asm/smcmod.h b/arch/arm/include/asm/smcmod.h
new file mode 100644
index 0000000..06918c4
--- /dev/null
+++ b/arch/arm/include/asm/smcmod.h
@@ -0,0 +1,123 @@
+/* Qualcomm SMC Module API */
+
+#ifndef __SMCMOD_H_
+#define __SMCMOD_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define SMCMOD_DEV "smcmod"
+
+#define SMCMOD_REG_REQ_MAX_ARGS	2
+
+/**
+ * struct smcmod_reg_req - for SMC register ioctl request
+ *
+ * @service_id - requested service.
+ * @command_id - requested command.
+ * @num_args - number of arguments.
+ * @args - argument(s) to be passed to the secure world.
+ * @return_val - return value from secure world operation.
+ */
+struct smcmod_reg_req {
+	uint32_t service_id; /* in */
+	uint32_t command_id; /* in */
+	uint8_t  num_args; /* in */
+	uint32_t args[SMCMOD_REG_REQ_MAX_ARGS]; /* in */
+	uint32_t return_val; /* out */
+};
+
+/**
+ * struct smcmod_buf_req - for SMC buffer ioctl request
+ *
+ * @service_id - requested service.
+ * @command_id - requested command.
+ * @ion_cmd_fd - fd obtained from ION_IOC_MAP or ION_IOC_SHARE.
+ * @cmd_len - length of command data buffer in bytes.
+ * @ion_resp_fd - fd obtained from ION_IOC_MAP or ION_IOC_SHARE.
+ * @resp_len - length of response data buffer in bytes.
+ * @return_val - return value from secure world operation.
+ */
+struct smcmod_buf_req {
+	uint32_t service_id;/* in */
+	uint32_t command_id; /* in */
+	int32_t ion_cmd_fd; /* in */
+	uint32_t cmd_len; /* in */
+	int32_t ion_resp_fd; /* in */
+	uint32_t resp_len; /* in */
+	uint32_t return_val; /* out */
+};
+
+/**
+ * struct smcmod_cipher_req - for SMC cipher command ioctl
+ *
+ * @algorithm - specifies the cipher algorithm.
+ * @operation - specifies encryption or decryption.
+ * @mode - specifies cipher mode.
+ * @ion_key_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE.
+ * @key_size - key size in bytes.
+ * @ion_plain_text_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE.
+ * @plain_text_size - size of plain text in bytes.
+ * @ion_cipher_text_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE.
+ * @cipher_text_size - cipher text size in bytes.
+ * @ion_init_vector_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE.
+ * @init_vector_size - size of initialization vector in bytes.
+ * @key_is_null - indicates that the key is null.
+ * @return_val - return value from secure world opreation.
+ */
+struct smcmod_cipher_req {
+	uint32_t algorithm; /* in */
+	uint32_t operation; /* in */
+	uint32_t mode; /* in */
+	int32_t ion_key_fd; /* in */
+	uint32_t key_size; /* in */
+	int32_t ion_plain_text_fd; /* in (encrypt)/out (decrypt) */
+	uint32_t plain_text_size; /* in */
+	int32_t ion_cipher_text_fd; /* out (encrypt)/in (decrypt) */
+	uint32_t cipher_text_size; /* in */
+	int32_t ion_init_vector_fd; /* in */
+	uint32_t init_vector_size; /* in */
+	uint32_t key_is_null; /* in */
+	uint32_t return_val; /* out */
+};
+
+/**
+ * struct smcmod_msg_digest_req - for message digest command ioctl
+ *
+ * @algorithm - specifies the cipher algorithm.
+ * @ion_key_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE.
+ * @key_size - hash key size in bytes.
+ * @ion_input_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE.
+ * @input_size - input data size in bytes.
+ * @ion_output_fd - fd obtained form ION_IOC_MAP or ION_IOC_SHARE.
+ * @output_size - size of output buffer in bytes.
+ * @fixed_block - indicates whether this is a fixed block digest.
+ * @key_is_null - indicates that the key is null.
+ * @return_val - return value from secure world opreation.
+ */
+struct smcmod_msg_digest_req {
+	uint32_t algorithm; /* in */
+	int32_t ion_key_fd; /* in */
+	uint32_t key_size; /* in */
+	int32_t ion_input_fd; /* in */
+	uint32_t input_size; /* in */
+	int32_t ion_output_fd; /* in/out */
+	uint32_t output_size; /* in */
+	uint32_t fixed_block; /* in */
+	uint32_t key_is_null; /* in */
+	uint32_t return_val; /* out */
+} __packed;
+
+#define SMCMOD_IOC_MAGIC	0x97
+
+/* Number chosen to avoid any conflicts */
+#define SMCMOD_IOCTL_SEND_REG_CMD \
+	_IOWR(SMCMOD_IOC_MAGIC, 32, struct smcmod_reg_req)
+#define SMCMOD_IOCTL_SEND_BUF_CMD \
+	_IOWR(SMCMOD_IOC_MAGIC, 33, struct smcmod_buf_req)
+#define SMCMOD_IOCTL_SEND_CIPHER_CMD \
+	_IOWR(SMCMOD_IOC_MAGIC, 34, struct smcmod_cipher_req)
+#define SMCMOD_IOCTL_SEND_MSG_DIGEST_CMD \
+	_IOWR(SMCMOD_IOC_MAGIC, 35, struct smcmod_msg_digest_req)
+#define SMCMOD_IOCTL_GET_VERSION _IOWR(SMCMOD_IOC_MAGIC, 36, uint32_t)
+#endif /* __SMCMOD_H_ */
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 2464140..d2e2e44 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->free_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 887fcbf..372d0ac 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -67,6 +67,7 @@
 	select MSM_PM2 if PM
 	select HOLES_IN_ZONE if SPARSEMEM
 	select MSM_MODEM_RESTART
+	select ARM_HAS_SG_CHAIN
 
 config ARCH_QSD8X50
 	bool "QSD8X50"
@@ -141,6 +142,7 @@
 	select MSM_PM8X60 if PM
 	select MSM_RUN_QUEUE_STATS
 	select ARM_HAS_SG_CHAIN
+	select USE_DEV_CTRL_VOLUME
 
 config ARCH_MSM8960
 	bool "MSM8960"
@@ -165,7 +167,6 @@
 	select MSM_NATIVE_RESTART
 	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select MSM_REMOTE_SPINLOCK_SFPB
-	select ARCH_SPARSEMEM_ENABLE
 	select ARCH_HAS_HOLES_MEMORYMODEL
 	select CLEANCACHE
 	select QCACHE
@@ -177,10 +178,12 @@
 	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
 	select MSM_USE_USER_ACCESSIBLE_TIMERS
+	select MSM_CPU_PWRCTL
 
 config ARCH_MSM8930
 	bool "MSM8930"
@@ -205,7 +208,6 @@
 	select MSM_NATIVE_RESTART
 	select DONT_MAP_HOLE_AFTER_MEMBANK0
 	select MSM_REMOTE_SPINLOCK_SFPB
-	select ARCH_SPARSEMEM_ENABLE
 	select ARCH_HAS_HOLES_MEMORYMODEL
 	select MSM_ULTRASOUND_A
 	select MULTI_IRQ_HANDLER
@@ -213,10 +215,12 @@
 	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
 	select MSM_USE_USER_ACCESSIBLE_TIMERS
+	select MSM_CPU_PWRCTL
 
 config ARCH_APQ8064
 	bool "APQ8064"
@@ -245,10 +249,12 @@
 	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
 	select MSM_USE_USER_ACCESSIBLE_TIMERS
+	select MSM_CPU_PWRCTL
 
 config ARCH_MSM8974
 	bool "MSM8974"
@@ -280,6 +286,7 @@
 	select MSM_RPM_STATS_LOG
 	select QMI_ENCDEC
 	select DONT_MAP_HOLE_AFTER_MEMBANK0
+	select SENSORS_ADSP
 
 config ARCH_MPQ8092
 	bool "MPQ8092"
@@ -500,7 +507,7 @@
 
 config MSM_MPM_OF
 	bool "Modem Power Manager"
-	depends on CONFIG_OF
+	depends on OF
 	help
 	  MPM is a dedicated hardware resource responsible for entering and
 	  waking up from a system wide low power mode. The MPM driver tracks
@@ -1534,6 +1541,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
@@ -1671,17 +1688,6 @@
 
 endif # CPU_FREQ_MSM
 
-config MSM_CPU_AVS
-	bool "Enable software controlled Adaptive Voltage Scaling (AVS)"
-	depends on (ARCH_MSM_SCORPION && QSD_SVS)
-	depends on ARCH_QSD8X50
-	default n
-	select MSM_AVS_HW
-	help
-	  This enables the s/w control of Adaptive Voltage Scaling feature
-	  in Qualcomm ARMv7 CPUs. It adjusts the voltage for each frequency
-	  based on feedback from three ring oscillators in the CPU.
-
 config MSM_AVS_HW
 	bool "Enable Adaptive Voltage Scaling (AVS)"
 	default n
@@ -1933,6 +1939,16 @@
 	  be used on systems which contain an RPM which communicates with the
 	  application processor over SMD.
 
+config MSM_SMCMOD
+	tristate "Secure Monitor Call (SMC) Module"
+	default n
+	depends on (ARCH_FSM9XXX && ION && ION_MSM && MSM_SCM)
+	help
+	  Enable support for smcmod driver. This driver provides a mechanism
+	  to execute the Secure Monitor Call (SMC) to switch from non-secure
+	  to secure execution in the fsm9xxx targets. This module utilizes Ion
+	  for buffer management.
+
 config MSM_SUBSYSTEM_RESTART
 	bool "MSM Subsystem Restart"
 	help
@@ -2087,7 +2103,7 @@
 
 config MSM_BUSPM_DEV
 	tristate "MSM Bus Performance Monitor Kernel Module"
-	depends on (ARCH_MSM8X60 || ARCH_MSM8960)
+	depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM8974)
 	default m
 	help
 	  This kernel module is used to mmap() hardware registers for the
@@ -2240,7 +2256,7 @@
 
 config MSM_RUN_QUEUE_STATS
 	bool "Enable collection and exporting of MSM Run Queue stats to userspace"
-	depends on (MSM_SOC_REV_A || ARCH_MSM8X60 || ARCH_MSM8960)
+	default n
 	help
 	 This option enalbes statistics collection on Run Queue. A daemon
          in user mode, called MPDecision will be using this data to decide
@@ -2467,6 +2483,14 @@
 	  never allowing them to be turned OFF. Both local power
 	  management and RPM assisted power modes are supported.
 
+config SENSORS_ADSP
+	bool "Enable Sensors Driver Support for ADSP"
+	help
+	  Add support for sensors ADSP driver.
+	  This driver is used for exercising different sensors use cases,
+	  such as for lower-power OCMEM use cases, and for time syncing
+	  with ADSP clock.
+
 config MSM_RTB
 	bool "Register tracing"
 	help
@@ -2685,4 +2709,16 @@
 	  Enables MSM-specific user accessible timers via a shared
 	  memory page containing the cycle counter.
 
+config USE_DEV_CTRL_VOLUME
+	bool "Use Device Control Volume"
+	help
+	  Use Device Control Volume as opposed to ALSA volume control.
+
+config MSM_CPU_PWRCTL
+	bool "Ensures that krait droop detectors are always off"
+	help
+	  Droop detector mechanism can adversely affect krait plls during
+	  stand alone power collapse operation. Selecting this option
+	  ensures that they are always off.
+
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 2c7424e..3320d27 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -28,7 +28,7 @@
 ifdef CONFIG_ARCH_MSM_KRAIT
 obj-$(CONFIG_DEBUG_FS) += acpuclock-krait-debug.o
 endif
-obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o clock-pll.o
+obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o acpuclock-8625q.o clock-pll.o
 obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
 obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
 obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o
@@ -57,7 +57,6 @@
 endif
 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
 
-obj-$(CONFIG_MSM_CPU_AVS) += avs.o
 obj-$(CONFIG_MSM_AVS_HW) += avs_hw.o
 obj-$(CONFIG_CPU_V6) += idle-v6.o
 obj-$(CONFIG_CPU_V7) += idle-v7.o
@@ -138,6 +137,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
@@ -296,6 +296,7 @@
 obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
 obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
 obj-$(CONFIG_ARCH_MSM8226) += gdsc.o
+obj-$(CONFIG_ARCH_MSM8910) += gdsc.o
 obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
 obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
 obj-$(CONFIG_ARCH_MSM9625) += clock-local2.o clock-pll.o clock-9625.o clock-rpm.o clock-voter.o acpuclock-9625.o
@@ -303,6 +304,7 @@
 obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
 obj-$(CONFIG_ARCH_MSM8910) += board-8910.o board-8910-gpiomux.o
+obj-$(CONFIG_ARCH_MSM8910) += clock-local2.o clock-pll.o clock-8910.o clock-rpm.o clock-voter.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -341,7 +343,13 @@
 obj-$(CONFIG_MSM_BUS_SCALING) += msm_bus/
 obj-$(CONFIG_MSM_BUSPM_DEV) += msm-buspm-dev.o
 
-obj-$(CONFIG_MSM_IOMMU)		+= devices-iommu.o iommu_domains.o
+obj-$(CONFIG_MSM_IOMMU)		+= iommu_domains.o
+ifdef CONFIG_IOMMU_SUPPORT
+obj-$(CONFIG_ARCH_MSM8960)	+= devices-iommu.o
+obj-$(CONFIG_ARCH_MSM8930)	+= devices-iommu.o
+obj-$(CONFIG_ARCH_MSM8064)	+= devices-iommu.o
+endif
+
 obj-$(CONFIG_MSM_EVENT_TIMER)		+= event_timer.o
 
 ifdef CONFIG_VCM
@@ -349,6 +357,7 @@
 endif
 obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o
 obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o ocmem_rdm.o ocmem_core.o
+obj-$(CONFIG_SENSORS_ADSP) += sensors_adsp.o
 
 obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
@@ -408,3 +417,6 @@
 obj-$(CONFIG_MSM_FIQ) += msm7k_fiq_handler.o
 
 obj-$(CONFIG_MEMORY_HOLE_CARVEOUT) +=  msm_mem_hole.o
+
+obj-$(CONFIG_MSM_SMCMOD) += smcmod.o
+obj-$(CONFIG_MSM_CPU_PWRCTL) +=  msm_cpu_pwrctl.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index cf1f401..e74d61a 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -47,15 +47,25 @@
 
 # MSM8974
    zreladdr-$(CONFIG_ARCH_MSM8974)	:= 0x00008000
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-fluid.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-liquid.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-rumi.dtb
+        dtb-$(CONFIG_ARCH_MSM8974)	+= msm8974-sim.dtb
 
 # MSM9615
    zreladdr-$(CONFIG_ARCH_MSM9615)	:= 0x40808000
 
 # MSM9625
    zreladdr-$(CONFIG_ARCH_MSM9625)	:= 0x00208000
+        dtb-$(CONFIG_ARCH_MSM9625)	+= msm9625-cdp.dtb
+        dtb-$(CONFIG_ARCH_MSM9625)	+= msm9625-mtp.dtb
+        dtb-$(CONFIG_ARCH_MSM9625)	+= msm9625-rumi.dtb
 
 # MSM8226
    zreladdr-$(CONFIG_ARCH_MSM8226)	:= 0x00008000
+        dtb-$(CONFIG_ARCH_MSM8226)	+= msm8226-sim.dtb
 
 # FSM9XXX
    zreladdr-$(CONFIG_ARCH_FSM9XXX)	:= 0x10008000
@@ -67,3 +77,5 @@
 
 # MSM8910
    zreladdr-$(CONFIG_ARCH_MSM8910)	:= 0x00008000
+        dtb-$(CONFIG_ARCH_MSM8910)	+= msm8910-rumi.dtb
+        dtb-$(CONFIG_ARCH_MSM8910)	+= msm8910-sim.dtb
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index dd27123..00b6458 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -857,8 +857,7 @@
 		goto out;
 
 	/* Change the AXI bus frequency if we can. */
-	if (reason != SETRATE_PC &&
-		strt_s->axiclk_khz != tgt_s->axiclk_khz) {
+	if (strt_s->axiclk_khz != tgt_s->axiclk_khz) {
 		res = clk_set_rate(drv_state.ebi1_clk,
 				tgt_s->axiclk_khz * 1000);
 		if (res < 0)
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 5c1d3e1..db77a34 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,20 +505,20 @@
 	[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),     25000 },
+	[1][2] = { tbl_PVS2_1700MHz, sizeof(tbl_PVS2_1700MHz),     25000 },
+	[1][3] = { tbl_PVS3_1700MHz, sizeof(tbl_PVS3_1700MHz),     25000 },
+	[1][4] = { tbl_PVS4_1700MHz, sizeof(tbl_PVS4_1700MHz),     25000 },
+	[1][5] = { tbl_PVS5_1700MHz, sizeof(tbl_PVS5_1700MHz),     25000 },
+	[1][6] = { tbl_PVS6_1700MHz, sizeof(tbl_PVS6_1700MHz),     25000 },
 
 	[2][0] = { tbl_PVS0_2000MHz, sizeof(tbl_PVS0_2000MHz),     0 },
-	[2][1] = { tbl_PVS1_2000MHz, sizeof(tbl_PVS1_2000MHz),     0 },
-	[2][2] = { tbl_PVS2_2000MHz, sizeof(tbl_PVS2_2000MHz),     0 },
-	[2][3] = { tbl_PVS3_2000MHz, sizeof(tbl_PVS3_2000MHz),     0 },
-	[2][4] = { tbl_PVS4_2000MHz, sizeof(tbl_PVS4_2000MHz),     0 },
-	[2][5] = { tbl_PVS5_2000MHz, sizeof(tbl_PVS5_2000MHz),     0 },
-	[2][6] = { tbl_PVS6_2000MHz, sizeof(tbl_PVS6_2000MHz),     0 },
+	[2][1] = { tbl_PVS1_2000MHz, sizeof(tbl_PVS1_2000MHz),     25000 },
+	[2][2] = { tbl_PVS2_2000MHz, sizeof(tbl_PVS2_2000MHz),     25000 },
+	[2][3] = { tbl_PVS3_2000MHz, sizeof(tbl_PVS3_2000MHz),     25000 },
+	[2][4] = { tbl_PVS4_2000MHz, sizeof(tbl_PVS4_2000MHz),     25000 },
+	[2][5] = { tbl_PVS5_2000MHz, sizeof(tbl_PVS5_2000MHz),     25000 },
+	[2][6] = { tbl_PVS6_2000MHz, sizeof(tbl_PVS6_2000MHz),     25000 },
 };
 
 static struct acpuclk_krait_params acpuclk_8064_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8625q.c b/arch/arm/mach-msm/acpuclock-8625q.c
new file mode 100644
index 0000000..0a6dfbe
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8625q.c
@@ -0,0 +1,770 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2012, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/sort.h>
+#include <linux/regulator/consumer.h>
+#include <linux/smp.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/clk-provider.h>
+
+#include <asm/cpu.h>
+
+#include "acpuclock.h"
+#include "acpuclock-8625q.h"
+
+#define A11S_CLK_CNTL_ADDR	(MSM_CSR_BASE + 0x100)
+#define A11S_CLK_SEL_ADDR	(MSM_CSR_BASE + 0x104)
+
+#define PLL4_L_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x378)
+#define PLL4_M_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x37C)
+#define PLL4_N_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x380)
+
+#define POWER_COLLAPSE_KHZ 19200
+
+/* Max CPU frequency allowed by hardware while in standby waiting for an irq. */
+#define MAX_WAIT_FOR_IRQ_KHZ 128000
+
+/**
+ * enum - For acpuclock PLL IDs
+ */
+enum {
+	ACPU_PLL_0	= 0,
+	ACPU_PLL_1,
+	ACPU_PLL_2,
+	ACPU_PLL_3,
+	ACPU_PLL_4,
+	ACPU_PLL_TCXO,
+	ACPU_PLL_END,
+};
+
+struct acpu_clk_src {
+	struct clk *clk;
+	const char *name;
+};
+
+struct pll_config {
+	unsigned int l;
+	unsigned int m;
+	unsigned int n;
+};
+
+static struct acpu_clk_src pll_clk[ACPU_PLL_END] = {
+	[ACPU_PLL_0] = { .name = "pll0_clk" },
+	[ACPU_PLL_1] = { .name = "pll1_clk" },
+	[ACPU_PLL_2] = { .name = "pll2_clk" },
+	[ACPU_PLL_4] = { .name = "pll4_clk" },
+};
+
+static struct pll_config pll4_cfg_tbl[] = {
+	[0] = {  36, 1, 2 }, /*  700.8 MHz */
+	[1] = {  52, 1, 2 }, /* 1008 MHz */
+	[2] = {  63, 0, 1 }, /* 1209.6 MHz */
+	[3] = {  73, 0, 1 }, /* 1401.6 MHz */
+};
+
+struct clock_state {
+	struct clkctl_acpu_speed	*current_speed;
+	struct mutex			lock;
+	uint32_t			max_speed_delta_khz;
+	struct clk			*ebi1_clk;
+	struct regulator		*vreg_cpu;
+};
+
+struct clkctl_acpu_speed {
+	unsigned int	use_for_scaling;
+	unsigned int	a11clk_khz;
+	int		pll;
+	unsigned int	a11clk_src_sel;
+	unsigned int	a11clk_src_div;
+	unsigned int	ahbclk_khz;
+	unsigned int	ahbclk_div;
+	int		vdd;
+	unsigned int	axiclk_khz;
+	struct pll_config *pll_rate;
+	unsigned long   lpj;
+};
+
+static struct clock_state drv_state = { 0 };
+
+/* PVS MAX Voltage in uV as per frequencies*/
+
+# define MAX_14GHZ_VOLTAGE 1350000
+# define MAX_12GHZ_VOLTAGE 1275000
+# define MAX_1GHZ_VOLTAGE 1175000
+# define MAX_NOMINAL_VOLTAGE 1150000
+
+/* PVS deltas as per formula*/
+# define DELTA_LEVEL_1_UV 0
+# define DELTA_LEVEL_2_UV 75000
+# define DELTA_LEVEL_3_UV 150000
+
+
+static struct clkctl_acpu_speed acpu_freq_tbl_cmn[] = {
+	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
+	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, MAX_NOMINAL_VOLTAGE, 61440 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, MAX_NOMINAL_VOLTAGE, 122880 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, MAX_NOMINAL_VOLTAGE, 122880 },
+	{ 0, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 0, 160000 },
+	{ 1, 700800, ACPU_PLL_4, 6, 0, 87500, 3, MAX_NOMINAL_VOLTAGE, 160000,
+						&pll4_cfg_tbl[0]},
+	{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, MAX_1GHZ_VOLTAGE, 200000,
+						&pll4_cfg_tbl[1]},
+};
+
+static struct clkctl_acpu_speed acpu_freq_tbl_1209[] = {
+	{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, MAX_12GHZ_VOLTAGE, 200000,
+						&pll4_cfg_tbl[2]},
+};
+
+static struct clkctl_acpu_speed acpu_freq_tbl_1401[] = {
+	{ 1, 1401600, ACPU_PLL_4, 6, 0, 175000, 3, MAX_14GHZ_VOLTAGE, 200000,
+						&pll4_cfg_tbl[3]},
+};
+
+/* Entry corresponding to CDMA build*/
+static struct clkctl_acpu_speed acpu_freq_tbl_196608[] = {
+	{ 1, 196608, ACPU_PLL_1, 1, 0,  65536, 2, MAX_NOMINAL_VOLTAGE, 98304 },
+};
+
+static struct clkctl_acpu_speed acpu_freq_tbl_null[] = {
+	{ 0 },
+};
+
+static struct clkctl_acpu_speed acpu_freq_tbl[ARRAY_SIZE(acpu_freq_tbl_cmn)
+	+ ARRAY_SIZE(acpu_freq_tbl_1209)
+	+ ARRAY_SIZE(acpu_freq_tbl_1401)
+	+ ARRAY_SIZE(acpu_freq_tbl_null)];
+
+/* Switch to this when reprogramming PLL4 */
+static struct clkctl_acpu_speed *backup_s;
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[NR_CPUS][20];
+
+static void __devinit cpufreq_table_init(void)
+{
+	int cpu;
+	for_each_possible_cpu(cpu) {
+		unsigned int i, freq_cnt = 0;
+
+		/* Construct the freq_table table from acpu_freq_tbl since
+		 * the freq_table values need to match frequencies specified
+		 * in acpu_freq_tbl and acpu_freq_tbl needs to be fixed up
+		 * during init.
+		 */
+		for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0
+				&& freq_cnt < ARRAY_SIZE(*freq_table)-1; i++) {
+			if (acpu_freq_tbl[i].use_for_scaling) {
+				freq_table[cpu][freq_cnt].index = freq_cnt;
+				freq_table[cpu][freq_cnt].frequency
+					= acpu_freq_tbl[i].a11clk_khz;
+				freq_cnt++;
+			}
+		}
+
+		/* freq_table not big enough to store all usable freqs. */
+		BUG_ON(acpu_freq_tbl[i].a11clk_khz != 0);
+
+		freq_table[cpu][freq_cnt].index = freq_cnt;
+		freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
+		/* Register table with CPUFreq. */
+		cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
+		pr_info("CPU%d: %d scaling frequencies supported.\n",
+			cpu, freq_cnt);
+	}
+}
+#else
+static void __devinit cpufreq_table_init(void) { }
+#endif
+
+static void update_jiffies(int cpu, unsigned long loops)
+{
+#ifdef CONFIG_SMP
+	for_each_possible_cpu(cpu) {
+		per_cpu(cpu_data, cpu).loops_per_jiffy =
+						loops;
+	}
+#endif
+	/* Adjust the global one */
+	loops_per_jiffy = loops;
+}
+
+/* Assumes PLL4 is off and the acpuclock isn't sourced from PLL4 */
+static void acpuclk_config_pll4(struct pll_config *pll)
+{
+	/*
+	 * Make sure write to disable PLL_4 has completed
+	 * before reconfiguring that PLL.
+	*/
+	mb();
+	writel_relaxed(pll->l, PLL4_L_VAL_ADDR);
+	writel_relaxed(pll->m, PLL4_M_VAL_ADDR);
+	writel_relaxed(pll->n, PLL4_N_VAL_ADDR);
+	/* Make sure PLL is programmed before returning. */
+	mb();
+}
+
+/* Set proper dividers for the given clock speed. */
+static void acpuclk_set_div(const struct clkctl_acpu_speed *hunt_s)
+{
+	uint32_t reg_clkctl, reg_clksel, clk_div, src_sel;
+
+	reg_clksel = readl_relaxed(A11S_CLK_SEL_ADDR);
+
+	/* AHB_CLK_DIV */
+	clk_div = (reg_clksel >> 1) & 0x03;
+	/* CLK_SEL_SRC1NO */
+	src_sel = reg_clksel & 1;
+
+	/*
+	 * If the new clock divider is higher than the previous, then
+	 * program the divider before switching the clock
+	 */
+	if (hunt_s->ahbclk_div > clk_div) {
+		reg_clksel &= ~(0x3 << 1);
+		reg_clksel |= (hunt_s->ahbclk_div << 1);
+		writel_relaxed(reg_clksel, A11S_CLK_SEL_ADDR);
+	}
+
+	/* Program clock source and divider */
+	reg_clkctl = readl_relaxed(A11S_CLK_CNTL_ADDR);
+	reg_clkctl &= ~(0xFF << (8 * src_sel));
+	reg_clkctl |= hunt_s->a11clk_src_sel << (4 + 8 * src_sel);
+	reg_clkctl |= hunt_s->a11clk_src_div << (0 + 8 * src_sel);
+	writel_relaxed(reg_clkctl, A11S_CLK_CNTL_ADDR);
+
+	/* Program clock source selection */
+	reg_clksel ^= 1;
+	writel_relaxed(reg_clksel, A11S_CLK_SEL_ADDR);
+
+	/* Wait for the clock switch to complete */
+	mb();
+	udelay(50);
+
+	/*
+	 * If the new clock divider is lower than the previous, then
+	 * program the divider after switching the clock
+	 */
+	if (hunt_s->ahbclk_div < clk_div) {
+		reg_clksel &= ~(0x3 << 1);
+		reg_clksel |= (hunt_s->ahbclk_div << 1);
+		writel_relaxed(reg_clksel, A11S_CLK_SEL_ADDR);
+	}
+}
+
+static int acpuclk_set_vdd_level(int vdd)
+{
+	int rc;
+
+	rc = regulator_set_voltage(drv_state.vreg_cpu, vdd, vdd);
+	if (rc) {
+		pr_err("failed to set vdd=%d uV\n", vdd);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int acpuclk_8625q_set_rate(int cpu, unsigned long rate,
+					enum setrate_reason reason)
+{
+	uint32_t reg_clkctl;
+	struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s;
+	int res, rc = 0;
+	unsigned int plls_enabled = 0, pll;
+	int delta;
+
+
+	if (reason == SETRATE_CPUFREQ)
+		mutex_lock(&drv_state.lock);
+
+	strt_s = cur_s = drv_state.current_speed;
+
+	WARN_ONCE(cur_s == NULL, "%s: not initialized\n", __func__);
+	if (cur_s == NULL) {
+		rc = -ENOENT;
+		goto out;
+	}
+
+	cur_s->vdd = regulator_get_voltage(drv_state.vreg_cpu);
+	if (cur_s->vdd <= 0)
+		goto out;
+
+	pr_debug("current freq=%dKhz vdd=%duV\n",
+			cur_s->a11clk_khz, cur_s->vdd);
+
+	if (rate == cur_s->a11clk_khz)
+		goto out;
+
+	for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) {
+		if (tgt_s->a11clk_khz == rate)
+			break;
+	}
+
+	if (tgt_s->a11clk_khz == 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Choose the highest speed at or below 'rate' with same PLL. */
+	if (reason != SETRATE_CPUFREQ
+		&& tgt_s->a11clk_khz < cur_s->a11clk_khz) {
+		while (tgt_s->pll != ACPU_PLL_TCXO &&
+					tgt_s->pll != cur_s->pll) {
+			pr_debug("Intermediate frequency changes: %u\n",
+					tgt_s->a11clk_khz);
+			tgt_s--;
+		}
+	}
+
+	if (strt_s->pll != ACPU_PLL_TCXO)
+		plls_enabled |= 1 << strt_s->pll;
+
+	/* Need to do this when coming out of power collapse since some modem
+	 * firmwares reset the VDD when the application processor enters power
+	 * collapse.
+	 */
+	if (reason == SETRATE_CPUFREQ || reason == SETRATE_PC) {
+		/* Increase VDD if needed. */
+		if (tgt_s->vdd > cur_s->vdd) {
+			rc = acpuclk_set_vdd_level(tgt_s->vdd);
+			if (rc < 0) {
+				pr_err("Unable to switch ACPU vdd (%d)\n", rc);
+				goto out;
+			}
+			pr_debug("Increased Vdd to %duV\n", tgt_s->vdd);
+		}
+	}
+
+	/* Set wait states for CPU inbetween frequency changes */
+	reg_clkctl = readl_relaxed(A11S_CLK_CNTL_ADDR);
+	reg_clkctl |= (100 << 16); /* set WT_ST_CNT */
+	writel_relaxed(reg_clkctl, A11S_CLK_CNTL_ADDR);
+
+	pr_debug("Switching from ACPU rate %u KHz -> %u KHz\n",
+			strt_s->a11clk_khz, tgt_s->a11clk_khz);
+
+	delta = abs((int)(strt_s->a11clk_khz - tgt_s->a11clk_khz));
+
+	if (tgt_s->pll == ACPU_PLL_4) {
+		if (strt_s->pll == ACPU_PLL_4 ||
+				delta > drv_state.max_speed_delta_khz) {
+			/*
+			 * Enable the backup PLL if required
+			 * and switch to it.
+			 */
+			clk_enable(pll_clk[backup_s->pll].clk);
+			acpuclk_set_div(backup_s);
+			update_jiffies(cpu, backup_s->lpj);
+		}
+		/* Make sure PLL4 is off before reprogramming */
+		if ((plls_enabled & (1 << tgt_s->pll))) {
+			clk_disable(pll_clk[tgt_s->pll].clk);
+			plls_enabled &= ~(1 << tgt_s->pll);
+		}
+		acpuclk_config_pll4(tgt_s->pll_rate);
+		pll_clk[tgt_s->pll].clk->rate = tgt_s->a11clk_khz*1000;
+
+	} else if (strt_s->pll == ACPU_PLL_4) {
+		if (delta > drv_state.max_speed_delta_khz) {
+			/*
+			 * Enable the bcackup PLL if required
+			 * and switch to it.
+			 */
+			clk_enable(pll_clk[backup_s->pll].clk);
+			acpuclk_set_div(backup_s);
+			update_jiffies(cpu, backup_s->lpj);
+		}
+	}
+
+	if ((tgt_s->pll != ACPU_PLL_TCXO) &&
+			!(plls_enabled & (1 << tgt_s->pll))) {
+		rc = clk_enable(pll_clk[tgt_s->pll].clk);
+		if (rc < 0) {
+			pr_err("PLL%d enable failed (%d)\n",
+					tgt_s->pll, rc);
+			goto out;
+		}
+		plls_enabled |= 1 << tgt_s->pll;
+	}
+	acpuclk_set_div(tgt_s);
+	drv_state.current_speed = tgt_s;
+	pr_debug("The new clock speed is %u\n", tgt_s->a11clk_khz);
+	/* Re-adjust lpj for the new clock speed. */
+	update_jiffies(cpu, tgt_s->lpj);
+
+	/* Disable the backup PLL */
+	if ((delta > drv_state.max_speed_delta_khz)
+			|| (strt_s->pll == ACPU_PLL_4 &&
+				tgt_s->pll == ACPU_PLL_4))
+		clk_disable(pll_clk[backup_s->pll].clk);
+
+	/* Nothing else to do for SWFI. */
+	if (reason == SETRATE_SWFI)
+		goto out;
+
+	/* Change the AXI bus frequency if we can. */
+	if (reason != SETRATE_PC &&
+		strt_s->axiclk_khz != tgt_s->axiclk_khz) {
+		res = clk_set_rate(drv_state.ebi1_clk,
+				tgt_s->axiclk_khz * 1000);
+		pr_debug("AXI bus set freq %d\n",
+				tgt_s->axiclk_khz * 1000);
+		if (res < 0)
+			pr_warning("Setting AXI min rate failed (%d)\n", res);
+	}
+
+	/* Disable PLLs we are not using anymore. */
+	if (tgt_s->pll != ACPU_PLL_TCXO)
+		plls_enabled &= ~(1 << tgt_s->pll);
+	for (pll = ACPU_PLL_0; pll < ACPU_PLL_END; pll++)
+		if (plls_enabled & (1 << pll))
+			clk_disable(pll_clk[pll].clk);
+
+	/* Nothing else to do for power collapse. */
+	if (reason == SETRATE_PC)
+		goto out;
+
+	/* Drop VDD level if we can. */
+	if (tgt_s->vdd < strt_s->vdd) {
+		res = acpuclk_set_vdd_level(tgt_s->vdd);
+		if (res < 0)
+			pr_warning("Unable to drop ACPU vdd (%d)\n", res);
+		pr_debug("Decreased Vdd to %duV\n", tgt_s->vdd);
+	}
+
+	pr_debug("ACPU speed change complete\n");
+out:
+	if (reason == SETRATE_CPUFREQ)
+		mutex_unlock(&drv_state.lock);
+
+	return rc;
+}
+
+static int __devinit acpuclk_hw_init(void)
+{
+	struct clkctl_acpu_speed *speed;
+	uint32_t div, sel, reg_clksel;
+	int res;
+
+	/*
+	 * Prepare all the PLLs because we enable/disable them
+	 * from atomic context and can't always ensure they're
+	 * all prepared in non-atomic context. Same goes for
+	 * ebi1_acpu_clk.
+	 */
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_0].clk));
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_1].clk));
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_2].clk));
+	BUG_ON(clk_prepare(pll_clk[ACPU_PLL_4].clk));
+	BUG_ON(clk_prepare(drv_state.ebi1_clk));
+
+	/*
+	 * Determine the rate of ACPU clock
+	 */
+
+	if (!(readl_relaxed(A11S_CLK_SEL_ADDR) & 0x01)) { /* CLK_SEL_SRC1N0 */
+		/* CLK_SRC0_SEL */
+		sel = (readl_relaxed(A11S_CLK_CNTL_ADDR) >> 12) & 0x7;
+		/* CLK_SRC0_DIV */
+		div = (readl_relaxed(A11S_CLK_CNTL_ADDR) >> 8) & 0x0f;
+	} else {
+		/* CLK_SRC1_SEL */
+		sel = (readl_relaxed(A11S_CLK_CNTL_ADDR) >> 4) & 0x07;
+		/* CLK_SRC1_DIV */
+		div = readl_relaxed(A11S_CLK_CNTL_ADDR) & 0x0f;
+	}
+
+	for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) {
+		if (speed->a11clk_src_sel == sel
+			&& (speed->a11clk_src_div == div))
+			break;
+	}
+	if (speed->a11clk_khz == 0) {
+		pr_err("Error - ACPU clock reports invalid speed\n");
+		return -EINVAL;
+	}
+
+	drv_state.current_speed = speed;
+	if (speed->pll != ACPU_PLL_TCXO) {
+		if (clk_enable(pll_clk[speed->pll].clk)) {
+			pr_warning("Failed to vote for boot PLL\n");
+			return -ENODEV;
+		}
+	}
+
+	reg_clksel = readl_relaxed(A11S_CLK_SEL_ADDR);
+	reg_clksel &= ~(0x3 << 14);
+	reg_clksel |= (0x1 << 14);
+	writel_relaxed(reg_clksel, A11S_CLK_SEL_ADDR);
+
+	res = clk_set_rate(drv_state.ebi1_clk, speed->axiclk_khz * 1000);
+	if (res < 0) {
+		pr_warning("Setting AXI min rate failed (%d)\n", res);
+		return -ENODEV;
+	}
+	res = clk_enable(drv_state.ebi1_clk);
+	if (res < 0) {
+		pr_warning("Enabling AXI clock failed (%d)\n", res);
+		return -ENODEV;
+	}
+
+	drv_state.vreg_cpu = regulator_get(NULL, "vddx_cx");
+	if (IS_ERR(drv_state.vreg_cpu)) {
+		res = PTR_ERR(drv_state.vreg_cpu);
+		pr_err("could not get regulator: %d\n", res);
+	}
+
+	pr_info("ACPU running at %d KHz\n", speed->a11clk_khz);
+	return 0;
+}
+
+static unsigned long acpuclk_8625q_get_rate(int cpu)
+{
+	WARN_ONCE(drv_state.current_speed == NULL,
+			"%s: not initialized\n", __func__);
+	if (drv_state.current_speed)
+		return drv_state.current_speed->a11clk_khz;
+	else
+		return 0;
+}
+
+#define MHZ 1000000
+
+static void __devinit select_freq_plan(unsigned int pvs_voltage,
+					unsigned int nominal_vol_uv,
+					unsigned int default_vol_uv)
+{
+	unsigned long pll_mhz[ACPU_PLL_END];
+	int i;
+	int size;
+	int delta[3] = {DELTA_LEVEL_1_UV, DELTA_LEVEL_2_UV, DELTA_LEVEL_3_UV};
+	struct clkctl_acpu_speed *tbl;
+
+	/* Get PLL clocks */
+	for (i = 0; i < ACPU_PLL_END; i++) {
+		if (pll_clk[i].name) {
+			pll_clk[i].clk = clk_get_sys("acpu", pll_clk[i].name);
+			if (IS_ERR(pll_clk[i].clk)) {
+				pll_mhz[i] = 0;
+				continue;
+			}
+			/* Get PLL's Rate */
+			pll_mhz[i] = clk_get_rate(pll_clk[i].clk)/MHZ;
+		}
+	}
+
+	memcpy(acpu_freq_tbl, acpu_freq_tbl_cmn, sizeof(acpu_freq_tbl_cmn));
+	size = ARRAY_SIZE(acpu_freq_tbl_cmn);
+
+	i = 0;		/* needed if we have a 1Ghz part */
+	/* select if it is a 1.2Ghz part */
+	if (pll_mhz[ACPU_PLL_4] == 1209) {
+		memcpy(acpu_freq_tbl + size, acpu_freq_tbl_1209,
+						sizeof(acpu_freq_tbl_1209));
+		size += sizeof(acpu_freq_tbl_1209);
+		i = 1;		/* set the delta index */
+	}
+	/* select if it is a 1.4Ghz part */
+	if (pll_mhz[ACPU_PLL_4] == 1401) {
+		memcpy(acpu_freq_tbl + size, acpu_freq_tbl_1209,
+						sizeof(acpu_freq_tbl_1209));
+		size += ARRAY_SIZE(acpu_freq_tbl_1209);
+		memcpy(acpu_freq_tbl + size, acpu_freq_tbl_1401,
+						sizeof(acpu_freq_tbl_1401));
+		size += ARRAY_SIZE(acpu_freq_tbl_1401);
+		i = 2;		/* set the delta index */
+	}
+
+	memcpy(acpu_freq_tbl + size, acpu_freq_tbl_null,
+						sizeof(acpu_freq_tbl_null));
+	size += sizeof(acpu_freq_tbl_null);
+
+	/* Alter the freq value in freq_tbl if it is a CDMA build*/
+	if (pll_mhz[ACPU_PLL_1] == 196) {
+
+		for (tbl = acpu_freq_tbl; tbl->a11clk_khz; tbl++) {
+			if (tbl->a11clk_khz == 245760 &&
+					tbl->pll == ACPU_PLL_1) {
+				pr_debug("Upgrading pll1 freq to 196  Mhz\n");
+				memcpy(tbl, acpu_freq_tbl_196608,
+						sizeof(acpu_freq_tbl_196608));
+				break;
+			}
+		}
+	}
+
+	/*
+	 *PVS Voltage calculation  formula
+	 *1.4 Ghz device
+	 *1.4 Ghz: Max(PVS_voltage,1.35V)
+	 *1.2 Ghz: Max(PVS_volatge - 75mV,1.275V)
+	 *1.0 Ghz: Max(PVS_voltage - 150mV, 1.175V)
+	 *1.2 Ghz device
+	 *1.2 Ghz: Max(PVS_voltage,1.275V)
+	 *1.0 Ghz: Max(PVS_volatge - 75mV,1.175V)
+	 *Nominal Mode: 1.15V
+	*/
+	for (tbl = acpu_freq_tbl; tbl->a11clk_khz; tbl++) {
+		if (tbl->a11clk_khz >= 1008000) {
+			if (tbl->a11clk_khz == 1209600)
+				tbl->vdd = default_vol_uv;
+			/*
+			 * Change voltage as per PVS formula,
+			 * i is initialized above with 2 or 1
+			 * depending upon whether it is a 1.4Ghz
+			 * or 1.2Ghz, so, we get the proper value
+			 * from delta[i] which is to be deducted
+			 * from PVS voltage.
+			*/
+
+			tbl->vdd = max((int)(pvs_voltage - delta[i]), tbl->vdd);
+			i--;
+		} else if (tbl->a11clk_khz != 600000
+					&& tbl->a11clk_khz != 19200)
+			tbl->vdd = nominal_vol_uv;
+	}
+
+
+	/* find the backup PLL entry from the table  */
+	for (tbl = acpu_freq_tbl; tbl->a11clk_khz; tbl++) {
+		if (tbl->pll == ACPU_PLL_2 &&
+				tbl->a11clk_src_div == 1) {
+			backup_s = tbl;
+			break;
+		}
+	}
+
+	BUG_ON(!backup_s);
+
+}
+
+/*
+ * Hardware requires the CPU to be dropped to less than MAX_WAIT_FOR_IRQ_KHZ
+ * before entering a wait for irq low-power mode. Find a suitable rate.
+ */
+static unsigned long __devinit find_wait_for_irq_khz(void)
+{
+	unsigned long found_khz = 0;
+	int i;
+
+	for (i = 0; acpu_freq_tbl[i].a11clk_khz &&
+		acpu_freq_tbl[i].a11clk_khz <= MAX_WAIT_FOR_IRQ_KHZ; i++)
+		found_khz = acpu_freq_tbl[i].a11clk_khz;
+
+	return found_khz;
+}
+
+static void __devinit lpj_init(void)
+{
+	int i = 0, cpu;
+	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
+	unsigned long loops;
+
+	for_each_possible_cpu(cpu) {
+#ifdef CONFIG_SMP
+		loops = per_cpu(cpu_data, cpu).loops_per_jiffy;
+#else
+		loops = loops_per_jiffy;
+#endif
+		for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) {
+			acpu_freq_tbl[i].lpj = cpufreq_scale(
+				loops,
+				base_clk->a11clk_khz,
+				acpu_freq_tbl[i].a11clk_khz);
+		}
+
+	}
+
+}
+
+static struct acpuclk_data acpuclk_8625q_data = {
+	.set_rate = acpuclk_8625q_set_rate,
+	.get_rate = acpuclk_8625q_get_rate,
+	.power_collapse_khz = POWER_COLLAPSE_KHZ,
+	.switch_time_us = 50,
+};
+
+static void __devinit print_acpu_freq_tbl(void)
+{
+	struct clkctl_acpu_speed *t;
+	int i;
+
+	pr_info("Id CPU-KHz PLL DIV AHB-KHz ADIV AXI-KHz Vdd\n");
+
+	t = &acpu_freq_tbl[0];
+	for (i = 0; t->a11clk_khz != 0; i++) {
+		pr_info("%2d %7d %3d %3d %7d %4d %7d %3d\n",
+			i, t->a11clk_khz, t->pll, t->a11clk_src_div + 1,
+			t->ahbclk_khz, t->ahbclk_div + 1, t->axiclk_khz,
+			t->vdd);
+		t++;
+	}
+}
+
+static int __devinit acpuclk_8625q_probe(struct platform_device *pdev)
+{
+	const struct acpuclk_pdata_8625q *pdata = pdev->dev.platform_data;
+	unsigned int pvs_voltage = pdata->pvs_voltage_uv;
+	unsigned int nom_vol_uv = pdata->nominal_voltage;
+	unsigned int default_vol_uv = pdata->default_turbo_voltage;
+
+	drv_state.max_speed_delta_khz = pdata->acpu_clk_data->
+						max_speed_delta_khz;
+
+	drv_state.ebi1_clk = clk_get(NULL, "ebi1_acpu_clk");
+	BUG_ON(IS_ERR(drv_state.ebi1_clk));
+
+	mutex_init(&drv_state.lock);
+	select_freq_plan(pvs_voltage, nom_vol_uv, default_vol_uv);
+	acpuclk_8625q_data.wait_for_irq_khz = find_wait_for_irq_khz();
+
+	if (acpuclk_hw_init() < 0)
+		pr_err("acpuclk_hw_init not successful.\n");
+
+	print_acpu_freq_tbl();
+	lpj_init();
+	acpuclk_register(&acpuclk_8625q_data);
+
+	cpufreq_table_init();
+
+	return 0;
+}
+
+static struct platform_driver acpuclk_8625q_driver = {
+	.probe = acpuclk_8625q_probe,
+	.driver = {
+		.name = "acpuclock-8625q",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init acpuclk_8625q_init(void)
+{
+
+	return platform_driver_register(&acpuclk_8625q_driver);
+}
+postcore_initcall(acpuclk_8625q_init);
diff --git a/arch/arm/mach-msm/acpuclock-8625q.h b/arch/arm/mach-msm/acpuclock-8625q.h
new file mode 100644
index 0000000..c91e3bd
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8625q.h
@@ -0,0 +1,30 @@
+/*
+ * MSM architecture CPU clock driver header
+ *
+ * Copyright (c) 2012, Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __ARCH_ARM_MACH_MSM_ACPUCLOCK_8625Q_H
+#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_8625Q_H
+
+# include "acpuclock.h"
+/**
+ * struct acpuclk_pdata_8625q - Platform data for acpuclk
+ */
+struct acpuclk_pdata_8625q {
+	struct acpuclk_pdata *acpu_clk_data;
+	unsigned int pvs_voltage_uv;
+	unsigned int nominal_voltage;
+	unsigned int default_turbo_voltage;
+};
+
+#endif /* __ARCH_ARM_MACH_MSM_ACPUCLOCK_8625Q_H */
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..5003862 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 } }
@@ -243,9 +243,9 @@
 
 /* TODO: Update boost voltage once the pvs data is available */
 static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-[0][PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow),     0 },
-[0][PVS_NOMINAL] = { acpu_freq_tbl_nom,  sizeof(acpu_freq_tbl_nom),      0 },
-[0][PVS_FAST]    = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast),     0 },
+[0][PVS_SLOW]    = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+[0][PVS_NOMINAL] = { acpu_freq_tbl_nom,  sizeof(acpu_freq_tbl_nom),  25000 },
+[0][PVS_FAST]    = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
 };
 
 static struct acpuclk_krait_params acpuclk_8930ab_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index 03a2004..9b4eecd 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -233,12 +233,12 @@
 
 static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
 [0][0] = { freq_tbl_PVS0, sizeof(freq_tbl_PVS0),  0 },
-[0][1] = { freq_tbl_PVS1, sizeof(freq_tbl_PVS1),  0 },
-[0][2] = { freq_tbl_PVS2, sizeof(freq_tbl_PVS2),  0 },
-[0][3] = { freq_tbl_PVS3, sizeof(freq_tbl_PVS3),  0 },
-[0][4] = { freq_tbl_PVS4, sizeof(freq_tbl_PVS4),  0 },
-[0][5] = { freq_tbl_PVS5, sizeof(freq_tbl_PVS5),  0 },
-[0][6] = { freq_tbl_PVS6, sizeof(freq_tbl_PVS6),  0 },
+[0][1] = { freq_tbl_PVS1, sizeof(freq_tbl_PVS1),  25000 },
+[0][2] = { freq_tbl_PVS2, sizeof(freq_tbl_PVS2),  25000 },
+[0][3] = { freq_tbl_PVS3, sizeof(freq_tbl_PVS3),  25000 },
+[0][4] = { freq_tbl_PVS4, sizeof(freq_tbl_PVS4),  25000 },
+[0][5] = { freq_tbl_PVS5, sizeof(freq_tbl_PVS5),  25000 },
+[0][6] = { freq_tbl_PVS6, sizeof(freq_tbl_PVS6),  25000 },
 };
 
 static struct acpuclk_krait_params acpuclk_8960ab_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 0fbd6dc..69b35e9 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -56,8 +56,7 @@
 		.vreg[VREG_CORE] = { "krait0",     1050000 },
 		.vreg[VREG_MEM]  = { "krait0_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait0_dig", LVL_HIGH },
-		.vreg[VREG_HFPLL_A] = { "krait0_hfpll_a", 2150000 },
-		.vreg[VREG_HFPLL_B] = { "krait0_hfpll_b", 1800000 },
+		.vreg[VREG_HFPLL_A] = { "krait0_hfpll", 1800000 },
 	},
 	[CPU1] = {
 		.hfpll_phys_base = 0xF909A000,
@@ -66,8 +65,7 @@
 		.vreg[VREG_CORE] = { "krait1",     1050000 },
 		.vreg[VREG_MEM]  = { "krait1_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait1_dig", LVL_HIGH },
-		.vreg[VREG_HFPLL_A] = { "krait1_hfpll_a", 2150000 },
-		.vreg[VREG_HFPLL_B] = { "krait1_hfpll_b", 1800000 },
+		.vreg[VREG_HFPLL_A] = { "krait1_hfpll", 1800000 },
 	},
 	[CPU2] = {
 		.hfpll_phys_base = 0xF90AA000,
@@ -76,8 +74,7 @@
 		.vreg[VREG_CORE] = { "krait2",     1050000 },
 		.vreg[VREG_MEM]  = { "krait2_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait2_dig", LVL_HIGH },
-		.vreg[VREG_HFPLL_A] = { "krait2_hfpll_a", 2150000 },
-		.vreg[VREG_HFPLL_B] = { "krait2_hfpll_b", 1800000 },
+		.vreg[VREG_HFPLL_A] = { "krait2_hfpll", 1800000 },
 	},
 	[CPU3] = {
 		.hfpll_phys_base = 0xF90BA000,
@@ -86,23 +83,25 @@
 		.vreg[VREG_CORE] = { "krait3",     1050000 },
 		.vreg[VREG_MEM]  = { "krait3_mem", 1050000 },
 		.vreg[VREG_DIG]  = { "krait3_dig", LVL_HIGH },
-		.vreg[VREG_HFPLL_A] = { "krait3_hfpll_a", 2150000 },
-		.vreg[VREG_HFPLL_B] = { "krait3_hfpll_b", 1800000 },
+		.vreg[VREG_HFPLL_A] = { "krait3_hfpll", 1800000 },
 	},
 	[L2] = {
 		.hfpll_phys_base = 0xF9016000,
 		.l2cpmr_iaddr = 0x0500,
 		.sec_clk_sel = 2,
-		.vreg[VREG_HFPLL_A] = { "l2_hfpll_a", 2150000 },
-		.vreg[VREG_HFPLL_B] = { "l2_hfpll_b", 1800000 },
+		.vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
 	},
 };
 
 static struct msm_bus_paths bw_level_tbl[] __initdata = {
-	[0] =  BW_MBPS(552), /* At least  69 MHz on bus. */
-	[1] = BW_MBPS(1112), /* At least 139 MHz on bus. */
-	[2] = BW_MBPS(2224), /* At least 278 MHz on bus. */
-	[3] = BW_MBPS(4448), /* At least 556 MHz on bus. */
+	[0] =  BW_MBPS(600), /* At least  75 MHz on bus. */
+	[1] =  BW_MBPS(800), /* At least 100 MHz on bus. */
+	[2] = BW_MBPS(1200), /* At least 150 MHz on bus. */
+	[3] = BW_MBPS(1600), /* At least 200 MHz on bus. */
+	[4] = BW_MBPS(2224), /* At least 278 MHz on bus. */
+	[5] = BW_MBPS(3200), /* At least 400 MHz on bus. */
+	[6] = BW_MBPS(4448), /* At least 556 MHz on bus. */
+	[7] = BW_MBPS(6400), /* At least 800 MHz on bus. */
 };
 
 static struct msm_bus_scale_pdata bus_scale_data __initdata = {
@@ -118,51 +117,51 @@
 	[2]  = { {  422400, HFPLL, 2,  44 }, LVL_NOM,  1050000, 1 },
 	[3]  = { {  499200, HFPLL, 2,  52 }, LVL_NOM,  1050000, 2 },
 	[4]  = { {  576000, HFPLL, 1,  30 }, LVL_NOM,  1050000, 2 },
-	[5]  = { {  652800, HFPLL, 1,  34 }, LVL_NOM,  1050000, 2 },
-	[6]  = { {  729600, HFPLL, 1,  38 }, LVL_NOM,  1050000, 2 },
-	[7]  = { {  806400, HFPLL, 1,  42 }, LVL_NOM,  1050000, 2 },
-	[8]  = { {  883200, HFPLL, 1,  46 }, LVL_HIGH, 1050000, 2 },
-	[9]  = { {  960000, HFPLL, 1,  50 }, LVL_HIGH, 1050000, 2 },
-	[10] = { { 1036800, HFPLL, 1,  54 }, LVL_HIGH, 1050000, 3 },
-	[11] = { { 1113600, HFPLL, 1,  58 }, LVL_HIGH, 1050000, 3 },
-	[12] = { { 1190400, HFPLL, 1,  62 }, LVL_HIGH, 1050000, 3 },
-	[13] = { { 1267200, HFPLL, 1,  66 }, LVL_HIGH, 1050000, 3 },
-	[14] = { { 1344000, HFPLL, 1,  70 }, LVL_HIGH, 1050000, 3 },
-	[15] = { { 1420800, HFPLL, 1,  74 }, LVL_HIGH, 1050000, 3 },
-	[16] = { { 1497600, HFPLL, 1,  78 }, LVL_HIGH, 1050000, 3 },
-	[17] = { { 1574400, HFPLL, 1,  82 }, LVL_HIGH, 1050000, 3 },
-	[18] = { { 1651200, HFPLL, 1,  86 }, LVL_HIGH, 1050000, 3 },
-	[19] = { { 1728000, HFPLL, 1,  90 }, LVL_HIGH, 1050000, 3 },
-	[20] = { { 1804800, HFPLL, 1,  94 }, LVL_HIGH, 1050000, 3 },
-	[21] = { { 1881600, HFPLL, 1,  98 }, LVL_HIGH, 1050000, 3 },
-	[22] = { { 1958400, HFPLL, 1, 102 }, LVL_HIGH, 1050000, 3 },
-	[23] = { { 2035200, HFPLL, 1, 106 }, LVL_HIGH, 1050000, 3 },
-	[24] = { { 2112000, HFPLL, 1, 110 }, LVL_HIGH, 1050000, 3 },
-	[25] = { { 2188800, HFPLL, 1, 114 }, LVL_HIGH, 1050000, 3 },
+	[5]  = { {  652800, HFPLL, 1,  34 }, LVL_NOM,  1050000, 3 },
+	[6]  = { {  729600, HFPLL, 1,  38 }, LVL_NOM,  1050000, 3 },
+	[7]  = { {  806400, HFPLL, 1,  42 }, LVL_NOM,  1050000, 3 },
+	[8]  = { {  883200, HFPLL, 1,  46 }, LVL_HIGH, 1050000, 4 },
+	[9]  = { {  960000, HFPLL, 1,  50 }, LVL_HIGH, 1050000, 4 },
+	[10] = { { 1036800, HFPLL, 1,  54 }, LVL_HIGH, 1050000, 4 },
+	[11] = { { 1113600, HFPLL, 1,  58 }, LVL_HIGH, 1050000, 5 },
+	[12] = { { 1190400, HFPLL, 1,  62 }, LVL_HIGH, 1050000, 5 },
+	[13] = { { 1267200, HFPLL, 1,  66 }, LVL_HIGH, 1050000, 6 },
+	[14] = { { 1344000, HFPLL, 1,  70 }, LVL_HIGH, 1050000, 6 },
+	[15] = { { 1420800, HFPLL, 1,  74 }, LVL_HIGH, 1050000, 7 },
+	[16] = { { 1497600, HFPLL, 1,  78 }, LVL_HIGH, 1050000, 7 },
+	[17] = { { 1574400, HFPLL, 1,  82 }, LVL_HIGH, 1050000, 7 },
+	[18] = { { 1651200, HFPLL, 1,  86 }, LVL_HIGH, 1050000, 7 },
+	[19] = { { 1728000, HFPLL, 1,  90 }, LVL_HIGH, 1050000, 7 },
+	[20] = { { 1804800, HFPLL, 1,  94 }, LVL_HIGH, 1050000, 7 },
+	[21] = { { 1881600, HFPLL, 1,  98 }, LVL_HIGH, 1050000, 7 },
+	[22] = { { 1958400, HFPLL, 1, 102 }, LVL_HIGH, 1050000, 7 },
+	[23] = { { 2035200, HFPLL, 1, 106 }, LVL_HIGH, 1050000, 7 },
+	[24] = { { 2112000, HFPLL, 1, 110 }, LVL_HIGH, 1050000, 7 },
+	[25] = { { 2188800, HFPLL, 1, 114 }, LVL_HIGH, 1050000, 7 },
 	{ }
 };
 
 static struct acpu_level acpu_freq_tbl[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   850000,  100000 },
-	{ 0, {  345600, HFPLL, 2,  36 }, L2(0),   850000, 3200000 },
-	{ 1, {  422400, HFPLL, 2,  44 }, L2(0),   850000, 3200000 },
-	{ 0, {  499200, HFPLL, 2,  52 }, L2(0),   850000, 3200000 },
-	{ 1, {  576000, HFPLL, 1,  30 }, L2(0),   850000, 3200000 },
-	{ 1, {  652800, HFPLL, 1,  34 }, L2(16),  850000, 3200000 },
-	{ 0, {  729600, HFPLL, 1,  38 }, L2(16),  850000, 3200000 },
-	{ 1, {  806400, HFPLL, 1,  42 }, L2(16),  850000, 3200000 },
-	{ 1, {  883200, HFPLL, 1,  46 }, L2(16),  870000, 3200000 },
-	{ 1, {  960000, HFPLL, 1,  50 }, L2(16),  880000, 3200000 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(16),  900000, 3200000 },
-	{ 1, { 1113600, HFPLL, 1,  58 }, L2(16),  915000, 3200000 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(16),  935000, 3200000 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(16),  950000, 3200000 },
-	{ 1, { 1344000, HFPLL, 1,  70 }, L2(16),  970000, 3200000 },
-	{ 1, { 1420800, HFPLL, 1,  74 }, L2(16),  985000, 3200000 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16), 1000000, 3200000 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(16), 1015000, 3200000 },
-	{ 1, { 1651200, HFPLL, 1,  86 }, L2(16), 1030000, 3200000 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 3200000 },
+	{ 1, {  300000, PLL_0, 0,   0 }, L2(0),   950000,  100000 },
+	{ 0, {  345600, HFPLL, 2,  36 }, L2(0),   950000, 3200000 },
+	{ 1, {  422400, HFPLL, 2,  44 }, L2(0),   950000, 3200000 },
+	{ 0, {  499200, HFPLL, 2,  52 }, L2(0),   950000, 3200000 },
+	{ 1, {  576000, HFPLL, 1,  30 }, L2(0),   950000, 3200000 },
+	{ 1, {  652800, HFPLL, 1,  34 }, L2(16),  950000, 3200000 },
+	{ 0, {  729600, HFPLL, 1,  38 }, L2(16),  950000, 3200000 },
+	{ 1, {  806400, HFPLL, 1,  42 }, L2(16),  950000, 3200000 },
+	{ 1, {  883200, HFPLL, 1,  46 }, L2(16),  950000, 3200000 },
+	{ 1, {  960000, HFPLL, 1,  50 }, L2(16),  950000, 3200000 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(16),  950000, 3200000 },
+	{ 1, { 1113600, HFPLL, 1,  58 }, L2(16), 1050000, 3200000 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(16), 1050000, 3200000 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(16), 1050000, 3200000 },
+	{ 1, { 1344000, HFPLL, 1,  70 }, L2(16), 1050000, 3200000 },
+	{ 1, { 1420800, HFPLL, 1,  74 }, L2(16), 1050000, 3200000 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16), 1050000, 3200000 },
+	{ 0, { 1574400, HFPLL, 1,  82 }, L2(16), 1050000, 3200000 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(16), 1050000, 3200000 },
+	{ 0, { 1728000, HFPLL, 1,  90 }, L2(16), 1050000, 3200000 },
 	{ 0, { 1804800, HFPLL, 1,  94 }, L2(16), 1050000, 3200000 },
 	{ 0, { 1881600, HFPLL, 1,  98 }, L2(16), 1050000, 3200000 },
 	{ 0, { 1958400, HFPLL, 1, 102 }, L2(16), 1050000, 3200000 },
diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c
index 996f883..eed8000 100644
--- a/arch/arm/mach-msm/acpuclock-8x50.c
+++ b/arch/arm/mach-msm/acpuclock-8x50.c
@@ -423,14 +423,6 @@
 	}
 
 	if (reason == SETRATE_CPUFREQ) {
-#ifdef CONFIG_MSM_CPU_AVS
-		/* Notify avs before changing frequency */
-		rc = avs_adjust_freq(freq_index, 1);
-		if (rc) {
-			pr_err("Unable to increase ACPU vdd (%d)\n", rc);
-			goto out;
-		}
-#endif
 		/* Increase VDD if needed. */
 		if (tgt_s->vdd > strt_s->vdd) {
 			rc = acpuclk_set_vdd_level(tgt_s->vdd);
@@ -485,13 +477,6 @@
 	if (reason == SETRATE_PC)
 		goto out;
 
-#ifdef CONFIG_MSM_CPU_AVS
-	/* notify avs after changing frequency */
-	res = avs_adjust_freq(freq_index, 0);
-	if (res)
-		pr_warning("Unable to drop ACPU vdd (%d)\n", res);
-#endif
-
 	/* Drop VDD level if we can. */
 	if (tgt_s->vdd < strt_s->vdd) {
 		res = acpuclk_set_vdd_level(tgt_s->vdd);
@@ -658,22 +643,6 @@
 	}
 }
 
-#ifdef CONFIG_MSM_CPU_AVS
-static int __devinit acpu_avs_init(int (*set_vdd) (int), int khz)
-{
-	int i;
-	int freq_count = 0;
-	int freq_index = -1;
-
-	for (i = 0; acpu_freq_tbl[i].acpuclk_khz; i++) {
-		freq_count++;
-		if (acpu_freq_tbl[i].acpuclk_khz == khz)
-			freq_index = i;
-	}
-
-	return avs_init(set_vdd, freq_count, freq_index);
-}
-#endif
 
 static int qsd8x50_tps65023_set_dcdc1(int mVolts)
 {
@@ -728,13 +697,6 @@
 	cpufreq_table_init();
 	cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
 #endif
-#ifdef CONFIG_MSM_CPU_AVS
-	if (!acpu_avs_init(drv_state.acpu_set_vdd,
-		drv_state.current_speed->acpuclk_khz)) {
-		/* avs init successful. avs will handle voltage changes */
-		drv_state.acpu_set_vdd = NULL;
-	}
-#endif
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/avs.c b/arch/arm/mach-msm/avs.c
deleted file mode 100644
index 827adab..0000000
--- a/arch/arm/mach-msm/avs.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/kernel_stat.h>
-#include <linux/workqueue.h>
-#include <linux/slab.h>
-
-#include "avs.h"
-
-#define AVSDSCR_INPUT 0x01004860 /* magic # from circuit designer */
-#define TSCSR_INPUT   0x00000001 /* enable temperature sense */
-
-#define TEMPRS 16                /* total number of temperature regions */
-#define GET_TEMPR() (avs_get_tscsr() >> 28) /* scale TSCSR[CTEMP] to regions */
-
-struct mutex avs_lock;
-
-static struct avs_state_s
-{
-	u32 freq_cnt;		/* Frequencies supported list */
-	short *avs_v;		/* Dyanmically allocated storage for
-				 * 2D table of voltages over temp &
-				 * freq.  Used as a set of 1D tables.
-				 * Each table is for a single temp.
-				 * For usage see avs_get_voltage
-				 */
-	int (*set_vdd) (int);	/* Function Ptr for setting voltage */
-	int changing;		/* Clock frequency is changing */
-	u32 freq_idx;		/* Current frequency index */
-	int vdd;		/* Current ACPU voltage */
-} avs_state;
-
-/*
- *  Update the AVS voltage vs frequency table, for current temperature
- *  Adjust based on the AVS delay circuit hardware status
- */
-static void avs_update_voltage_table(short *vdd_table)
-{
-	u32 avscsr;
-	int cpu;
-	int vu;
-	int l2;
-	int i;
-	u32 cur_freq_idx;
-	short cur_voltage;
-
-	cur_freq_idx = avs_state.freq_idx;
-	cur_voltage = avs_state.vdd;
-
-	avscsr = avs_test_delays();
-	AVSDEBUG("avscsr=%x, avsdscr=%x\n", avscsr, avs_get_avsdscr());
-
-	/*
-	 * Read the results for the various unit's AVS delay circuits
-	 * 2=> up, 1=>down, 0=>no-change
-	 */
-	cpu = ((avscsr >> 23) & 2) + ((avscsr >> 16) & 1);
-	vu  = ((avscsr >> 28) & 2) + ((avscsr >> 21) & 1);
-	l2  = ((avscsr >> 29) & 2) + ((avscsr >> 22) & 1);
-
-	if ((cpu == 3) || (vu == 3) || (l2 == 3)) {
-		printk(KERN_ERR "AVS: Dly Synth O/P error\n");
-	} else if ((cpu == 2) || (l2 == 2) || (vu == 2)) {
-		/*
-		 * even if one oscillator asks for up, increase the voltage,
-		 * as its an indication we are running outside the
-		 * critical acceptable range of v-f combination.
-		 */
-		AVSDEBUG("cpu=%d l2=%d vu=%d\n", cpu, l2, vu);
-		AVSDEBUG("Voltage up at %d\n", cur_freq_idx);
-
-		if (cur_voltage >= VOLTAGE_MAX)
-			printk(KERN_ERR
-				"AVS: Voltage can not get high enough!\n");
-
-		/* Raise the voltage for all frequencies */
-		for (i = 0; i < avs_state.freq_cnt; i++) {
-			vdd_table[i] = cur_voltage + VOLTAGE_STEP;
-			if (vdd_table[i] > VOLTAGE_MAX)
-				vdd_table[i] = VOLTAGE_MAX;
-		}
-	} else if ((cpu == 1) && (l2 == 1) && (vu == 1)) {
-		if ((cur_voltage - VOLTAGE_STEP >= VOLTAGE_MIN) &&
-		    (cur_voltage <= vdd_table[cur_freq_idx])) {
-			vdd_table[cur_freq_idx] = cur_voltage - VOLTAGE_STEP;
-			AVSDEBUG("Voltage down for %d and lower levels\n",
-				cur_freq_idx);
-
-			/* clamp to this voltage for all lower levels */
-			for (i = 0; i < cur_freq_idx; i++) {
-				if (vdd_table[i] > vdd_table[cur_freq_idx])
-					vdd_table[i] = vdd_table[cur_freq_idx];
-			}
-		}
-	}
-}
-
-/*
- * Return the voltage for the target performance freq_idx and optionally
- * use AVS hardware to check the present voltage freq_idx
- */
-static short avs_get_target_voltage(int freq_idx, bool update_table)
-{
-	unsigned cur_tempr = GET_TEMPR();
-	unsigned temp_index = cur_tempr*avs_state.freq_cnt;
-
-	/* Table of voltages vs frequencies for this temp */
-	short *vdd_table = avs_state.avs_v + temp_index;
-
-	if (update_table)
-		avs_update_voltage_table(vdd_table);
-
-	return vdd_table[freq_idx];
-}
-
-
-/*
- * Set the voltage for the freq_idx and optionally
- * use AVS hardware to update the voltage
- */
-static int avs_set_target_voltage(int freq_idx, bool update_table)
-{
-	int rc = 0;
-	int new_voltage = avs_get_target_voltage(freq_idx, update_table);
-	if (avs_state.vdd != new_voltage) {
-		AVSDEBUG("AVS setting V to %d mV @%d\n",
-			new_voltage, freq_idx);
-		rc = avs_state.set_vdd(new_voltage);
-		if (rc)
-			return rc;
-		avs_state.vdd = new_voltage;
-	}
-	return rc;
-}
-
-/*
- * Notify avs of clk frquency transition begin & end
- */
-int avs_adjust_freq(u32 freq_idx, int begin)
-{
-	int rc = 0;
-
-	if (!avs_state.set_vdd) {
-		/* AVS not initialized */
-		return 0;
-	}
-
-	if (freq_idx >= avs_state.freq_cnt) {
-		AVSDEBUG("Out of range :%d\n", freq_idx);
-		return -EINVAL;
-	}
-
-	mutex_lock(&avs_lock);
-	if ((begin && (freq_idx > avs_state.freq_idx)) ||
-	    (!begin && (freq_idx < avs_state.freq_idx))) {
-		/* Update voltage before increasing frequency &
-		 * after decreasing frequency
-		 */
-		rc = avs_set_target_voltage(freq_idx, 0);
-		if (rc)
-			goto aaf_out;
-
-		avs_state.freq_idx = freq_idx;
-	}
-	avs_state.changing = begin;
-aaf_out:
-	mutex_unlock(&avs_lock);
-
-	return rc;
-}
-
-
-static struct delayed_work avs_work;
-static struct workqueue_struct  *kavs_wq;
-#define AVS_DELAY ((CONFIG_HZ * 50 + 999) / 1000)
-
-static void do_avs_timer(struct work_struct *work)
-{
-	int cur_freq_idx;
-
-	mutex_lock(&avs_lock);
-	if (!avs_state.changing) {
-		/* Only adjust the voltage if clk is stable */
-		cur_freq_idx = avs_state.freq_idx;
-		avs_set_target_voltage(cur_freq_idx, 1);
-	}
-	mutex_unlock(&avs_lock);
-	queue_delayed_work_on(0, kavs_wq, &avs_work, AVS_DELAY);
-}
-
-
-static void __init avs_timer_init(void)
-{
-	INIT_DELAYED_WORK_DEFERRABLE(&avs_work, do_avs_timer);
-	queue_delayed_work_on(0, kavs_wq, &avs_work, AVS_DELAY);
-}
-
-static void __exit avs_timer_exit(void)
-{
-	cancel_delayed_work(&avs_work);
-}
-
-static int __init avs_work_init(void)
-{
-	kavs_wq = create_workqueue("avs");
-	if (!kavs_wq) {
-		printk(KERN_ERR "AVS initialization failed\n");
-		return -EFAULT;
-	}
-	avs_timer_init();
-
-	return 1;
-}
-
-static void __exit avs_work_exit(void)
-{
-	avs_timer_exit();
-	destroy_workqueue(kavs_wq);
-}
-
-int __init avs_init(int (*set_vdd)(int), u32 freq_cnt, u32 freq_idx)
-{
-	int i;
-
-	mutex_init(&avs_lock);
-
-	if (freq_cnt == 0)
-		return -EINVAL;
-
-	avs_state.freq_cnt = freq_cnt;
-
-	if (freq_idx >= avs_state.freq_cnt)
-		return -EINVAL;
-
-	avs_state.avs_v = kmalloc(TEMPRS * avs_state.freq_cnt *
-		sizeof(avs_state.avs_v[0]), GFP_KERNEL);
-
-	if (avs_state.avs_v == 0)
-		return -ENOMEM;
-
-	for (i = 0; i < TEMPRS*avs_state.freq_cnt; i++)
-		avs_state.avs_v[i] = VOLTAGE_MAX;
-
-	avs_reset_delays(AVSDSCR_INPUT);
-	avs_set_tscsr(TSCSR_INPUT);
-
-	avs_state.set_vdd = set_vdd;
-	avs_state.changing = 0;
-	avs_state.freq_idx = -1;
-	avs_state.vdd = -1;
-	avs_adjust_freq(freq_idx, 0);
-
-	avs_work_init();
-
-	return 0;
-}
-
-void __exit avs_exit()
-{
-	avs_work_exit();
-
-	kfree(avs_state.avs_v);
-}
-
-
diff --git a/arch/arm/mach-msm/avs.h b/arch/arm/mach-msm/avs.h
index e87bded..556603a 100644
--- a/arch/arm/mach-msm/avs.h
+++ b/arch/arm/mach-msm/avs.h
@@ -14,23 +14,6 @@
 #ifndef AVS_H
 #define AVS_H
 
-#define VOLTAGE_MIN  1000 /* mV */
-#define VOLTAGE_MAX  1250
-#define VOLTAGE_STEP 25
-
-int __init avs_init(int (*set_vdd)(int), u32 freq_cnt, u32 freq_idx);
-void __exit avs_exit(void);
-
-int avs_adjust_freq(u32 freq_index, int begin);
-
-/* Routines exported from avs_hw.S */
-#ifdef CONFIG_MSM_CPU_AVS
-u32 avs_test_delays(void);
-#else
-static inline u32 avs_test_delays(void)
-{ return 0; }
-#endif
-
 #ifdef CONFIG_MSM_AVS_HW
 u32 avs_reset_delays(u32 avsdscr);
 u32 avs_get_avscsr(void);
@@ -54,9 +37,6 @@
 static inline void avs_enable(u32 avscsr) {}
 #endif
 
-/*#define AVSDEBUG(x...) pr_info("AVS: " x);*/
-#define AVSDEBUG(...)
-
 #define AVS_DISABLE(cpu) do {			\
 		if (get_cpu() == (cpu))		\
 			avs_disable();		\
diff --git a/arch/arm/mach-msm/avs_hw.S b/arch/arm/mach-msm/avs_hw.S
index efb9c47..6fad8bd 100644
--- a/arch/arm/mach-msm/avs_hw.S
+++ b/arch/arm/mach-msm/avs_hw.S
@@ -13,52 +13,6 @@
 
 	.text
 
-#ifdef CONFIG_MSM_CPU_AVS
-	.global avs_test_delays
-avs_test_delays:
-
-/*      Read r1=CPMR and enable Never Sleep for VSLPDLY */
-		mrc  p15, 7, r1, c15, c0, 5
-		orr  r12, r1, #3, 24
-		mcr  p15, 7, r12, c15, c0, 5
-
-/*      Read r2=CPACR and enable full access to CP10 and CP11 space */
-		mrc p15, 0, r2, c1, c0, 2
-		orr r12, r2, #(0xf << 20)
-		mcr p15, 0, r12, c1, c0, 2
-		isb
-
-/*      Read r3=FPEXC and or in FP enable, VFP/ASE enable = FPEXC[30]; */
-		fmrx r3, fpexc
-		orr  r12, r3, #1, 2
-		fmxr fpexc, r12
-
-/*
- *      Do floating-point operations to prime the VFP pipeline.   Use
- *      fcpyd d0, d0 as a floating point nop.  This avoids changing VFP
- *      state.
- */
-		fcpyd d0, d0
-		fcpyd d0, d0
-		fcpyd d0, d0
-
-/*      Read r0=AVSCSR to get status from CPU, VFP, and L2 ring oscillators */
-		mrc p15, 7, r0, c15, c1, 7
-
-/*      Restore FPEXC */
-		fmxr fpexc, r3
-
-/*      Restore CPACR */
-                MCR p15, 0, r2, c1, c0, 2
-
-/*      Restore CPMR */
-		mcr p15, 7, r1, c15, c0, 5
-                isb
-
-		bx lr
-#endif
-
-
 	.global avs_get_avscsr
 /*      Read r0=AVSCSR to get status from CPU, VFP, and L2 ring oscillators */
 
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index fc44b18..9e34f47 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));
@@ -1624,7 +1647,8 @@
 		msm_gpiomux_install(mpq8064_mi2s_configs,
 			ARRAY_SIZE(mpq8064_mi2s_configs));
 
-	msm_gpiomux_install(apq8064_ext_regulator_configs,
+	if (!machine_is_mpq8064_hrd())
+		msm_gpiomux_install(apq8064_ext_regulator_configs,
 			ARRAY_SIZE(apq8064_ext_regulator_configs));
 
 	if (machine_is_apq8064_mtp()) {
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 38ac83e..6b15883 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -51,7 +51,7 @@
 		.ss_win_size_min_us	= 1000000,
 		.ss_win_size_max_us	= 1000000,
 		.ss_util_pct		= 95,
-		.ss_iobusy_conv		= 100,
+		.ss_no_corr_below_freq	= 0,
 	},
 
 	.energy_coeffs		= {
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..c5bea4f 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -25,6 +25,7 @@
 #include <linux/mfd/pm8xxx/misc.h>
 #include <linux/msm_ssbi.h>
 #include <linux/spi/spi.h>
+#include <linux/dma-contiguous.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/qcom_crypto_device.h>
 #include <linux/msm_ion.h>
@@ -101,6 +102,7 @@
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define HOLE_SIZE		0x20000
+#define MSM_ION_MFC_META_SIZE  0x40000 /* 256 Kbytes */
 #define MSM_CONTIG_MEM_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE		0x3800000
@@ -114,7 +116,7 @@
 #define MSM_ION_HEAP_NUM	8
 #endif
 #define MSM_ION_MM_FW_SIZE	(0x200000 - HOLE_SIZE) /* (2MB - 128KB) */
-#define MSM_ION_MFC_SIZE	SZ_8K
+#define MSM_ION_MFC_SIZE	(SZ_8K + MSM_ION_MFC_META_SIZE)
 #define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
 #else
 #define MSM_CONTIG_MEM_SIZE  0x110C000
@@ -295,6 +297,8 @@
 	.reusable = FMEM_ENABLED,
 	.mem_is_fmem = FMEM_ENABLED,
 	.fixed_position = FIXED_MIDDLE,
+	.is_cma = 1,
+	.no_nonsecure_alloc = 1,
 };
 
 static struct ion_cp_heap_pdata cp_mfc_apq8064_ion_pdata = {
@@ -303,6 +307,7 @@
 	.reusable = 0,
 	.mem_is_fmem = FMEM_ENABLED,
 	.fixed_position = FIXED_HIGH,
+	.no_nonsecure_alloc = 1,
 };
 
 static struct ion_co_heap_pdata co_apq8064_ion_pdata = {
@@ -319,6 +324,17 @@
 };
 #endif
 
+static u64 msm_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device ion_mm_heap_device = {
+	.name = "ion-mm-heap-device",
+	.id = -1,
+	.dev = {
+		.dma_mask = &msm_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	}
+};
+
 /**
  * These heaps are listed in the order they will be allocated. Due to
  * video hardware restrictions and content protection the FW heap has to
@@ -330,9 +346,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,
@@ -346,6 +360,7 @@
 			.size	= MSM_ION_MM_SIZE,
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *) &cp_mm_apq8064_ion_pdata,
+			.priv	= &ion_mm_heap_device.dev
 		},
 		{
 			.id	= ION_MM_FIRMWARE_HEAP_ID,
@@ -395,7 +410,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 = {
@@ -451,26 +470,45 @@
 {
 #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
 	unsigned int i;
+	unsigned int ret;
 	unsigned int fixed_size = 0;
 	unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
 	unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+	unsigned long cma_alignment;
+	unsigned int low_use_cma = 0;
+	unsigned int middle_use_cma = 0;
+	unsigned int high_use_cma = 0;
+
 
 	fixed_low_size = 0;
 	fixed_middle_size = 0;
 	fixed_high_size = 0;
 
+	cma_alignment = PAGE_SIZE << max(MAX_ORDER, pageblock_order);
+
 	for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
-		const struct ion_platform_heap *heap =
+		struct ion_platform_heap *heap =
 			&(apq8064_ion_pdata.heaps[i]);
+		int use_cma = 0;
+
 
 		if (heap->extra_data) {
 			int fixed_position = NOT_FIXED;
 
 			switch ((int)heap->type) {
 			case ION_HEAP_TYPE_CP:
+				if (((struct ion_cp_heap_pdata *)
+					heap->extra_data)->is_cma) {
+					heap->size = ALIGN(heap->size,
+						cma_alignment);
+					use_cma = 1;
+				}
 				fixed_position = ((struct ion_cp_heap_pdata *)
 					heap->extra_data)->fixed_position;
 				break;
+			case ION_HEAP_TYPE_DMA:
+				use_cma = 1;
+				/* Purposely fall through here */
 			case ION_HEAP_TYPE_CARVEOUT:
 				fixed_position = ((struct ion_co_heap_pdata *)
 					heap->extra_data)->fixed_position;
@@ -484,28 +522,70 @@
 			else
 				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
 
-			if (fixed_position == FIXED_LOW)
+			if (fixed_position == FIXED_LOW) {
 				fixed_low_size += heap->size;
-			else if (fixed_position == FIXED_MIDDLE)
+				low_use_cma = use_cma;
+			} else if (fixed_position == FIXED_MIDDLE) {
 				fixed_middle_size += heap->size;
-			else if (fixed_position == FIXED_HIGH)
+				middle_use_cma = use_cma;
+			} else if (fixed_position == FIXED_HIGH) {
 				fixed_high_size += heap->size;
+				high_use_cma = use_cma;
+			} else if (use_cma) {
+				/*
+				 * Heaps that use CMA but are not part of the
+				 * fixed set. Create wherever.
+				 */
+				dma_declare_contiguous(
+					heap->priv,
+					heap->size,
+					0,
+					0xb0000000);
+
+			}
 		}
 	}
 
 	if (!fixed_size)
 		return;
 
-	/* Since the fixed area may be carved out of lowmem,
-	 * make sure the length is a multiple of 1M.
+	/*
+	 * Given the setup for the fixed area, we can't round up all sizes.
+	 * Some sizes must be set up exactly and aligned correctly. Incorrect
+	 * alignments are considered a configuration issue
 	 */
-	fixed_size = (fixed_size + HOLE_SIZE + SECTION_SIZE - 1)
-		& SECTION_MASK;
-	apq8064_reserve_fixed_area(fixed_size);
 
 	fixed_low_start = APQ8064_FIXED_AREA_START;
+	if (low_use_cma) {
+		BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, cma_alignment));
+		BUG_ON(!IS_ALIGNED(fixed_low_start, cma_alignment));
+	} else {
+		BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, SECTION_SIZE));
+		ret = memblock_remove(fixed_low_start,
+				      fixed_low_size + HOLE_SIZE);
+		BUG_ON(ret);
+	}
+
 	fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
+	if (middle_use_cma) {
+		BUG_ON(!IS_ALIGNED(fixed_middle_start, cma_alignment));
+		BUG_ON(!IS_ALIGNED(fixed_middle_size, cma_alignment));
+	} else {
+		BUG_ON(!IS_ALIGNED(fixed_middle_size, SECTION_SIZE));
+		ret = memblock_remove(fixed_middle_start, fixed_middle_size);
+		BUG_ON(ret);
+	}
+
 	fixed_high_start = fixed_middle_start + fixed_middle_size;
+	if (high_use_cma) {
+		fixed_high_size = ALIGN(fixed_high_size, cma_alignment);
+		BUG_ON(!IS_ALIGNED(fixed_high_start, cma_alignment));
+	} else {
+		/* This is the end of the fixed area so it's okay to round up */
+		fixed_high_size = ALIGN(fixed_high_size, SECTION_SIZE);
+		ret = memblock_remove(fixed_high_start, fixed_high_size);
+		BUG_ON(ret);
+	}
 
 	for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
 		struct ion_platform_heap *heap = &(apq8064_ion_pdata.heaps[i]);
@@ -521,6 +601,7 @@
 				fixed_position = pdata->fixed_position;
 				break;
 			case ION_HEAP_TYPE_CARVEOUT:
+			case ION_HEAP_TYPE_DMA:
 				fixed_position = ((struct ion_co_heap_pdata *)
 					heap->extra_data)->fixed_position;
 				break;
@@ -534,6 +615,14 @@
 				break;
 			case FIXED_MIDDLE:
 				heap->base = fixed_middle_start;
+				if (middle_use_cma) {
+					ret = dma_declare_contiguous(
+						heap->priv,
+						heap->size,
+						fixed_middle_start,
+						0xa0000000);
+					WARN_ON(ret);
+				}
 				pdata->secure_base = fixed_middle_start
 								- HOLE_SIZE;
 				pdata->secure_size = HOLE_SIZE + heap->size;
@@ -1548,10 +1637,10 @@
 static struct cyttsp_platform_data cyttsp_pdata = {
 	.panel_maxx = 634,
 	.panel_maxy = 1166,
-	.disp_maxx = 599,
-	.disp_maxy = 1023,
-	.disp_minx = 0,
-	.disp_miny = 0,
+	.disp_minx = 18,
+	.disp_maxx = 617,
+	.disp_miny = 18,
+	.disp_maxy = 1041,
 	.flags = 0x01,
 	.gen = CY_GEN3,
 	.use_st = CY_USE_ST,
@@ -2440,6 +2529,13 @@
 	&apq8064_device_ssbi_pmic2,
 };
 
+static struct platform_device *pm8921_mpq_hrd_common_devices[] __initdata = {
+	&apq8064_device_ext_5v_vreg,
+	&apq8064_device_ext_mpp8_vreg,
+	&apq8064_device_ssbi_pmic1,
+	&apq8064_device_ssbi_pmic2,
+};
+
 static struct platform_device *pm8917_common_devices[] __initdata = {
 	&apq8064_device_ext_mpp8_vreg,
 	&apq8064_device_ext_3p3v_vreg,
@@ -2632,6 +2728,11 @@
 	.id	= -1,
 };
 
+static struct platform_device sp_input_loopback_pdev = {
+	.name	= "sp-user-input",
+	.id	= -1,
+};
+
 static int rf4ce_gpio_init(void)
 {
 	if (!machine_is_mpq8064_cdp() &&
@@ -2696,6 +2797,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
@@ -2712,6 +2814,7 @@
 #endif
 	&rc_input_loopback_pdev,
 	&mpq8064_device_qup_spi_gsbi6,
+	&sp_input_loopback_pdev,
 };
 
 static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
@@ -2792,10 +2895,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);
@@ -3147,6 +3261,11 @@
 	},
 };
 
+static struct platform_device msm_dev_avtimer_device = {
+	.name = "dev_avtimer",
+	.dev = { .platform_data = &dev_avtimer_pdata },
+};
+
 /* Sensors DSPS platform data */
 #define DSPS_PIL_GENERIC_NAME		"dsps"
 static void __init apq8064_init_dsps(void)
@@ -3446,9 +3565,14 @@
 
 	platform_add_devices(early_common_devices,
 				ARRAY_SIZE(early_common_devices));
-	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
-		platform_add_devices(pm8921_common_devices,
-					ARRAY_SIZE(pm8921_common_devices));
+	if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+		if (!machine_is_mpq8064_hrd())
+			platform_add_devices(pm8921_common_devices,
+				ARRAY_SIZE(pm8921_common_devices));
+		else
+			platform_add_devices(pm8921_mpq_hrd_common_devices,
+				ARRAY_SIZE(pm8921_mpq_hrd_common_devices));
+	}
 	else
 		platform_add_devices(pm8917_common_devices,
 					ARRAY_SIZE(pm8917_common_devices));
@@ -3586,6 +3710,9 @@
 		platform_device_register(&mpq_keypad_device);
 	} else if (machine_is_mpq8064_hrd())
 		platform_device_register(&mpq_hrd_keys_pdev);
+	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+		machine_is_mpq8064_dtv())
+		platform_device_register(&msm_dev_avtimer_device);
 }
 
 MACHINE_START(APQ8064_CDP, "QCT APQ8064 CDP")
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 3e90489..fde82f4 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -64,6 +64,8 @@
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
 	CLK_DUMMY("iface_clk",  HSUSB_IFACE_CLK, "f9a55000.usb", OFF),
 	CLK_DUMMY("core_clk",	HSUSB_CORE_CLK, "f9a55000.usb", OFF),
+	CLK_DUMMY("dfab_clk",	DFAB_CLK, "msm_sps", OFF),
+	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK, "msm_sps", OFF),
 	CLK_DUMMY("iface_clk",	NULL,		"msm_sdcc.1", OFF),
 	CLK_DUMMY("core_clk",	NULL,		"msm_sdcc.1", OFF),
 	CLK_DUMMY("bus_clk",	NULL,		"msm_sdcc.1", OFF),
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
index 42fe1ea..a4bafa5 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8910.c
@@ -58,24 +58,6 @@
 	return MEMTYPE_EBI1;
 }
 
-static struct clk_lookup msm_clocks_dummy[] = {
-	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
-	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
-	CLK_DUMMY("iface_clk",  HSUSB_IFACE_CLK, "f9a55000.usb", OFF),
-	CLK_DUMMY("core_clk",	HSUSB_CORE_CLK, "f9a55000.usb", OFF),
-	CLK_DUMMY("iface_clk",	NULL,		"msm_sdcc.1", OFF),
-	CLK_DUMMY("core_clk",	NULL,		"msm_sdcc.1", OFF),
-	CLK_DUMMY("bus_clk",	NULL,		"msm_sdcc.1", OFF),
-	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),
-};
-
-static struct clock_init_data msm_dummy_clock_init_data __initdata = {
-	.table = msm_clocks_dummy,
-	.size = ARRAY_SIZE(msm_clocks_dummy),
-};
-
 static struct of_dev_auxdata msm8910_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
 			"msm_sdcc.1", NULL),
@@ -105,7 +87,11 @@
 	struct of_dev_auxdata *adata = msm8910_auxdata_lookup;
 
 	msm8910_init_gpiomux();
-	msm_clock_init(&msm_dummy_clock_init_data);
+
+	if (machine_is_msm8910_rumi())
+		msm_clock_init(&msm8910_rumi_clock_init_data);
+	else
+		msm_clock_init(&msm8910_clock_init_data);
 
 	if (socinfo_init() < 0)
 		pr_err("%s: socinfo_init() failed\n", __func__);
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index be55031..e35b3c1 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -264,7 +264,7 @@
 	{
 		.src = MSM_BUS_MASTER_VFE,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = 274406400,
+		.ab  = 600000000,
 		.ib  = 2656000000UL,
 	},
 	{
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..5d4f874 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -29,6 +29,7 @@
 #ifdef CONFIG_ANDROID_PMEM
 #include <linux/android_pmem.h>
 #endif
+#include <linux/dma-contiguous.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/qcom_crypto_device.h>
 #include <linux/platform_data/qcom_wcnss_device.h>
@@ -132,7 +133,7 @@
 #endif
 
 #define MSM_PMEM_ADSP_SIZE         0x7800000
-#define MSM_PMEM_AUDIO_SIZE        0x314000
+#define MSM_PMEM_AUDIO_SIZE        0x408000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 #define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 #else
@@ -341,6 +342,8 @@
 	.reusable = FMEM_ENABLED,
 	.mem_is_fmem = FMEM_ENABLED,
 	.fixed_position = FIXED_MIDDLE,
+	.is_cma	= 1,
+	.no_nonsecure_alloc = 1,
 };
 
 static struct ion_cp_heap_pdata cp_mfc_msm8930_ion_pdata = {
@@ -349,6 +352,7 @@
 	.reusable = 0,
 	.mem_is_fmem = FMEM_ENABLED,
 	.fixed_position = FIXED_HIGH,
+	.no_nonsecure_alloc = 1,
 };
 
 static struct ion_co_heap_pdata co_msm8930_ion_pdata = {
@@ -365,6 +369,18 @@
 };
 #endif
 
+
+static u64 msm_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device ion_mm_heap_device = {
+	.name = "ion-mm-heap-device",
+	.id = -1,
+	.dev = {
+		.dma_mask = &msm_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	}
+};
+
 /**
  * These heaps are listed in the order they will be allocated. Due to
  * video hardware restrictions and content protection the FW heap has to
@@ -376,9 +392,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,
@@ -392,6 +406,7 @@
 			.size	= MSM_ION_MM_SIZE,
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *) &cp_mm_msm8930_ion_pdata,
+			.priv	= &ion_mm_heap_device.dev
 		},
 		{
 			.id	= ION_MM_FIRMWARE_HEAP_ID,
@@ -441,7 +456,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 = {
@@ -497,26 +517,44 @@
 {
 #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
 	unsigned int i;
+	int ret;
 	unsigned int fixed_size = 0;
 	unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
 	unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+	unsigned long cma_alignment;
+	unsigned int low_use_cma = 0;
+	unsigned int middle_use_cma = 0;
+	unsigned int high_use_cma = 0;
 
 	fixed_low_size = 0;
 	fixed_middle_size = 0;
 	fixed_high_size = 0;
 
+	cma_alignment = PAGE_SIZE << max(MAX_ORDER, pageblock_order);
+
 	for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
-		const struct ion_platform_heap *heap =
+		struct ion_platform_heap *heap =
 						&(msm8930_ion_pdata.heaps[i]);
 
+		int use_cma = 0;
+
 		if (heap->extra_data) {
 			int fixed_position = NOT_FIXED;
 
 			switch ((int) heap->type) {
 			case ION_HEAP_TYPE_CP:
+				if (((struct ion_cp_heap_pdata *)
+					heap->extra_data)->is_cma) {
+					heap->size = ALIGN(heap->size,
+						cma_alignment);
+						use_cma = 1;
+				}
 				fixed_position = ((struct ion_cp_heap_pdata *)
 					heap->extra_data)->fixed_position;
 				break;
+			case ION_HEAP_TYPE_DMA:
+				use_cma = 1;
+				/* Purposely fall through here */
 			case ION_HEAP_TYPE_CARVEOUT:
 				fixed_position = ((struct ion_co_heap_pdata *)
 					heap->extra_data)->fixed_position;
@@ -530,29 +568,68 @@
 			else
 				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
 
-			if (fixed_position == FIXED_LOW)
+			if (fixed_position == FIXED_LOW) {
 				fixed_low_size += heap->size;
-			else if (fixed_position == FIXED_MIDDLE)
+				low_use_cma = use_cma;
+			} else if (fixed_position == FIXED_MIDDLE) {
 				fixed_middle_size += heap->size;
-			else if (fixed_position == FIXED_HIGH)
+				middle_use_cma = use_cma;
+			} else if (fixed_position == FIXED_HIGH) {
 				fixed_high_size += heap->size;
-
+				high_use_cma = use_cma;
+			} else if (use_cma) {
+				/*
+				 * Heaps that use CMA but are not part of the
+				 * fixed set. Create wherever.
+				 */
+				dma_declare_contiguous(
+					heap->priv,
+					heap->size,
+					0,
+					0xb0000000);
+			}
 		}
 	}
 
 	if (!fixed_size)
 		return;
-
-	/* Since the fixed area may be carved out of lowmem,
-	 * make sure the length is a multiple of 1M.
+	/*
+	 * Given the setup for the fixed area, we can't round up all sizes.
+	 * Some sizes must be set up exactly and aligned correctly. Incorrect
+	 * alignments are considered a configuration issue
 	 */
-	fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
-		& SECTION_MASK;
-	msm8930_reserve_fixed_area(fixed_size);
 
 	fixed_low_start = MSM8930_FIXED_AREA_START;
+	if (low_use_cma) {
+		BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, cma_alignment));
+		BUG_ON(!IS_ALIGNED(fixed_low_start, cma_alignment));
+	} else {
+		BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, SECTION_SIZE));
+		ret = memblock_remove(fixed_low_start,
+				      fixed_low_size + HOLE_SIZE);
+		BUG_ON(ret);
+	}
+
 	fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
+	if (middle_use_cma) {
+		BUG_ON(!IS_ALIGNED(fixed_middle_start, cma_alignment));
+		BUG_ON(!IS_ALIGNED(fixed_middle_size, cma_alignment));
+	} else {
+		BUG_ON(!IS_ALIGNED(fixed_middle_size, SECTION_SIZE));
+		ret = memblock_remove(fixed_middle_start, fixed_middle_size);
+		BUG_ON(ret);
+	}
+
 	fixed_high_start = fixed_middle_start + fixed_middle_size;
+	if (high_use_cma) {
+		fixed_high_size = ALIGN(fixed_high_size, cma_alignment);
+		BUG_ON(!IS_ALIGNED(fixed_high_start, cma_alignment));
+	} else {
+		/* This is the end of the fixed area so it's okay to round up */
+		fixed_high_size = ALIGN(fixed_high_size, SECTION_SIZE);
+		ret = memblock_remove(fixed_high_start, fixed_high_size);
+		BUG_ON(ret);
+	}
 
 	for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
 		struct ion_platform_heap *heap = &(msm8930_ion_pdata.heaps[i]);
@@ -567,6 +644,7 @@
 				(struct ion_cp_heap_pdata *)heap->extra_data;
 				fixed_position = pdata->fixed_position;
 				break;
+			case ION_HEAP_TYPE_DMA:
 			case ION_HEAP_TYPE_CARVEOUT:
 				fixed_position = ((struct ion_co_heap_pdata *)
 					heap->extra_data)->fixed_position;
@@ -581,6 +659,12 @@
 				break;
 			case FIXED_MIDDLE:
 				heap->base = fixed_middle_start;
+				if (middle_use_cma)
+					dma_declare_contiguous(
+						&ion_mm_heap_device.dev,
+						heap->size,
+						fixed_middle_start,
+						0xa0000000);
 				pdata->secure_base = fixed_middle_start
 							- HOLE_SIZE;
 				pdata->secure_size = HOLE_SIZE + heap->size;
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 7a2e9e1..3853e4c 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -15,6 +15,7 @@
 #include <linux/gpio.h>
 #include <mach/camera.h>
 #include <mach/msm_bus_board.h>
+#include <mach/socinfo.h>
 #include <mach/gpiomux.h>
 #include "devices.h"
 #include "board-8960.h"
@@ -182,6 +183,23 @@
 	},
 };
 
+static struct msm_gpiomux_config msm8960_cam_2d_configs_sglte[] = {
+	{
+		.gpio = 20,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 21,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+};
+
 #define VFE_CAMIF_TIMER1_GPIO 2
 #define VFE_CAMIF_TIMER2_GPIO 3
 #define VFE_CAMIF_TIMER3_GPIO_INT 4
@@ -828,6 +846,16 @@
 
 void __init msm8960_init_cam(void)
 {
+	if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+		msm_8960_front_cam_gpio_conf.cam_gpiomux_conf_tbl =
+			msm8960_cam_2d_configs_sglte;
+		msm_8960_front_cam_gpio_conf.cam_gpiomux_conf_tbl_size =
+			ARRAY_SIZE(msm8960_cam_2d_configs_sglte);
+		msm_8960_back_cam_gpio_conf.cam_gpiomux_conf_tbl =
+			msm8960_cam_2d_configs_sglte;
+		msm_8960_back_cam_gpio_conf.cam_gpiomux_conf_tbl_size =
+			ARRAY_SIZE(msm8960_cam_2d_configs_sglte);
+	}
 	msm_gpiomux_install(msm8960_cam_common_configs,
 			ARRAY_SIZE(msm8960_cam_common_configs));
 
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..72d926f 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -30,6 +30,7 @@
 #include <linux/android_pmem.h>
 #endif
 #include <linux/cyttsp-qc.h>
+#include <linux/dma-contiguous.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/qcom_crypto_device.h>
 #include <linux/platform_data/qcom_wcnss_device.h>
@@ -151,6 +152,7 @@
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define HOLE_SIZE	0x20000
+#define MSM_ION_MFC_META_SIZE 0x40000 /* 256 Kbytes */
 #define MSM_CONTIG_MEM_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE            0x3800000 /* Need to be multiple of 64K */
@@ -164,7 +166,7 @@
 #define MSM_ION_HEAP_NUM	8
 #endif
 #define MSM_ION_MM_FW_SIZE	(0x200000 - HOLE_SIZE) /* 128kb */
-#define MSM_ION_MFC_SIZE	SZ_8K
+#define MSM_ION_MFC_SIZE	(SZ_8K + MSM_ION_MFC_META_SIZE)
 #define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
 
 #define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000)
@@ -363,6 +365,8 @@
 	.fixed_position = FIXED_MIDDLE,
 	.iommu_map_all = 1,
 	.iommu_2x_map_domain = VIDEO_DOMAIN,
+	.is_cma = 1,
+	.no_nonsecure_alloc = 1,
 };
 
 static struct ion_cp_heap_pdata cp_mfc_msm8960_ion_pdata = {
@@ -371,6 +375,7 @@
 	.reusable = 0,
 	.mem_is_fmem = FMEM_ENABLED,
 	.fixed_position = FIXED_HIGH,
+	.no_nonsecure_alloc = 1,
 };
 
 static struct ion_co_heap_pdata co_msm8960_ion_pdata = {
@@ -387,6 +392,17 @@
 };
 #endif
 
+static u64 msm_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device ion_mm_heap_device = {
+	.name = "ion-mm-heap-device",
+	.id = -1,
+	.dev = {
+		.dma_mask = &msm_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	}
+};
+
 /**
  * These heaps are listed in the order they will be allocated. Due to
  * video hardware restrictions and content protection the FW heap has to
@@ -398,9 +414,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,
@@ -414,6 +428,7 @@
 			.size	= MSM_ION_MM_SIZE,
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *) &cp_mm_msm8960_ion_pdata,
+			.priv	= &ion_mm_heap_device.dev,
 		},
 		{
 			.id	= ION_MM_FIRMWARE_HEAP_ID,
@@ -463,7 +478,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 = {
@@ -546,21 +565,29 @@
 {
 #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
 	unsigned int i;
+	int ret;
 	unsigned int fixed_size = 0;
 	unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
 	unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+	unsigned long cma_alignment;
+	unsigned int low_use_cma = 0;
+	unsigned int middle_use_cma = 0;
+	unsigned int high_use_cma = 0;
 
 	adjust_mem_for_liquid();
 	fixed_low_size = 0;
 	fixed_middle_size = 0;
 	fixed_high_size = 0;
 
+	cma_alignment = PAGE_SIZE << max(MAX_ORDER, pageblock_order);
+
 	for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
 		struct ion_platform_heap *heap =
 						&(msm8960_ion_pdata.heaps[i]);
 		int align = SZ_4K;
 		int iommu_map_all = 0;
 		int adjacent_mem_id = INVALID_HEAP_ID;
+		int use_cma = 0;
 
 		if (heap->extra_data) {
 			int fixed_position = NOT_FIXED;
@@ -574,7 +601,16 @@
 				iommu_map_all =
 					((struct ion_cp_heap_pdata *)
 					heap->extra_data)->iommu_map_all;
+				if (((struct ion_cp_heap_pdata *)
+					heap->extra_data)->is_cma) {
+					heap->size = ALIGN(heap->size,
+							cma_alignment);
+					use_cma = 1;
+				}
 				break;
+			case ION_HEAP_TYPE_DMA:
+					use_cma = 1;
+				/* Purposely fall through here */
 			case ION_HEAP_TYPE_CARVEOUT:
 				fixed_position = ((struct ion_co_heap_pdata *)
 					heap->extra_data)->fixed_position;
@@ -598,28 +634,71 @@
 			else
 				reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
 
-			if (fixed_position == FIXED_LOW)
+			if (fixed_position == FIXED_LOW) {
 				fixed_low_size += heap->size;
-			else if (fixed_position == FIXED_MIDDLE)
+				low_use_cma = use_cma;
+			} else if (fixed_position == FIXED_MIDDLE) {
 				fixed_middle_size += heap->size;
-			else if (fixed_position == FIXED_HIGH)
+				middle_use_cma = use_cma;
+			} else if (fixed_position == FIXED_HIGH) {
 				fixed_high_size += heap->size;
+				high_use_cma = use_cma;
+			} else if (use_cma) {
+				/*
+				 * Heaps that use CMA but are not part of the
+				 * fixed set. Create wherever.
+				 */
+				dma_declare_contiguous(
+					heap->priv,
+					heap->size,
+					0,
+					0xb0000000);
+			}
 		}
 	}
 
 	if (!fixed_size)
 		return;
 
-	/* Since the fixed area may be carved out of lowmem,
-	 * make sure the length is a multiple of 1M.
+	/*
+	 * Given the setup for the fixed area, we can't round up all sizes.
+	 * Some sizes must be set up exactly and aligned correctly. Incorrect
+	 * alignments are considered a configuration issue
 	 */
-	fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
-		& SECTION_MASK;
-	msm8960_reserve_fixed_area(fixed_size);
 
 	fixed_low_start = MSM8960_FIXED_AREA_START;
+	if (low_use_cma) {
+		BUG_ON(!IS_ALIGNED(fixed_low_start, cma_alignment));
+		BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, cma_alignment));
+	} else {
+		BUG_ON(!IS_ALIGNED(fixed_low_size + HOLE_SIZE, SECTION_SIZE));
+		ret = memblock_remove(fixed_low_start,
+				      fixed_low_size + HOLE_SIZE);
+		BUG_ON(ret);
+	}
+
 	fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
+	if (middle_use_cma) {
+		BUG_ON(!IS_ALIGNED(fixed_middle_start, cma_alignment));
+		BUG_ON(!IS_ALIGNED(fixed_middle_size, cma_alignment));
+	} else {
+		BUG_ON(!IS_ALIGNED(fixed_middle_size, SECTION_SIZE));
+		ret = memblock_remove(fixed_middle_start, fixed_middle_size);
+		BUG_ON(ret);
+	}
+
 	fixed_high_start = fixed_middle_start + fixed_middle_size;
+	if (high_use_cma) {
+		fixed_high_size = ALIGN(fixed_high_size, cma_alignment);
+		BUG_ON(!IS_ALIGNED(fixed_high_start, cma_alignment));
+	} else {
+		/* This is the end of the fixed area so it's okay to round up */
+		fixed_high_size = ALIGN(fixed_high_size, SECTION_SIZE);
+		ret = memblock_remove(fixed_high_start, fixed_high_size);
+		BUG_ON(ret);
+	}
+
+
 
 	for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
 		struct ion_platform_heap *heap = &(msm8960_ion_pdata.heaps[i]);
@@ -635,6 +714,7 @@
 				fixed_position = pdata->fixed_position;
 				break;
 			case ION_HEAP_TYPE_CARVEOUT:
+			case ION_HEAP_TYPE_DMA:
 				fixed_position = ((struct ion_co_heap_pdata *)
 					heap->extra_data)->fixed_position;
 				break;
@@ -648,6 +728,14 @@
 				break;
 			case FIXED_MIDDLE:
 				heap->base = fixed_middle_start;
+				if (middle_use_cma) {
+					ret = dma_declare_contiguous(
+						&ion_mm_heap_device.dev,
+						heap->size,
+						fixed_middle_start,
+						0xa0000000);
+					WARN_ON(ret);
+				}
 				pdata->secure_base = fixed_middle_start
 							- HOLE_SIZE;
 				pdata->secure_size = HOLE_SIZE + heap->size;
@@ -663,6 +751,29 @@
 #endif
 }
 
+static void ion_adjust_secure_allocation(void)
+{
+	int i;
+
+	for (i = 0; i < msm8960_ion_pdata.nr; i++) {
+		struct ion_platform_heap *heap =
+			&(msm8960_ion_pdata.heaps[i]);
+
+
+		if (heap->extra_data) {
+			switch ((int) heap->type) {
+			case ION_HEAP_TYPE_CP:
+				if (cpu_is_msm8960()) {
+					((struct ion_cp_heap_pdata *)
+					heap->extra_data)->no_nonsecure_alloc =
+						0;
+				}
+
+			}
+		}
+	}
+}
+
 static void __init reserve_mdp_memory(void)
 {
 	msm8960_mdp_writeback(msm8960_reserve_table);
@@ -1676,7 +1787,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 +1802,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 +3427,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();
@@ -3389,6 +3501,7 @@
 		platform_device_register(&mdm_sglte_device);
 	}
 	msm_pm_set_tz_retention_flag(1);
+	ion_adjust_secure_allocation();
 }
 
 MACHINE_START(MSM8960_CDP, "QCT MSM8960 CDP")
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 89ad4ef..28d50cc 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
 
@@ -67,6 +68,12 @@
 };
 #endif
 
+static struct gpiomux_setting gpio_epm_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv  = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
 static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv  = GPIOMUX_DRV_2MA,
@@ -152,6 +159,53 @@
 
 };
 
+static struct gpiomux_setting hsic_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting hsic_act_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_12MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting hsic_hub_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config msm_hsic_configs[] = {
+	{
+		.gpio = 144,               /*HSIC_STROBE */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+	{
+		.gpio = 145,               /* HSIC_DATA */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config msm_hsic_hub_configs[] = {
+	{
+		.gpio = 50,               /* HSIC_HUB_INT_N */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsic_hub_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+		},
+	},
+};
+
 static struct gpiomux_setting mhl_suspend_config = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
@@ -171,7 +225,6 @@
 	.pull = GPIOMUX_PULL_UP,
 };
 
-
 static struct gpiomux_setting hdmi_suspend_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
@@ -249,6 +302,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)
 	{
@@ -349,6 +417,12 @@
 			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
 		},
 	},
+	{
+		.gpio      = 81,		/* EPM enable */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_epm_config,
+		},
+	},
 };
 
 static struct msm_gpiomux_config msm8974_slimbus_config[] __initdata = {
@@ -622,6 +696,14 @@
 
 	msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
 
+	msm_gpiomux_install(msm_hsic_configs, ARRAY_SIZE(msm_hsic_configs));
+	msm_gpiomux_install(msm_hsic_hub_configs,
+				ARRAY_SIZE(msm_hsic_hub_configs));
+
 	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..f0b6389 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, \
@@ -314,11 +312,6 @@
 			"msm_sdcc.3", NULL),
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98E4000, \
 			"msm_sdcc.4", NULL),
-	OF_DEV_AUXDATA("qcom,pil-q6v5-lpass",   0xFE200000, \
-			"pil-q6v5-lpass", NULL),
-	OF_DEV_AUXDATA("qcom,pil-q6v5-mss", 0xFC880000, "pil-q6v5-mss", NULL),
-	OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
-			"pil_pronto", NULL),
 	OF_DEV_AUXDATA("arm,coresight-tmc", 0xFC322000, \
 			"coresight-tmc-etr", NULL),
 	OF_DEV_AUXDATA("arm,coresight-tpiu", 0xFC318000, \
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 39060ad..2392f57 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,
@@ -880,7 +882,9 @@
 	&msm_device_hsic_host,
 	&msm_device_usb_bam,
 	&msm_android_usb_device,
+#ifdef CONFIG_USB_CI13XXX_MSM_HSIC
 	&msm_android_usb_hsic_device,
+#endif
 	&msm9615_device_uart_gsbi4,
 	&msm9615_device_ext_2p95v_vreg,
 	&msm9615_device_ssbi_pmic1,
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 42f3f41..f6a354f 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -125,135 +125,6 @@
 	msm_reserve();
 }
 
-static struct resource smd_resource[] = {
-	{
-		.name   = "modem_smd_in",
-		.start  = 32 + 25,              /* mss_sw_to_kpss_ipc_irq0  */
-		.flags  = IORESOURCE_IRQ,
-	},
-	{
-		.name   = "modem_smsm_in",
-		.start  = 32 + 26,              /* mss_sw_to_kpss_ipc_irq1  */
-		.flags  = IORESOURCE_IRQ,
-	},
-	{
-		.name   = "adsp_smd_in",
-		.start  = 32 + 156,             /* lpass_to_kpss_ipc_irq0  */
-		.flags  = IORESOURCE_IRQ,
-	},
-	{
-		.name   = "adsp_smsm_in",
-		.start  = 32 + 157,             /* lpass_to_kpss_ipc_irq1  */
-		.flags  = IORESOURCE_IRQ,
-	},
-	{
-		.name   = "rpm_smd_in",
-		.start  = 32 + 168,             /* rpm_to_kpss_ipc_irq4  */
-		.flags  = IORESOURCE_IRQ,
-	},
-};
-
-static struct smd_subsystem_config smd_config_list[] = {
-	{
-		.irq_config_id = SMD_MODEM,
-		.subsys_name = "modem",
-		.edge = SMD_APPS_MODEM,
-
-		.smd_int.irq_name = "modem_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 12,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = "modem_smsm_in",
-		.smsm_int.flags = IRQF_TRIGGER_RISING,
-		.smsm_int.irq_id = -1,
-		.smsm_int.device_name = "smsm_dev",
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 1 << 13,
-		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smsm_int.out_offset = 0x8,
-	},
-	{
-		.irq_config_id = SMD_Q6,
-		.subsys_name = "adsp",
-		.edge = SMD_APPS_QDSP,
-
-		.smd_int.irq_name = "adsp_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 8,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = "adsp_smsm_in",
-		.smsm_int.flags = IRQF_TRIGGER_RISING,
-		.smsm_int.irq_id = -1,
-		.smsm_int.device_name = "smsm_dev",
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 1 << 9,
-		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smsm_int.out_offset = 0x8,
-	},
-	{
-		.irq_config_id = SMD_RPM,
-		.subsys_name = NULL, /* do not use PIL to load RPM */
-		.edge = SMD_APPS_RPM,
-
-		.smd_int.irq_name = "rpm_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 0,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = NULL, /* RPM does not support SMSM */
-		.smsm_int.flags = 0,
-		.smsm_int.irq_id = 0,
-		.smsm_int.device_name = NULL,
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 0,
-		.smsm_int.out_base = NULL,
-		.smsm_int.out_offset = 0,
-	},
-};
-
-static struct smd_smem_regions aux_smem_areas[] = {
-	{
-		.phys_addr = (void *)(0xfc428000),
-		.size = 0x4000,
-	},
-};
-
-static struct smd_subsystem_restart_config smd_ssr_cfg = {
-	.disable_smsm_reset_handshake = 1,
-};
-
-static struct smd_platform smd_platform_data = {
-	.num_ss_configs = ARRAY_SIZE(smd_config_list),
-	.smd_ss_configs = smd_config_list,
-	.smd_ssr_config = &smd_ssr_cfg,
-	.num_smem_areas = ARRAY_SIZE(aux_smem_areas),
-	.smd_smem_areas = aux_smem_areas,
-};
-
-struct platform_device msm_device_smd_9625 = {
-	.name   = "msm_smd",
-	.id     = -1,
-	.resource = smd_resource,
-	.num_resources = ARRAY_SIZE(smd_resource),
-	.dev = {
-		.platform_data = &smd_platform_data,
-	}
-};
-
 #define BIMC_BASE	0xfc380000
 #define BIMC_SIZE	0x0006A000
 #define SYS_NOC_BASE	0xfc460000
@@ -345,11 +216,6 @@
 				ARRAY_SIZE(msm_bus_9625_devices));
 }
 
-void __init msm9625_add_devices(void)
-{
-	platform_device_register(&msm_device_smd_9625);
-}
-
 /*
  * Used to satisfy dependencies for devices that need to be
  * run early or in a particular order. Most likely your device doesn't fall
@@ -376,7 +242,6 @@
 	msm9625_init_gpiomux();
 	of_platform_populate(NULL, of_default_bus_match_table,
 			msm9625_auxdata_lookup, NULL);
-	msm9625_add_devices();
 	msm9625_add_drivers();
 }
 
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 1d6eb01..274b338 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-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
@@ -46,6 +46,7 @@
 #include <linux/msm_adc.h>
 #include <linux/m_adcproc.h>
 #include <linux/platform_data/qcom_crypto_device.h>
+#include <linux/msm_ion.h>
 
 #define PMIC_GPIO_INT		144
 #define PMIC_VREG_WLAN_LEVEL	2900
@@ -723,32 +724,32 @@
 
 static struct resource qcrypto_resources[] = {
 	[0] = {
-		.start = QCE_0_BASE,
-		.end = QCE_0_BASE + QCE_SIZE - 1,
+		.start = QCE_1_BASE,
+		.end = QCE_1_BASE + QCE_SIZE - 1,
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
 		.name = "crypto_channels",
-		.start = DMOV_CE1_IN_CHAN,
-		.end = DMOV_CE1_OUT_CHAN,
+		.start = DMOV_CE2_IN_CHAN,
+		.end = DMOV_CE2_OUT_CHAN,
 		.flags = IORESOURCE_DMA,
 	},
 	[2] = {
 		.name = "crypto_crci_in",
-		.start = DMOV_CE1_IN_CRCI,
-		.end = DMOV_CE1_IN_CRCI,
+		.start = DMOV_CE2_IN_CRCI,
+		.end = DMOV_CE2_IN_CRCI,
 		.flags = IORESOURCE_DMA,
 	},
 	[3] = {
 		.name = "crypto_crci_out",
-		.start = DMOV_CE1_OUT_CRCI,
-		.end = DMOV_CE1_OUT_CRCI,
+		.start = DMOV_CE2_OUT_CRCI,
+		.end = DMOV_CE2_OUT_CRCI,
 		.flags = IORESOURCE_DMA,
 	},
 	[4] = {
 		.name = "crypto_crci_hash",
-		.start = DMOV_CE1_HASH_CRCI,
-		.end = DMOV_CE1_HASH_CRCI,
+		.start = DMOV_CE2_HASH_CRCI,
+		.end = DMOV_CE2_HASH_CRCI,
 		.flags = IORESOURCE_DMA,
 	},
 };
@@ -774,57 +775,6 @@
 
 static struct resource qcedev_resources[] = {
 	[0] = {
-		.start = QCE_0_BASE,
-		.end = QCE_0_BASE + QCE_SIZE - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.name = "crypto_channels",
-		.start = DMOV_CE1_IN_CHAN,
-		.end = DMOV_CE1_OUT_CHAN,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.name = "crypto_crci_in",
-		.start = DMOV_CE1_IN_CRCI,
-		.end = DMOV_CE1_IN_CRCI,
-		.flags = IORESOURCE_DMA,
-	},
-	[3] = {
-		.name = "crypto_crci_out",
-		.start = DMOV_CE1_OUT_CRCI,
-		.end = DMOV_CE1_OUT_CRCI,
-		.flags = IORESOURCE_DMA,
-	},
-	[4] = {
-		.name = "crypto_crci_hash",
-		.start = DMOV_CE1_HASH_CRCI,
-		.end = DMOV_CE1_HASH_CRCI,
-		.flags = IORESOURCE_DMA,
-	},
-};
-
-static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
-	.ce_shared = QCE_NO_CE_SHARED,
-	.shared_ce_resource = QCE_NO_SHARE_CE_RESOURCE,
-	.hw_key_support = QCE_NO_HW_KEY_SUPPORT,
-	.sha_hmac = QCE_NO_SHA_HMAC_SUPPORT,
-	.bus_scale_table = NULL,
-};
-
-static struct platform_device qcedev_device = {
-	.name		= "qce",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(qcedev_resources),
-	.resource	= qcedev_resources,
-	.dev		= {
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-		.platform_data = &qcedev_ce_hw_suppport,
-	},
-};
-
-static struct resource ota_qcrypto_resources[] = {
-	[0] = {
 		.start = QCE_1_BASE,
 		.end = QCE_1_BASE + QCE_SIZE - 1,
 		.flags = IORESOURCE_MEM,
@@ -855,6 +805,57 @@
 	},
 };
 
+static struct msm_ce_hw_support qcedev_ce_hw_suppport = {
+	.ce_shared = QCE_NO_CE_SHARED,
+	.shared_ce_resource = QCE_NO_SHARE_CE_RESOURCE,
+	.hw_key_support = QCE_NO_HW_KEY_SUPPORT,
+	.sha_hmac = QCE_NO_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
+};
+
+static struct platform_device qcedev_device = {
+	.name		= "qce",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(qcedev_resources),
+	.resource	= qcedev_resources,
+	.dev		= {
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &qcedev_ce_hw_suppport,
+	},
+};
+
+static struct resource ota_qcrypto_resources[] = {
+	[0] = {
+		.start = QCE_2_BASE,
+		.end = QCE_2_BASE + QCE_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name = "crypto_channels",
+		.start = DMOV_CE3_IN_CHAN,
+		.end = DMOV_CE3_OUT_CHAN,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.name = "crypto_crci_in",
+		.start = DMOV_CE3_IN_CRCI,
+		.end = DMOV_CE3_IN_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[3] = {
+		.name = "crypto_crci_out",
+		.start = DMOV_CE3_OUT_CRCI,
+		.end = DMOV_CE3_OUT_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+	[4] = {
+		.name = "crypto_crci_hash",
+		.start = DMOV_CE3_HASH_DONE_CRCI,
+		.end = DMOV_CE3_HASH_DONE_CRCI,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
 struct platform_device ota_qcrypto_device = {
 	.name		= "qcota",
 	.id		= 0,
@@ -870,6 +871,27 @@
 	.id		= -1,
 };
 
+struct ion_platform_heap msm_ion_heaps[] = {
+	{
+		.id = ION_SYSTEM_HEAP_ID,
+		.type = ION_HEAP_TYPE_SYSTEM_CONTIG,
+		.name = "kmalloc",
+	},
+};
+
+static struct ion_platform_data msm_ion_pdata = {
+	.nr = 1,
+	.heaps = msm_ion_heaps,
+};
+
+static struct platform_device msm_ion_device = {
+	.name = "ion-msm",
+	.id = 1,
+	.dev = {
+		.platform_data = &msm_ion_pdata,
+	},
+};
+
 /*
  * Devices
  */
@@ -905,6 +927,7 @@
 	&ota_qcrypto_device,
 	&fsm_xo_device,
 	&fsm9xxx_device_watchdog,
+	&msm_ion_device,
 };
 
 static void __init fsm9xxx_init_irq(void)
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 2983dc0..4ec1d33 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,
@@ -878,7 +887,9 @@
 		ft5x06_touchpad_setup();
 	}
 
-	/* headset */
+	/* headset and power key*/
+	/* ignore end key as this target doesn't need it */
+	hs_platform_data.ignore_end_key = true;
 	platform_device_register(&hs_pdev);
 
 	/* vibrator */
@@ -887,13 +898,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-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index 07ff389..5351d41 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -369,6 +369,14 @@
 	if (!(machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())) {
 		if (mmc_regulator_init(3, "emmc", 3000000))
 			return;
+		/*
+		 * On 7x25A FFA data CRC errors are seen, which are
+		 * probably due to the proximity of SIM card and eMMC.
+		 * Hence, reducing the clock to 24.7Mhz from 49Mhz.
+		 */
+		if (machine_is_msm7625a_ffa())
+			sdc3_plat_data.msmsdcc_fmax =
+				sdc3_plat_data.msmsdcc_fmid;
 		msm_add_sdcc(3, &sdc3_plat_data);
 	}
 #endif
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 4e14ff3..2bd92f2 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -403,7 +403,7 @@
 					.idle_enabled = 0,
 					.suspend_enabled = 0,
 					.latency = 500,
-					.residency = 6000,
+					.residency = 500,
 	},
 
 	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -422,7 +422,7 @@
 					.idle_enabled = 0,
 					.suspend_enabled = 0,
 					.latency = 500,
-					.residency = 6000,
+					.residency = 500,
 	},
 
 	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -441,7 +441,7 @@
 					.idle_enabled = 0,
 					.suspend_enabled = 0,
 					.latency = 500,
-					.residency = 6000,
+					.residency = 500,
 	},
 
 	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -460,7 +460,7 @@
 					.idle_enabled = 0,
 					.suspend_enabled = 0,
 					.latency = 500,
-					.residency = 6000,
+					.residency = 500,
 	},
 
 	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -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 = {
@@ -952,7 +954,7 @@
 	}
 	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
 
-	if (cpu_is_msm8625())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		rpc_adsp_pdev->pdev = msm8625_device_adsp;
 	else
 		rpc_adsp_pdev->pdev = msm_adsp_device;
@@ -1029,7 +1031,7 @@
 {
 	msm7x27a_cfg_uart2dm_serial();
 	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
-	if (cpu_is_msm8625())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		msm8625_device_uart_dm1.dev.platform_data =
 			&msm_uart_dm1_pdata;
 	else
@@ -1038,7 +1040,7 @@
 
 static void __init msm7x27a_otg_gadget(void)
 {
-	if (cpu_is_msm8625()) {
+	if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		msm_otg_pdata.swfi_latency =
 		msm8625_pm_data[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency;
 		msm8625_device_otg.dev.platform_data = &msm_otg_pdata;
@@ -1078,7 +1080,7 @@
 	/* Initialize regulators first so that other devices can use them */
 	msm7x27a_init_regulators();
 	msm_adsp_add_pdev();
-	if (cpu_is_msm8625())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		msm8625_device_i2c_init();
 	else
 		msm7x27a_device_i2c_init();
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..53d3023 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" },
@@ -377,7 +382,7 @@
 					.idle_enabled = 0,
 					.suspend_enabled = 0,
 					.latency = 500,
-					.residency = 6000,
+					.residency = 500,
 	},
 
 	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -396,7 +401,7 @@
 					.idle_enabled = 0,
 					.suspend_enabled = 0,
 					.latency = 500,
-					.residency = 6000,
+					.residency = 500,
 	},
 
 	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -415,7 +420,7 @@
 					.idle_enabled = 0,
 					.suspend_enabled = 0,
 					.latency = 500,
-					.residency = 6000,
+					.residency = 500,
 	},
 
 	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -434,7 +439,7 @@
 					.idle_enabled = 0,
 					.suspend_enabled = 0,
 					.latency = 500,
-					.residency = 6000,
+					.residency = 500,
 	},
 
 	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
@@ -662,6 +667,10 @@
 /* Regulator configuration for the NCP6335D buck */
 struct regulator_consumer_supply ncp6335d_consumer_supplies[] = {
 	REGULATOR_SUPPLY("ncp6335d", NULL),
+	/* TO DO: NULL entry needs to be fixed once
+	 * we fix the cross-dependencies.
+	*/
+	REGULATOR_SUPPLY("vddx_cx", NULL),
 };
 
 static struct regulator_init_data ncp6335d_init_data = {
@@ -797,10 +806,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 +838,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 = {
@@ -926,7 +937,7 @@
 	}
 	rpc_adsp_pdev->prog = ADSP_RPC_PROG;
 
-	if (cpu_is_msm8625())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		rpc_adsp_pdev->pdev = msm8625_device_adsp;
 	else
 		rpc_adsp_pdev->pdev = msm_adsp_device;
@@ -994,6 +1005,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,
@@ -1033,7 +1045,7 @@
 static void __init qrd7627a_uart1dm_config(void)
 {
 	msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
-	if (cpu_is_msm8625())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		msm8625_device_uart_dm1.dev.platform_data =
 			&msm_uart_dm1_pdata;
 	else
@@ -1042,7 +1054,7 @@
 
 static void __init qrd7627a_otg_gadget(void)
 {
-	if (cpu_is_msm8625()) {
+	if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		msm_otg_pdata.swfi_latency = msm8625_pm_data
 		[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency;
 		msm8625_device_otg.dev.platform_data = &msm_otg_pdata;
@@ -1061,7 +1073,7 @@
 static void __init msm_pm_init(void)
 {
 
-	if (!cpu_is_msm8625()) {
+	if (!cpu_is_msm8625() && !cpu_is_msm8625q()) {
 		msm_pm_set_platform_data(msm7627a_pm_data,
 				ARRAY_SIZE(msm7627a_pm_data));
 		BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
@@ -1080,7 +1092,7 @@
 	msm7627a_init_regulators();
 	msmqrd_adsp_add_pdev();
 
-	if (cpu_is_msm8625())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		msm8625_device_i2c_init();
 	else
 		msm7627a_device_i2c_init();
diff --git a/arch/arm/mach-msm/clock-8910.c b/arch/arm/mach-msm/clock-8910.c
new file mode 100644
index 0000000..c5541b4
--- /dev/null
+++ b/arch/arm/mach-msm/clock-8910.c
@@ -0,0 +1,3443 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+
+#include <mach/rpm-regulator-smd.h>
+#include <mach/socinfo.h>
+#include <mach/rpm-smd.h>
+
+#include "clock-local2.h"
+#include "clock-pll.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
+#include "clock.h"
+
+enum {
+	GCC_BASE,
+	MMSS_BASE,
+	LPASS_BASE,
+	APCS_BASE,
+	N_BASES,
+};
+
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+#define MMSS_REG_BASE(x) (void __iomem *)(virt_bases[MMSS_BASE] + (x))
+#define LPASS_REG_BASE(x) (void __iomem *)(virt_bases[LPASS_BASE] + (x))
+#define APCS_REG_BASE(x) (void __iomem *)(virt_bases[APCS_BASE] + (x))
+
+#define                     GPLL0_MODE	    0x0000
+#define                    GPLL0_L_VAL	    0x0004
+#define                    GPLL0_M_VAL	    0x0008
+#define                    GPLL0_N_VAL	    0x000C
+#define                 GPLL0_USER_CTL	    0x0010
+#define                   GPLL0_STATUS	    0x001C
+#define                     GPLL2_MODE	    0x0080
+#define                    GPLL2_L_VAL	    0x0084
+#define                    GPLL2_M_VAL	    0x0088
+#define                    GPLL2_N_VAL	    0x008C
+#define                 GPLL2_USER_CTL	    0x0090
+#define                   GPLL2_STATUS	    0x009C
+#define                 CONFIG_NOC_BCR	    0x0140
+#define                       MMSS_BCR	    0x0240
+#define          MMSS_NOC_CFG_AHB_CBCR	    0x024C
+#define               MSS_CFG_AHB_CBCR	    0x0280
+#define           MSS_Q6_BIMC_AXI_CBCR	    0x0284
+#define                     USB_HS_BCR	    0x0480
+#define             USB_HS_SYSTEM_CBCR	    0x0484
+#define                USB_HS_AHB_CBCR	    0x0488
+#define         USB_HS_SYSTEM_CMD_RCGR	    0x0490
+#define                  USB2A_PHY_BCR	    0x04A8
+#define           USB2A_PHY_SLEEP_CBCR	    0x04AC
+#define                      SDCC1_BCR	    0x04C0
+#define            SDCC1_APPS_CMD_RCGR	    0x04D0
+#define                SDCC1_APPS_CBCR	    0x04C4
+#define                 SDCC1_AHB_CBCR	    0x04C8
+#define                      SDCC2_BCR	    0x0500
+#define            SDCC2_APPS_CMD_RCGR	    0x0510
+#define                SDCC2_APPS_CBCR	    0x0504
+#define                 SDCC2_AHB_CBCR	    0x0508
+#define                      BLSP1_BCR	    0x05C0
+#define                 BLSP1_AHB_CBCR	    0x05C4
+#define                 BLSP1_QUP1_BCR	    0x0640
+#define       BLSP1_QUP1_SPI_APPS_CBCR	    0x0644
+#define       BLSP1_QUP1_I2C_APPS_CBCR	    0x0648
+#define   BLSP1_QUP1_SPI_APPS_CMD_RCGR	    0x064C
+#define                BLSP1_UART1_BCR	    0x0680
+#define          BLSP1_UART1_APPS_CBCR	    0x0684
+#define           BLSP1_UART1_SIM_CBCR	    0x0688
+#define      BLSP1_UART1_APPS_CMD_RCGR	    0x068C
+#define                 BLSP1_QUP2_BCR	    0x06C0
+#define       BLSP1_QUP2_SPI_APPS_CBCR	    0x06C4
+#define       BLSP1_QUP2_I2C_APPS_CBCR	    0x06C8
+#define   BLSP1_QUP2_SPI_APPS_CMD_RCGR	    0x06CC
+#define                BLSP1_UART2_BCR	    0x0700
+#define          BLSP1_UART2_APPS_CBCR	    0x0704
+#define           BLSP1_UART2_SIM_CBCR	    0x0708
+#define      BLSP1_UART2_APPS_CMD_RCGR	    0x070C
+#define                 BLSP1_QUP3_BCR	    0x0740
+#define       BLSP1_QUP3_SPI_APPS_CBCR	    0x0744
+#define       BLSP1_QUP3_I2C_APPS_CBCR	    0x0748
+#define   BLSP1_QUP3_SPI_APPS_CMD_RCGR	    0x074C
+#define                BLSP1_UART3_BCR	    0x0780
+#define          BLSP1_UART3_APPS_CBCR	    0x0784
+#define           BLSP1_UART3_SIM_CBCR	    0x0788
+#define      BLSP1_UART3_APPS_CMD_RCGR	    0x078C
+#define                 BLSP1_QUP4_BCR	    0x07C0
+#define       BLSP1_QUP4_SPI_APPS_CBCR	    0x07C4
+#define       BLSP1_QUP4_I2C_APPS_CBCR	    0x07C8
+#define   BLSP1_QUP4_SPI_APPS_CMD_RCGR	    0x07CC
+#define                BLSP1_UART4_BCR	    0x0800
+#define          BLSP1_UART4_APPS_CBCR	    0x0804
+#define           BLSP1_UART4_SIM_CBCR	    0x0808
+#define      BLSP1_UART4_APPS_CMD_RCGR	    0x080C
+#define                 BLSP1_QUP5_BCR	    0x0840
+#define       BLSP1_QUP5_SPI_APPS_CBCR	    0x0844
+#define       BLSP1_QUP5_I2C_APPS_CBCR	    0x0848
+#define   BLSP1_QUP5_SPI_APPS_CMD_RCGR	    0x084C
+#define                BLSP1_UART5_BCR	    0x0880
+#define          BLSP1_UART5_APPS_CBCR	    0x0884
+#define           BLSP1_UART5_SIM_CBCR	    0x0888
+#define      BLSP1_UART5_APPS_CMD_RCGR	    0x088C
+#define                 BLSP1_QUP6_BCR	    0x08C0
+#define       BLSP1_QUP6_SPI_APPS_CBCR	    0x08C4
+#define       BLSP1_QUP6_I2C_APPS_CBCR	    0x08C8
+#define   BLSP1_QUP6_SPI_APPS_CMD_RCGR	    0x08CC
+#define                BLSP1_UART6_BCR	    0x0900
+#define          BLSP1_UART6_APPS_CBCR	    0x0904
+#define           BLSP1_UART6_SIM_CBCR	    0x0908
+#define      BLSP1_UART6_APPS_CMD_RCGR	    0x090C
+#define                        PDM_BCR	    0x0CC0
+#define                   PDM_AHB_CBCR	    0x0CC4
+#define                      PDM2_CBCR	    0x0CCC
+#define                  PDM2_CMD_RCGR	    0x0CD0
+#define                       PRNG_BCR	    0x0D00
+#define                  PRNG_AHB_CBCR	    0x0D04
+#define                   BOOT_ROM_BCR	    0x0E00
+#define              BOOT_ROM_AHB_CBCR	    0x0E04
+#define                        CE1_BCR	    0x1040
+#define                   CE1_CMD_RCGR	    0x1050
+#define                       CE1_CBCR	    0x1044
+#define                   CE1_AXI_CBCR	    0x1048
+#define                   CE1_AHB_CBCR	    0x104C
+#define            COPSS_SMMU_AHB_CBCR      0x015C
+#define             LPSS_SMMU_AHB_CBCR      0x0158
+#define              LPASS_Q6_AXI_CBCR	    0x11C0
+#define             APCS_GPLL_ENA_VOTE	    0x1480
+#define     APCS_CLOCK_BRANCH_ENA_VOTE	    0x1484
+#define      APCS_CLOCK_SLEEP_ENA_VOTE	    0x1488
+#define                       GP1_CBCR	    0x1900
+#define                   GP1_CMD_RCGR	    0x1904
+#define                       GP2_CBCR	    0x1940
+#define                   GP2_CMD_RCGR	    0x1944
+#define                       GP3_CBCR	    0x1980
+#define                   GP3_CMD_RCGR	    0x1984
+#define                        XO_CBCR	    0x0034
+
+#define                MMPLL0_PLL_MODE	    0x0000
+#define               MMPLL0_PLL_L_VAL	    0x0004
+#define               MMPLL0_PLL_M_VAL	    0x0008
+#define               MMPLL0_PLL_N_VAL	    0x000C
+#define            MMPLL0_PLL_USER_CTL	    0x0010
+#define              MMPLL0_PLL_STATUS	    0x001C
+#define         MMSS_PLL_VOTE_APCS_REG      0x0100
+#define                MMPLL1_PLL_MODE	    0x4100
+#define               MMPLL1_PLL_L_VAL	    0x4104
+#define               MMPLL1_PLL_M_VAL	    0x4108
+#define               MMPLL1_PLL_N_VAL	    0x410C
+#define            MMPLL1_PLL_USER_CTL	    0x4110
+#define              MMPLL1_PLL_STATUS	    0x411C
+#define              DSI_PCLK_CMD_RCGR	    0x2000
+#define                   DSI_CMD_RCGR	    0x2020
+#define             MDP_VSYNC_CMD_RCGR	    0x2080
+#define              DSI_BYTE_CMD_RCGR	    0x2120
+#define               DSI_ESC_CMD_RCGR	    0x2160
+#define                        DSI_BCR	    0x2200
+#define                   DSI_BYTE_BCR	    0x2204
+#define                    DSI_ESC_BCR	    0x2208
+#define                    DSI_AHB_BCR	    0x220C
+#define                   DSI_PCLK_BCR	    0x2214
+#define                   MDP_LCDC_BCR	    0x2218
+#define                    MDP_DSI_BCR	    0x221C
+#define                  MDP_VSYNC_BCR	    0x2220
+#define                    MDP_AXI_BCR	    0x2224
+#define                    MDP_AHB_BCR	    0x2228
+#define                   MDP_AXI_CBCR	    0x2314
+#define                 MDP_VSYNC_CBCR	    0x231C
+#define                   MDP_AHB_CBCR	    0x2318
+#define                  DSI_PCLK_CBCR	    0x233C
+#define                GMEM_GFX3D_CBCR      0x4038
+#define                  MDP_LCDC_CBCR	    0x2340
+#define                   MDP_DSI_CBCR	    0x2320
+#define                       DSI_CBCR	    0x2324
+#define                  DSI_BYTE_CBCR	    0x2328
+#define                   DSI_ESC_CBCR	    0x232C
+#define                   DSI_AHB_CBCR	    0x2330
+#define          CSI0PHYTIMER_CMD_RCGR	    0x3000
+#define               CSI0PHYTIMER_BCR	    0x3020
+#define              CSI0PHYTIMER_CBCR	    0x3024
+#define          CSI1PHYTIMER_CMD_RCGR	    0x3030
+#define               CSI1PHYTIMER_BCR	    0x3050
+#define              CSI1PHYTIMER_CBCR	    0x3054
+#define                  CSI0_CMD_RCGR	    0x3090
+#define                       CSI0_BCR	    0x30B0
+#define                      CSI0_CBCR	    0x30B4
+#define                    CSI_AHB_BCR	    0x30B8
+#define                   CSI_AHB_CBCR	    0x30BC
+#define                    CSI0PHY_BCR	    0x30C0
+#define                   CSI0PHY_CBCR	    0x30C4
+#define                    CSI0RDI_BCR	    0x30D0
+#define                   CSI0RDI_CBCR	    0x30D4
+#define                    CSI0PIX_BCR	    0x30E0
+#define                   CSI0PIX_CBCR	    0x30E4
+#define                  CSI1_CMD_RCGR	    0x3100
+#define                       CSI1_BCR	    0x3120
+#define                      CSI1_CBCR	    0x3124
+#define                    CSI1PHY_BCR	    0x3130
+#define                   CSI1PHY_CBCR	    0x3134
+#define                    CSI1RDI_BCR	    0x3140
+#define                   CSI1RDI_CBCR	    0x3144
+#define                    CSI1PIX_BCR	    0x3150
+#define                   CSI1PIX_CBCR	    0x3154
+#define                 MCLK0_CMD_RCGR	    0x3360
+#define                      MCLK0_BCR	    0x3380
+#define                     MCLK0_CBCR	    0x3384
+#define                 MCLK1_CMD_RCGR	    0x3390
+#define                      MCLK1_BCR	    0x33B0
+#define                     MCLK1_CBCR	    0x33B4
+#define                   VFE_CMD_RCGR	    0x3600
+#define                        VFE_BCR	    0x36A0
+#define                    VFE_AHB_BCR	    0x36AC
+#define                    VFE_AXI_BCR	    0x36B0
+#define                       VFE_CBCR	    0x36A8
+#define                   VFE_AHB_CBCR	    0x36B8
+#define                   VFE_AXI_CBCR	    0x36BC
+#define                    CSI_VFE_BCR	    0x3700
+#define                   CSI_VFE_CBCR	    0x3704
+#define                 GFX3D_CMD_RCGR	    0x4000
+#define               OXILI_GFX3D_CBCR	    0x4028
+#define                OXILI_GFX3D_BCR	    0x4030
+#define                  OXILI_AHB_BCR	    0x4044
+#define                 OXILI_AHB_CBCR	    0x403C
+#define                   AHB_CMD_RCGR	    0x5000
+#define                 MMSSNOCAHB_BCR	    0x5020
+#define             MMSSNOCAHB_BTO_BCR	    0x5030
+#define              MMSS_MISC_AHB_BCR	    0x5034
+#define          MMSS_MMSSNOC_AHB_CBCR	    0x5024
+#define      MMSS_MMSSNOC_BTO_AHB_CBCR	    0x5028
+#define             MMSS_MISC_AHB_CBCR	    0x502C
+#define                   AXI_CMD_RCGR	    0x5040
+#define                 MMSSNOCAXI_BCR	    0x5060
+#define                MMSS_S0_AXI_BCR	    0x5068
+#define               MMSS_S0_AXI_CBCR	    0x5064
+#define          MMSS_MMSSNOC_AXI_CBCR	    0x506C
+#define                   BIMC_GFX_BCR	    0x5090
+#define                  BIMC_GFX_CBCR	    0x5094
+
+#define				AUDIO_CORE_GDSCR	    0x7000
+#define                                 SPDM_BCR	    0x1000
+#define                        LPAAUDIO_PLL_MODE	    0x0000
+#define                       LPAAUDIO_PLL_L_VAL	    0x0004
+#define                       LPAAUDIO_PLL_M_VAL	    0x0008
+#define                       LPAAUDIO_PLL_N_VAL	    0x000C
+#define                    LPAAUDIO_PLL_USER_CTL	    0x0010
+#define                      LPAAUDIO_PLL_STATUS	    0x001C
+#define                           LPAQ6_PLL_MODE	    0x1000
+#define                       LPAQ6_PLL_USER_CTL	    0x1010
+#define                         LPAQ6_PLL_STATUS	    0x101C
+#define                        LPA_PLL_VOTE_APPS            0x2000
+#define                  AUDIO_CORE_BCR_SLP_CBCR	    0x4004
+#define                        Q6SS_BCR_SLP_CBCR	    0x6004
+#define                  AUDIO_CORE_GDSC_XO_CBCR	    0x7004
+#define                AUDIO_CORE_LPAIF_DMA_CBCR	    0x9000
+#define                AUDIO_CORE_LPAIF_CSR_CBCR	    0x9004
+#define                      LPAIF_SPKR_CMD_RCGR	    0xA000
+#define     AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR	    0xA014
+#define    AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR	    0xA018
+#define    AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR	    0xA01C
+#define                       LPAIF_PRI_CMD_RCGR	    0xB000
+#define            AUDIO_CORE_LPAIF_PRI_OSR_CBCR	    0xB014
+#define           AUDIO_CORE_LPAIF_PRI_IBIT_CBCR	    0xB018
+#define           AUDIO_CORE_LPAIF_PRI_EBIT_CBCR	    0xB01C
+#define                       LPAIF_SEC_CMD_RCGR	    0xC000
+#define            AUDIO_CORE_LPAIF_SEC_OSR_CBCR	    0xC014
+#define           AUDIO_CORE_LPAIF_SEC_IBIT_CBCR	    0xC018
+#define           AUDIO_CORE_LPAIF_SEC_EBIT_CBCR	    0xC01C
+#define                       LPAIF_TER_CMD_RCGR	    0xD000
+#define            AUDIO_CORE_LPAIF_TER_OSR_CBCR	    0xD014
+#define           AUDIO_CORE_LPAIF_TER_IBIT_CBCR	    0xD018
+#define           AUDIO_CORE_LPAIF_TER_EBIT_CBCR	    0xD01C
+#define                      LPAIF_QUAD_CMD_RCGR	    0xE000
+#define           AUDIO_CORE_LPAIF_QUAD_OSR_CBCR	    0xE014
+#define          AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR	    0xE018
+#define          AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR	    0xE01C
+#define                      LPAIF_PCM0_CMD_RCGR	    0xF000
+#define          AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR	    0xF014
+#define          AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR	    0xF018
+#define                      LPAIF_PCM1_CMD_RCGR	   0x10000
+#define          AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR	   0x10014
+#define          AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR	   0x10018
+#define                         SLIMBUS_CMD_RCGR           0x12000
+#define             AUDIO_CORE_SLIMBUS_CORE_CBCR           0x12014
+#define                     LPAIF_PCMOE_CMD_RCGR	   0x13000
+#define        AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR	   0x13014
+#define                          Q6CORE_CMD_RCGR	   0x14000
+#define                           SLEEP_CMD_RCGR	   0x15000
+#define                            SPDM_CMD_RCGR	   0x16000
+#define                  AUDIO_WRAPPER_SPDM_CBCR	   0x16014
+#define                              XO_CMD_RCGR	   0x17000
+#define                       AHBFABRIC_CMD_RCGR	   0x18000
+#define                      AUDIO_CORE_LPM_CBCR	   0x19000
+#define               AUDIO_CORE_AVSYNC_CSR_CBCR	   0x1A000
+#define                AUDIO_CORE_AVSYNC_XO_CBCR	   0x1A004
+#define             AUDIO_CORE_AVSYNC_BT_XO_CBCR	   0x1A008
+#define             AUDIO_CORE_AVSYNC_FM_XO_CBCR	   0x1A00C
+#define                 AUDIO_CORE_IXFABRIC_CBCR	   0x1B000
+#define               AUDIO_WRAPPER_EFABRIC_CBCR	   0x1B004
+#define                AUDIO_CORE_TCM_SLAVE_CBCR	   0x1C000
+#define                      AUDIO_CORE_CSR_CBCR	   0x1D000
+#define                      AUDIO_CORE_DML_CBCR	   0x1E000
+#define                   AUDIO_CORE_SYSNOC_CBCR	   0x1F000
+#define           AUDIO_WRAPPER_SYSNOC_SWAY_CBCR	   0x1F004
+#define                  AUDIO_CORE_TIMEOUT_CBCR	   0x20000
+#define               AUDIO_WRAPPER_TIMEOUT_CBCR	   0x20004
+#define                 AUDIO_CORE_SECURITY_CBCR	   0x21000
+#define              AUDIO_WRAPPER_SECURITY_CBCR	   0x21004
+#define                     Q6SS_AHB_LFABIF_CBCR	   0x22000
+#define                           Q6SS_AHBM_CBCR	   0x22004
+#define               AUDIO_WRAPPER_LCC_CSR_CBCR	   0x23000
+#define                    AUDIO_WRAPPER_BR_CBCR	   0x24000
+#define                  AUDIO_WRAPPER_SMEM_CBCR	   0x25000
+#define                             Q6SS_XO_CBCR	   0x26000
+#define                            Q6SS_SLP_CBCR	   0x26004
+#define                           LPASS_Q6SS_BCR           0x6000
+#define                AUDIO_WRAPPER_STM_XO_CBCR	   0x27000
+#define      AUDIO_CORE_IXFABRIC_SPDMTM_CSR_CBCR	   0x28000
+#define    AUDIO_WRAPPER_EFABRIC_SPDMTM_CSR_CBCR	   0x28004
+
+/* Mux source select values */
+#define        gcc_xo_source_val 0
+#define         gpll0_source_val 1
+#define           gnd_source_val 5
+#define     mmpll0_mm_source_val 1
+#define     mmpll1_mm_source_val 2
+#define      gpll0_mm_source_val 5
+#define     gcc_xo_mm_source_val 0
+#define        mm_gnd_source_val 6
+#define     cxo_lpass_source_val 0
+#define lpapll0_lpass_source_val 1
+#define   gpll0_lpass_source_val 5
+#define     dsipll_mm_source_val 1
+
+#define F(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_source_val), \
+	}
+
+#define F_MM(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
+#define F_HDMI(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
+#define F_MDSS(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
+#define F_LPASS(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_lpass_source_val), \
+	}
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+	.vdd_class = &vdd_dig,			\
+	.fmax = (unsigned long[VDD_DIG_NUM]) {	\
+		[VDD_DIG_##l1] = (f1),		\
+		[VDD_DIG_##l2] = (f2),		\
+		[VDD_DIG_##l3] = (f3),		\
+	},					\
+	.num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+	VDD_DIG_NONE,
+	VDD_DIG_LOW,
+	VDD_DIG_NOMINAL,
+	VDD_DIG_HIGH,
+	VDD_DIG_NUM
+};
+
+static const int vdd_corner[] = {
+	[VDD_DIG_NONE]	  = RPM_REGULATOR_CORNER_NONE,
+	[VDD_DIG_LOW]	  = RPM_REGULATOR_CORNER_SVS_SOC,
+	[VDD_DIG_NOMINAL] = RPM_REGULATOR_CORNER_NORMAL,
+	[VDD_DIG_HIGH]	  = RPM_REGULATOR_CORNER_SUPER_TURBO,
+};
+
+static struct rpm_regulator *vdd_dig_reg;
+
+static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
+{
+	return rpm_regulator_set_voltage(vdd_dig_reg, vdd_corner[level],
+					RPM_REGULATOR_CORNER_SUPER_TURBO);
+}
+
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig, VDD_DIG_NUM);
+
+#define RPM_MISC_CLK_TYPE	0x306b6c63
+#define RPM_BUS_CLK_TYPE	0x316b6c63
+#define RPM_MEM_CLK_TYPE	0x326b6c63
+
+#define RPM_SMD_KEY_ENABLE	0x62616E45
+
+#define CXO_ID			0x0
+#define QDSS_ID			0x1
+#define RPM_SCALING_ENABLE_ID	0x2
+
+#define PNOC_ID		0x0
+#define SNOC_ID		0x1
+#define CNOC_ID		0x2
+#define MMSSNOC_AHB_ID  0x3
+
+#define BIMC_ID		0x0
+#define OXILI_ID	0x1
+#define OCMEM_ID	0x2
+
+#define D0_ID		 1
+#define D1_ID		 2
+#define A0_ID		 3
+#define A1_ID		 4
+#define A2_ID		 5
+#define DIFF_CLK_ID	 7
+#define DIV_CLK_ID	11
+
+DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(cnoc_clk, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, RPM_BUS_CLK_TYPE,
+			MMSSNOC_AHB_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD_BRANCH(gcc_xo_clk_src, gcc_xo_a_clk_src,
+				RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_d0, cxo_d0_a, D0_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_d1, cxo_d1_a, D1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a0, cxo_a0_a, A0_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a1, cxo_a1_a, A1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a2, cxo_a2_a, A2_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk, div_a_clk, DIV_CLK_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(diff_clk, diff_a_clk, DIFF_CLK_ID);
+
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d0_pin, cxo_d0_a_pin, D0_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d1_pin, cxo_d1_a_pin, D1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_a0_pin, cxo_a0_a_pin, A0_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_a1_pin, cxo_a1_a_pin, A1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_a2_pin, cxo_a2_a_pin, A2_ID);
+
+static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, &cnoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_acpu_a_clk, &bimc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_iommu_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_qseecom_clk, &pnoc_clk.c, LONG_MAX);
+
+static struct pll_vote_clk gpll0_clk_src = {
+	.en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)GPLL0_STATUS,
+	.status_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.rate = 600000000,
+		.dbg_name = "gpll0_clk_src",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(gpll0_clk_src.c),
+	},
+};
+
+static struct pll_vote_clk mmpll0_clk_src = {
+	.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS_REG,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)MMPLL0_PLL_STATUS,
+	.status_mask = BIT(17),
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.dbg_name = "mmpll0_clk_src",
+		.rate = 800000000,
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(mmpll0_clk_src.c),
+	},
+};
+
+static struct pll_config_regs mmpll0_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL0_PLL_L_VAL,
+	.m_reg = (void __iomem *)MMPLL0_PLL_M_VAL,
+	.n_reg = (void __iomem *)MMPLL0_PLL_N_VAL,
+	.config_reg = (void __iomem *)MMPLL0_PLL_USER_CTL,
+	.mode_reg = (void __iomem *)MMPLL0_PLL_MODE,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+static struct pll_clk mmpll1_clk_src = {
+	.mode_reg = (void __iomem *)MMPLL1_PLL_MODE,
+	.status_reg = (void __iomem *)MMPLL1_PLL_STATUS,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.dbg_name = "mmpll1_clk_src",
+		.rate = 1200000000,
+		.ops = &clk_ops_local_pll,
+		CLK_INIT(mmpll1_clk_src.c),
+	},
+};
+
+static struct pll_config_regs mmpll1_regs __initdata = {
+	.l_reg = (void __iomem *)MMPLL1_PLL_L_VAL,
+	.m_reg = (void __iomem *)MMPLL1_PLL_M_VAL,
+	.n_reg = (void __iomem *)MMPLL1_PLL_N_VAL,
+	.config_reg = (void __iomem *)MMPLL1_PLL_USER_CTL,
+	.mode_reg = (void __iomem *)MMPLL1_PLL_MODE,
+	.base = &virt_bases[MMSS_BASE],
+};
+
+static struct pll_vote_clk lpapll0_clk_src = {
+	.en_reg = (void __iomem *)LPA_PLL_VOTE_APPS,
+	.en_mask = BIT(0),
+	.status_reg = (void __iomem *)LPAAUDIO_PLL_STATUS,
+	.status_mask = BIT(17),
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.rate = 491520000,
+		.dbg_name = "lpapll0_clk_src",
+		.ops = &clk_ops_pll_vote,
+		CLK_INIT(lpapll0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
+	F(  960000, gcc_xo, 10, 1, 2),
+	F( 4800000, gcc_xo,  4, 0, 0),
+	F( 9600000, gcc_xo,  2, 0, 0),
+	F(15000000,  gpll0, 10, 1, 4),
+	F(19200000, gcc_xo,  1, 0, 0),
+	F(25000000,  gpll0, 12, 1, 2),
+	F(50000000,  gpll0, 12, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup1_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup2_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup3_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup4_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup5_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_qup6_spi_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+		CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_uart1_6_apps_clk[] = {
+	F( 3686400,  gpll0,    1,   96, 15625),
+	F( 7372800,  gpll0,    1,  192, 15625),
+	F(14745600,  gpll0,    1,  384, 15625),
+	F(16000000,  gpll0,    5,    2,    15),
+	F(19200000, gcc_xo,    1,    0,     0),
+	F(24000000,  gpll0,    5,    1,     5),
+	F(32000000,  gpll0,    1,    4,    75),
+	F(40000000,  gpll0,   15,    0,     0),
+	F(46400000,  gpll0,    1,   29,   375),
+	F(48000000,  gpll0, 12.5,    0,     0),
+	F(51200000,  gpll0,    1,   32,   375),
+	F(56000000,  gpll0,    1,    7,    75),
+	F(58982400,  gpll0,    1, 1536, 15625),
+	F(60000000,  gpll0,   10,    0,     0),
+	F_END,
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart2_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART3_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart3_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart3_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART4_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart4_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart4_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart5_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART5_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart5_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart5_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk blsp1_uart6_apps_clk_src = {
+	.cmd_rcgr_reg =  BLSP1_UART6_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "blsp1_uart6_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+		CLK_INIT(blsp1_uart6_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_ce1_clk[] = {
+	F(50000000, gpll0, 12, 0, 0),
+	F(100000000, gpll0, 6, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk ce1_clk_src = {
+	.cmd_rcgr_reg = CE1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_ce1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "ce1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+		CLK_INIT(ce1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_gp1_3_clk[] = {
+	F(19200000, gcc_xo, 1, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk gp1_clk_src = {
+	.cmd_rcgr_reg =  GP1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp1_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp2_clk_src = {
+	.cmd_rcgr_reg =  GP2_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp2_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp2_clk_src.c),
+	},
+};
+
+static struct rcg_clk gp3_clk_src = {
+	.cmd_rcgr_reg =  GP3_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_gp1_3_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gp3_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(gp3_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+	F(60000000, gpll0, 10, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk pdm2_clk_src = {
+	.cmd_rcgr_reg = PDM2_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_pdm2_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "pdm2_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 120000000),
+		CLK_INIT(pdm2_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc1_2_apps_clk[] = {
+	F(   144000, gcc_xo, 16, 3, 25),
+	F(   400000, gcc_xo, 12, 1,  4),
+	F( 20000000,  gpll0, 15, 1,  2),
+	F( 25000000,  gpll0, 12, 1,  2),
+	F( 50000000,  gpll0, 12, 0,  0),
+	F(100000000,  gpll0,  6, 0,  0),
+	F(200000000,  gpll0,  3, 0,  0),
+	F_END,
+};
+
+static struct rcg_clk sdcc1_apps_clk_src = {
+	.cmd_rcgr_reg =  SDCC1_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc1_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc1_apps_clk_src.c),
+	},
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+	.cmd_rcgr_reg =  SDCC2_APPS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "sdcc2_apps_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(sdcc2_apps_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+	F(75000000, gpll0, 8, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+	.cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_gcc_usb_hs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "usb_hs_system_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 60000000, NOMINAL, 100000000),
+		CLK_INIT(usb_hs_system_clk_src.c),
+	},
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg = BLSP1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(17),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_blsp1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_qup1_spi_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_qup2_spi_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_qup3_spi_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_qup4_spi_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_qup5_spi_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+	.cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_qup6_spi_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+	.cbcr_reg = BLSP1_UART1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_uart1_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_uart1_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+	.cbcr_reg = BLSP1_UART2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_uart2_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+	.cbcr_reg = BLSP1_UART3_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_uart3_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_uart3_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+	.cbcr_reg = BLSP1_UART4_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_uart4_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_uart4_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart5_apps_clk = {
+	.cbcr_reg = BLSP1_UART5_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_uart5_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_uart5_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart5_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart6_apps_clk = {
+	.cbcr_reg = BLSP1_UART6_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &blsp1_uart6_apps_clk_src.c,
+		.dbg_name = "gcc_blsp1_uart6_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_blsp1_uart6_apps_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+	.cbcr_reg = BOOT_ROM_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(10),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_boot_rom_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_boot_rom_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_ahb_clk = {
+	.cbcr_reg = CE1_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(3),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_axi_clk = {
+	.cbcr_reg = CE1_AXI_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(4),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_axi_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_axi_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_ce1_clk = {
+	.cbcr_reg = CE1_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(5),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ce1_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_ce1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_copss_smmu_ahb_clk = {
+	.cbcr_reg = COPSS_SMMU_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_copss_smmu_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_copss_smmu_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_lpss_smmu_ahb_clk = {
+	.cbcr_reg = LPSS_SMMU_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+			.dbg_name = "gcc_lpss_smmu_ahb_clk",
+			.ops = &clk_ops_branch,
+			CLK_INIT(gcc_lpss_smmu_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp1_clk = {
+	.cbcr_reg = GP1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gp1_clk_src.c,
+		.dbg_name = "gcc_gp1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp1_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp2_clk = {
+	.cbcr_reg = GP2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gp2_clk_src.c,
+		.dbg_name = "gcc_gp2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_gp3_clk = {
+	.cbcr_reg = GP3_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &gp3_clk_src.c,
+		.dbg_name = "gcc_gp3_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_gp3_clk.c),
+	},
+};
+
+static struct branch_clk gcc_lpass_q6_axi_clk = {
+	.cbcr_reg = LPASS_Q6_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_lpass_q6_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_lpass_q6_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mmss_noc_cfg_ahb_clk = {
+	.cbcr_reg = MMSS_NOC_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mmss_noc_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mmss_noc_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+	.cbcr_reg = MSS_CFG_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_cfg_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+	.cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_mss_q6_bimc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+	.cbcr_reg = PDM2_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &pdm2_clk_src.c,
+		.dbg_name = "gcc_pdm2_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm2_clk.c),
+	},
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+	.cbcr_reg = PDM_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_pdm_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_pdm_ahb_clk.c),
+	},
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+	.cbcr_reg = PRNG_AHB_CBCR,
+	.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask = BIT(13),
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_prng_ahb_clk",
+		.ops = &clk_ops_vote,
+		CLK_INIT(gcc_prng_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_ahb_clk = {
+	.cbcr_reg = SDCC1_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc1_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc1_apps_clk = {
+	.cbcr_reg = SDCC1_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &sdcc1_apps_clk_src.c,
+		.dbg_name = "gcc_sdcc1_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc1_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+	.cbcr_reg = SDCC2_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_sdcc2_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+	.cbcr_reg = SDCC2_APPS_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &sdcc2_apps_clk_src.c,
+		.dbg_name = "gcc_sdcc2_apps_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_sdcc2_apps_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb2a_phy_sleep_clk = {
+	.cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb2a_phy_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+	.cbcr_reg = USB_HS_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_ahb_clk.c),
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+	.cbcr_reg = USB_HS_SYSTEM_CBCR,
+	.has_sibling = 0,
+	.bcr_reg = USB_HS_BCR,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.parent = &usb_hs_system_clk_src.c,
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_usb_hs_system_clk.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_csi0_1_clk[] = {
+	F_MM(100000000,  gpll0, 6, 0, 0),
+	F_MM(200000000, mmpll0, 4, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk csi0_clk_src = {
+	.cmd_rcgr_reg = CSI0_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_csi0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi0_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi0_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mmss_mmssnoc_ahb_clk[] = {
+	F_MM(19200000, gcc_xo,  1, 0, 0),
+	F_MM(40000000,  gpll0, 15, 0, 0),
+	F_MM(80000000, mmpll0, 10, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk ahb_clk_src = {
+	.cmd_rcgr_reg = AHB_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mmss_mmssnoc_ahb_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "ahb_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 40000000, NOMINAL, 80000000),
+		CLK_INIT(ahb_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mmss_mmssnoc_axi_clk[] = {
+	F_MM( 19200000, gcc_xo,  1, 0, 0),
+	F_MM( 37500000,  gpll0, 16, 0, 0),
+	F_MM( 50000000,  gpll0, 12, 0, 0),
+	F_MM( 75000000,  gpll0,  8, 0, 0),
+	F_MM(100000000,  gpll0,  6, 0, 0),
+	F_MM(150000000,  gpll0,  4, 0, 0),
+	F_MM(200000000, mmpll0,  4, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk axi_clk_src = {
+	.cmd_rcgr_reg = AXI_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mmss_mmssnoc_axi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "axi_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(axi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_dsi_pclk_clk[] = {
+	F_MDSS( 50000000, dsipll, 10, 0, 0),
+	F_MDSS(103330000, dsipll,  9, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk dsi_pclk_clk_src = {
+	.cmd_rcgr_reg =  DSI_PCLK_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_dsi_pclk_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "dsi_pclk_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 103330000),
+		CLK_INIT(dsi_pclk_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_oxili_gfx3d_clk[] = {
+	F_MM( 19200000, gcc_xo,  1, 0, 0),
+	F_MM( 37500000,  gpll0, 16, 0, 0),
+	F_MM( 50000000,  gpll0, 12, 0, 0),
+	F_MM( 75000000,  gpll0,  8, 0, 0),
+	F_MM(100000000,  gpll0,  6, 0, 0),
+	F_MM(150000000,  gpll0,  4, 0, 0),
+	F_MM(200000000,  gpll0,  3, 0, 0),
+	F_MM(300000000,  gpll0,  2, 0, 0),
+	F_MM(400000000, mmpll1,  3, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk gfx3d_clk_src = {
+	.cmd_rcgr_reg = GFX3D_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_oxili_gfx3d_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "gfx3d_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 300000000, HIGH,
+					400000000),
+		CLK_INIT(gfx3d_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_vfe_clk[] = {
+	F_MM( 37500000,  gpll0,  16, 0, 0),
+	F_MM( 50000000,  gpll0,  12, 0, 0),
+	F_MM( 60000000,  gpll0,  10, 0, 0),
+	F_MM( 80000000,  gpll0, 7.5, 0, 0),
+	F_MM(100000000,  gpll0,   6, 0, 0),
+	F_MM(109090000,  gpll0, 5.5, 0, 0),
+	F_MM(133330000,  gpll0, 4.5, 0, 0),
+	F_MM(200000000,  gpll0,   3, 0, 0),
+	F_MM(228570000, mmpll0, 3.5, 0, 0),
+	F_MM(266670000, mmpll0,   3, 0, 0),
+	F_MM(320000000, mmpll0, 2.5, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk vfe_clk_src = {
+	.cmd_rcgr_reg = VFE_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_vfe_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vfe_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000, HIGH,
+					320000000),
+		CLK_INIT(vfe_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1_clk_src = {
+	.cmd_rcgr_reg = CSI1_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_csi0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi1_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_csi0_1phytimer_clk[] = {
+	F_MM(100000000,  gpll0, 6, 0, 0),
+	F_MM(200000000, mmpll0, 4, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk csi0phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI0PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_csi0_1phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi0phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi0phytimer_clk_src.c),
+	},
+};
+
+static struct rcg_clk csi1phytimer_clk_src = {
+	.cmd_rcgr_reg = CSI1PHYTIMER_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_csi0_1phytimer_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi1phytimer_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+		CLK_INIT(csi1phytimer_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_dsi_clk[] = {
+	F_MDSS(155000000,  dsipll, 6, 0, 0),
+	F_MDSS(310000000,  dsipll, 3, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk dsi_clk_src = {
+	.cmd_rcgr_reg =  DSI_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_dsi_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "dsi_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 155000000, NOMINAL, 310000000),
+		CLK_INIT(dsi_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_dsi_byte_clk[] = {
+	F_MDSS( 62500000, dsipll, 12, 0, 0),
+	F_MDSS(125000000, dsipll,  6, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk dsi_byte_clk_src = {
+	.cmd_rcgr_reg = DSI_BYTE_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_dsi_byte_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "dsi_byte_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
+		CLK_INIT(dsi_byte_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_dsi_esc_clk[] = {
+	F_MM(19200000, gcc_xo, 1, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk dsi_esc_clk_src = {
+	.cmd_rcgr_reg = DSI_ESC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_dsi_esc_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "dsi_esc_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(dsi_esc_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mclk0_1_clk[] = {
+	F_MM(66670000, gpll0, 9, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk mclk0_clk_src = {
+	.cmd_rcgr_reg =  MCLK0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_mclk0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk0_clk_src.c),
+	},
+};
+
+static struct rcg_clk mclk1_clk_src = {
+	.cmd_rcgr_reg =  MCLK1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_mclk0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mclk1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP1(LOW, 66670000),
+		CLK_INIT(mclk1_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdp_vsync_clk[] = {
+	F_MM(19200000, gcc_xo, 1, 0, 0),
+	F_END,
+};
+
+static struct rcg_clk mdp_vsync_clk_src = {
+	.cmd_rcgr_reg = MDP_VSYNC_CMD_RCGR,
+	.set_rate = set_rate_hid,
+	.freq_tbl = ftbl_mdp_vsync_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdp_vsync_clk_src",
+		.ops = &clk_ops_rcg,
+		VDD_DIG_FMAX_MAP1(LOW, 19200000),
+		CLK_INIT(mdp_vsync_clk_src.c),
+	},
+};
+
+static struct branch_clk bimc_gfx_clk = {
+	.cbcr_reg = BIMC_GFX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "bimc_gfx_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(bimc_gfx_clk.c),
+	},
+};
+
+static struct branch_clk csi0_clk = {
+	.cbcr_reg = CSI0_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &csi0_clk_src.c,
+		.dbg_name = "csi0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0_clk.c),
+	},
+};
+
+static struct branch_clk csi0phy_clk = {
+	.cbcr_reg = CSI0PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &csi0_clk_src.c,
+		.dbg_name = "csi0phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0phy_clk.c),
+	},
+};
+
+static struct branch_clk csi0phytimer_clk = {
+	.cbcr_reg = CSI0PHYTIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &csi0phytimer_clk_src.c,
+		.dbg_name = "csi0phytimer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0phytimer_clk.c),
+	},
+};
+
+static struct branch_clk csi0pix_clk = {
+	.cbcr_reg = CSI0PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &csi0_clk_src.c,
+		.dbg_name = "csi0pix_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0pix_clk.c),
+	},
+};
+
+static struct branch_clk csi0rdi_clk = {
+	.cbcr_reg = CSI0RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &csi0_clk_src.c,
+		.dbg_name = "csi0rdi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi0rdi_clk.c),
+	},
+};
+
+static struct branch_clk csi1_clk = {
+	.cbcr_reg = CSI1_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &csi1_clk_src.c,
+		.dbg_name = "csi1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1_clk.c),
+	},
+};
+
+static struct branch_clk csi1phy_clk = {
+	.cbcr_reg = CSI1PHY_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &csi1_clk_src.c,
+		.dbg_name = "csi1phy_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1phy_clk.c),
+	},
+};
+
+static struct branch_clk csi1phytimer_clk = {
+	.cbcr_reg = CSI1PHYTIMER_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &csi1phytimer_clk_src.c,
+		.dbg_name = "csi1phytimer_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1phytimer_clk.c),
+	},
+};
+
+static struct branch_clk csi1pix_clk = {
+	.cbcr_reg = CSI1PIX_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &csi0_clk_src.c,
+		.dbg_name = "csi1pix_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1pix_clk.c),
+	},
+};
+
+static struct branch_clk csi1rdi_clk = {
+	.cbcr_reg = CSI1RDI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &csi0_clk_src.c,
+		.dbg_name = "csi1rdi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi1rdi_clk.c),
+	},
+};
+
+static struct branch_clk csi_ahb_clk = {
+	.cbcr_reg = CSI_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "csi_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi_ahb_clk.c),
+	},
+};
+
+static struct branch_clk csi_vfe_clk = {
+	.cbcr_reg = CSI_VFE_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &vfe_clk_src.c,
+		.dbg_name = "csi_vfe_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(csi_vfe_clk.c),
+	},
+};
+
+static struct branch_clk dsi_clk = {
+	.cbcr_reg = DSI_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &dsi_clk_src.c,
+		.dbg_name = "dsi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi_clk.c),
+	},
+};
+
+static struct branch_clk dsi_ahb_clk = {
+	.cbcr_reg = DSI_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "dsi_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi_ahb_clk.c),
+	},
+};
+
+static struct branch_clk dsi_byte_clk = {
+	.cbcr_reg = DSI_BYTE_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &dsi_byte_clk_src.c,
+		.dbg_name = "dsi_byte_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi_byte_clk.c),
+	},
+};
+
+static struct branch_clk dsi_esc_clk = {
+	.cbcr_reg = DSI_ESC_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &dsi_esc_clk_src.c,
+		.dbg_name = "dsi_esc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi_esc_clk.c),
+	},
+};
+
+static struct branch_clk dsi_pclk_clk = {
+	.cbcr_reg = DSI_PCLK_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &dsi_pclk_clk_src.c,
+		.dbg_name = "dsi_pclk_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(dsi_pclk_clk.c),
+	},
+};
+
+static struct branch_clk gmem_gfx3d_clk = {
+	.cbcr_reg = GMEM_GFX3D_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &gfx3d_clk_src.c,
+		.dbg_name = "gmem_gfx3d_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gmem_gfx3d_clk.c),
+	},
+};
+
+static struct branch_clk mclk0_clk = {
+	.cbcr_reg = MCLK0_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &mclk0_clk_src.c,
+		.dbg_name = "mclk0_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mclk0_clk.c),
+	},
+};
+
+static struct branch_clk mclk1_clk = {
+	.cbcr_reg = MCLK1_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &mclk1_clk_src.c,
+		.dbg_name = "mclk1_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mclk1_clk.c),
+	},
+};
+
+static struct branch_clk mdp_ahb_clk = {
+	.cbcr_reg = MDP_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mdp_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mdp_axi_clk = {
+	.cbcr_reg = MDP_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &axi_clk_src.c,
+		.dbg_name = "mdp_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_axi_clk.c),
+	},
+};
+
+static struct branch_clk mdp_dsi_clk = {
+	.cbcr_reg = MDP_DSI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &dsi_pclk_clk_src.c,
+		.dbg_name = "mdp_dsi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_dsi_clk.c),
+	},
+};
+
+static struct branch_clk mdp_lcdc_clk = {
+	.cbcr_reg = MDP_LCDC_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &dsi_pclk_clk_src.c,
+		.dbg_name = "mdp_lcdc_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_lcdc_clk.c),
+	},
+};
+
+static struct branch_clk mdp_vsync_clk = {
+	.cbcr_reg = MDP_VSYNC_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &mdp_vsync_clk_src.c,
+		.dbg_name = "mdp_vsync_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mdp_vsync_clk.c),
+	},
+};
+
+static struct branch_clk mmss_misc_ahb_clk = {
+	.cbcr_reg = MMSS_MISC_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_misc_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_misc_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mmss_mmssnoc_axi_clk = {
+	.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &axi_clk_src.c,
+		.dbg_name = "mmss_mmssnoc_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_mmssnoc_axi_clk.c),
+	},
+};
+
+static struct branch_clk mmss_s0_axi_clk = {
+	.cbcr_reg = MMSS_S0_AXI_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &axi_clk_src.c,
+		.dbg_name = "mmss_s0_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_s0_axi_clk.c),
+		.depends = &mmss_mmssnoc_axi_clk.c,
+	},
+};
+
+static struct branch_clk mmss_mmssnoc_ahb_clk = {
+	.cbcr_reg = MMSS_MMSSNOC_AHB_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &ahb_clk_src.c,
+		.dbg_name = "mmss_mmssnoc_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_mmssnoc_ahb_clk.c),
+	},
+};
+
+static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
+	.cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "mmss_mmssnoc_bto_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
+	},
+};
+
+static struct branch_clk oxili_ahb_clk = {
+	.cbcr_reg = OXILI_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "oxili_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxili_ahb_clk.c),
+	},
+};
+
+static struct branch_clk oxili_gfx3d_clk = {
+	.cbcr_reg = OXILI_GFX3D_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &gfx3d_clk_src.c,
+		.dbg_name = "oxili_gfx3d_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxili_gfx3d_clk.c),
+	},
+};
+
+static struct branch_clk vfe_clk = {
+	.cbcr_reg = VFE_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &vfe_clk_src.c,
+		.dbg_name = "vfe_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vfe_clk.c),
+	},
+};
+
+static struct branch_clk vfe_ahb_clk = {
+	.cbcr_reg = VFE_AHB_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "vfe_ahb_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vfe_ahb_clk.c),
+	},
+};
+
+static struct branch_clk vfe_axi_clk = {
+	.cbcr_reg = VFE_AXI_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.parent = &axi_clk_src.c,
+		.dbg_name = "vfe_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(vfe_axi_clk.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_audio_core_lpaif_clk[] = {
+	F_LPASS(  512000, lpapll0, 16, 1, 60),
+	F_LPASS(  768000, lpapll0, 16, 1, 40),
+	F_LPASS( 1024000, lpapll0, 16, 1, 30),
+	F_LPASS( 1536000, lpapll0, 16, 1, 20),
+	F_LPASS( 2048000, lpapll0, 16, 1, 15),
+	F_LPASS( 3072000, lpapll0, 16, 1, 10),
+	F_LPASS( 4096000, lpapll0, 15, 1,  8),
+	F_LPASS( 6144000, lpapll0, 10, 1,  8),
+	F_LPASS( 8192000, lpapll0, 15, 1,  4),
+	F_LPASS(12288000, lpapll0, 10, 1,  4),
+	F_END,
+};
+
+static struct rcg_clk lpaif_pri_clk_src = {
+	.cmd_rcgr_reg =  LPAIF_PRI_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "lpaif_pri_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
+		CLK_INIT(lpaif_pri_clk_src.c),
+	},
+};
+
+static struct rcg_clk lpaif_quad_clk_src = {
+	.cmd_rcgr_reg =  LPAIF_QUAD_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "lpaif_quad_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
+		CLK_INIT(lpaif_quad_clk_src.c),
+	},
+};
+
+static struct rcg_clk lpaif_sec_clk_src = {
+	.cmd_rcgr_reg =  LPAIF_SEC_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "lpaif_sec_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
+		CLK_INIT(lpaif_sec_clk_src.c),
+	},
+};
+
+static struct rcg_clk lpaif_spkr_clk_src = {
+	.cmd_rcgr_reg =  LPAIF_SPKR_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "lpaif_spkr_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
+		CLK_INIT(lpaif_spkr_clk_src.c),
+	},
+};
+
+static struct rcg_clk lpaif_ter_clk_src = {
+	.cmd_rcgr_reg =  LPAIF_TER_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "lpaif_ter_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
+		CLK_INIT(lpaif_ter_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_audio_core_lpaif_pcm0_1_clk[] = {
+	F_LPASS( 512000, lpapll0, 16, 1, 60),
+	F_LPASS( 768000, lpapll0, 16, 1, 40),
+	F_LPASS(1024000, lpapll0, 16, 1, 30),
+	F_LPASS(1536000, lpapll0, 16, 1, 20),
+	F_LPASS(2048000, lpapll0, 16, 1, 15),
+	F_LPASS(3072000, lpapll0, 16, 1, 10),
+	F_LPASS(4096000, lpapll0, 15, 1,  8),
+	F_LPASS(6144000, lpapll0, 10, 1,  8),
+	F_LPASS(8192000, lpapll0, 15, 1,  4),
+	F_END,
+};
+
+static struct rcg_clk lpaif_pcm0_clk_src = {
+	.cmd_rcgr_reg =  LPAIF_PCM0_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "lpaif_pcm0_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8192000),
+		CLK_INIT(lpaif_pcm0_clk_src.c),
+	},
+};
+
+static struct rcg_clk lpaif_pcm1_clk_src = {
+	.cmd_rcgr_reg =  LPAIF_PCM1_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "lpaif_pcm1_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8192000),
+		CLK_INIT(lpaif_pcm1_clk_src.c),
+	},
+};
+
+static struct rcg_clk lpaif_pcmoe_clk_src = {
+	.cmd_rcgr_reg =  LPAIF_PCMOE_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_lpaif_pcm0_1_clk,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "lpaif_pcmoe_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 6140000, NOMINAL, 12290000),
+		CLK_INIT(lpaif_pcmoe_clk_src.c),
+	},
+};
+
+static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
+	F_LPASS(24576000, lpapll0, 4, 1, 5),
+	F_END
+};
+
+static struct rcg_clk audio_core_slimbus_core_clk_src = {
+	.cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
+	.set_rate = set_rate_mnd,
+	.freq_tbl = ftbl_audio_core_slimbus_core_clock,
+	.current_freq = &rcg_dummy_freq,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_slimbus_core_clk_src",
+		.ops = &clk_ops_rcg_mnd,
+		VDD_DIG_FMAX_MAP2(LOW, 12935000, NOMINAL, 25869000),
+		CLK_INIT(audio_core_slimbus_core_clk_src.c),
+	},
+};
+
+static struct branch_clk audio_core_slimbus_core_clk = {
+	.cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &audio_core_slimbus_core_clk_src.c,
+		.dbg_name = "audio_core_slimbus_core_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_slimbus_core_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_ixfabric_clk = {
+	.cbcr_reg = AUDIO_CORE_IXFABRIC_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_ixfabric_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_ixfabric_clk.c),
+	},
+};
+
+static struct branch_clk audio_wrapper_br_clk = {
+	.cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_wrapper_br_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_wrapper_br_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_ahb_lfabif_clk = {
+	.cbcr_reg = Q6SS_AHB_LFABIF_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_ahb_lfabif_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_ahb_lfabif_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_ahbm_clk = {
+	.cbcr_reg = Q6SS_AHBM_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "q6ss_ahbm_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_ahbm_clk.c),
+	},
+};
+
+static struct branch_clk q6ss_xo_clk = {
+	.cbcr_reg = Q6SS_XO_CBCR,
+	.has_sibling = 1,
+	.bcr_reg = LPASS_Q6SS_BCR,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &gcc_xo_clk_src.c,
+		.dbg_name = "q6ss_xo_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(q6ss_xo_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm_data_oe_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_pcmoe_clk_src.c,
+		.dbg_name = "audio_core_lpaif_pcm_data_oe_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm_data_oe_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pri_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
+	.has_sibling = 0,
+	.max_div = 511,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_pri_clk_src.c,
+		.dbg_name = "audio_core_lpaif_pri_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pri_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_pri_clk_src.c,
+		.dbg_name = "audio_core_lpaif_pri_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_pcm0_clk_src.c,
+		.dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_quad_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
+	.has_sibling = 0,
+	.max_div = 511,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_quad_clk_src.c,
+		.dbg_name = "audio_core_lpaif_quad_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_quad_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_quad_clk_src.c,
+		.dbg_name = "audio_core_lpaif_quad_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_sec_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
+	.has_sibling = 0,
+	.max_div = 511,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_sec_clk_src.c,
+		.dbg_name = "audio_core_lpaif_sec_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_sec_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_sec_clk_src.c,
+		.dbg_name = "audio_core_lpaif_sec_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_pcm1_clk_src.c,
+		.dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_codec_spkr_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_codec_spkr_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
+	.has_sibling = 1,
+	.max_div = 511,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_spkr_clk_src.c,
+		.dbg_name = "audio_core_lpaif_codec_spkr_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_codec_spkr_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_spkr_clk_src.c,
+		.dbg_name = "audio_core_lpaif_codec_spkr_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_codec_spkr_osr_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.dbg_name = "audio_core_lpaif_ter_ebit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
+	.has_sibling = 0,
+	.max_div = 511,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_ter_clk_src.c,
+		.dbg_name = "audio_core_lpaif_ter_ibit_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
+	},
+};
+
+static struct branch_clk audio_core_lpaif_ter_osr_clk = {
+	.cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
+	.has_sibling = 0,
+	.base = &virt_bases[LPASS_BASE],
+	.c = {
+		.parent = &lpaif_ter_clk_src.c,
+		.dbg_name = "audio_core_lpaif_ter_osr_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
+	},
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+struct measure_mux_entry {
+	struct clk *c;
+	int base;
+	u32 debug_mux;
+};
+
+static struct measure_mux_entry measure_mux[] = {
+	{                   &snoc_clk.c, GCC_BASE, 0x0000},
+	{                   &cnoc_clk.c, GCC_BASE, 0x0008},
+	{     &gcc_copss_smmu_ahb_clk.c, GCC_BASE, 0x000c},
+	{      &gcc_lpss_smmu_ahb_clk.c, GCC_BASE, 0x000d},
+	{                   &pnoc_clk.c, GCC_BASE, 0x0010},
+	{   &gcc_mmss_noc_cfg_ahb_clk.c, GCC_BASE, 0x002a},
+	{        &gcc_mss_cfg_ahb_clk.c, GCC_BASE, 0x0030},
+	{    &gcc_mss_q6_bimc_axi_clk.c, GCC_BASE, 0x0031},
+	{      &gcc_usb_hs_system_clk.c, GCC_BASE, 0x0060},
+	{         &gcc_usb_hs_ahb_clk.c, GCC_BASE, 0x0061},
+	{    &gcc_usb2a_phy_sleep_clk.c, GCC_BASE, 0x0063},
+	{         &gcc_sdcc1_apps_clk.c, GCC_BASE, 0x0068},
+	{          &gcc_sdcc1_ahb_clk.c, GCC_BASE, 0x0069},
+	{         &gcc_sdcc2_apps_clk.c, GCC_BASE, 0x0070},
+	{          &gcc_sdcc2_ahb_clk.c, GCC_BASE, 0x0071},
+	{          &gcc_blsp1_ahb_clk.c, GCC_BASE, 0x0088},
+	{&gcc_blsp1_qup1_spi_apps_clk.c, GCC_BASE, 0x008a},
+	{&gcc_blsp1_qup1_i2c_apps_clk.c, GCC_BASE, 0x008b},
+	{   &gcc_blsp1_uart1_apps_clk.c, GCC_BASE, 0x008c},
+	{&gcc_blsp1_qup2_spi_apps_clk.c, GCC_BASE, 0x008e},
+	{&gcc_blsp1_qup2_i2c_apps_clk.c, GCC_BASE, 0x0090},
+	{   &gcc_blsp1_uart2_apps_clk.c, GCC_BASE, 0x0091},
+	{&gcc_blsp1_qup3_spi_apps_clk.c, GCC_BASE, 0x0093},
+	{&gcc_blsp1_qup3_i2c_apps_clk.c, GCC_BASE, 0x0094},
+	{   &gcc_blsp1_uart3_apps_clk.c, GCC_BASE, 0x0095},
+	{&gcc_blsp1_qup4_spi_apps_clk.c, GCC_BASE, 0x0098},
+	{&gcc_blsp1_qup4_i2c_apps_clk.c, GCC_BASE, 0x0099},
+	{   &gcc_blsp1_uart4_apps_clk.c, GCC_BASE, 0x009a},
+	{&gcc_blsp1_qup5_spi_apps_clk.c, GCC_BASE, 0x009c},
+	{&gcc_blsp1_qup5_i2c_apps_clk.c, GCC_BASE, 0x009d},
+	{   &gcc_blsp1_uart5_apps_clk.c, GCC_BASE, 0x009e},
+	{&gcc_blsp1_qup6_spi_apps_clk.c, GCC_BASE, 0x00a1},
+	{&gcc_blsp1_qup6_i2c_apps_clk.c, GCC_BASE, 0x00a2},
+	{   &gcc_blsp1_uart6_apps_clk.c, GCC_BASE, 0x00a3},
+	{            &gcc_pdm_ahb_clk.c, GCC_BASE, 0x00d0},
+	{               &gcc_pdm2_clk.c, GCC_BASE, 0x00d2},
+	{           &gcc_prng_ahb_clk.c, GCC_BASE, 0x00d8},
+	{       &gcc_boot_rom_ahb_clk.c, GCC_BASE, 0x00f8},
+	{                &gcc_ce1_clk.c, GCC_BASE, 0x0138},
+	{            &gcc_ce1_axi_clk.c, GCC_BASE, 0x0139},
+	{            &gcc_ce1_ahb_clk.c, GCC_BASE, 0x013a},
+	{             &gcc_xo_clk_src.c, GCC_BASE, 0x0149},
+	{                   &bimc_clk.c, GCC_BASE, 0x0154},
+	{       &gcc_lpass_q6_axi_clk.c, GCC_BASE, 0x0160},
+
+	{&mmss_mmssnoc_ahb_clk.c, MMSS_BASE, 0x0001},
+	{   &mmss_misc_ahb_clk.c, MMSS_BASE, 0x0003},
+	{&mmss_mmssnoc_axi_clk.c, MMSS_BASE, 0x0004},
+	{     &mmss_s0_axi_clk.c, MMSS_BASE, 0x0005},
+	{       &oxili_ahb_clk.c, MMSS_BASE, 0x0007},
+	{     &oxili_gfx3d_clk.c, MMSS_BASE, 0x0008},
+	{      &gmem_gfx3d_clk.c, MMSS_BASE, 0x0009},
+	{         &mdp_axi_clk.c, MMSS_BASE, 0x000a},
+	{       &mdp_vsync_clk.c, MMSS_BASE, 0x000b},
+	{         &mdp_ahb_clk.c, MMSS_BASE, 0x000c},
+	{        &dsi_pclk_clk.c, MMSS_BASE, 0x000d},
+	{         &mdp_dsi_clk.c, MMSS_BASE, 0x000e},
+	{        &mdp_lcdc_clk.c, MMSS_BASE, 0x000f},
+	{             &dsi_clk.c, MMSS_BASE, 0x0010},
+	{        &dsi_byte_clk.c, MMSS_BASE, 0x0011},
+	{         &dsi_esc_clk.c, MMSS_BASE, 0x0012},
+	{         &dsi_ahb_clk.c, MMSS_BASE, 0x0013},
+	{           &mclk0_clk.c, MMSS_BASE, 0x0015},
+	{           &mclk1_clk.c, MMSS_BASE, 0x0016},
+	{    &csi0phytimer_clk.c, MMSS_BASE, 0x0017},
+	{    &csi1phytimer_clk.c, MMSS_BASE, 0x0018},
+	{             &vfe_clk.c, MMSS_BASE, 0x0019},
+	{         &vfe_ahb_clk.c, MMSS_BASE, 0x001a},
+	{         &vfe_axi_clk.c, MMSS_BASE, 0x001b},
+	{         &csi_vfe_clk.c, MMSS_BASE, 0x001c},
+	{            &csi0_clk.c, MMSS_BASE, 0x001d},
+	{         &csi_ahb_clk.c, MMSS_BASE, 0x001e},
+	{         &csi0phy_clk.c, MMSS_BASE, 0x001f},
+	{         &csi0rdi_clk.c, MMSS_BASE, 0x0020},
+	{         &csi0pix_clk.c, MMSS_BASE, 0x0021},
+	{            &csi1_clk.c, MMSS_BASE, 0x0022},
+	{         &csi1phy_clk.c, MMSS_BASE, 0x0023},
+	{         &csi1rdi_clk.c, MMSS_BASE, 0x0024},
+	{         &csi1pix_clk.c, MMSS_BASE, 0x0025},
+	{        &bimc_gfx_clk.c, MMSS_BASE, 0x0032},
+
+	{             &lpaif_pcmoe_clk_src.c, LPASS_BASE, 0x000f},
+	{              &lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
+	{              &lpaif_pcm0_clk_src.c, LPASS_BASE, 0x0013},
+	{              &lpaif_quad_clk_src.c, LPASS_BASE, 0x0014},
+	{               &lpaif_ter_clk_src.c, LPASS_BASE, 0x0015},
+	{               &lpaif_sec_clk_src.c, LPASS_BASE, 0x0016},
+	{               &lpaif_pri_clk_src.c, LPASS_BASE, 0x0017},
+	{              &lpaif_spkr_clk_src.c, LPASS_BASE, 0x0018},
+	{                   &q6ss_ahbm_clk.c, LPASS_BASE, 0x001d},
+	{             &q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
+	{            &audio_wrapper_br_clk.c, LPASS_BASE, 0x0022},
+	{                     &q6ss_xo_clk.c, LPASS_BASE, 0x002b},
+	{&audio_core_lpaif_pcm_data_oe_clk.c, LPASS_BASE, 0x0030},
+	{         &audio_core_ixfabric_clk.c, LPASS_BASE, 0x0059},
+
+	{&dummy_clk, N_BASES, 0x0000},
+};
+
+#define GCC_DEBUG_CLK_CTL		0x1880
+#define MMSS_DEBUG_CLK_CTL		0x0900
+#define LPASS_DEBUG_CLK_CTL		0x29000
+#define GLB_CLK_DIAG			0x001C
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned long flags;
+	u32 regval, clk_sel, i;
+
+	if (!parent)
+		return -EINVAL;
+
+	for (i = 0; i < (ARRAY_SIZE(measure_mux) - 1); i++)
+		if (measure_mux[i].c == parent)
+			break;
+
+	if (measure_mux[i].c == &dummy_clk)
+		return -EINVAL;
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	/*
+	 * Program the test vector, measurement period (sample_ticks)
+	 * and scaling multiplier.
+	 */
+	clk->sample_ticks = 0x10000;
+	clk->multiplier = 1;
+
+	switch (measure_mux[i].base) {
+
+	case GCC_BASE:
+		writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+		clk_sel = measure_mux[i].debug_mux;
+		break;
+
+	case MMSS_BASE:
+		writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL));
+		clk_sel = 0x02C;
+		regval = BVAL(11, 0, measure_mux[i].debug_mux);
+		writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL));
+
+		/* Activate debug clock output */
+		regval |= BIT(16);
+		writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL));
+		break;
+
+	case LPASS_BASE:
+		writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL));
+		clk_sel = 0x161;
+		regval = BVAL(11, 0, measure_mux[i].debug_mux);
+		writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL));
+
+		/* Activate debug clock output */
+		regval |= BIT(20);
+		writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL));
+		break;
+
+	case APCS_BASE:
+		clk->multiplier = 4;
+		clk_sel = 0x16A;
+		regval = measure_mux[i].debug_mux;
+		writel_relaxed(regval, APCS_REG_BASE(GLB_CLK_DIAG));
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/* Set debug mux clock index */
+	regval = BVAL(8, 0, clk_sel);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	/* Activate debug clock output */
+	regval |= BIT(16);
+	writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+	/* Make sure test vector is set before starting measurements. */
+	mb();
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	return 0;
+}
+
+#define CLOCK_FRQ_MEASURE_CTL		0x1884
+#define CLOCK_FRQ_MEASURE_STATUS	0x1888
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks)
+{
+	/* Stop counters and set the XO4 counter start value. */
+	writel_relaxed(ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+
+	/* Wait for timer to become ready. */
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+			BIT(25)) != 0)
+		cpu_relax();
+
+	/* Run measurement and wait for completion. */
+	writel_relaxed(BIT(20)|ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+	while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+			BIT(25)) == 0)
+		cpu_relax();
+
+	/* Return measured ticks. */
+	return readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+				BM(24, 0);
+}
+
+#define GCC_XO_DIV4_CBCR	0x10C8
+#define PLLTEST_PAD_CFG		0x188C
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+	unsigned long flags;
+	u32 gcc_xo4_reg_backup;
+	u64 raw_count_short, raw_count_full;
+	struct measure_clk *clk = to_measure_clk(c);
+	unsigned ret;
+
+	ret = clk_prepare_enable(&gcc_xo_clk_src.c);
+	if (ret) {
+		pr_warning("CXO clock failed to enable. Can't measure\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+	/* Enable CXO/4 and RINGOSC branch. */
+	gcc_xo4_reg_backup = readl_relaxed(GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+	writel_relaxed(0x1, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+	/*
+	 * The ring oscillator counter will not reset if the measured clock
+	 * is not running.  To detect this, run a short measurement before
+	 * the full measurement.  If the raw results of the two are the same
+	 * then the clock must be off.
+	 */
+
+	/* Run a short measurement. (~1 ms) */
+	raw_count_short = run_measurement(0x1000);
+	/* Run a full measurement. (~14 ms) */
+	raw_count_full = run_measurement(clk->sample_ticks);
+
+	writel_relaxed(gcc_xo4_reg_backup, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+	/* Return 0 if the clock is off. */
+	if (raw_count_full == raw_count_short) {
+		ret = 0;
+	} else {
+		/* Compute rate in Hz. */
+		raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+		do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+		ret = (raw_count_full * clk->multiplier);
+	}
+
+	writel_relaxed(0x51A00, GCC_REG_BASE(PLLTEST_PAD_CFG));
+	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+	clk_disable_unprepare(&gcc_xo_clk_src.c);
+
+	return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+	.set_parent = measure_clk_set_parent,
+	.get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+	.c = {
+		.dbg_name = "measure_clk",
+		.ops = &clk_ops_measure,
+		CLK_INIT(measure_clk.c),
+	},
+	.multiplier = 1,
+};
+
+static struct clk_lookup msm_clocks_8910[] = {
+	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "msm_otg"),
+	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "pil-q6v5-mss"),
+	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "pil-mba"),
+	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "fb000000.qcom,wcnss-wlan"),
+	CLK_LOOKUP("xo",	gcc_xo_clk_src.c, "pil_pronto"),
+	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
+
+	CLK_LOOKUP("iface_clk",  gcc_blsp1_ahb_clk.c, "f991f000.serial"),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
+
+	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
+	CLK_LOOKUP("bus_clk",  pnoc_qseecom_clk.c, "qseecom"),
+
+	CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
+	CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
+	CLK_LOOKUP("bus_clk", cnoc_clk.c, ""),
+	CLK_LOOKUP("mem_clk", bimc_clk.c, ""),
+	CLK_LOOKUP("bus_clk", snoc_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk", pnoc_a_clk.c, ""),
+	CLK_LOOKUP("bus_clk", cnoc_a_clk.c, ""),
+	CLK_LOOKUP("mem_clk", bimc_a_clk.c, ""),
+
+	CLK_LOOKUP("bus_clk",	cnoc_msmbus_clk.c,	"msm_config_noc"),
+	CLK_LOOKUP("bus_a_clk",	cnoc_msmbus_a_clk.c,	"msm_config_noc"),
+	CLK_LOOKUP("bus_clk",	snoc_msmbus_clk.c,	"msm_sys_noc"),
+	CLK_LOOKUP("bus_a_clk",	snoc_msmbus_a_clk.c,	"msm_sys_noc"),
+	CLK_LOOKUP("bus_clk",	pnoc_msmbus_clk.c,	"msm_periph_noc"),
+	CLK_LOOKUP("bus_a_clk",	pnoc_msmbus_a_clk.c,	"msm_periph_noc"),
+	CLK_LOOKUP("mem_clk",	bimc_msmbus_clk.c,	"msm_bimc"),
+	CLK_LOOKUP("mem_a_clk",	bimc_msmbus_a_clk.c,	"msm_bimc"),
+	CLK_LOOKUP("mem_clk",	bimc_acpu_a_clk.c,	""),
+
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etr"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tpiu"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-replicator"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etf"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-merg"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in0"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in1"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-kpss"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-mmss"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-stm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm0"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm1"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm2"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm3"),
+
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etr"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tpiu"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-replicator"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etf"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-merg"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in0"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in1"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-kpss"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-mmss"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-stm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm0"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm1"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm2"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm3"),
+
+	CLK_LOOKUP("core_clk_src", blsp1_qup1_spi_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src", blsp1_qup2_spi_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src", blsp1_qup3_spi_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src", blsp1_qup4_spi_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src", blsp1_qup5_spi_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src", blsp1_qup6_spi_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",    blsp1_uart1_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",    blsp1_uart2_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",    blsp1_uart3_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",    blsp1_uart4_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",    blsp1_uart5_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",    blsp1_uart6_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                 ce1_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                 gp1_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                 gp2_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                 gp3_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                pdm2_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",          sdcc1_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",          sdcc2_apps_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",       usb_hs_system_clk_src.c, ""),
+
+	CLK_LOOKUP("iface_clk",            gcc_blsp1_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup1_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup1_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup2_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup2_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup3_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup3_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup4_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup4_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup5_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup6_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup6_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",     gcc_blsp1_uart1_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",     gcc_blsp1_uart2_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",     gcc_blsp1_uart3_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",     gcc_blsp1_uart4_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",     gcc_blsp1_uart5_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",     gcc_blsp1_uart6_apps_clk.c, ""),
+	CLK_LOOKUP("iface_clk",         gcc_boot_rom_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk",              gcc_ce1_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",              gcc_ce1_axi_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  gcc_ce1_clk.c, ""),
+	CLK_LOOKUP("iface_clk",       gcc_copss_smmu_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk",        gcc_lpss_smmu_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  gcc_gp1_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  gcc_gp2_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  gcc_gp3_clk.c, ""),
+	CLK_LOOKUP("core_clk",         gcc_lpass_q6_axi_clk.c, ""),
+	CLK_LOOKUP("iface_clk",          gcc_mss_cfg_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",      gcc_mss_q6_bimc_axi_clk.c, ""),
+	CLK_LOOKUP("core_clk",                 gcc_pdm2_clk.c, ""),
+	CLK_LOOKUP("iface_clk",              gcc_pdm_ahb_clk.c, ""),
+	CLK_LOOKUP("iface_clk",             gcc_prng_ahb_clk.c, ""),
+	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("iface_clk",            gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",           gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("core_clk",      gcc_usb2a_phy_sleep_clk.c, ""),
+	CLK_LOOKUP("iface_clk",           gcc_usb_hs_ahb_clk.c, "f9a55000.usb"),
+	CLK_LOOKUP("core_clk",        gcc_usb_hs_system_clk.c, "f9a55000.usb"),
+
+	CLK_LOOKUP("core_clk_src",                csi0_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                 axi_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",            dsi_pclk_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",               gfx3d_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                 vfe_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                csi1_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",        csi0phytimer_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",        csi1phytimer_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                 dsi_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",            dsi_byte_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",             dsi_esc_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",               mclk0_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",               mclk1_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",           mdp_vsync_clk_src.c, ""),
+
+	CLK_LOOKUP("core_clk",                 bimc_gfx_clk.c, ""),
+	CLK_LOOKUP("core_clk",                     csi0_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  csi0phy_clk.c, ""),
+	CLK_LOOKUP("core_clk",             csi0phytimer_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  csi0pix_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  csi0rdi_clk.c, ""),
+	CLK_LOOKUP("core_clk",                     csi1_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  csi1phy_clk.c, ""),
+	CLK_LOOKUP("core_clk",             csi1phytimer_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  csi1pix_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  csi1rdi_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  csi_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  csi_vfe_clk.c, ""),
+	CLK_LOOKUP("core_clk",                      dsi_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  dsi_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",                 dsi_byte_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  dsi_esc_clk.c, ""),
+	CLK_LOOKUP("core_clk",                 dsi_pclk_clk.c, ""),
+	CLK_LOOKUP("core_clk",               gmem_gfx3d_clk.c, ""),
+	CLK_LOOKUP("core_clk",                    mclk0_clk.c, ""),
+	CLK_LOOKUP("core_clk",                    mclk1_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  mdp_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  mdp_axi_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  mdp_dsi_clk.c, ""),
+	CLK_LOOKUP("core_clk",                 mdp_lcdc_clk.c, ""),
+	CLK_LOOKUP("core_clk",                mdp_vsync_clk.c, ""),
+	CLK_LOOKUP("core_clk",            mmss_misc_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",              mmss_s0_axi_clk.c, ""),
+	CLK_LOOKUP("core_clk",         mmss_mmssnoc_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",     mmss_mmssnoc_bto_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",         mmss_mmssnoc_axi_clk.c, ""),
+	CLK_LOOKUP("core_clk",                      vfe_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  vfe_ahb_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  vfe_axi_clk.c, ""),
+
+	CLK_LOOKUP("core_clk",   oxili_gfx3d_clk.c, "fdc00000.qcom,kgsl-3d0"),
+	CLK_LOOKUP("iface_clk",    oxili_ahb_clk.c, "fdc00000.qcom,kgsl-3d0"),
+	CLK_LOOKUP("mem_iface_clk", bimc_gfx_clk.c, "fdc00000.qcom,kgsl-3d0"),
+	CLK_LOOKUP("mem_clk",     gmem_gfx3d_clk.c, "fdc00000.qcom,kgsl-3d0"),
+
+	CLK_LOOKUP("iface_clk",           vfe_ahb_clk.c, "fd890000.qcom,iommu"),
+	CLK_LOOKUP("core_clk",            vfe_axi_clk.c, "fd890000.qcom,iommu"),
+	CLK_LOOKUP("iface_clk",           mdp_ahb_clk.c, "fd860000.qcom,iommu"),
+	CLK_LOOKUP("core_clk",            mdp_axi_clk.c, "fd860000.qcom,iommu"),
+	CLK_LOOKUP("iface_clk",           mdp_ahb_clk.c, "fd870000.qcom,iommu"),
+	CLK_LOOKUP("core_clk",            mdp_axi_clk.c, "fd870000.qcom,iommu"),
+	CLK_LOOKUP("iface_clk",         oxili_ahb_clk.c, "fd880000.qcom,iommu"),
+	CLK_LOOKUP("core_clk",           bimc_gfx_clk.c, "fd880000.qcom,iommu"),
+	CLK_LOOKUP("iface_clk", gcc_lpss_smmu_ahb_clk.c, "fd000000.qcom,iommu"),
+	CLK_LOOKUP("core_clk",   gcc_lpass_q6_axi_clk.c, "fd000000.qcom,iommu"),
+	CLK_LOOKUP("iface_clk", gcc_copss_smmu_ahb_clk.c,
+							 "fd010000.qcom,iommu"),
+	CLK_LOOKUP("core_clk",         pnoc_iommu_clk.c, "fd010000.qcom,iommu"),
+
+	CLK_LOOKUP("core_clk_src",                 lpaif_pri_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                lpaif_quad_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                 lpaif_sec_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                lpaif_spkr_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                 lpaif_ter_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                lpaif_pcm0_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",                lpaif_pcm1_clk_src.c, ""),
+	CLK_LOOKUP("core_clk_src",               lpaif_pcmoe_clk_src.c, ""),
+	CLK_LOOKUP("core_clk",               audio_core_ixfabric_clk.c, ""),
+	CLK_LOOKUP("core_clk",                  audio_wrapper_br_clk.c, ""),
+	CLK_LOOKUP("core_clk",                   q6ss_ahb_lfabif_clk.c, ""),
+	CLK_LOOKUP("core_clk",                         q6ss_ahbm_clk.c, ""),
+	CLK_LOOKUP("core_clk",                           q6ss_xo_clk.c, ""),
+	CLK_LOOKUP("core_clk",      audio_core_lpaif_pcm_data_oe_clk.c, ""),
+	CLK_LOOKUP("core_clk",         audio_core_lpaif_pri_ebit_clk.c, ""),
+	CLK_LOOKUP("core_clk",         audio_core_lpaif_pri_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk",          audio_core_lpaif_pri_osr_clk.c, ""),
+	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm0_ebit_clk.c, ""),
+	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm0_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk",        audio_core_lpaif_quad_ebit_clk.c, ""),
+	CLK_LOOKUP("core_clk",        audio_core_lpaif_quad_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk",         audio_core_lpaif_quad_osr_clk.c, ""),
+	CLK_LOOKUP("core_clk",         audio_core_lpaif_sec_ebit_clk.c, ""),
+	CLK_LOOKUP("core_clk",         audio_core_lpaif_sec_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk",          audio_core_lpaif_sec_osr_clk.c, ""),
+	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm1_ebit_clk.c, ""),
+	CLK_LOOKUP("core_clk",        audio_core_lpaif_pcm1_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk",  audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
+	CLK_LOOKUP("core_clk",  audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk",   audio_core_lpaif_codec_spkr_osr_clk.c, ""),
+	CLK_LOOKUP("core_clk",         audio_core_lpaif_ter_ebit_clk.c, ""),
+	CLK_LOOKUP("core_clk",         audio_core_lpaif_ter_ibit_clk.c, ""),
+	CLK_LOOKUP("core_clk",          audio_core_lpaif_ter_osr_clk.c, ""),
+
+	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c,  "fe200000.qcom,lpass"),
+	CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c,  "fe200000.qcom,lpass"),
+	CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("reg_clk",        q6ss_ahbm_clk.c,  "fe200000.qcom,lpass"),
+};
+
+static struct clk_lookup msm_clocks_8910_rumi[] = {
+	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
+	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
+	CLK_DUMMY("iface_clk",  HSUSB_IFACE_CLK, "f9a55000.usb", OFF),
+	CLK_DUMMY("core_clk",	HSUSB_CORE_CLK, "f9a55000.usb", OFF),
+	CLK_DUMMY("iface_clk",	NULL,		"msm_sdcc.1", OFF),
+	CLK_DUMMY("core_clk",	NULL,		"msm_sdcc.1", OFF),
+	CLK_DUMMY("bus_clk",	NULL,		"msm_sdcc.1", OFF),
+	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),
+	CLK_DUMMY("iface_clk",  NULL, "fd890000.qcom,iommu", OFF),
+	CLK_DUMMY("core_clk",   NULL, "fd890000.qcom,iommu", OFF),
+	CLK_DUMMY("iface_clk",  NULL, "fd860000.qcom,iommu", OFF),
+	CLK_DUMMY("core_clk",   NULL, "fd860000.qcom,iommu", OFF),
+	CLK_DUMMY("iface_clk",  NULL, "fd870000.qcom,iommu", OFF),
+	CLK_DUMMY("core_clk",   NULL, "fd870000.qcom,iommu", OFF),
+	CLK_DUMMY("iface_clk",  NULL, "fd880000.qcom,iommu", OFF),
+	CLK_DUMMY("core_clk",   NULL, "fd880000.qcom,iommu", OFF),
+	CLK_DUMMY("iface_clk",  NULL, "fd000000.qcom,iommu", OFF),
+	CLK_DUMMY("core_clk",   NULL, "fd000000.qcom,iommu", OFF),
+	CLK_DUMMY("iface_clk",  NULL, "fd010000.qcom,iommu", OFF),
+	CLK_DUMMY("core_clk",   NULL, "fd010000.qcom,iommu", OFF),
+};
+
+struct clock_init_data msm8910_rumi_clock_init_data __initdata = {
+	.table = msm_clocks_8910_rumi,
+	.size = ARRAY_SIZE(msm_clocks_8910_rumi),
+};
+
+static struct pll_config_regs gpll0_regs __initdata = {
+	.l_reg = (void __iomem *)GPLL0_L_VAL,
+	.m_reg = (void __iomem *)GPLL0_M_VAL,
+	.n_reg = (void __iomem *)GPLL0_N_VAL,
+	.config_reg = (void __iomem *)GPLL0_USER_CTL,
+	.mode_reg = (void __iomem *)GPLL0_MODE,
+	.base = &virt_bases[GCC_BASE],
+};
+
+/* GPLL0 at 600 MHz, main output enabled. */
+static struct pll_config gpll0_config __initdata = {
+	.l = 0x1f,
+	.m = 0x1,
+	.n = 0x4,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+/* MMPLL0 at 800 MHz, main output enabled. */
+static struct pll_config mmpll0_config __initdata = {
+	.l = 0x29,
+	.m = 0x2,
+	.n = 0x3,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+/* MMPLL1 at 1200 MHz, main output enabled. */
+static struct pll_config mmpll1_config __initdata = {
+	.l = 0x3E,
+	.m = 0x1,
+	.n = 0x2,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = 0x0,
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+static struct pll_config_regs lpapll0_regs __initdata = {
+	.l_reg = (void __iomem *)LPAAUDIO_PLL_L_VAL,
+	.m_reg = (void __iomem *)LPAAUDIO_PLL_M_VAL,
+	.n_reg = (void __iomem *)LPAAUDIO_PLL_N_VAL,
+	.config_reg = (void __iomem *)LPAAUDIO_PLL_USER_CTL,
+	.mode_reg = (void __iomem *)LPAAUDIO_PLL_MODE,
+	.base = &virt_bases[LPASS_BASE],
+};
+
+/* LPAPLL0 at 491.52 MHz, main output enabled. */
+static struct pll_config lpapll0_config __initdata = {
+	.l = 0x33,
+	.m = 0x1,
+	.n = 0x5,
+	.vco_val = 0x0,
+	.vco_mask = BM(21, 20),
+	.pre_div_val = BVAL(14, 12, 0x1),
+	.pre_div_mask = BM(14, 12),
+	.post_div_val = 0x0,
+	.post_div_mask = BM(9, 8),
+	.mn_ena_val = BIT(24),
+	.mn_ena_mask = BIT(24),
+	.main_output_val = BIT(0),
+	.main_output_mask = BIT(0),
+};
+
+#define PLL_AUX_OUTPUT_BIT 1
+#define PLL_AUX2_OUTPUT_BIT 2
+
+#define PWR_ON_MASK		BIT(31)
+#define EN_REST_WAIT_MASK	(0xF << 20)
+#define EN_FEW_WAIT_MASK	(0xF << 16)
+#define CLK_DIS_WAIT_MASK	(0xF << 12)
+#define SW_OVERRIDE_MASK	BIT(2)
+#define HW_CONTROL_MASK		BIT(1)
+#define SW_COLLAPSE_MASK	BIT(0)
+
+/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
+#define EN_REST_WAIT_VAL	(0x2 << 20)
+#define EN_FEW_WAIT_VAL		(0x2 << 16)
+#define CLK_DIS_WAIT_VAL	(0x2 << 12)
+#define GDSC_TIMEOUT_US		50000
+
+static void __init reg_init(void)
+{
+	u32 regval, status;
+	int ret;
+
+	if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS))
+			& gpll0_clk_src.status_mask))
+		configure_sr_hpm_lp_pll(&gpll0_config, &gpll0_regs, 1);
+
+	configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
+	configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
+	configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
+
+	/* Enable GPLL0's aux outputs. */
+	regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL));
+	regval |= BIT(PLL_AUX_OUTPUT_BIT) | BIT(PLL_AUX2_OUTPUT_BIT);
+	writel_relaxed(regval, GCC_REG_BASE(GPLL0_USER_CTL));
+
+	/* Vote for GPLL0 to turn on. Needed by acpuclock. */
+	regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+	regval |= BIT(0);
+	writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+
+	/*
+	 * TODO: Confirm that no clocks need to be voted on in this sleep vote
+	 * register.
+	 */
+	writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
+
+	/*
+	 * TODO: The following sequence enables the LPASS audio core GDSC.
+	 * Remove when this becomes unnecessary.
+	 */
+
+	/*
+	 * Disable HW trigger: collapse/restore occur based on registers writes.
+	 * Disable SW override: Use hardware state-machine for sequencing.
+	 */
+	regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+	regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
+
+	/* Configure wait time between states. */
+	regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
+	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
+	writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+
+	regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+	regval &= ~BIT(0);
+	writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
+
+	ret = readl_poll_timeout(LPASS_REG_BASE(AUDIO_CORE_GDSCR), status,
+				status & PWR_ON_MASK, 50, GDSC_TIMEOUT_US);
+	WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
+}
+
+static void __init msm8910_clock_post_init(void)
+{
+	/*
+	 * Hold an active set vote for CXO; this is because CXO is expected
+	 * to remain on whenever CPUs aren't power collapsed.
+	 */
+	clk_prepare_enable(&gcc_xo_a_clk_src.c);
+
+
+	/* Set rates for single-rate clocks. */
+	clk_set_rate(&usb_hs_system_clk_src.c,
+			usb_hs_system_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&pdm2_clk_src.c, pdm2_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&mclk0_clk_src.c, mclk0_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
+	clk_set_rate(&audio_core_slimbus_core_clk_src.c,
+			audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
+}
+
+#define GCC_CC_PHYS		0xFC400000
+#define GCC_CC_SIZE		SZ_16K
+
+#define MMSS_CC_PHYS		0xFD8C0000
+#define MMSS_CC_SIZE		SZ_256K
+
+#define LPASS_CC_PHYS		0xFE000000
+#define LPASS_CC_SIZE		SZ_256K
+
+#define APCS_GCC_CC_PHYS	0xF9011000
+#define APCS_GCC_CC_SIZE	SZ_4K
+
+static void __init msm8910_clock_pre_init(void)
+{
+	virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
+	if (!virt_bases[GCC_BASE])
+		panic("clock-8910: Unable to ioremap GCC memory!");
+
+	virt_bases[MMSS_BASE] = ioremap(MMSS_CC_PHYS, MMSS_CC_SIZE);
+	if (!virt_bases[MMSS_BASE])
+		panic("clock-8910: Unable to ioremap MMSS_CC memory!");
+
+	virt_bases[LPASS_BASE] = ioremap(LPASS_CC_PHYS, LPASS_CC_SIZE);
+	if (!virt_bases[LPASS_BASE])
+		panic("clock-8910: Unable to ioremap LPASS_CC memory!");
+
+	virt_bases[APCS_BASE] = ioremap(APCS_GCC_CC_PHYS, APCS_GCC_CC_SIZE);
+	if (!virt_bases[APCS_BASE])
+		panic("clock-8910: Unable to ioremap APCS_GCC_CC memory!");
+
+	clk_ops_local_pll.enable = sr_hpm_lp_pll_clk_enable;
+
+	vdd_dig_reg = rpm_regulator_get(NULL, "vdd_dig");
+	if (IS_ERR(vdd_dig_reg))
+		panic("clock-8910: Unable to get the vdd_dig regulator!");
+
+	/*
+	 * TODO: Set a voltage and enable vdd_dig, leaving the voltage high
+	 * until late_init. This may not be necessary with clock handoff;
+	 * Investigate this code on a real non-simulator target to determine
+	 * its necessity.
+	 */
+	vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+	rpm_regulator_enable(vdd_dig_reg);
+
+	enable_rpm_scaling();
+
+	/* Enable a clock to allow access to MMSS clock registers */
+	clk_prepare_enable(&gcc_mmss_noc_cfg_ahb_clk.c),
+
+	reg_init();
+
+	/* TODO: Remove this once the bus driver is in place */
+	clk_set_rate(&ahb_clk_src.c,  40000000);
+	clk_set_rate(&axi_clk_src.c, 200000000);
+	clk_prepare_enable(&mmss_mmssnoc_ahb_clk.c);
+	clk_prepare_enable(&mmss_s0_axi_clk.c);
+
+	/* TODO: Temporarily enable a clock to allow access to LPASS core
+	 * registers.
+	 */
+	clk_prepare_enable(&audio_core_ixfabric_clk.c);
+}
+
+static int __init msm8910_clock_late_init(void)
+{
+	return unvote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+}
+
+struct clock_init_data msm8910_clock_init_data __initdata = {
+	.table = msm_clocks_8910,
+	.size = ARRAY_SIZE(msm_clocks_8910),
+	.pre_init = msm8910_clock_pre_init,
+	.post_init = msm8910_clock_post_init,
+	.late_init = msm8910_clock_late_init,
+};
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index a4d7e61..7038b06 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"),
@@ -5458,7 +5459,18 @@
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,		"mdp.0"),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,	"footswitch-8x60.4"),
-	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,		"msm_iommu"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.0"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.1"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.2"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.3"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.4"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.5"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.6"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.7"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.8"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.9"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.10"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.11"),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,		"msm_vidc.0"),
@@ -5806,7 +5818,16 @@
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,		"mdp.0"),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,	"footswitch-8x60.4"),
-	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.0"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.1"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.2"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.3"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.4"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.5"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.6"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.7"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.8"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.9"),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"msm_vidc.0"),
@@ -5901,12 +5922,15 @@
 	CLK_LOOKUP("iface_clk",		gfx2d0_p_clk.c,	"footswitch-8x60.0"),
 	CLK_LOOKUP("iface_clk",		gfx2d1_p_clk.c,	"kgsl-2d1.1"),
 	CLK_LOOKUP("iface_clk",		gfx2d1_p_clk.c,	"footswitch-8x60.1"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,		"msm_iommu.10"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,		"msm_iommu.11"),
 	CLK_LOOKUP("core_clk",		gfx2d0_clk.c,		"msm_iommu.10"),
 	CLK_LOOKUP("core_clk",		gfx2d1_clk.c,		"msm_iommu.11"),
 };
 
 static struct clk_lookup msm_clocks_8960ab_only[] __initdata = {
 	CLK_LOOKUP("bus_clk", gfx3d_axi_clk.c, "footswitch-8x60.2"),
+	CLK_LOOKUP("iface_clk",	smmu_p_clk.c,	"msm_iommu.10"),
 	CLK_LOOKUP("core_clk", gfx3d_axi_clk.c, "msm_iommu.10"),
 	CLK_LOOKUP("div_clk",	tv_src_div_clk.c,	""),
 };
@@ -6143,7 +6167,17 @@
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,		"mdp.0"),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,	"footswitch-8x60.4"),
-	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.0"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.1"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.2"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.3"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.4"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.5"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.6"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.7"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.8"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.9"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.10"),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"msm_vidc.0"),
@@ -6319,12 +6353,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 +6376,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 +6399,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..94fb856 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), \
@@ -658,7 +666,8 @@
 #define A1_ID		 4
 #define A2_ID		 5
 #define DIFF_CLK_ID	 7
-#define DIV_CLK_ID	11
+#define DIV_CLK1_ID	11
+#define DIV_CLK2_ID	12
 
 DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
 DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
@@ -681,7 +690,8 @@
 DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a0, cxo_a0_a, A0_ID);
 DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a1, cxo_a1_a, A1_ID);
 DEFINE_CLK_RPM_SMD_XO_BUFFER(cxo_a2, cxo_a2_a, A2_ID);
-DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk, div_a_clk, DIV_CLK_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk1, div_a_clk1, DIV_CLK1_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER(div_clk2, div_a_clk2, DIV_CLK2_ID);
 DEFINE_CLK_RPM_SMD_XO_BUFFER(diff_clk, diff_a_clk, DIFF_CLK_ID);
 
 DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(cxo_d0_pin, cxo_d0_a_pin, D0_ID);
@@ -792,11 +802,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 +919,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 +2966,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
 };
@@ -3014,34 +3020,17 @@
 
 static int hdmi_pll_clk_enable(struct clk *c)
 {
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-	ret = hdmi_pll_enable();
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-	return ret;
+	return hdmi_pll_enable();
 }
 
 static void hdmi_pll_clk_disable(struct clk *c)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
 	hdmi_pll_disable();
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 }
 
 static int hdmi_pll_clk_set_rate(struct clk *c, unsigned long rate)
 {
-	unsigned long flags;
-	int rc;
-
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
-	rc = hdmi_pll_set_rate(rate);
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
-	return rc;
+	return hdmi_pll_set_rate(rate);
 }
 
 static struct clk_ops clk_ops_hdmi_pll = {
@@ -3065,9 +3054,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
 };
@@ -3076,21 +3067,39 @@
  * Unlike other clocks, the HDMI rate is adjusted through PLL
  * re-programming. It is also routed through an HID divider.
  */
-static void set_rate_hdmi(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
+static int rcg_clk_set_rate_hdmi(struct clk *c, unsigned long rate)
 {
-	clk_set_rate(nf->src_clk, nf->freq_hz);
+	struct clk_freq_tbl *nf;
+	struct rcg_clk *rcg = to_rcg_clk(c);
+	int rc;
+
+	for (nf = rcg->freq_tbl; nf->freq_hz != rate; nf++)
+		if (nf->freq_hz == FREQ_END) {
+			rc = -EINVAL;
+			goto out;
+		}
+
+	rc = clk_set_rate(nf->src_clk, rate);
+	if (rc < 0)
+		goto out;
 	set_rate_hid(rcg, nf);
+
+	rcg->current_freq = nf;
+	c->parent = nf->src_clk;
+out:
+	return rc;
 }
 
+static struct clk_ops clk_ops_rcg_hdmi;
+
 static struct rcg_clk extpclk_clk_src = {
 	.cmd_rcgr_reg = EXTPCLK_CMD_RCGR,
-	.set_rate = set_rate_hdmi,
 	.freq_tbl = ftbl_mdss_extpclk_clk,
 	.current_freq = &rcg_dummy_freq,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "extpclk_clk_src",
-		.ops = &clk_ops_rcg,
+		.ops = &clk_ops_rcg_hdmi,
 		VDD_DIG_FMAX_MAP2(LOW, 148500000, NOMINAL, 297000000),
 		CLK_INIT(extpclk_clk_src.c),
 	},
@@ -4976,18 +4985,14 @@
 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("xo",		XO_CLK,		"fb21b000.qcom,pronto", OFF),
 	CLK_DUMMY("core_clk",	BLSP2_UART_CLK,	"f991f000.serial",	OFF),
 	CLK_DUMMY("iface_clk",	BLSP2_UART_CLK,	"f991f000.serial",	OFF),
 	CLK_DUMMY("core_clk",	SDC1_CLK,	NULL,			OFF),
@@ -5016,10 +5021,10 @@
 
 static struct clk_lookup msm_clocks_8974[] = {
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"msm_otg"),
-	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-lpass"),
-	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil-q6v5-mss"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"fe200000.qcom,lpass"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"fc880000.qcom,mss"),
 	CLK_LOOKUP("xo",	cxo_clk_src.c,	"fb000000.qcom,wcnss-wlan"),
-	CLK_LOOKUP("xo",	cxo_clk_src.c,	"pil_pronto"),
+	CLK_LOOKUP("xo",	cxo_clk_src.c,	"fb21b000.qcom,pronto"),
 	CLK_LOOKUP("measure",	measure_clk.c,	"debug"),
 
 	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
@@ -5101,16 +5106,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 +5121,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"),
@@ -5130,6 +5132,7 @@
 	CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c,	  "msm_hsic_host"),
 	CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c,  "msm_hsic_host"),
 	CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
+	CLK_LOOKUP("ref_clk", div_clk2.c, "msm_smsc_hub"),
 
 	/* Multimedia clocks */
 	CLK_LOOKUP("bus_clk_src", axi_clk_src.c, ""),
@@ -5345,10 +5348,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, ""),
@@ -5364,14 +5371,14 @@
 						"msm-dai-q6.4106"),
 	CLK_LOOKUP("br_clk", audio_wrapper_br_clk.c, "fdd00000.qcom,ocmem"),
 
-	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "pil-q6v5-mss"),
-	CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "pil-q6v5-mss"),
-	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c,  "pil-q6v5-mss"),
+	CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
+	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c,  "fc880000.qcom,mss"),
 
-	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c,  "pil-q6v5-lpass"),
-	CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c,  "pil-q6v5-lpass"),
-	CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
-	CLK_LOOKUP("reg_clk",        q6ss_ahbm_clk.c,  "pil-q6v5-lpass"),
+	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c,  "fe200000.qcom,lpass"),
+	CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c,  "fe200000.qcom,lpass"),
+	CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
+	CLK_LOOKUP("reg_clk",        q6ss_ahbm_clk.c,  "fe200000.qcom,lpass"),
 	CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
 
 	CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
@@ -5681,6 +5688,9 @@
 	clk_ops_pixel = clk_ops_rcg;
 	clk_ops_pixel.set_rate = set_rate_pixel;
 
+	clk_ops_rcg_hdmi = clk_ops_rcg;
+	clk_ops_rcg_hdmi.set_rate = rcg_clk_set_rate_hdmi;
+
 	mdss_clk_ctrl_init();
 }
 
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 2ad425d..dade0ed 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3689,7 +3689,18 @@
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,		"mdp.0"),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,	"footswitch-8x60.4"),
-	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.0"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.1"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.2"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.3"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.4"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.5"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.6"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.7"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.8"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.9"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.10"),
+	CLK_LOOKUP("iface_clk",		smmu_p_clk.c,	"msm_iommu.11"),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("iface_clk",		rot_p_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("tv_enc_pclk",	tv_enc_p_clk.c,		NULL),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index b284168..2e85006 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),
@@ -1309,6 +1318,17 @@
 	},
 };
 
+static struct branch_clk gcc_ipa_sleep_clk = {
+	.cbcr_reg = IPA_SLEEP_CBCR,
+	.has_sibling = 1,
+	.base = &virt_bases[GCC_BASE],
+	.c = {
+		.dbg_name = "gcc_ipa_sleep_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(gcc_ipa_sleep_clk.c),
+	},
+};
+
 static struct branch_clk gcc_pdm2_clk = {
 	.cbcr_reg = PDM2_CBCR,
 	.has_sibling = 0,
@@ -2063,6 +2083,7 @@
 	CLK_LOOKUP("core_clk", gcc_ipa_clk.c, "fd4c0000.qcom,ipa"),
 	CLK_LOOKUP("bus_clk",  gcc_sys_noc_ipa_axi_clk.c, "fd4c0000.qcom,ipa"),
 	CLK_LOOKUP("iface_clk",  gcc_ipa_cnoc_clk.c, "fd4c0000.qcom,ipa"),
+	CLK_LOOKUP("inactivity_clk",  gcc_ipa_sleep_clk.c, "fd4c0000.qcom,ipa"),
 
 	CLK_LOOKUP("core_clk", gcc_pdm2_clk.c, ""),
 	CLK_LOOKUP("iface_clk", gcc_pdm_ahb_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index e7a596d..79bc639 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;
@@ -315,9 +350,11 @@
 
 void hdmi_pll_disable(void)
 {
+	clk_enable(mdss_dsi_ahb_clk);
 	REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
 	udelay(5);
 	REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+	clk_disable(mdss_dsi_ahb_clk);
 
 	hdmi_pll_on = 0;
 } /* hdmi_pll_disable */
@@ -327,6 +364,7 @@
 	u32 status;
 	u32 max_reads, timeout_us;
 
+	clk_enable(mdss_dsi_ahb_clk);
 	/* Global Enable */
 	REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
 	/* Power up power gen */
@@ -352,6 +390,7 @@
 		pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
 		       __func__, status);
 		hdmi_pll_disable();
+		clk_disable(mdss_dsi_ahb_clk);
 		return -EINVAL;
 	}
 	pr_debug("%s: hdmi phy pll is locked\n", __func__);
@@ -365,9 +404,11 @@
 		pr_err("%s: hdmi phy status=%x failed to Lock\n",
 		       __func__, status);
 		hdmi_pll_disable();
+		clk_disable(mdss_dsi_ahb_clk);
 		return -EINVAL;
 	}
 	pr_debug("%s: hdmi phy is locked\n", __func__);
+	clk_disable(mdss_dsi_ahb_clk);
 
 	hdmi_pll_on = 1;
 
@@ -383,6 +424,7 @@
 		set_power_dwn = 1;
 	}
 
+	clk_enable(mdss_dsi_ahb_clk);
 	pr_debug("%s: rate=%ld\n", __func__, rate);
 	switch (rate) {
 	case 0:
@@ -391,32 +433,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 +541,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 +571,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 +721,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);
 	}
@@ -504,6 +753,8 @@
 	/* Make sure writes complete before disabling iface clock */
 	mb();
 
+	clk_disable(mdss_dsi_ahb_clk);
+
 	if (set_power_dwn)
 		hdmi_pll_enable();
 
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index 63e67b3..a4def28 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -78,6 +78,13 @@
 
 static int clk_rpmrs_handoff_smd(struct rpm_clk *r)
 {
+	if (!r->branch) {
+		r->last_set_khz = INT_MAX;
+		if (!r->active_only)
+			r->last_set_sleep_khz = INT_MAX;
+		r->c.rate = 1 * r->factor;
+	}
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 8a75d390..181cf4c 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -49,6 +49,8 @@
 extern struct clock_init_data msm8930_pm8917_clock_init_data;
 extern struct clock_init_data msm8974_clock_init_data;
 extern struct clock_init_data msm8974_rumi_clock_init_data;
+extern struct clock_init_data msm8910_clock_init_data;
+extern struct clock_init_data msm8910_rumi_clock_init_data;
 
 int msm_clock_init(struct clock_init_data *data);
 int find_vdd_level(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index e0d98b7..d862d6d 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -227,7 +227,7 @@
 	 * be changed independently. Each cpu is bound to
 	 * same frequency. Hence set the cpumask to all cpu.
 	 */
-	if (cpu_is_msm8625())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		cpumask_setall(policy->cpus);
 
 	if (cpufreq_frequency_table_cpuinfo(policy, table)) {
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f559629..fd5fc81 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -19,6 +19,7 @@
 #include <linux/clkdev.h>
 #include <linux/dma-mapping.h>
 #include <linux/coresight.h>
+#include <linux/avtimer.h>
 #include <mach/irqs-8064.h>
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
@@ -59,6 +60,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)
 
@@ -102,6 +104,9 @@
 #define MSM8064_PC_CNTR_PHYS	(APQ8064_IMEM_PHYS + 0x664)
 #define MSM8064_PC_CNTR_SIZE		0x40
 #define MSM8064_RPM_MASTER_STATS_BASE	0x10BB00
+/* avtimer */
+#define AVTIMER_MSW_PHYSICAL_ADDRESS 0x2800900C
+#define AVTIMER_LSW_PHYSICAL_ADDRESS 0x28009008
 
 static struct resource msm8064_resources_pccntr[] = {
 	{
@@ -465,6 +470,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[] = {
 	{
@@ -2764,7 +2796,7 @@
 		.slack_weight_thresh_pct	= 3,
 		.slack_time_min_us		= 45000,
 		.slack_time_max_us		= 45000,
-		.ss_iobusy_conv			= 100,
+		.ss_no_corr_below_freq		= 0,
 		.ss_win_size_min_us		= 1000000,
 		.ss_win_size_max_us		= 1000000,
 		.ss_util_pct			= 95,
@@ -3264,3 +3296,8 @@
 		.platform_data = &apq8064_cache_dump_pdata,
 	},
 };
+
+struct dev_avtimer_data dev_avtimer_pdata = {
+	.avtimer_msw_phy_addr = AVTIMER_MSW_PHYSICAL_ADDRESS,
+	.avtimer_lsw_phy_addr = AVTIMER_LSW_PHYSICAL_ADDRESS,
+};
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-8960.c b/arch/arm/mach-msm/devices-8960.c
index c59461a..4780c57 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2485,6 +2485,17 @@
 	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
 };
 
+static struct fs_driver_data gfx3d_fs_data_8960ab = {
+	.clks = (struct fs_clk_data[]){
+		{ .name = "core_clk", .reset_rate = 27000000 },
+		{ .name = "iface_clk" },
+		{ .name = "bus_clk" },
+		{ 0 }
+	},
+	.bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+	.bus_port1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+};
+
 static struct fs_driver_data ijpeg_fs_data = {
 	.clks = (struct fs_clk_data[]){
 		{ .name = "core_clk" },
@@ -2583,7 +2594,7 @@
 	FS_8X60(FS_IJPEG,  "vdd",	"msm_gemini.0",	&ijpeg_fs_data),
 	FS_8X60(FS_VFE,    "vdd",	"msm_vfe.0",	&vfe_fs_data),
 	FS_8X60(FS_VPE,    "vdd",	"msm_vpe.0",	&vpe_fs_data),
-	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data),
+	FS_8X60(FS_GFX3D,  "vdd",	"kgsl-3d0.0",	&gfx3d_fs_data_8960ab),
 	FS_8X60(FS_VED,    "vdd",	"msm_vidc.0",	&ved_fs_data_8960ab),
 };
 unsigned msm8960ab_num_footswitch __initdata = ARRAY_SIZE(msm8960ab_footswitch);
@@ -3019,7 +3030,7 @@
 		.ss_win_size_min_us		= 1000000,
 		.ss_win_size_max_us		= 1000000,
 		.ss_util_pct			= 95,
-		.ss_iobusy_conv			= 100,
+		.ss_no_corr_below_freq		= 0,
 	},
 	.energy_coeffs	= {
 		.active_coeff_a		= 2492,
@@ -3056,7 +3067,7 @@
 		.ss_win_size_min_us		= 1000000,
 		.ss_win_size_max_us		= 1000000,
 		.ss_util_pct			= 95,
-		.ss_iobusy_conv			= 100,
+		.ss_no_corr_below_freq		= 0,
 	},
 	.energy_coeffs	= {
 		.active_coeff_a		= 2492,
@@ -4419,9 +4430,19 @@
 	},
 };
 
+static struct resource msm_gpio_resources[] = {
+	{
+		.start	= TLMM_MSM_SUMMARY_IRQ,
+		.end	= TLMM_MSM_SUMMARY_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
 struct platform_device msm_gpio_device = {
 	.name = "msmgpio",
 	.id = -1,
+	.num_resources	= ARRAY_SIZE(msm_gpio_resources),
+	.resource	= msm_gpio_resources,
 };
 
 struct platform_device mdm_sglte_device = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index e55e9a7..fc65cb7 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1506,9 +1506,19 @@
 	},
 };
 
+static struct resource msm_gpio_resources[] = {
+	{
+		.start	= TLMM_MSM_SUMMARY_IRQ,
+		.end	= TLMM_MSM_SUMMARY_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
 struct platform_device msm_gpio_device = {
 	.name = "msmgpio",
 	.id = -1,
+	.num_resources	= ARRAY_SIZE(msm_gpio_resources),
+	.resource	= msm_gpio_resources,
 };
 
 void __init msm9615_device_init(void)
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index b4ef76d2..2d9872e 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -36,6 +36,7 @@
 #include "devices-msm7x2xa.h"
 #include "footswitch.h"
 #include "acpuclock.h"
+#include "acpuclock-8625q.h"
 #include "spm.h"
 #include "mpm-8625.h"
 #include "irq.h"
@@ -240,6 +241,21 @@
 	.dev.platform_data = &msm7x27aa_acpuclk_pdata,
 };
 
+static struct acpuclk_pdata msm8625q_pdata = {
+	.max_speed_delta_khz = 801600,
+};
+
+static struct acpuclk_pdata_8625q msm8625q_acpuclk_pdata = {
+	.acpu_clk_data = &msm8625q_pdata,
+	.pvs_voltage_uv = 1350000,
+};
+
+struct platform_device msm8625q_device_acpuclk = {
+	.name		= "acpuclock-8625q",
+	.id		= -1,
+	.dev.platform_data = &msm8625q_acpuclk_pdata,
+};
+
 static struct acpuclk_pdata msm8625_acpuclk_pdata = {
 	/* TODO: Need to update speed delta from H/w Team */
 	.max_speed_delta_khz = 604800,
@@ -501,9 +517,21 @@
 	.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())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		msm_pm_set_irq_extns(&msm8625_pm_irq_calls);
 	else
 		msm_pm_set_irq_extns(&msm7x27a_pm_irq_calls);
@@ -518,8 +546,9 @@
 void __init msm_pm_register_cpr_ops(void)
 {
 	/* CPR presents on revision >= v2.0 chipsets */
-	if (cpu_is_msm8625() &&
+	if ((cpu_is_msm8625() &&
 			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+			|| cpu_is_msm8625q())
 		msm_pm_set_cpr_ops(&msm8625_pm_cpr_ops);
 }
 
@@ -940,7 +969,7 @@
 
 void __init msm8x25_kgsl_3d0_init(void)
 {
-	if (cpu_is_msm8625()) {
+	if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		kgsl_3d0_pdata.idle_timeout = HZ/5;
 		kgsl_3d0_pdata.strtstp_sleepwake = false;
 
@@ -1394,7 +1423,7 @@
 	if (controller < 1 || controller > 4)
 		return -EINVAL;
 
-	if (cpu_is_msm8625())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		pdev = msm8625_sdcc_devices[controller-1];
 	else
 		pdev = msm_sdcc_devices[controller-1];
@@ -1483,7 +1512,7 @@
 {
 	struct platform_device	*pdev;
 
-	if (cpu_is_msm8625())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		pdev = msm8625_host_devices[host];
 	else
 		pdev = msm_host_devices[host];
@@ -1586,12 +1615,12 @@
 void __init msm_fb_register_device(char *name, void *data)
 {
 	if (!strncmp(name, "mdp", 3)) {
-		if (cpu_is_msm8625())
+		if (cpu_is_msm8625() || cpu_is_msm8625q())
 			msm_register_device(&msm8625_mdp_device, data);
 		else
 			msm_register_device(&msm_mdp_device, data);
 	} else if (!strncmp(name, "mipi_dsi", 8)) {
-		if (cpu_is_msm8625()) {
+		if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 			msm_register_device(&msm8625_mipi_dsi_device, data);
 			mipi_dsi_device = msm8625_mipi_dsi_device;
 		} else {
@@ -1762,13 +1791,6 @@
 	},
 };
 
-struct msm_cpr_vp_data vp_data = {
-	.min_volt = 1000000,
-	.max_volt = 1350000,
-	.default_volt = 1300000,
-	.step_size = 12500,
-};
-
 static uint32_t
 msm_cpr_get_quot(uint32_t max_quot, uint32_t max_freq, uint32_t new_freq)
 {
@@ -1810,7 +1832,7 @@
 	.max_freq = 1401600,
 	.max_quot = 0,
 	.disable_cpr = false,
-	.vp_data = &vp_data,
+	.step_size = 12500,
 	.get_quot = msm_cpr_get_quot,
 	.clk_enable = msm_cpr_clk_enable,
 };
@@ -1917,6 +1939,8 @@
 	else if (msm8625_cpu_id() == MSM8625)
 		msm_cpr_pdata.max_freq = 1008000;
 
+	if (machine_is_qrd_skud_prime() || cpu_is_msm8625q())
+		msm_cpr_pdata.step_size = 6250;
 	platform_device_register(&msm8625_vp_device);
 	platform_device_register(&msm8625_device_cpr);
 }
@@ -2023,6 +2047,24 @@
 	return ret;
 }
 
+static int __init msm_acpuclock_init(int nominal_voltage,
+					int default_turbo_voltage)
+{
+	struct cpr_info_type *acpu_info = NULL;
+	acpu_info = kzalloc(sizeof(struct cpr_info_type), GFP_KERNEL);
+	if (!acpu_info) {
+		pr_err("%s: Out of memory %d\n", __func__, -ENOMEM);
+		return -ENOMEM;
+	}
+	msm_smem_get_cpr_info(acpu_info);
+	msm8625q_acpuclk_pdata.pvs_voltage_uv =
+			msm_c2_pmic_mv[acpu_info->pvs_fuse & 0x1F];
+	kfree(acpu_info);
+	msm8625q_acpuclk_pdata.nominal_voltage = nominal_voltage;
+	msm8625q_acpuclk_pdata.default_turbo_voltage = default_turbo_voltage;
+	return 0;
+}
+
 int __init msm7x2x_misc_init(void)
 {
 	if (machine_is_msm8625_rumi3()) {
@@ -2034,8 +2076,14 @@
 	msm_clock_init(&msm7x27a_clock_init_data);
 	if (cpu_is_msm7x27aa() || cpu_is_msm7x25ab())
 		platform_device_register(&msm7x27aa_device_acpuclk);
-	else if (cpu_is_msm8625()) {
-		if (msm8625_cpu_id() == MSM8625)
+	else if (cpu_is_msm8625q()) {
+			msm_acpuclock_init(1050000, 0);
+			platform_device_register(&msm8625q_device_acpuclk);
+	} else if (cpu_is_msm8625()) {
+		if (machine_is_qrd_skud_prime()) {
+			msm_acpuclock_init(1150000, 1275000);
+			platform_device_register(&msm8625q_device_acpuclk);
+		} else if (msm8625_cpu_id() == MSM8625)
 			platform_device_register(&msm7x27aa_device_acpuclk);
 		else if (msm8625_cpu_id() == MSM8625A)
 			platform_device_register(&msm8625_device_acpuclk);
@@ -2045,11 +2093,11 @@
 		platform_device_register(&msm7x27a_device_acpuclk);
 	}
 
-	if (cpu_is_msm8625() &&
-			(SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2))
+	if (cpu_is_msm8625() || (cpu_is_msm8625q() &&
+			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2))
 		msm_cpr_init();
 
-	if (!cpu_is_msm8625())
+	if (!cpu_is_msm8625() && !cpu_is_msm8625q())
 		pl310_resources[1].start = INT_L2CC_INTR;
 
 	platform_device_register(&pl310_erp_device);
@@ -2071,7 +2119,7 @@
 		   (0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
 		   (0x1 << L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT);
 
-	if (cpu_is_msm8625()) {
+	if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		/* Way Size 011(0x3) 64KB */
 		aux_ctrl |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
 			    (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | \
@@ -2087,7 +2135,7 @@
 	}
 
 	l2x0_init(MSM_L2CC_BASE, aux_ctrl, L2X0_AUX_CTRL_MASK);
-	if (cpu_is_msm8625()) {
+	if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		pctrl = readl_relaxed(MSM_L2CC_BASE + L2X0_PREFETCH_CTRL);
 		pr_info("Prfetch Ctrl: 0x%08x\n", pctrl);
 	}
@@ -2124,7 +2172,7 @@
 
 static int msm7627a_init_gpio(void)
 {
-	if (cpu_is_msm8625())
+	if (cpu_is_msm8625() || cpu_is_msm8625q())
 		platform_device_register(&msm8625_device_gpio);
 	else
 		platform_device_register(&msm_device_gpio);
@@ -2135,6 +2183,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-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index c6513d9..0a080b1 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -100,9 +100,19 @@
 #define MSM_UART9DM_PHYS    (MSM_GSBI9_PHYS + 0x40000)
 #define INT_UART9DM_IRQ     GSBI9_UARTDM_IRQ
 
+static struct resource msm_gpio_resources[] = {
+	{
+		.start	= TLMM_MSM_SUMMARY_IRQ,
+		.end	= TLMM_MSM_SUMMARY_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
 struct platform_device msm_gpio_device = {
 	.name = "msmgpio",
 	.id = -1,
+	.num_resources	= ARRAY_SIZE(msm_gpio_resources),
+	.resource	= msm_gpio_resources,
 };
 
 static void charm_ap2mdm_kpdpwr_on(void)
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index bd9ea49..b676518 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;
@@ -470,4 +471,5 @@
 extern struct platform_device apq_cpudai_mi2s;
 extern struct platform_device apq_cpudai_i2s_rx;
 extern struct platform_device apq_cpudai_i2s_tx;
+extern struct dev_avtimer_data dev_avtimer_pdata;
 
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index 12f5aa9..22fc1ac 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -373,9 +373,8 @@
 
 	spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
 	list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]);
-	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
-
 	queue_work(dmov_conf[adm].cmd_wq, &cmd->work);
+	spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
 }
 
 void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
diff --git a/arch/arm/mach-msm/event_timer.c b/arch/arm/mach-msm/event_timer.c
index e06dad4..9f46f68 100644
--- a/arch/arm/mach-msm/event_timer.c
+++ b/arch/arm/mach-msm/event_timer.c
@@ -193,21 +193,7 @@
 	unsigned long flags;
 	struct event_timer_info *event =
 		(struct event_timer_info *)data;
-
-	local_irq_save(flags);
-	create_hrtimer(event->node.expires);
-	local_irq_restore(flags);
-}
-
-/**
- *  setup_timer() : Helper function to setup timer on primary
- *                  core during hrtimer callback.
- *  @event: event handle causing the wakeup.
- */
-static void setup_event_hrtimer(struct event_timer_info *event)
-{
 	struct timerqueue_node *next;
-	unsigned long flags;
 
 	spin_lock_irqsave(&event_timer_lock, flags);
 	if (is_event_active(event))
@@ -223,9 +209,18 @@
 		if (msm_event_debug_mask && MSM_EVENT_TIMER_DEBUG)
 			pr_info("%s: Setting timer for %lu", __func__,
 			(unsigned long)ktime_to_ns(event->node.expires));
+		create_hrtimer(event->node.expires);
+	}
+}
 
-		smp_call_function_single(0, create_timer_smp, event, 1);
-		}
+/**
+ *  setup_timer() : Helper function to setup timer on primary
+ *                  core during hrtimer callback.
+ *  @event: event handle causing the wakeup.
+ */
+static void setup_event_hrtimer(struct event_timer_info *event)
+{
+	smp_call_function_single(0, create_timer_smp, event, 1);
 }
 
 /**
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index ccd0bf7..9a22996 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -96,20 +96,6 @@
 	mrc     p15, 0, r9, c13, c0, 3 /* TPIDRURO */
 	mrc     p15, 0, ip, c13, c0, 1 /* context ID */
 	stmia   r0!, {r1-r9, ip}
-#ifdef CONFIG_MSM_CPU_AVS
-	mrc     p15, 7, r1, c15, c1, 7 /* AVSCSR is the Adaptive Voltage Scaling
-	                                * Control and Status Register */
-	mrc     p15, 7, r2, c15, c0, 6 /* AVSDSCR is the Adaptive Voltage
-	                                * Scaling Delay Synthesizer Control
-					* Register */
-#ifndef CONFIG_ARCH_MSM_KRAIT
-	mrc     p15, 7, r3, c15, c1, 0 /* TSCSR is the Temperature Status and
-	                                * Control Register
-					*/
-#endif
-
-	stmia   r0!, {r1-r3}
-#endif
 
 #ifdef CONFIG_MSM_JTAG
 	bl      msm_jtag_save_state
@@ -240,14 +226,6 @@
 	add	r1, r1, r2
 #endif
 
-#ifdef CONFIG_MSM_CPU_AVS
-	ldmdb   r1!, {r2-r4}
-#ifndef CONFIG_ARCH_MSM_KRAIT
-	mcr     p15, 7, r4, c15, c1, 0 /* TSCSR */
-#endif
-	mcr     p15, 7, r3, c15, c0, 6 /* AVSDSCR */
-	mcr     p15, 7, r2, c15, c1, 7 /* AVSCSR */
-#endif
 	ldmdb   r1!, {r2-r11}
 	mcr     p15, 0, r4, c3, c0, 0 /* dacr */
 	mcr     p15, 0, r3, c2, c0, 0 /* TTBR0 */
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index ee3209c..5550e96 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -14,13 +14,8 @@
 #ifndef _ARCH_ARM_MACH_MSM_IDLE_H_
 #define _ARCH_ARM_MACH_MSM_IDLE_H_
 
-#ifdef CONFIG_MSM_CPU_AVS
-/* 11 general purpose registers (r4-r14), 10 cp15 registers, 3 AVS registers */
-#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10 + 4 * 3)
-#else
 /* 11 general purpose registers (r4-r14), 10 cp15 registers */
 #define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10)
-#endif
 
 #define ON	1
 #define OFF	0
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..975b12c 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -83,6 +83,7 @@
 /**
  * struct msm_iommu_drvdata - A single IOMMU hardware instance
  * @base:	IOMMU config port base address (VA)
+ * @glb_base:	IOMMU config port base address for global register space (VA)
  * @ncb		The number of contexts on this IOMMU
  * @irq:	Interrupt number
  * @clk:	The bus clock for this IOMMU hardware instance
@@ -99,6 +100,7 @@
  */
 struct msm_iommu_drvdata {
 	void __iomem *base;
+	void __iomem *glb_base;
 	int ncb;
 	int ttbr_split;
 	struct clk *clk;
@@ -123,8 +125,8 @@
  *			attached to them
  * @attached_domain	Domain currently attached to this context (if any)
  * @name		Human-readable name of this context device
- * @sids		List of Stream IDs mapped to this context (v2 only)
- * @nsid		Number of Stream IDs mapped to this context (v2 only)
+ * @sids		List of Stream IDs mapped to this context
+ * @nsid		Number of Stream IDs mapped to this context
  *
  * A msm_iommu_ctx_drvdata holds the driver data for a single context bank
  * within each IOMMU hardware instance
@@ -147,6 +149,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.
@@ -178,6 +233,12 @@
 		of_node_put(node);
 		return 0;
 	}
+
+	node = of_find_compatible_node(NULL, NULL, "qcom,msm-smmu-v1");
+	if (node) {
+		of_node_put(node);
+		return 1;
+	}
 #endif
 	if (cpu_is_msm8960() &&
 	    SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 2)
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h b/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
index af82fd9..31b2b4f 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, 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
@@ -811,24 +811,24 @@
 
 
 /* Global Registers */
-#define M2VCBR_N	(0xFF000)
-#define CBACR_N		(0xFF800)
-#define TLBRSW		(0xFFE00)
-#define TLBTR0		(0xFFE80)
-#define TLBTR1		(0xFFE84)
-#define TLBTR2		(0xFFE88)
-#define TESTBUSCR	(0xFFE8C)
-#define GLOBAL_TLBIALL	(0xFFF00)
-#define TLBIVMID	(0xFFF04)
-#define CR		(0xFFF80)
-#define EAR		(0xFFF84)
-#define ESR		(0xFFF88)
-#define ESRRESTORE	(0xFFF8C)
-#define ESYNR0		(0xFFF90)
-#define ESYNR1		(0xFFF94)
-#define REV		(0xFFFF4)
-#define IDR		(0xFFFF8)
-#define RPU_ACR		(0xFFFFC)
+#define M2VCBR_N	(0x000)
+#define CBACR_N		(0x800)
+#define TLBRSW		(0xE00)
+#define TLBTR0		(0xE80)
+#define TLBTR1		(0xE84)
+#define TLBTR2		(0xE88)
+#define TESTBUSCR	(0xE8C)
+#define GLOBAL_TLBIALL	(0xF00)
+#define TLBIVMID	(0xF04)
+#define CR		(0xF80)
+#define EAR		(0xF84)
+#define ESR		(0xF88)
+#define ESRRESTORE	(0xF8C)
+#define ESYNR0		(0xF90)
+#define ESYNR1		(0xF94)
+#define REV		(0xFF4)
+#define IDR		(0xFF8)
+#define RPU_ACR		(0xFFC)
 
 
 /* Context Bank Registers */
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index dae6d3b..c37b518 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -457,7 +457,7 @@
 
 int ipa_teardown_sys_pipe(u32 clnt_hdl);
 
-#else
+#else /* CONFIG_IPA */
 
 /*
  * Connect / Disconnect
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..d11c35c 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8974.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8974.h
@@ -15,29 +15,11 @@
 
 /* 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..9ba77af 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9625.h
@@ -15,21 +15,10 @@
 
 /* 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)
 
 #define NR_MSM_IRQS 288
 #define NR_GPIO_IRQS 76
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 7aff770..8c6b959 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -17,11 +17,43 @@
 #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 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 +90,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 +102,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_adsp.h b/arch/arm/mach-msm/include/mach/msm_adsp.h
index e40c07d..ea08f0c 100644
--- a/arch/arm/mach-msm/include/mach/msm_adsp.h
+++ b/arch/arm/mach-msm/include/mach/msm_adsp.h
@@ -39,6 +39,7 @@
 void msm_adsp_put(struct msm_adsp_module *module);
 int msm_adsp_enable(struct msm_adsp_module *module);
 int msm_adsp_disable(struct msm_adsp_module *module);
+int msm_adsp_dump(struct msm_adsp_module *module);
 int adsp_set_clkrate(struct msm_adsp_module *module, unsigned long clk_rate);
 int msm_adsp_disable_event_rsp(struct msm_adsp_module *module);
 int32_t get_adsp_resource(unsigned short client_idx,
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_dcvs_scm.h b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
index 597fdc0..7eefd54 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
@@ -48,7 +48,7 @@
 	uint32_t slack_time_min_us;
 	uint32_t slack_time_max_us;
 	uint32_t slack_weight_thresh_pct;
-	uint32_t ss_iobusy_conv;
+	uint32_t ss_no_corr_below_freq;
 	uint32_t ss_win_size_min_us;
 	uint32_t ss_win_size_max_us;
 	uint32_t ss_util_pct;
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
index 08f21b6..64990da 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
@@ -22,7 +22,7 @@
  *
  */
 
-#define MSM8910_MSM_SHARED_RAM_PHYS	0x0FA00000
+#define MSM8910_MSM_SHARED_RAM_PHYS	0x0D600000
 
 #define MSM8910_APCS_GCC_PHYS	0xF9011000
 #define MSM8910_APCS_GCC_SIZE	SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index 17156b1..fe928b9 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -127,6 +127,7 @@
 #define MSM_HDMI_SIZE		SZ_4K
 
 /* Needed to keep the unified iomap happy */
+#define MSM_APCS_GCC_BASE       IOMEM(0xFA006000)       /*  4K  */
 #define MSM_MPM2_PSHOLD_BASE	MSM_TLMM_BASE
 
 #ifdef CONFIG_DEBUG_MSM8660_UART
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/rpc_server_handset.h b/arch/arm/mach-msm/include/mach/rpc_server_handset.h
index e1dc841..0856a4a 100644
--- a/arch/arm/mach-msm/include/mach/rpc_server_handset.h
+++ b/arch/arm/mach-msm/include/mach/rpc_server_handset.h
@@ -17,6 +17,7 @@
 struct msm_handset_platform_data {
 	const char *hs_name;
 	uint32_t pwr_key_delay_ms; /* default 500ms */
+	bool ignore_end_key;
 };
 
 void report_headset_status(bool connected);
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/sensors_adsp.h b/arch/arm/mach-msm/include/mach/sensors_adsp.h
new file mode 100644
index 0000000..3c65e37
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/sensors_adsp.h
@@ -0,0 +1,111 @@
+/* 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 SENSORS_ADSP_H
+#define SENSORS_ADSP_H
+
+#include <linux/types.h>
+
+/** Maximum number of segments that may be mapped from DDR to OCMEM  */
+#define SNS_OCMEM_MAX_NUM_SEG_V01 16
+
+/**  Maximum size of the ocmem_vectors structure  */
+#define SNS_OCMEM_MAX_VECTORS_SIZE_V01 512
+
+/* Sensor OCMEM message id  */
+
+#define SNS_OCMEM_CANCEL_REQ_V01 0x0000
+#define SNS_OCMEM_CANCEL_RESP_V01 0x0000
+#define SNS_OCMEM_VERSION_REQ_V01 0x0001
+#define SNS_OCMEM_VERSION_RESP_V01 0x0001
+#define SNS_OCMEM_PHYS_ADDR_REQ_V01 0x0002
+#define SNS_OCMEM_PHYS_ADDR_RESP_V01 0x0002
+#define SNS_OCMEM_HAS_CLIENT_IND_V01 0x0002
+#define SNS_OCMEM_BW_VOTE_REQ_V01 0x0003
+#define SNS_OCMEM_BW_VOTE_RESP_V01 0x0003
+#define SNS_OCMEM_BW_VOTE_IND_V01 0x0003
+
+enum {
+	SNS_OCMEM_MODULE_KERNEL = 0,
+	SNS_OCMEM_MODULE_ADSP
+};
+
+/**
+ * Defines the types of response messages
+ */
+enum {
+	SNS_OCMEM_MSG_TYPE_REQ = 0,  /* Request */
+	SNS_OCMEM_MSG_TYPE_RESP,     /* Response to a request */
+	SNS_OCMEM_MSG_TYPE_IND       /* Asynchronous indication */
+};
+
+/**
+ * The message header. Used in both incoming and outgoing messages
+ */
+struct sns_ocmem_hdr_s {
+	int32_t  msg_id ;	/* Message ID, as defined in the IDL */
+	uint16_t msg_size;	/* Size of message, in bytes */
+	uint8_t  dst_module;	/* Destination module */
+	uint8_t  src_module;	/* Source module */
+	uint8_t  msg_type;	/* The message type */
+} __packed;
+
+struct sns_ocmem_common_resp_s_v01 {
+	/*  This shall be the first element of every response message  */
+	uint8_t sns_result_t;
+	/**<   0 == SUCCESS; 1 == FAILURE
+	A result of FAILURE indicates that that any data contained in the
+	response should not be used other than sns_err_t, to determine the
+	type of error */
+	uint8_t sns_err_t;
+	/**<   See sns_ocmem_error_e in ocmem_sensors.h */
+};
+
+/* This structure represents a single memory region that must be
+mapped from DDR to OCMEM */
+struct sns_mem_segment_s_v01 {
+
+	uint64_t start_address; /* Physical start address of segment */
+	uint32_t size; /* Size (in bytes) of this segment */
+	uint16_t type; /*  1 == Read only; 2 == Read/Write Data */
+} __packed;
+
+struct sns_ocmem_phys_addr_resp_msg_v01 {
+	struct sns_ocmem_common_resp_s_v01 resp; /* response */
+	uint32_t segments_len; /* number of elements in segments */
+	/* Segments mapped from DDR to OCMEM */
+	struct sns_mem_segment_s_v01 segments[SNS_OCMEM_MAX_NUM_SEG_V01];
+	uint8_t segments_valid; /* true if segments is being passed */
+} __packed ;
+
+struct sns_ocmem_has_client_ind_msg_v01 {
+	uint16_t num_clients; /* Number of active clients on the ADSP */
+} __packed;
+
+struct sns_ocmem_bw_vote_req_msg_v01 {
+	uint8_t is_map;		/* True if mapping; false if unmapping */
+	uint8_t vectors_valid;  /* True if vectors is being passed */
+	uint32_t vectors_len;	/* Number of elements in vectors */
+	uint8_t vectors[SNS_OCMEM_MAX_VECTORS_SIZE_V01]; /* vectors */
+} __packed;
+
+struct sns_ocmem_bw_vote_resp_msg_v01 {
+	struct sns_ocmem_common_resp_s_v01 resp;
+};
+
+struct sns_ocmem_bw_vote_ind_msg_v01 {
+	/* If the ADSP just voted for, or took away its vote for
+	OCMEM bandwidth */
+	uint8_t is_vote_on;
+} __packed;
+
+#endif /* SENSORS_ADSP_H */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 0499a7a..d41a1f0 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -60,6 +60,8 @@
 	of_machine_is_compatible("qcom,msm8910")
 #define machine_is_msm8910_sim()		\
 	of_machine_is_compatible("qcom,msm8910-sim")
+#define machine_is_msm8910_rumi()		\
+	of_machine_is_compatible("qcom,msm8910-rumi")
 #else
 #define early_machine_is_msm8974()	0
 #define machine_is_msm8974()		0
@@ -75,6 +77,7 @@
 #define early_machine_is_msm8910()	0
 #define machine_is_msm8910()		0
 #define machine_is_msm8910_sim()	0
+#define machine_is_msm8910_rumi()	0
 
 #endif
 
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/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index c21ea33..5d7fc94 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -47,8 +47,6 @@
 static bool msm_lpm_get_rpm_notif = true;
 
 /*Macros*/
-#define VDD_DIG_ACTIVE		(5)
-#define VDD_MEM_ACTIVE		(1050000)
 #define MAX_RS_NAME		(16)
 #define MAX_RS_SIZE		(4)
 #define IS_RPM_CTL(rs) \
@@ -133,10 +131,6 @@
 	.flush = msm_lpm_flush_l2,
 	.notify = NULL,
 	.valid = false,
-	.rs_data = {
-		.value = MSM_LPM_L2_CACHE_ACTIVE,
-		.default_value = MSM_LPM_L2_CACHE_ACTIVE,
-	},
 	.ko_attr = RPMRS_ATTR(l2),
 };
 
@@ -147,10 +141,6 @@
 	.flush = msm_lpm_flush_vdd_dig,
 	.notify = msm_lpm_notify_vdd_dig,
 	.valid = false,
-	.rs_data = {
-		.value = VDD_DIG_ACTIVE,
-		.default_value = VDD_DIG_ACTIVE,
-	},
 	.ko_attr = RPMRS_ATTR(vdd_dig),
 };
 
@@ -161,10 +151,6 @@
 	.flush = msm_lpm_flush_vdd_mem,
 	.notify = msm_lpm_notify_vdd_mem,
 	.valid = false,
-	.rs_data = {
-		.value = VDD_MEM_ACTIVE,
-		.default_value = VDD_MEM_ACTIVE,
-	},
 	.ko_attr = RPMRS_ATTR(vdd_mem),
 };
 
@@ -175,10 +161,6 @@
 	.flush = msm_lpm_flush_pxo,
 	.notify = msm_lpm_notify_pxo,
 	.valid = false,
-	.rs_data = {
-		.value = MSM_LPM_PXO_ON,
-		.default_value = MSM_LPM_PXO_ON,
-	},
 	.ko_attr = RPMRS_ATTR(pxo),
 };
 
@@ -421,13 +403,13 @@
 	trace_lpm_resources(rs->sleep_value, rs->name);
 }
 
-static void msm_lpm_flush_l2(int notify_rpm)
+static void msm_lpm_set_l2_mode(int sleep_mode, int notify_rpm)
 {
-	struct msm_lpm_resource *rs = &msm_lpm_l2;
-	int lpm;
-	int rc;
+	int lpm, rc;
 
-	switch (rs->sleep_value) {
+	msm_pm_set_l2_flush_flag(0);
+
+	switch (sleep_mode) {
 	case MSM_LPM_L2_CACHE_HSFS_OPEN:
 		lpm = MSM_SPM_L2_MODE_POWER_COLLAPSE;
 		msm_pm_set_l2_flush_flag(1);
@@ -455,6 +437,13 @@
 				__func__, lpm);
 }
 
+static void msm_lpm_flush_l2(int notify_rpm)
+{
+	struct msm_lpm_resource *rs = &msm_lpm_l2;
+
+	msm_lpm_set_l2_mode(rs->sleep_value, notify_rpm);
+}
+
 /* RPM CTL */
 static void msm_lpm_flush_rpm_ctl(int notify_rpm)
 {
@@ -679,8 +668,7 @@
 	}
 	msm_lpm_get_rpm_notif = true;
 
-	if (msm_lpm_use_mpm(limits))
-		msm_mpm_enter_sleep(sclk_count, from_idle);
+	msm_mpm_enter_sleep(sclk_count, from_idle);
 
 	return ret;
 }
@@ -688,11 +676,11 @@
 void msm_lpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
 		bool from_idle, bool notify_rpm, bool collapsed)
 {
-	/* MPM exit sleep
 	if (msm_lpm_use_mpm(limits))
-		msm_mpm_exit_sleep(from_idle);*/
+		msm_mpm_exit_sleep(from_idle);
 
-	msm_spm_l2_set_low_power_mode(MSM_SPM_MODE_DISABLED, notify_rpm);
+	if (msm_lpm_l2.valid)
+		msm_lpm_set_l2_mode(msm_lpm_l2.rs_data.default_value, false);
 }
 
 static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
@@ -702,12 +690,12 @@
 	switch (action) {
 	case CPU_UP_PREPARE:
 	case CPU_UP_PREPARE_FROZEN:
-		rs->rs_data.value = MSM_LPM_L2_CACHE_ACTIVE;
+		rs->rs_data.value = rs->rs_data.default_value;
 		break;
 	case CPU_ONLINE_FROZEN:
 	case CPU_ONLINE:
 		if (num_online_cpus() > 1)
-			rs->rs_data.value = MSM_LPM_L2_CACHE_ACTIVE;
+			rs->rs_data.value = rs->rs_data.default_value;
 		break;
 	case CPU_DEAD_FROZEN:
 	case CPU_DEAD:
@@ -825,6 +813,16 @@
 			continue;
 		}
 
+		key = "qcom,init-value";
+		ret = of_property_read_u32(node, key,
+				&rs->rs_data.default_value);
+		if (ret) {
+			pr_err("%s():Failed to read %s\n", __func__, key);
+			goto fail;
+		}
+
+		rs->rs_data.value = rs->rs_data.default_value;
+
 		key = "qcom,resource-type";
 		ret = of_property_read_u32(node, key, &resource_type);
 		if (ret) {
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-buspm-dev.c b/arch/arm/mach-msm/msm-buspm-dev.c
index a818eed..ec0f1bd 100644
--- a/arch/arm/mach-msm/msm-buspm-dev.c
+++ b/arch/arm/mach-msm/msm-buspm-dev.c
@@ -22,10 +22,17 @@
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
 #include <linux/memory_alloc.h>
+#include <mach/rpm-smd.h>
 #include "msm-buspm-dev.h"
 
 #define MSM_BUSPM_DRV_NAME "msm-buspm-dev"
 
+enum msm_buspm_spdm_res {
+	SPDM_RES_ID = 0,
+	SPDM_RES_TYPE = 0x63707362,
+	SPDM_KEY = 0x00006e65,
+	SPDM_SIZE = 4,
+};
 /*
  * Allocate kernel buffer.
  * Currently limited to one buffer per file descriptor.  If alloc() is
@@ -113,6 +120,61 @@
 	return 0;
 }
 
+static int msm_bus_rpm_req(u32 rsc_type, u32 key, u32 hwid,
+	int ctx, u32 val)
+{
+	struct msm_rpm_request *rpm_req;
+	int ret, msg_id;
+
+	rpm_req = msm_rpm_create_request(ctx, rsc_type, SPDM_RES_ID, 1);
+	if (rpm_req == NULL) {
+		pr_err("RPM: Couldn't create RPM Request\n");
+		return -ENXIO;
+	}
+
+	ret = msm_rpm_add_kvp_data(rpm_req, key, (const uint8_t *)&val,
+		(int)(sizeof(uint32_t)));
+	if (ret) {
+		pr_err("RPM: Add KVP failed for RPM Req:%u\n",
+			rsc_type);
+		goto err;
+	}
+
+	pr_debug("Added Key: %d, Val: %u, size: %d\n", key,
+		(uint32_t)val, sizeof(uint32_t));
+	msg_id = msm_rpm_send_request(rpm_req);
+	if (!msg_id) {
+		pr_err("RPM: No message ID for req\n");
+		ret = -ENXIO;
+		goto err;
+	}
+
+	ret = msm_rpm_wait_for_ack(msg_id);
+	if (ret) {
+		pr_err("RPM: Ack failed\n");
+		goto err;
+	}
+
+err:
+	msm_rpm_free_request(rpm_req);
+	return ret;
+}
+
+static int msm_buspm_ioc_cmds(uint32_t arg)
+{
+	switch (arg) {
+	case MSM_BUSPM_SPDM_CLK_DIS:
+	case MSM_BUSPM_SPDM_CLK_EN:
+		return msm_bus_rpm_req(SPDM_RES_TYPE, SPDM_KEY, 0,
+				MSM_RPM_CTX_ACTIVE_SET, arg);
+	default:
+		pr_warn("Unsupported ioctl command: %d\n", arg);
+		return -EINVAL;
+	}
+}
+
+
+
 static long
 msm_buspm_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
@@ -124,6 +186,11 @@
 	unsigned int buflen = msm_buspm_dev_get_buflen(filp);
 	unsigned char *dbgbuf = buf;
 
+	if (_IOC_TYPE(cmd) != MSM_BUSPM_IOC_MAGIC) {
+		pr_err("Wrong IOC_MAGIC.Exiting\n");
+		return -ENOTTY;
+	}
+
 	switch (cmd) {
 	case MSM_BUSPM_IOC_FREE:
 		pr_debug("cmd = 0x%x (FREE)\n", cmd);
@@ -193,6 +260,11 @@
 		}
 		break;
 
+	case MSM_BUSPM_IOC_CMD:
+		pr_debug("IOCTL command: cmd: %d arg: %lu\n", cmd, arg);
+		retval = msm_buspm_ioc_cmds(arg);
+		break;
+
 	default:
 		pr_debug("Unknown command 0x%x\n", cmd);
 		retval = -EINVAL;
diff --git a/arch/arm/mach-msm/msm-buspm-dev.h b/arch/arm/mach-msm/msm-buspm-dev.h
index 5839087..854626d 100644
--- a/arch/arm/mach-msm/msm-buspm-dev.h
+++ b/arch/arm/mach-msm/msm-buspm-dev.h
@@ -31,6 +31,11 @@
 	int size;
 };
 
+enum msm_buspm_ioc_cmds {
+	MSM_BUSPM_SPDM_CLK_DIS = 0,
+	MSM_BUSPM_SPDM_CLK_EN,
+};
+
 #define MSM_BUSPM_IOC_MAGIC	'p'
 
 #define MSM_BUSPM_IOC_FREE	\
@@ -47,4 +52,7 @@
 
 #define MSM_BUSPM_IOC_RD_PHYS_ADDR	\
 	_IOR(MSM_BUSPM_IOC_MAGIC, 4, unsigned long)
+
+#define MSM_BUSPM_IOC_CMD	\
+	_IOR(MSM_BUSPM_IOC_MAGIC, 5, uint32_t)
 #endif
diff --git a/arch/arm/mach-msm/msm7k_fiq.c b/arch/arm/mach-msm/msm7k_fiq.c
index 421b4f9..d644121 100644
--- a/arch/arm/mach-msm/msm7k_fiq.c
+++ b/arch/arm/mach-msm/msm7k_fiq.c
@@ -75,7 +75,7 @@
 
 static int __init init7k_fiq(void)
 {
-	if (!cpu_is_msm8625())
+	if (!cpu_is_msm8625() && !cpu_is_msm8625q())
 		return 0;
 
 	if (msm_setup_fiq_handler())
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 65539c6..e61eb6d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -614,6 +614,15 @@
 			MSM_BUS_DBG("ab: %llu ib: %llu\n", curr_bw, curr_clk);
 		}
 
+		if (index == 0) {
+			/* This check protects the bus driver from clients
+			 * that can leave non-zero requests after
+			 * unregistering.
+			 * */
+			req_clk = 0;
+			req_bw = 0;
+		}
+
 		if (!pdata->active_only) {
 			ret = update_path(src, pnode, req_clk, req_bw,
 				curr_clk, curr_bw, 0, pdata->active_only);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 70bb406..d079e77 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -447,10 +447,8 @@
 static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
 static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
 static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
-static int pro_mport_graphics_3d[] = {
-	MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT0,
-	MSM_BUS_MASTER_PORT_GRAPHICS_3D,
-};
+static int pro_mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT0,};
+static int pro_mport_graphics_3d_p1[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
 static int mport_jpeg_dec[] = {MSM_BUS_MASTER_PORT_JPEG_DEC,};
 static int mport_graphics_2d_core0[] = {MSM_BUS_MASTER_PORT_GRAPHICS_2D_CORE0,};
 static int mport_vfe[] = {MSM_BUS_MASTER_PORT_VFE,};
@@ -627,6 +625,13 @@
 		.num_tiers = ARRAY_SIZE(tier2),
 	},
 	{
+		.id = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.masterp = pro_mport_graphics_3d_p1,
+		.num_mports = ARRAY_SIZE(pro_mport_graphics_3d_p1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
 		.id = MSM_BUS_MASTER_JPEG_DEC,
 		.masterp = mport_jpeg_dec,
 		.num_mports = ARRAY_SIZE(mport_jpeg_dec),
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_cpr.c b/arch/arm/mach-msm/msm_cpr.c
index c7a8b98..dd6ffab 100644
--- a/arch/arm/mach-msm/msm_cpr.c
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -91,7 +91,7 @@
 	struct regulator *vreg_cx;
 	const struct msm_cpr_config *config;
 	struct notifier_block freq_transition;
-	struct msm_cpr_vp_data *vp;
+	uint32_t step_size;
 };
 
 /* Need to maintain state data for suspend and resume APIs */
@@ -219,7 +219,7 @@
 	 *
 	 */
 	level_uV = chip_data->turbo_Vmax -
-		(chip_data->tgt_volt_offset * cpr->vp->step_size);
+		(chip_data->tgt_volt_offset * cpr->step_size);
 	msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
 		"tgt_volt_uV = %d\n", level_uV);
 
@@ -260,7 +260,7 @@
 	quot1 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
 
 	/* Take second CPR measurement at a lower voltage to get QUOT2 */
-	level_uV -= 4 * cpr->vp->step_size;
+	level_uV -= 4 * cpr->step_size;
 	msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
 		"tgt_volt_uV = %d\n", level_uV);
 
@@ -493,7 +493,7 @@
 		error_step += 1;
 
 		/* Calculte new PMIC voltage */
-		new_volt = curr_volt + (error_step * cpr->vp->step_size);
+		new_volt = curr_volt + (error_step * cpr->step_size);
 		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
 			"UP_INT: new_volt: %d, error_step=%d\n",
 					new_volt, error_step);
@@ -531,7 +531,7 @@
 			error_step = 2;
 
 		/* Calculte new PMIC voltage */
-		new_volt = curr_volt - (error_step * cpr->vp->step_size);
+		new_volt = curr_volt - (error_step * cpr->step_size);
 		msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
 			"DOWN_INT: new_volt: %d, error_step=%d\n",
 			new_volt, error_step);
@@ -953,7 +953,7 @@
 
 	cpr->base = base;
 
-	cpr->vp = pdata->vp_data;
+	cpr->step_size = pdata->step_size;
 
 	spin_lock_init(&cpr->cpr_lock);
 
diff --git a/arch/arm/mach-msm/msm_cpr.h b/arch/arm/mach-msm/msm_cpr.h
index 3d10478..d9c8e9b 100644
--- a/arch/arm/mach-msm/msm_cpr.h
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -122,20 +122,6 @@
 };
 
 /**
- * struct msm_vp_data - structure for VP configuration
- * @min_volt: minimum microvolt level for VP
- * @max_volt: maximum microvolt level for VP
- * @default_volt: default microvolt for VP
- * @step_size: step size of voltage in microvolt
- */
-struct msm_cpr_vp_data {
-	int min_volt;
-	int max_volt;
-	int default_volt;
-	int step_size;
-};
-
-/**
  * struct msm_cpr_osc -  Data for CPR ring oscillator
  * @gcnt: gate count value for the oscillator
  * @quot: target value for ring oscillator
@@ -189,7 +175,7 @@
 	uint32_t max_freq;
 	uint32_t max_quot;
 	bool disable_cpr;
-	struct msm_cpr_vp_data *vp_data;
+	uint32_t step_size;
 	uint32_t (*get_quot)(uint32_t max_quot, uint32_t max_freq,
 				uint32_t new_freq);
 	void (*clk_enable)(void);
diff --git a/arch/arm/mach-msm/msm_cpu_pwrctl.c b/arch/arm/mach-msm/msm_cpu_pwrctl.c
new file mode 100644
index 0000000..6e339dd
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpu_pwrctl.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/compiler.h>
+#include <linux/notifier.h>
+#include <linux/percpu.h>
+#include <linux/workqueue.h>
+
+#define MSM_CPU_SECONDARY_CORE_OFFSET	0x10000
+
+static const phys_addr_t primary_cpu_pwrctl_phys = 0x2088004;
+static DEFINE_PER_CPU(int, pll_clamp_set);
+static void msm_cpu_pwrctl_work_cb(struct work_struct *work);
+static __cpuinitdata DECLARE_WORK(msm_cpu_pwrctl_work, msm_cpu_pwrctl_work_cb);
+static int nr_cpus_done;
+static int __cpuinit msm_cpu_pwrctl_cpu_callback(struct notifier_block *nfb,
+				    unsigned long action, void *hcpu);
+static struct notifier_block __cpuinitdata msm_cpu_pwrctl_cpu_notifier = {
+	.notifier_call = msm_cpu_pwrctl_cpu_callback,
+};
+
+static void __cpuinit msm_cpu_pwrctl_work_cb(struct work_struct *work)
+{
+	unregister_hotcpu_notifier(&msm_cpu_pwrctl_cpu_notifier);
+}
+
+static int __cpuinit msm_cpu_pwrctl_cpu_callback(struct notifier_block *nfb,
+				    unsigned long action, void *hcpu)
+{
+	int cpu = (int) hcpu;
+	int *pll_clamp;
+	void *pwrctl_ptr;
+	unsigned int value;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_ONLINE:
+		pll_clamp = &per_cpu(pll_clamp_set, cpu);
+		if (likely(*pll_clamp))
+			goto done;
+
+		pwrctl_ptr = ioremap_nocache(primary_cpu_pwrctl_phys +
+			(cpu * MSM_CPU_SECONDARY_CORE_OFFSET), SZ_4K);
+		if (unlikely(!pwrctl_ptr))
+			goto done;
+
+		value = readl_relaxed(pwrctl_ptr);
+		value |= 0x100;
+		writel_relaxed(value, pwrctl_ptr);
+		*pll_clamp = 1;
+		iounmap(pwrctl_ptr);
+
+		if (++nr_cpus_done == cpumask_weight(cpu_possible_mask))
+			schedule_work(&msm_cpu_pwrctl_work);
+done:
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+
+}
+
+static int __init msm_cpu_pwrctl_init(void)
+{
+	int cpu = smp_processor_id();
+
+	/* We won't get cpu online notification for this CPU,
+	 * so take this opportunity to process this CPU.
+	 */
+	msm_cpu_pwrctl_cpu_callback(&msm_cpu_pwrctl_cpu_notifier,
+					CPU_ONLINE, (void *) cpu);
+
+	register_hotcpu_notifier(&msm_cpu_pwrctl_cpu_notifier);
+	return 0;
+}
+
+early_initcall(msm_cpu_pwrctl_init);
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 41afd24..9e0be63 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -49,7 +49,7 @@
 	struct kobj_attribute slack_time_min_us;
 	struct kobj_attribute slack_time_max_us;
 	struct kobj_attribute slack_weight_thresh_pct;
-	struct kobj_attribute ss_iobusy_conv;
+	struct kobj_attribute ss_no_corr_below_freq;
 	struct kobj_attribute ss_win_size_min_us;
 	struct kobj_attribute ss_win_size_max_us;
 	struct kobj_attribute ss_util_pct;
@@ -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;
 };
@@ -150,6 +151,7 @@
 static unsigned num_cpu_freqs;
 static struct msm_dcvs_platform_data *dcvs_pdata;
 
+static DEFINE_MUTEX(param_update_mutex);
 static DEFINE_MUTEX(gpu_floor_mutex);
 
 static void force_stop_slack_timer(struct dcvs_core *core)
@@ -295,14 +297,33 @@
 			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);
 }
 
+static void check_power_collapse_modes(struct dcvs_core *core)
+{
+	struct msm_dcvs_algo_param *params;
+
+	params = &core_list[CPU_OFFSET + num_online_cpus() - 1].algo_param;
+
+	if (core->actual_freq >= params->disable_pc_threshold)
+		core->idle_enable(core->type_core_num,
+				  MSM_DCVS_DISABLE_HIGH_LATENCY_MODES);
+	else
+		core->idle_enable(core->type_core_num,
+				  MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
+}
+
 static int __msm_dcvs_change_freq(struct dcvs_core *core)
 {
 	int ret = 0;
@@ -349,16 +370,11 @@
 	core->freq_change_us = (uint32_t)ktime_to_us(
 					ktime_sub(ktime_get(), time_start));
 
-	/**
-	 * Disable low power modes if the actual frequency is >
-	 * disable_pc_threshold.
-	 */
-	if (core->actual_freq > core->algo_param.disable_pc_threshold) {
-		core->idle_enable(core->type_core_num,
-				MSM_DCVS_DISABLE_HIGH_LATENCY_MODES);
-	} else if (core->actual_freq <= core->algo_param.disable_pc_threshold) {
-		core->idle_enable(core->type_core_num,
-				MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
+	if (core->type == MSM_DCVS_CORE_TYPE_CPU &&
+	    core->type_core_num == 0) {
+		mutex_lock(&param_update_mutex);
+		check_power_collapse_modes(core);
+		mutex_unlock(&param_update_mutex);
 	}
 
 	/**
@@ -550,7 +566,6 @@
 int msm_dcvs_update_algo_params(void)
 {
 	static struct msm_dcvs_algo_param curr_params;
-	static DEFINE_MUTEX(param_update_mutex);
 	struct msm_dcvs_algo_param *new_params;
 	int cpu, ret = 0;
 
@@ -560,6 +575,7 @@
 	if (memcmp(&curr_params, new_params,
 		   sizeof(struct msm_dcvs_algo_param))) {
 		for_each_possible_cpu(cpu) {
+			struct dcvs_core *core = &core_list[CPU_OFFSET + cpu];
 			ret = msm_dcvs_scm_set_algo_params(CPU_OFFSET + cpu,
 							   new_params);
 			if (ret) {
@@ -568,6 +584,8 @@
 				mutex_unlock(&param_update_mutex);
 				return ret;
 			}
+			if (cpu == 0)
+				check_power_collapse_modes(core);
 		}
 		memcpy(&curr_params, new_params,
 		       sizeof(struct msm_dcvs_algo_param));
@@ -700,7 +718,7 @@
 DCVS_ALGO_PARAM(slack_time_min_us)
 DCVS_ALGO_PARAM(slack_time_max_us)
 DCVS_ALGO_PARAM(slack_weight_thresh_pct)
-DCVS_ALGO_PARAM(ss_iobusy_conv)
+DCVS_ALGO_PARAM(ss_no_corr_below_freq)
 DCVS_ALGO_PARAM(ss_win_size_min_us)
 DCVS_ALGO_PARAM(ss_win_size_max_us)
 DCVS_ALGO_PARAM(ss_util_pct)
@@ -715,6 +733,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 +880,7 @@
 {
 	int ret = 0;
 	struct kobject *core_kobj = NULL;
-	const int attr_count = 25;
+	const int attr_count = 26;
 
 	BUG_ON(!cores_kobj);
 
@@ -815,7 +904,7 @@
 	DCVS_RW_ATTRIB(8, slack_weight_thresh_pct);
 	DCVS_RW_ATTRIB(9, slack_time_min_us);
 	DCVS_RW_ATTRIB(10, slack_time_max_us);
-	DCVS_RW_ATTRIB(11, ss_iobusy_conv);
+	DCVS_RW_ATTRIB(11, ss_no_corr_below_freq);
 	DCVS_RW_ATTRIB(12, ss_win_size_min_us);
 	DCVS_RW_ATTRIB(13, ss_win_size_max_us);
 	DCVS_RW_ATTRIB(14, ss_util_pct);
@@ -830,8 +919,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 +1009,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 +1044,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/msm_mpdecision.c b/arch/arm/mach-msm/msm_mpdecision.c
index 94b546a..746bbe8 100644
--- a/arch/arm/mach-msm/msm_mpdecision.c
+++ b/arch/arm/mach-msm/msm_mpdecision.c
@@ -41,12 +41,14 @@
 #include <trace/events/mpdcvs_trace.h>
 
 #define DEFAULT_RQ_AVG_POLL_MS    (1)
+#define DEFAULT_RQ_AVG_DIVIDE    (25)
 
 struct mpd_attrib {
 	struct kobj_attribute	enabled;
 	struct kobj_attribute	rq_avg_poll_ms;
-	struct kobj_attribute iowait_threshold_pct;
+	struct kobj_attribute	iowait_threshold_pct;
 
+	struct kobj_attribute	rq_avg_divide;
 	struct kobj_attribute	em_win_size_min_us;
 	struct kobj_attribute	em_win_size_max_us;
 	struct kobj_attribute	em_max_util_pct;
@@ -75,6 +77,7 @@
 	atomic_t			algo_cpu_mask;
 	uint32_t			rq_avg_poll_ms;
 	uint32_t			iowait_threshold_pct;
+	uint32_t			rq_avg_divide;
 	ktime_t				next_update;
 	uint32_t			slack_us;
 	struct msm_mpd_algo_param	mp_param;
@@ -125,20 +128,19 @@
 static int num_present_hundreds;
 static ktime_t last_down_time;
 
-#define RQ_AVG_INSIGNIFICANT_BITS	3
 static bool ok_to_update_tz(int nr, int last_nr)
 {
 	/*
 	 * Exclude unnecessary TZ reports if run queue haven't changed much from
-	 * the last reported value. The left shift by INSIGNIFICANT_BITS is to
+	 * the last reported value. The divison by rq_avg_divide is to
 	 * filter out small changes in the run queue average which won't cause
 	 * a online cpu mask change. Also if the cpu online count does not match
 	 * the count requested by TZ and we are not in the process of bringing
 	 * cpus online as indicated by a HPUPDATE_IN_PROGRESS in msm_mpd.hpdata
 	 */
 	return
-	(((nr >> RQ_AVG_INSIGNIFICANT_BITS)
-				!= (last_nr >> RQ_AVG_INSIGNIFICANT_BITS))
+	(((nr / msm_mpd.rq_avg_divide)
+				!= (last_nr / msm_mpd.rq_avg_divide))
 	|| ((hweight32(atomic_read(&msm_mpd.algo_cpu_mask))
 				!= num_online_cpus())
 		&& (msm_mpd.hpupdate != HPUPDATE_IN_PROGRESS)));
@@ -360,6 +362,7 @@
 	int cpu;
 
 	while (1) {
+		msm_dcvs_update_algo_params();
 		wait_event(msm_mpd.wait_hpq, *event || kthread_should_stop());
 		if (kthread_should_stop())
 			break;
@@ -392,7 +395,6 @@
 				}
 		msm_mpd.hpupdate = HPUPDATE_WAITING;
 		msm_dcvs_apply_gpu_floor(0);
-		msm_dcvs_update_algo_params();
 	}
 
 	return 0;
@@ -509,6 +511,20 @@
 	return 0;
 }
 
+static int msm_mpd_set_rq_avg_divide(uint32_t val)
+{
+	/*
+	 * No need to do anything. New value will be used next time
+	 * the decision is made as to whether to update tz.
+	 */
+
+	if (val == 0)
+		return -EINVAL;
+
+	msm_mpd.rq_avg_divide = val;
+	return 0;
+}
+
 #define MPD_ALGO_PARAM(_name, _param) \
 static ssize_t msm_mpd_attr_##_name##_show(struct kobject *kobj, \
 			struct kobj_attribute *attr, char *buf) \
@@ -580,6 +596,7 @@
 MPD_PARAM(enabled, msm_mpd.enabled);
 MPD_PARAM(rq_avg_poll_ms, msm_mpd.rq_avg_poll_ms);
 MPD_PARAM(iowait_threshold_pct, msm_mpd.iowait_threshold_pct);
+MPD_PARAM(rq_avg_divide, msm_mpd.rq_avg_divide);
 MPD_ALGO_PARAM(em_win_size_min_us, msm_mpd.mp_param.em_win_size_min_us);
 MPD_ALGO_PARAM(em_win_size_max_us, msm_mpd.mp_param.em_win_size_max_us);
 MPD_ALGO_PARAM(em_max_util_pct, msm_mpd.mp_param.em_max_util_pct);
@@ -602,7 +619,7 @@
 {
 	struct kobject *module_kobj = NULL;
 	int ret = 0;
-	const int attr_count = 19;
+	const int attr_count = 20;
 	struct msm_mpd_algo_param *param = NULL;
 
 	param = pdev->dev.platform_data;
@@ -624,28 +641,30 @@
 	MPD_RW_ATTRIB(0, enabled);
 	MPD_RW_ATTRIB(1, rq_avg_poll_ms);
 	MPD_RW_ATTRIB(2, iowait_threshold_pct);
-	MPD_RW_ATTRIB(3, em_win_size_min_us);
-	MPD_RW_ATTRIB(4, em_win_size_max_us);
-	MPD_RW_ATTRIB(5, em_max_util_pct);
-	MPD_RW_ATTRIB(6, mp_em_rounding_point_min);
-	MPD_RW_ATTRIB(7, mp_em_rounding_point_max);
-	MPD_RW_ATTRIB(8, online_util_pct_min);
-	MPD_RW_ATTRIB(9, online_util_pct_max);
-	MPD_RW_ATTRIB(10, slack_time_min_us);
-	MPD_RW_ATTRIB(11, slack_time_max_us);
-	MPD_RW_ATTRIB(12, hp_up_max_ms);
-	MPD_RW_ATTRIB(13, hp_up_ms);
-	MPD_RW_ATTRIB(14, hp_up_count);
-	MPD_RW_ATTRIB(15, hp_dw_max_ms);
-	MPD_RW_ATTRIB(16, hp_dw_ms);
-	MPD_RW_ATTRIB(17, hp_dw_count);
+	MPD_RW_ATTRIB(3, rq_avg_divide);
+	MPD_RW_ATTRIB(4, em_win_size_min_us);
+	MPD_RW_ATTRIB(5, em_win_size_max_us);
+	MPD_RW_ATTRIB(6, em_max_util_pct);
+	MPD_RW_ATTRIB(7, mp_em_rounding_point_min);
+	MPD_RW_ATTRIB(8, mp_em_rounding_point_max);
+	MPD_RW_ATTRIB(9, online_util_pct_min);
+	MPD_RW_ATTRIB(10, online_util_pct_max);
+	MPD_RW_ATTRIB(11, slack_time_min_us);
+	MPD_RW_ATTRIB(12, slack_time_max_us);
+	MPD_RW_ATTRIB(13, hp_up_max_ms);
+	MPD_RW_ATTRIB(14, hp_up_ms);
+	MPD_RW_ATTRIB(15, hp_up_count);
+	MPD_RW_ATTRIB(16, hp_dw_max_ms);
+	MPD_RW_ATTRIB(17, hp_dw_ms);
+	MPD_RW_ATTRIB(18, hp_dw_count);
 
-	msm_mpd.attrib.attrib_group.attrs[18] = NULL;
+	msm_mpd.attrib.attrib_group.attrs[19] = NULL;
 	ret = sysfs_create_group(module_kobj, &msm_mpd.attrib.attrib_group);
 	if (ret)
 		pr_err("Unable to create sysfs objects :%d\n", ret);
 
 	msm_mpd.rq_avg_poll_ms = DEFAULT_RQ_AVG_POLL_MS;
+	msm_mpd.rq_avg_divide = DEFAULT_RQ_AVG_DIVIDE;
 
 	memcpy(&msm_mpd.mp_param, param, sizeof(struct msm_mpd_algo_param));
 
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 818a20a..8962729 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -191,6 +191,7 @@
 	int table_end = 0;
 	int br_ctrl = 0;
 	int br_id = 0;
+	int client_id = 0;
 	int dm_ctrl = 0;
 	int i = 0;
 	int j = 0;
@@ -244,6 +245,8 @@
 	dm_ctrl |= (table_start << DM_TBL_START);
 	dm_ctrl |= (table_end << DM_TBL_END);
 
+	client_id = client_ctrl_id(id);
+	dm_ctrl |= (client_id << DM_CLIENT_SHIFT);
 	dm_ctrl |= (DM_BR_ID_LPASS << DM_BR_ID_SHIFT);
 	dm_ctrl |= (DM_BLOCK_256 << DM_BR_BLK_SHIFT);
 	dm_ctrl |= (direction << DM_DIR_SHIFT);
diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
index 103eef0..26c5e58 100644
--- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
@@ -72,9 +72,11 @@
  */
 struct pmu_constraints {
 	u64 pmu_bitmap;
+	u8 codes[64];
 	raw_spinlock_t lock;
 } l2_pmu_constraints = {
 	.pmu_bitmap = 0,
+	.codes = {-1},
 	.lock = __RAW_SPIN_LOCK_UNLOCKED(l2_pmu_constraints.lock),
 };
 
@@ -335,8 +337,10 @@
 	int ctr = 0;
 
 	if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
-		if (!test_and_set_bit(l2_cycle_ctr_idx, cpuc->used_mask))
-			return l2_cycle_ctr_idx;
+		if (test_and_set_bit(l2_cycle_ctr_idx, cpuc->used_mask))
+			return -EAGAIN;
+
+		return l2_cycle_ctr_idx;
 	}
 
 	for (ctr = 0; ctr < total_l2_ctrs - 1; ctr++) {
@@ -453,22 +457,48 @@
 {
 	u32 evt_type = event->attr.config & L2_EVT_MASK;
 	u8 reg   = (evt_type & 0x0F000) >> 12;
-	u8 group =  evt_type & 0x0000F;
+	u8 group = evt_type & 0x0000F;
+	u8 code = (evt_type & 0x00FF0) >> 4;
 	unsigned long flags;
 	u32 err = 0;
 	u64 bitmap_t;
+	u32 shift_idx;
+
+	/*
+	 * Cycle counter collision is detected in
+	 * get_event_idx().
+	 */
+	if (evt_type == L2CYCLE_CTR_RAW_CODE)
+		return err;
 
 	raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags);
 
-	bitmap_t = 1 << ((reg * 4) + group);
+	shift_idx = ((reg * 4) + group);
+
+	bitmap_t = 1 << shift_idx;
 
 	if (!(l2_pmu_constraints.pmu_bitmap & bitmap_t)) {
 		l2_pmu_constraints.pmu_bitmap |= bitmap_t;
+		l2_pmu_constraints.codes[shift_idx] = code;
 		goto out;
+	} else {
+		/*
+		 * If NRCCG's are identical,
+		 * its not column exclusion.
+		 */
+		if (l2_pmu_constraints.codes[shift_idx] != code)
+			err = -EPERM;
+		else
+			/*
+			 * If the event is counted in syswide mode
+			 * then we want to count only on one CPU
+			 * and set its filter to count from all.
+			 * This sets the event OFF on all but one
+			 * CPU.
+			 */
+			if (!(event->cpu < 0))
+				event->state = PERF_EVENT_STATE_OFF;
 	}
-
-	/* Bit is already set. Constraint failed. */
-	err = -EPERM;
 out:
 	raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags);
 	return err;
@@ -481,14 +511,20 @@
 	u8 group =  evt_type & 0x0000F;
 	unsigned long flags;
 	u64 bitmap_t;
+	u32 shift_idx;
 
 	raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags);
 
-	bitmap_t = 1 << ((reg * 4) + group);
+	shift_idx = ((reg * 4) + group);
+
+	bitmap_t = 1 << shift_idx;
 
 	/* Clear constraint bit. */
 	l2_pmu_constraints.pmu_bitmap &= ~bitmap_t;
 
+	/* Clear code. */
+	l2_pmu_constraints.codes[shift_idx] = -1;
+
 	raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags);
 	return 1;
 }
diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c
index 2ad36df..c1b7d23 100644
--- a/arch/arm/mach-msm/perf_event_msm_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_l2.c
@@ -38,9 +38,11 @@
  */
 struct pmu_constraints {
 	u64 pmu_bitmap;
+	u8 codes[64];
 	raw_spinlock_t lock;
 } l2_pmu_constraints = {
 	.pmu_bitmap = 0,
+	.codes = {-1},
 	.lock = __RAW_SPIN_LOCK_UNLOCKED(l2_pmu_constraints.lock),
 };
 
@@ -667,9 +669,11 @@
 	int ctr = 0;
 
 	if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE) {
-		if (!test_and_set_bit(l2_cycle_ctr_idx,
+		if (test_and_set_bit(l2_cycle_ctr_idx,
 					cpuc->used_mask))
-			return l2_cycle_ctr_idx;
+			return -EAGAIN;
+
+		return l2_cycle_ctr_idx;
 	}
 
 	for (ctr = 0; ctr < total_l2_ctrs - 1; ctr++) {
@@ -792,25 +796,50 @@
 	u8 prefix = (evt_type & 0xF0000) >> 16;
 	u8 reg   = (evt_type & 0x0F000) >> 12;
 	u8 group =  evt_type & 0x0000F;
+	u8 code = (evt_type & 0x00FF0) >> 4;
 	unsigned long flags;
 	u32 err = 0;
 	u64 bitmap_t;
+	u32 shift_idx;
 
 	if (!prefix)
 		return 0;
+	/*
+	 * Cycle counter collision is detected in
+	 * get_event_idx().
+	 */
+	if (evt_type == SCORPION_L2CYCLE_CTR_RAW_CODE)
+		return err;
 
 	raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags);
 
-	bitmap_t = 1 << ((reg * 4) + group);
+	shift_idx = ((reg * 4) + group);
+
+	bitmap_t = 1 << shift_idx;
 
 	if (!(l2_pmu_constraints.pmu_bitmap & bitmap_t)) {
 		l2_pmu_constraints.pmu_bitmap |= bitmap_t;
+		l2_pmu_constraints.codes[shift_idx] = code;
 		goto out;
+	} else {
+		/*
+		 * If NRCCG's are identical,
+		 * its not column exclusion.
+		 */
+		if (l2_pmu_constraints.codes[shift_idx] != code)
+			err = -EPERM;
+		else
+			/*
+			 * If the event is counted in syswide mode
+			 * then we want to count only on one CPU
+			 * and set its filter to count from all.
+			 * This sets the event OFF on all but one
+			 * CPU.
+			 */
+			if (!(event->cpu < 0))
+				event->state = PERF_EVENT_STATE_OFF;
 	}
 
-	/* Bit is already set. Constraint failed. */
-	err = -EPERM;
-
 out:
 	raw_spin_unlock_irqrestore(&l2_pmu_constraints.lock, flags);
 	return err;
@@ -824,13 +853,16 @@
 	u8 group =  evt_type & 0x0000F;
 	unsigned long flags;
 	u64 bitmap_t;
+	u32 shift_idx;
 
 	if (!prefix)
 		return 0;
 
 	raw_spin_lock_irqsave(&l2_pmu_constraints.lock, flags);
 
-	bitmap_t = 1 << ((reg * 4) + group);
+	shift_idx = ((reg * 4) + group);
+
+	bitmap_t = 1 << shift_idx;
 
 	/* Clear constraint bit. */
 	l2_pmu_constraints.pmu_bitmap &= ~bitmap_t;
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 65e05a9..88aae81 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -28,17 +28,24 @@
 #include <linux/msm_ion.h>
 #include <linux/list.h>
 #include <linux/list_sort.h>
+#include <linux/idr.h>
 
 #include <asm/uaccess.h>
 #include <asm/setup.h>
+#include <asm-generic/io-64-nonatomic-lo-hi.h>
+
+#include <mach/msm_iomap.h>
 
 #include "peripheral-loader.h"
+#include "ramdump.h"
 
 #define pil_err(desc, fmt, ...)						\
 	dev_err(desc->dev, "%s: " fmt, desc->name, ##__VA_ARGS__)
 #define pil_info(desc, fmt, ...)					\
 	dev_info(desc->dev, "%s: " fmt, desc->name, ##__VA_ARGS__)
 
+#define PIL_IMAGE_INFO_BASE	(MSM_IMEM_BASE + 0x94c)
+
 /**
  * proxy_timeout - Override for proxy vote timeouts
  * -1: Use driver-specified timeout
@@ -80,6 +87,18 @@
 };
 
 /**
+ * struct pil_image_info - information in IMEM about image and where it is loaded
+ * @name: name of image (may or may not be NULL terminated)
+ * @start: indicates physical address where image starts (little endian)
+ * @size: size of image (little endian)
+ */
+struct pil_image_info {
+	char name[8];
+	__le64 start;
+	__le32 size;
+} __attribute__((__packed__));
+
+/**
  * struct pil_priv - Private state for a pil_desc
  * @proxy: work item used to run the proxy unvoting routine
  * @wlock: wakelock to prevent suspend during pil_boot
@@ -110,8 +129,46 @@
 	phys_addr_t region_start;
 	phys_addr_t region_end;
 	struct ion_handle *region;
+	struct pil_image_info __iomem *info;
+	int id;
 };
 
+/**
+ * pil_do_ramdump() - Ramdump an image
+ * @desc: descriptor from pil_desc_init()
+ * @ramdump_dev: ramdump device returned from create_ramdump_device()
+ *
+ * Calls the ramdump API with a list of segments generated from the addresses
+ * that the descriptor corresponds to.
+ */
+int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev)
+{
+	struct pil_priv *priv = desc->priv;
+	struct pil_seg *seg;
+	int count = 0, ret;
+	struct ramdump_segment *ramdump_segs, *s;
+
+	list_for_each_entry(seg, &priv->segs, list)
+		count++;
+
+	ramdump_segs = kmalloc_array(count, sizeof(*ramdump_segs), GFP_KERNEL);
+	if (!ramdump_segs)
+		return -ENOMEM;
+
+	s = ramdump_segs;
+	list_for_each_entry(seg, &priv->segs, list) {
+		s->address = seg->paddr;
+		s->size = seg->sz;
+		s++;
+	}
+
+	ret = do_elf_ramdump(ramdump_dev, ramdump_segs, count);
+	kfree(ramdump_segs);
+
+	return ret;
+}
+EXPORT_SYMBOL(pil_do_ramdump);
+
 static struct ion_client *ion;
 
 /**
@@ -337,6 +394,10 @@
 		priv->base_addr = min_addr_n;
 	}
 
+	writeq(priv->region_start, &priv->info->start);
+	writel_relaxed(priv->region_end - priv->region_start,
+			&priv->info->size);
+
 	return ret;
 }
 
@@ -380,8 +441,12 @@
 	struct pil_priv *priv = desc->priv;
 	struct pil_seg *p, *tmp;
 
+	writeq(0, &priv->info->start);
+	writel_relaxed(0, &priv->info->size);
+
 	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);
@@ -592,6 +657,8 @@
 }
 EXPORT_SYMBOL(pil_shutdown);
 
+static DEFINE_IDA(pil_ida);
+
 /**
  * pil_desc_init() - Initialize a pil descriptor
  * @desc: descriptor to intialize
@@ -604,6 +671,9 @@
 int pil_desc_init(struct pil_desc *desc)
 {
 	struct pil_priv *priv;
+	int id;
+	void __iomem *addr;
+	size_t len;
 
 	/* Ignore users who don't make any sense */
 	WARN(desc->ops->proxy_unvote && !desc->proxy_timeout,
@@ -618,6 +688,18 @@
 	desc->priv = priv;
 	priv->desc = desc;
 
+	priv->id = id = ida_simple_get(&pil_ida, 0, 10, GFP_KERNEL);
+	if (id < 0) {
+		kfree(priv);
+		return id;
+	}
+	addr = PIL_IMAGE_INFO_BASE + sizeof(struct pil_image_info) * id;
+	priv->info = (struct pil_image_info __iomem *)addr;
+
+	len = min(strlen(desc->name), sizeof(priv->info->name));
+	memset_io(priv->info->name, 0, sizeof(priv->info->name));
+	memcpy_toio(priv->info->name, desc->name, len);
+
 	snprintf(priv->wname, sizeof(priv->wname), "pil-%s", desc->name);
 	wake_lock_init(&priv->wlock, WAKE_LOCK_SUSPEND, priv->wname);
 	INIT_DELAYED_WORK(&priv->proxy, pil_proxy_work);
@@ -636,6 +718,7 @@
 	struct pil_priv *priv = desc->priv;
 
 	if (priv) {
+		ida_simple_remove(&pil_ida, priv->id);
 		flush_delayed_work(&priv->proxy);
 		wake_lock_destroy(&priv->wlock);
 	}
diff --git a/arch/arm/mach-msm/peripheral-loader.h b/arch/arm/mach-msm/peripheral-loader.h
index 1c2faf7..8442289 100644
--- a/arch/arm/mach-msm/peripheral-loader.h
+++ b/arch/arm/mach-msm/peripheral-loader.h
@@ -65,6 +65,7 @@
 extern void pil_shutdown(struct pil_desc *desc);
 extern void pil_desc_release(struct pil_desc *desc);
 extern phys_addr_t pil_get_entry_addr(struct pil_desc *desc);
+extern int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev);
 #else
 static inline int pil_desc_init(struct pil_desc *desc) { return 0; }
 static inline int pil_boot(struct pil_desc *desc) { return 0; }
@@ -74,6 +75,10 @@
 {
 	return 0;
 }
+static inline int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev)
+{
+	return 0;
+}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index 519e1c9..d315d82 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -48,7 +48,6 @@
 	void __iomem *ppss_base;
 
 	void *ramdump_dev;
-	struct ramdump_segment fw_ramdump_segments[4];
 
 	void *smem_ramdump_dev;
 	struct ramdump_segment smem_ramdump_segments[1];
@@ -212,16 +211,13 @@
 	if (!enable)
 		return 0;
 
-	ret = do_ramdump(drv->ramdump_dev,
-		drv->fw_ramdump_segments,
-		ARRAY_SIZE(drv->fw_ramdump_segments));
+	ret = pil_do_ramdump(&drv->desc, drv->ramdump_dev);
 	if (ret < 0) {
 		pr_err("%s: Unable to dump DSPS memory (rc = %d).\n",
 		       __func__, ret);
 		return ret;
 	}
-	ret = do_ramdump(drv->smem_ramdump_dev,
-		drv->smem_ramdump_segments,
+	ret = do_elf_ramdump(drv->smem_ramdump_dev, drv->smem_ramdump_segments,
 		ARRAY_SIZE(drv->smem_ramdump_segments));
 	if (ret < 0) {
 		pr_err("%s: Unable to dump smem memory (rc = %d).\n",
@@ -293,14 +289,6 @@
 	if (ret)
 		return ret;
 
-	drv->fw_ramdump_segments[0].address = 0x12000000;
-	drv->fw_ramdump_segments[0].size = 0x28000;
-	drv->fw_ramdump_segments[1].address = 0x12040000;
-	drv->fw_ramdump_segments[1].size = 0x4000;
-	drv->fw_ramdump_segments[2].address = 0x12800000;
-	drv->fw_ramdump_segments[2].size = 0x4000;
-	drv->fw_ramdump_segments[3].address = 0x8fe00000;
-	drv->fw_ramdump_segments[3].size = 0x100000;
 	drv->ramdump_dev = create_ramdump_device("dsps", &pdev->dev);
 	if (!drv->ramdump_dev) {
 		ret = -ENOMEM;
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index a6d13d0..f4d4449 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -404,11 +404,6 @@
 	smsm_reset_modem(SMSM_RESET);
 }
 
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment gss_segments[] = {
-	{0x89000000, 0x00D00000}
-};
-
 static struct ramdump_segment smem_segments[] = {
 	{0x80000000, 0x00200000},
 };
@@ -418,20 +413,20 @@
 	int ret;
 	struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
 
-	if (enable) {
-		ret = do_ramdump(drv->ramdump_dev, gss_segments,
-				ARRAY_SIZE(gss_segments));
-		if (ret < 0) {
-			pr_err("Unable to dump gss memory\n");
-			return ret;
-		}
+	if (!enable)
+		return 0;
 
-		ret = do_ramdump(drv->smem_ramdump_dev, smem_segments,
-			ARRAY_SIZE(smem_segments));
-		if (ret < 0) {
-			pr_err("Unable to dump smem memory (rc = %d).\n", ret);
-			return ret;
-		}
+	ret = pil_do_ramdump(&drv->pil_desc, drv->ramdump_dev);
+	if (ret < 0) {
+		pr_err("Unable to dump gss memory\n");
+		return ret;
+	}
+
+	ret = do_elf_ramdump(drv->smem_ramdump_dev, smem_segments,
+		ARRAY_SIZE(smem_segments));
+	if (ret < 0) {
+		pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+		return ret;
 	}
 
 	return 0;
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index d3c832b..3546705 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -393,21 +393,15 @@
 	return ret;
 }
 
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment modem_segments[] = {
-	{ 0x42F00000, 0x46000000 - 0x42F00000 },
-};
-
 static int modem_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	struct modem_data *drv;
 
 	drv = container_of(subsys, struct modem_data, subsys_desc);
-	if (enable)
-		return do_ramdump(drv->ramdump_dev, modem_segments,
-				ARRAY_SIZE(modem_segments));
-	else
+	if (!enable)
 		return 0;
+
+	return pil_do_ramdump(&drv->pil_desc, drv->ramdump_dev);
 }
 
 static int __devinit pil_modem_driver_probe(struct platform_device *pdev)
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 6e8d127..b457599 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)
@@ -361,19 +385,14 @@
 		smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
 }
 
-static struct ramdump_segment pronto_segments[] = {
-	{ 0x0D200000, 0x0D980000 - 0x0D200000 }
-};
-
 static int wcnss_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	struct pronto_data *drv = subsys_to_drv(subsys);
 
-	if (enable)
-		return do_ramdump(drv->ramdump_dev, pronto_segments,
-				ARRAY_SIZE(pronto_segments));
-	else
+	if (!enable)
 		return 0;
+
+	return pil_do_ramdump(&drv->desc, drv->ramdump_dev);
 }
 
 static int __devinit pil_pronto_probe(struct platform_device *pdev)
@@ -418,9 +437,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-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index d7e712c..1f53f17 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -279,22 +279,15 @@
 	return ret;
 }
 
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment q6_segments[] = {
-	{ 0x46700000, 0x47f00000 - 0x46700000 },
-	{ 0x28400000, 0x12800 }
-};
-
 static int lpass_q6_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	struct q6v3_data *drv;
 
 	drv = container_of(subsys, struct q6v3_data, subsys_desc);
-	if (enable)
-		return do_ramdump(drv->ramdump_dev, q6_segments,
-				ARRAY_SIZE(q6_segments));
-	else
+	if (!enable)
 		return 0;
+
+	return pil_do_ramdump(&drv->pil_desc, drv->ramdump_dev);
 }
 
 static void lpass_q6_crash_shutdown(const struct subsys_desc *subsys)
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
index 1e6c1f6..1387433 100644
--- a/arch/arm/mach-msm/pil-q6v4-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.c
@@ -231,18 +231,14 @@
 	return ret;
 }
 
-static struct ramdump_segment segments[] = {
-	{0x8da00000, 0x8f200000 - 0x8da00000},
-	{0x28400000, 0x20000}
-};
-
 static int lpass_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	struct lpass_q6v4 *drv = subsys_to_lpass(subsys);
 
 	if (!enable)
 		return 0;
-	return do_ramdump(drv->ramdump_dev, segments, ARRAY_SIZE(segments));
+
+	return pil_do_ramdump(&drv->q6.desc, drv->ramdump_dev);
 }
 
 static void lpass_crash_shutdown(const struct subsys_desc *subsys)
diff --git a/arch/arm/mach-msm/pil-q6v4-mss.c b/arch/arm/mach-msm/pil-q6v4-mss.c
index ee01f04..f2b090f 100644
--- a/arch/arm/mach-msm/pil-q6v4-mss.c
+++ b/arch/arm/mach-msm/pil-q6v4-mss.c
@@ -243,14 +243,6 @@
 	smsm_reset_modem(SMSM_RESET);
 }
 
-static struct ramdump_segment sw_segments[] = {
-	{0x89000000, 0x8D400000 - 0x89000000},
-};
-
-static struct ramdump_segment fw_segments[] = {
-	{0x8D400000, 0x8DA00000 - 0x8D400000},
-};
-
 static struct ramdump_segment smem_segments[] = {
 	{0x80000000, 0x00200000},
 };
@@ -263,17 +255,15 @@
 	if (!enable)
 		return 0;
 
-	ret = do_ramdump(drv->sw_ramdump_dev, sw_segments,
-		ARRAY_SIZE(sw_segments));
+	ret = pil_do_ramdump(&drv->q6_sw.desc, drv->sw_ramdump_dev);
 	if (ret < 0)
 		return ret;
 
-	ret = do_ramdump(drv->fw_ramdump_dev, fw_segments,
-		ARRAY_SIZE(fw_segments));
+	ret = pil_do_ramdump(&drv->q6_fw.desc, drv->fw_ramdump_dev);
 	if (ret < 0)
 		return ret;
 
-	ret = do_ramdump(drv->smem_ramdump_dev, smem_segments,
+	ret = do_elf_ramdump(drv->smem_ramdump_dev, smem_segments,
 		ARRAY_SIZE(smem_segments));
 	if (ret < 0)
 		return ret;
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 662377d..5e03aa8 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -195,15 +195,10 @@
 								void *ss_handle)
 {
 	int ret;
-	switch (code) {
-	case SUBSYS_BEFORE_SHUTDOWN:
-		pr_debug("%s: M-Notify: Shutdown started\n", __func__);
-		ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
-				SUBSYS_BEFORE_SHUTDOWN);
-		if (ret < 0)
-			pr_err("%s: sysmon_send_event error %d", __func__, ret);
-		break;
-	}
+	pr_debug("%s: M-Notify: event %lu\n", __func__, code);
+	ret = sysmon_send_event(SYSMON_SS_LPASS, "modem", code);
+	if (ret < 0)
+		pr_err("%s: sysmon_send_event error %d", __func__, ret);
 	return NOTIFY_DONE;
 }
 
@@ -295,27 +290,19 @@
 {
 	struct lpass_data *drv = subsys_to_lpass(subsys);
 	int ret = 0;
-
-	if (get_restart_level() == RESET_SUBSYS_INDEPENDENT) {
-		pr_debug("%s: Wait for ADSP power up!", __func__);
-		msleep(10000);
-	}
-
 	ret = pil_boot(&drv->q6->desc);
 	enable_irq(drv->wdog_irq);
-
 	return ret;
 }
 
-static struct ramdump_segment segments = { 0xdc00000, 0x1800000 };
-
 static int adsp_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	struct lpass_data *drv = subsys_to_lpass(subsys);
 
 	if (!enable)
 		return 0;
-	return do_ramdump(drv->ramdump_dev, &segments, 1);
+
+	return pil_do_ramdump(&drv->q6->desc, drv->ramdump_dev);
 }
 
 static void adsp_crash_shutdown(const struct subsys_desc *subsys)
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 07cbe19..ed85c95 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -56,6 +56,9 @@
 #define RMB_PMI_CODE_START		0x14
 #define RMB_PMI_CODE_LENGTH		0x18
 
+#define VDD_MSS_UV			1050000
+#define MAX_VDD_MX_UV			1050000
+
 #define PROXY_TIMEOUT_MS		10000
 #define POLL_INTERVAL_US		50
 
@@ -99,7 +102,7 @@
 
 	ret = regulator_enable(drv->vreg);
 	if (ret)
-		dev_err(dev, "Failed to enable regulator.\n");
+		dev_err(dev, "Failed to enable modem regulator.\n");
 
 	return ret;
 }
@@ -264,9 +267,44 @@
 	return ret;
 }
 
+static int pil_q6v5_mss_make_proxy_votes(struct pil_desc *pil)
+{
+	int ret;
+	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+
+	ret = regulator_set_voltage(drv->vreg_mx, VDD_MSS_UV, MAX_VDD_MX_UV);
+	if (ret) {
+		dev_err(pil->dev, "Failed to request vreg_mx voltage\n");
+		return ret;
+	}
+
+	ret = regulator_enable(drv->vreg_mx);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable vreg_mx\n");
+		regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+		return ret;
+	}
+
+	ret = pil_q6v5_make_proxy_votes(pil);
+	if (ret) {
+		regulator_disable(drv->vreg_mx);
+		regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+	}
+
+	return ret;
+}
+
+static void pil_q6v5_mss_remove_proxy_votes(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+	pil_q6v5_remove_proxy_votes(pil);
+	regulator_disable(drv->vreg_mx);
+	regulator_set_voltage(drv->vreg_mx, 0, MAX_VDD_MX_UV);
+}
+
 static struct pil_reset_ops pil_mss_ops = {
-	.proxy_vote = pil_q6v5_make_proxy_votes,
-	.proxy_unvote = pil_q6v5_remove_proxy_votes,
+	.proxy_vote = pil_q6v5_mss_make_proxy_votes,
+	.proxy_unvote = pil_q6v5_mss_remove_proxy_votes,
 	.auth_and_reset = pil_mss_reset,
 	.shutdown = pil_mss_shutdown,
 };
@@ -458,10 +496,6 @@
 	smsm_reset_modem(SMSM_RESET);
 }
 
-static struct ramdump_segment modem_segments[] = {
-	{0x08400000, 0x0D100000 - 0x08400000},
-};
-
 static struct ramdump_segment smem_segments[] = {
 	{0x0FA00000, 0x0FC00000 - 0x0FA00000},
 };
@@ -478,14 +512,13 @@
 	if (ret)
 		return ret;
 
-	ret = do_ramdump(drv->ramdump_dev, modem_segments,
-				ARRAY_SIZE(modem_segments));
+	ret = pil_do_ramdump(&drv->q6->desc, drv->ramdump_dev);
 	if (ret < 0) {
 		pr_err("Unable to dump modem fw memory (rc = %d).\n", ret);
 		goto out;
 	}
 
-	ret = do_ramdump(drv->smem_ramdump_dev, smem_segments,
+	ret = do_elf_ramdump(drv->smem_ramdump_dev, smem_segments,
 		ARRAY_SIZE(smem_segments));
 	if (ret < 0) {
 		pr_err("Unable to dump smem memory (rc = %d).\n", ret);
@@ -674,7 +707,11 @@
 	if (IS_ERR(q6->vreg))
 		return PTR_ERR(q6->vreg);
 
-	ret = regulator_set_voltage(q6->vreg, 1050000, 1050000);
+	q6->vreg_mx = devm_regulator_get(&pdev->dev, "vdd_mx");
+	if (IS_ERR(q6->vreg_mx))
+		return PTR_ERR(q6->vreg_mx);
+
+	ret = regulator_set_voltage(q6->vreg, VDD_MSS_UV, VDD_MSS_UV);
 	if (ret)
 		dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
 
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index ecdaf9b..d9ad6ae 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -31,6 +31,7 @@
 	void __iomem *axi_halt_base;
 	void __iomem *restart_reg;
 	struct regulator *vreg;
+	struct regulator *vreg_mx;
 	bool is_booted;
 	struct pil_desc desc;
 };
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 7993090..96b9882 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -412,26 +412,16 @@
 	return ret;
 }
 
-/*
- * 7MB RAM segments for Riva SS;
- * Riva 1.1 0x8f000000 - 0x8f700000
- * Riva 1.0 0x8f200000 - 0x8f700000
- */
-static struct ramdump_segment riva_segments[] = {
-	{0x8f000000, 0x8f700000 - 0x8f000000}
-};
-
 static int riva_ramdump(int enable, const struct subsys_desc *desc)
 {
 	struct riva_data *drv;
 
 	drv = container_of(desc, struct riva_data, subsys_desc);
 
-	if (enable)
-		return do_ramdump(drv->ramdump_dev, riva_segments,
-				ARRAY_SIZE(riva_segments));
-	else
+	if (!enable)
 		return 0;
+
+	return pil_do_ramdump(&drv->pil_desc, drv->ramdump_dev);
 }
 
 /* Riva crash handler */
@@ -542,7 +532,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..eb222e3 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -28,9 +28,12 @@
 #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"
+#include "ramdump.h"
 
 /* VENUS WRAPPER registers */
 #define VENUS_WRAPPER_CLOCK_CONFIG			0x4
@@ -74,9 +77,11 @@
 	struct iommu_domain *iommu_fw_domain;
 	int venus_domain_num;
 	bool is_booted;
+	void *ramdump_dev;
 	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 +152,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 +201,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 +230,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 */
@@ -404,6 +461,29 @@
 	pil_shutdown(&drv->desc);
 }
 
+static int venus_shutdown(const struct subsys_desc *desc)
+{
+	struct venus_data *drv = subsys_to_drv(desc);
+	pil_shutdown(&drv->desc);
+	return 0;
+}
+
+static int venus_powerup(const struct subsys_desc *desc)
+{
+	struct venus_data *drv = subsys_to_drv(desc);
+	return pil_boot(&drv->desc);
+}
+
+static int venus_ramdump(int enable, const struct subsys_desc *desc)
+{
+	struct venus_data *drv = subsys_to_drv(desc);
+
+	if (!enable)
+		return 0;
+
+	return pil_do_ramdump(&drv->desc, drv->ramdump_dev);
+}
+
 static int __devinit pil_venus_probe(struct platform_device *pdev)
 {
 	struct venus_data *drv;
@@ -438,6 +518,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");
@@ -462,23 +549,34 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 
+	drv->ramdump_dev = create_ramdump_device("venus", &pdev->dev);
+	if (!drv->ramdump_dev)
+		return -ENOMEM;
+
 	rc = pil_desc_init(desc);
 	if (rc)
-		return rc;
+		goto err_ramdump;
 
 	drv->subsys_desc.name = desc->name;
 	drv->subsys_desc.owner = THIS_MODULE;
 	drv->subsys_desc.dev = &pdev->dev;
 	drv->subsys_desc.start = venus_start;
 	drv->subsys_desc.stop = venus_stop;
+	drv->subsys_desc.shutdown = venus_shutdown;
+	drv->subsys_desc.powerup = venus_powerup;
+	drv->subsys_desc.ramdump = venus_ramdump;
 
 	drv->subsys = subsys_register(&drv->subsys_desc);
 	if (IS_ERR(drv->subsys)) {
-		pil_desc_release(desc);
-		return PTR_ERR(drv->subsys);
+		rc = PTR_ERR(drv->subsys);
+		goto err_subsys;
 	}
-
-	return 0;
+	return rc;
+err_subsys:
+	pil_desc_release(desc);
+err_ramdump:
+	destroy_ramdump_device(drv->ramdump_dev);
+	return rc;
 }
 
 static int __devexit pil_venus_remove(struct platform_device *pdev)
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/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index f32e149..53cc0f5 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -137,7 +137,7 @@
 			= msm_pm_config_rst_vector_after_pc;
 		break;
 	case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
-		if (!cpu_is_msm8625()) {
+		if (!cpu_is_msm8625() && !cpu_is_msm8625q()) {
 			void *remapped;
 
 			/*
@@ -200,7 +200,7 @@
 					pdata->v_addr + mpa5_cfg_ctl[0]);
 
 			/* 8x25Q changes */
-			if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3) {
+			if (cpu_is_msm8625q()) {
 				/* write 'entry' to boot remapper register */
 				__raw_writel(entry, (pdata->v_addr +
 						mpa5_boot_remap_addr[1]));
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 96c1218..ec9f030 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -562,7 +562,7 @@
 		__raw_writel(0, APPS_PWRDOWN);
 		mb();
 		msm_spm_reinit();
-	} else if (cpu_is_msm8625()) {
+	} else if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		__raw_writel(0, APPS_PWRDOWN);
 		mb();
 
@@ -881,7 +881,7 @@
 
 	memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data));
 
-	if (cpu_is_msm8625()) {
+	if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		/* Program the SPM */
 		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE,
 									false);
@@ -971,7 +971,7 @@
 #endif
 
 #ifdef CONFIG_CACHE_L2X0
-	if (!cpu_is_msm8625())
+	if (!cpu_is_msm8625() && !cpu_is_msm8625q())
 		l2cc_suspend();
 	else
 		apps_power_collapse = 1;
@@ -983,7 +983,7 @@
 	 * TBD: Currently recognise the MODEM early exit
 	 * path by reading the MPA5_GDFS_CNT_VAL register.
 	 */
-	if (cpu_is_msm8625()) {
+	if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		int cpu;
 		/*
 		 * on system reset, default value of MPA5_GDFS_CNT_VAL
@@ -997,7 +997,7 @@
 		val = __raw_readl(MSM_CFG_CTL_BASE + 0x38);
 
 		/* 8x25Q */
-		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3) {
+		if (cpu_is_msm8625q()) {
 			if (val != 0x000F0002) {
 				for_each_possible_cpu(cpu) {
 					if (!cpu)
@@ -1031,7 +1031,7 @@
 	}
 
 #ifdef CONFIG_CACHE_L2X0
-	if (!cpu_is_msm8625())
+	if (!cpu_is_msm8625() && !cpu_is_msm8625q())
 		l2cc_resume();
 	else
 		apps_power_collapse = 0;
@@ -1153,7 +1153,7 @@
 
 	smd_sleep_exit();
 
-	if (cpu_is_msm8625()) {
+	if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
 									false);
 		WARN_ON(ret);
@@ -1220,7 +1220,7 @@
 		msm_cpr_ops->cpr_resume();
 
 power_collapse_bail:
-	if (cpu_is_msm8625()) {
+	if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
 									false);
 		WARN_ON(ret);
@@ -1258,14 +1258,14 @@
 #endif
 
 #ifdef CONFIG_CACHE_L2X0
-	if (!cpu_is_msm8625())
+	if (!cpu_is_msm8625() && !cpu_is_msm8625q())
 		l2cc_suspend();
 #endif
 
 	collapsed = msm_pm_collapse();
 
 #ifdef CONFIG_CACHE_L2X0
-	if (!cpu_is_msm8625())
+	if (!cpu_is_msm8625() && !cpu_is_msm8625q())
 		l2cc_resume();
 #endif
 
@@ -1310,7 +1310,7 @@
 			return -EIO;
 	}
 
-	if (!cpu_is_msm8625())
+	if (!cpu_is_msm8625() && !cpu_is_msm8625q())
 		msm_pm_config_hw_before_swfi();
 
 	msm_arch_idle();
@@ -1713,7 +1713,7 @@
 		return ret;
 	}
 
-	if (cpu_is_msm8625()) {
+	if (cpu_is_msm8625() || cpu_is_msm8625q()) {
 		target_type = TARGET_IS_8625;
 		clean_caches((unsigned long)&target_type, sizeof(target_type),
 				virt_to_phys(&target_type));
@@ -1725,7 +1725,7 @@
 		 * MPA5_GDFS_CNT_VAL[9:0] = Delay counter for
 		 * GDFS control.
 		 */
-		if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3)
+		if (cpu_is_msm8625q())
 			val = 0x000F0002;
 		else
 			val = 0x00030002;
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 6189da8..81af66b 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -1080,6 +1080,21 @@
 	return 0;
 }
 
+int msm_adsp_dump(struct msm_adsp_module *module)
+{
+	int rc = 0;
+	if (!module) {
+		MM_INFO("Invalid module. Dumps are not collected\n");
+		return -EINVAL;
+	}
+	MM_INFO("starting DSP DUMP\n");
+	rc = rpc_adsp_rtos_app_to_modem(RPC_ADSP_RTOS_CMD_CORE_DUMP,
+			module->id, module);
+	MM_INFO("DSP DUMP done rc =%d\n", rc);
+	return rc;
+}
+EXPORT_SYMBOL(msm_adsp_dump);
+
 int msm_adsp_enable(struct msm_adsp_module *module)
 {
 	int rc = 0;
@@ -1123,6 +1138,7 @@
 			rc = 0;
 		} else {
 			MM_ERR("module '%s' enable timed out\n", module->name);
+			msm_adsp_dump(module);
 			rc = -ETIMEDOUT;
 		}
 		if (module->open_count++ == 0 && module->clk)
diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h
index 50f5b83..4e9d311 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.h
+++ b/arch/arm/mach-msm/qdsp5/adsp.h
@@ -152,6 +152,7 @@
 	RPC_ADSP_RTOS_CMD_SET_STATE,
 	RPC_ADSP_RTOS_CMD_REMOTE_INIT_INFO_EVENT,
 	RPC_ADSP_RTOS_CMD_GET_INIT_INFO,
+	RPC_ADSP_RTOS_CMD_CORE_DUMP,
 };
 
 enum rpc_adsp_rtos_mod_status_type {
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index 46a80d7..c36cac7 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -261,8 +261,10 @@
 		cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 		rc = audmgr_enable(&audio->audmgr, &cfg);
-		if (rc < 0)
+		if (rc < 0) {
+			msm_adsp_dump(audio->audplay);
 			return rc;
+		}
 	}
 
 	if (msm_adsp_enable(audio->audplay)) {
@@ -306,8 +308,12 @@
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
-			audmgr_disable(&audio->audmgr);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+			rc = audmgr_disable(&audio->audmgr);
+			if (rc < 0)
+				msm_adsp_dump(audio->audplay);
+		}
+
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_ac3.c b/arch/arm/mach-msm/qdsp5/audio_ac3.c
index e453ec5..b5337bd 100644
--- a/arch/arm/mach-msm/qdsp5/audio_ac3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_ac3.c
@@ -252,8 +252,10 @@
 		cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 		rc = audmgr_enable(&audio->audmgr, &cfg);
-		if (rc < 0)
+		if (rc < 0) {
+			msm_adsp_dump(audio->audplay);
 			return rc;
+		}
 	}
 
 	if (msm_adsp_enable(audio->audplay)) {
@@ -296,8 +298,11 @@
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
-			audmgr_disable(&audio->audmgr);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+			rc = audmgr_disable(&audio->audmgr);
+			if (rc < 0)
+				msm_adsp_dump(audio->audplay);
+		}
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 0792e3f..4aa7403 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -265,8 +265,10 @@
 		cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 		rc = audmgr_enable(&audio->audmgr, &cfg);
-		if (rc < 0)
+		if (rc < 0) {
+			msm_adsp_dump(audio->audplay);
 			return rc;
+		}
 	}
 
 	if (msm_adsp_enable(audio->audplay)) {
@@ -310,8 +312,11 @@
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
-			audmgr_disable(&audio->audmgr);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+			rc = audmgr_disable(&audio->audmgr);
+			if (rc < 0)
+				msm_adsp_dump(audio->audplay);
+		}
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index 7d37cea..57df4ad 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -262,8 +262,10 @@
 		cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 		rc = audmgr_enable(&audio->audmgr, &cfg);
-		if (rc < 0)
+		if (rc < 0) {
+			msm_adsp_dump(audio->audplay);
 			return rc;
+		}
 	}
 
 	if (msm_adsp_enable(audio->audplay)) {
@@ -307,8 +309,11 @@
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
-			audmgr_disable(&audio->audmgr);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+			rc = audmgr_disable(&audio->audmgr);
+			if (rc < 0)
+				msm_adsp_dump(audio->audplay);
+		}
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 155b0e1..0799ee1 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -255,8 +255,10 @@
 		cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 		rc = audmgr_enable(&audio->audmgr, &cfg);
-		if (rc < 0)
+		if (rc < 0) {
+			msm_adsp_dump(audio->audplay);
 			return rc;
+		}
 	}
 
 	if (msm_adsp_enable(audio->audplay)) {
@@ -299,8 +301,11 @@
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
-			audmgr_disable(&audio->audmgr);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+			rc = audmgr_disable(&audio->audmgr);
+			if (rc < 0)
+				msm_adsp_dump(audio->audplay);
+		}
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index 8120d7b..e896e85 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -293,9 +293,10 @@
 	cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 	rc = audmgr_enable(&audio->audmgr, &cfg);
-	if (rc < 0)
+	if (rc < 0) {
+		msm_adsp_dump(audio->audplay);
 		return rc;
-
+	}
 	if (msm_adsp_enable(audio->audplay)) {
 		MM_ERR("msm_adsp_enable(audplay) failed\n");
 		audmgr_disable(&audio->audmgr);
@@ -335,7 +336,9 @@
 		wake_up(&audio->write_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		audmgr_disable(&audio->audmgr);
+		rc = audmgr_disable(&audio->audmgr);
+		if (rc < 0)
+			msm_adsp_dump(audio->audplay);
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index b8c64be..a606bd5 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -330,8 +330,10 @@
 		cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 		rc = audmgr_enable(&audio->audmgr, &cfg);
-		if (rc < 0)
+		if (rc < 0) {
+			msm_adsp_dump(audio->audplay);
 			return rc;
+		}
 	}
 
 	if (msm_adsp_enable(audio->audplay)) {
@@ -376,8 +378,11 @@
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
-			audmgr_disable(&audio->audmgr);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+			rc = audmgr_disable(&audio->audmgr);
+			if (rc < 0)
+				msm_adsp_dump(audio->audplay);
+		}
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 3eb72c8..d19f80b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -299,9 +299,10 @@
 	cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 	rc = audmgr_enable(&audio->audmgr, &cfg);
-	if (rc < 0)
+	if (rc < 0) {
+		msm_adsp_dump(audio->audplay);
 		return rc;
-
+	}
 	if (msm_adsp_enable(audio->audplay)) {
 		MM_ERR("msm_adsp_enable(audplay) failed\n");
 		audmgr_disable(&audio->audmgr);
@@ -341,7 +342,9 @@
 		wake_up(&audio->write_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		audmgr_disable(&audio->audmgr);
+		rc = audmgr_disable(&audio->audmgr);
+		if (rc < 0)
+			msm_adsp_dump(audio->audplay);
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 68ffcfef..7b2090d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -218,9 +218,10 @@
 	cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 	rc = audmgr_enable(&audio->audmgr, &cfg);
-	if (rc < 0)
+	if (rc < 0) {
+		msm_adsp_dump(audio->audrec);
 		return rc;
-
+	}
 	if (audpreproc_enable(audio->enc_id, &audpre_dsp_event, audio)) {
 		MM_ERR("msm_adsp_enable(audpreproc) failed\n");
 		audmgr_disable(&audio->audmgr);
@@ -249,6 +250,8 @@
 /* must be called with audio->lock held */
 static int audpcm_in_disable(struct audio_in *audio)
 {
+	int rc;
+
 	if (audio->enabled) {
 		audio->enabled = 0;
 
@@ -262,7 +265,9 @@
 		/*reset the sampling frequency information at audpreproc layer*/
 		audio->session_info.sampling_freq = 0;
 		audpreproc_update_audrec_info(&audio->session_info);
-		audmgr_disable(&audio->audmgr);
+		rc = audmgr_disable(&audio->audmgr);
+		if (rc < 0)
+			msm_adsp_dump(audio->audrec);
 	}
 	return 0;
 }
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index 876c909..3fc489c 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -251,8 +251,10 @@
 		cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 		rc = audmgr_enable(&audio->audmgr, &cfg);
-		if (rc < 0)
+		if (rc < 0) {
+			msm_adsp_dump(audio->audplay);
 			return rc;
+		}
 	}
 
 	if (msm_adsp_enable(audio->audplay)) {
@@ -296,8 +298,11 @@
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
-			audmgr_disable(&audio->audmgr);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+			rc = audmgr_disable(&audio->audmgr);
+			if (rc < 0)
+				msm_adsp_dump(audio->audplay);
+		}
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index 6d520b4..f7d54cc 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -268,8 +268,10 @@
 		cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 		rc = audmgr_enable(&audio->audmgr, &cfg);
-		if (rc < 0)
+		if (rc < 0) {
+			msm_adsp_dump(audio->audplay);
 			return rc;
+		}
 	}
 
 	if (msm_adsp_enable(audio->audplay)) {
@@ -314,8 +316,11 @@
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
-			audmgr_disable(&audio->audmgr);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+			rc = audmgr_disable(&audio->audmgr);
+			if (rc < 0)
+				msm_adsp_dump(audio->audplay);
+		}
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index a08f3c9..8dba4a6 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -266,8 +266,10 @@
 	cfg.snd_method = RPC_SND_METHOD_MIDI;
 
 	rc = audmgr_enable(&audio->audmgr, &cfg);
-	if (rc < 0)
+	if (rc < 0) {
+		msm_adsp_dump(audio->audplay);
 		return rc;
+	}
 
 	if (msm_adsp_enable(audio->audplay)) {
 		MM_ERR("msm_adsp_enable(audplay) failed\n");
@@ -309,7 +311,10 @@
 		wake_up(&audio->read_wait);
 		msm_adsp_disable(audio->audplay);
 		audpp_disable(audio->dec_id, audio);
-		audmgr_disable(&audio->audmgr);
+		rc = audmgr_disable(&audio->audmgr);
+		if (rc < 0)
+			msm_adsp_dump(audio->audplay);
+
 		audio->out_needed = 0;
 		rmt_put_resource(audio);
 		audio->rmt_resource_released = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audpp.c b/arch/arm/mach-msm/qdsp5/audpp.c
index b4ead5c..b4b7338f 100644
--- a/arch/arm/mach-msm/qdsp5/audpp.c
+++ b/arch/arm/mach-msm/qdsp5/audpp.c
@@ -292,6 +292,7 @@
 			MM_INFO("ENABLE\n");
 			if (!audpp->enabled) {
 				audpp->enabled = 1;
+				wake_up(&audpp->event_wait);
 				audpp_broadcast(audpp, id, msg);
 			} else {
 				cid = msg[1];
@@ -344,6 +345,7 @@
 	struct audpp_state *audpp = &the_audpp_state;
 	uint16_t msg[8];
 	int res = 0;
+	int rc;
 
 	if (id < -1 || id > 4)
 		return -EINVAL;
@@ -374,6 +376,11 @@
 		LOG(EV_ENABLE, 2);
 		msm_adsp_enable(audpp->mod);
 		audpp_dsp_config(1);
+		rc = wait_event_timeout(audpp->event_wait,
+					(audpp->enabled == 1),
+					3 * HZ);
+		if (rc == 0)
+			msm_adsp_dump(audpp->mod);
 	} else {
 		if (audpp->enabled) {
 			msg[0] = AUDPP_MSG_ENA_ENA;
@@ -424,13 +431,17 @@
 		MM_DBG("disable\n");
 		LOG(EV_DISABLE, 2);
 		audpp_dsp_config(0);
-		rc = wait_event_interruptible(audpp->event_wait,
-				(audpp->enabled == 0));
+		rc = wait_event_timeout(audpp->event_wait,
+					(audpp->enabled == 0),
+					3 * HZ);
 		if (audpp->enabled == 0)
 			MM_INFO("Received CFG_MSG_DISABLE from ADSP\n");
-		else
+		else {
 			MM_ERR("Didn't receive CFG_MSG DISABLE \
 					message from ADSP\n");
+			if (rc == 0)
+				msm_adsp_dump(audpp->mod);
+		}
 		msm_adsp_disable(audpp->mod);
 		msm_adsp_put(audpp->mod);
 		audpp->mod = NULL;
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_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index a24b9ec..cad845f 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -730,12 +730,19 @@
 
 static int deregister_memory(void)
 {
+	int i;
+
 	if (atomic64_read(&acdb_data.mem_len)) {
 		mutex_lock(&acdb_data.acdb_mutex);
+		atomic64_set(&acdb_data.mem_len, 0);
 		atomic_set(&acdb_data.vocstrm_total_cal_size, 0);
 		atomic_set(&acdb_data.vocproc_total_cal_size, 0);
 		atomic_set(&acdb_data.vocvol_total_cal_size, 0);
-		atomic64_set(&acdb_data.mem_len, 0);
+
+		for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+			kfree(acdb_data.col_data[i]);
+			acdb_data.col_data[i] = NULL;
+		}
 		ion_unmap_kernel(acdb_data.ion_client, acdb_data.ion_handle);
 		ion_free(acdb_data.ion_client, acdb_data.ion_handle);
 		ion_client_destroy(acdb_data.ion_client);
@@ -747,12 +754,19 @@
 static int register_memory(void)
 {
 	int			result;
+	int			i;
 	unsigned long		paddr;
 	void                    *kvptr;
 	unsigned long		kvaddr;
 	unsigned long		mem_len;
 
 	mutex_lock(&acdb_data.acdb_mutex);
+	for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+		acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
+		atomic_set(&acdb_data.vocproc_col_cal[i].cal_kvaddr,
+			(uint32_t)acdb_data.col_data[i]);
+	}
+
 	acdb_data.ion_client =
 		msm_ion_client_create(UINT_MAX, "audio_acdb_client");
 	if (IS_ERR_OR_NULL(acdb_data.ion_client)) {
@@ -1029,7 +1043,6 @@
 
 static int acdb_release(struct inode *inode, struct file *f)
 {
-	int i;
 	s32 result = 0;
 
 	atomic_dec(&usage_count);
@@ -1038,11 +1051,6 @@
 	pr_debug("%s: ref count %d!\n", __func__,
 		atomic_read(&usage_count));
 
-	for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
-		kfree(acdb_data.col_data[i]);
-		acdb_data.col_data[i] = NULL;
-	}
-
 	if (atomic_read(&usage_count) >= 1)
 		result = -EBUSY;
 	else
@@ -1067,16 +1075,10 @@
 
 static int __init acdb_init(void)
 {
-	int i;
 	memset(&acdb_data, 0, sizeof(acdb_data));
 	mutex_init(&acdb_data.acdb_mutex);
 	atomic_set(&usage_count, 0);
 
-	for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
-		acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
-		atomic_set(&acdb_data.vocproc_col_cal[i].cal_kvaddr,
-			(uint32_t)acdb_data.col_data[i]);
-	}
 	return misc_register(&acdb_misc);
 }
 
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..ad5f1b5 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -25,6 +25,9 @@
 #include <asm/ioctls.h>
 #include <linux/debugfs.h>
 #include "audio_utils_aio.h"
+#ifdef CONFIG_USE_DEV_CTRL_VOLUME
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
 
 #ifdef CONFIG_DEBUG_FS
 ssize_t audio_aio_debug_open(struct inode *inode, struct file *file)
@@ -424,6 +427,67 @@
 	}
 }
 
+#ifdef CONFIG_USE_DEV_CTRL_VOLUME
+
+static void audio_aio_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct q6audio_aio *audio = (struct q6audio_aio *) private_data;
+	int rc  = 0;
+
+	switch (evt_id) {
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->volume = evt_payload->session_vol;
+		pr_debug("%s[%p]: AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d, enabled = %d\n",
+			__func__, audio, audio->volume, audio->enabled);
+		if (audio->enabled == 1) {
+			if (audio->ac) {
+				rc = q6asm_set_volume(audio->ac, audio->volume);
+				if (rc < 0) {
+					pr_err("%s[%p]: Send Volume command failed rc=%d\n",
+						__func__, audio, rc);
+				}
+			}
+		}
+		break;
+	default:
+		pr_err("%s[%p]:ERROR:wrong event\n", __func__, audio);
+		break;
+	}
+}
+
+int register_volume_listener(struct q6audio_aio *audio)
+{
+	int rc  = 0;
+	audio->device_events = AUDDEV_EVT_STREAM_VOL_CHG;
+	audio->drv_status &= ~ADRV_STATUS_PAUSE;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->ac->session,
+					audio_aio_listner,
+					(void *)audio);
+	if (rc < 0) {
+		pr_err("%s[%p]: Event listener failed\n", __func__, audio);
+		rc = -EACCES;
+	}
+	return rc;
+}
+void unregister_volume_listener(struct q6audio_aio *audio)
+{
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
+}
+#else /*CONFIG_USE_DEV_CTRL_VOLUME*/
+int register_volume_listener(struct q6audio_aio *audio)
+{
+	return 0;/* do nothing */
+}
+void unregister_volume_listener(struct q6audio_aio *audio)
+{
+	return;/* do nothing */
+}
+#endif /*CONFIG_USE_DEV_CTRL_VOLUME*/
+
 int audio_aio_release(struct inode *inode, struct file *file)
 {
 	struct q6audio_aio *audio = file->private_data;
@@ -448,6 +512,8 @@
 	mutex_destroy(&audio->read_lock);
 	mutex_destroy(&audio->write_lock);
 	mutex_destroy(&audio->get_event_lock);
+	unregister_volume_listener(audio);
+
 #ifdef CONFIG_DEBUG_FS
 	if (audio->dentry)
 		debugfs_remove(audio->dentry);
@@ -1049,7 +1115,13 @@
 		goto fail;
 	}
 	pr_debug("Ion client create in audio_aio_open %p", audio->client);
+
+	rc = register_volume_listener(audio);
+	if (rc < 0)
+		goto fail;
+
 	return 0;
+
 fail:
 	q6asm_audio_client_free(audio->ac);
 	kfree(audio->codec_cfg);
@@ -1142,6 +1214,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 +1255,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/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index dedf991..d518254 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -1,6 +1,6 @@
 /* Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -176,7 +176,8 @@
 	struct ion_client *client;
 	struct audio_aio_drv_operations drv_ops;
 	union msm_audio_event_payload eos_write_payload;
-
+	uint32_t device_events;
+	uint16_t volume;
 	uint32_t drv_status;
 	int event_abort;
 	int eos_rsp;
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c b/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
index 84f136a..5faee21 100644
--- a/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in_proxy.c
@@ -72,31 +72,36 @@
 	if (pcm->start) {
 		if (pcm->dsp_idx == pcm->buffer_count)
 			pcm->dsp_idx = 0;
-		rc = wait_event_timeout(pcm->wait,
-				(pcm->dma_buf[pcm->dsp_idx].used == 0) ||
-				atomic_read(&pcm->in_stopped), 1 * HZ);
-		if (!rc) {
-			pr_err("%s: wait_event_timeout failed\n", __func__);
-			goto fail;
+		if (pcm->dma_buf[pcm->dsp_idx].used == 0) {
+			if (atomic_read(&pcm->in_stopped)) {
+				pr_err("%s: Driver closed - return\n",
+					__func__);
+				return HRTIMER_NORESTART;
+			}
+			rc = afe_rt_proxy_port_read(
+				pcm->dma_buf[pcm->dsp_idx].addr,
+				pcm->buffer_size);
+			if (rc < 0) {
+				pr_err("%s afe_rt_proxy_port_read fail\n",
+					__func__);
+				goto fail;
+			}
+			pcm->dma_buf[pcm->dsp_idx].used = 1;
+			pcm->dsp_idx++;
+			pr_debug("sending frame rec to DSP: poll_time: %d\n",
+					pcm->poll_time);
+		} else {
+			pr_err("Qcom: Used flag not reset retry after %d msec\n",
+				(pcm->poll_time/10));
+			goto fail_timer;
 		}
-		if (atomic_read(&pcm->in_stopped)) {
-			pr_err("%s: Driver closed - return\n", __func__);
-			return HRTIMER_NORESTART;
-		}
-		rc = afe_rt_proxy_port_read(
-			pcm->dma_buf[pcm->dsp_idx].addr,
-			pcm->buffer_size);
-		if (rc < 0) {
-			pr_err("%s afe_rt_proxy_port_read fail\n", __func__);
-			goto fail;
-		}
-		pcm->dma_buf[pcm->dsp_idx].used = 1;
-		pcm->dsp_idx++;
-		pr_debug("%s: sending frame rec to DSP: poll_time: %d\n",
-				__func__, pcm->poll_time);
 fail:
 		hrtimer_forward_now(hrt, ns_to_ktime(pcm->poll_time
 				* 1000));
+		return HRTIMER_RESTART;
+fail_timer:
+		hrtimer_forward_now(hrt, ns_to_ktime((pcm->poll_time/10)
+				* 1000));
 
 		return HRTIMER_RESTART;
 	} else {
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/ramdump.c b/arch/arm/mach-msm/ramdump.c
index e33ec48..aac49d0 100644
--- a/arch/arm/mach-msm/ramdump.c
+++ b/arch/arm/mach-msm/ramdump.c
@@ -11,14 +11,10 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
 #include <linux/workqueue.h>
 #include <linux/io.h>
 #include <linux/jiffies.h>
 #include <linux/sched.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
@@ -26,8 +22,8 @@
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/uaccess.h>
-
-#include <asm-generic/poll.h>
+#include <linux/elf.h>
+#include <linux/wait.h>
 
 #include "ramdump.h"
 
@@ -46,6 +42,8 @@
 	wait_queue_head_t dump_wait_q;
 	int nsegments;
 	struct ramdump_segment *segments;
+	size_t elfcore_size;
+	char *elfcore_buf;
 };
 
 static int ramdump_open(struct inode *inode, struct file *filep)
@@ -107,13 +105,29 @@
 	size_t copy_size = 0;
 	int ret = 0;
 
-	if (rd_dev->data_ready == 0) {
-		pr_err("Ramdump(%s): Read when there's no dump available!",
-			rd_dev->name);
-		return -EPIPE;
+	if ((filep->f_flags & O_NONBLOCK) && !rd_dev->data_ready)
+		return -EAGAIN;
+
+	ret = wait_event_interruptible(rd_dev->dump_wait_q, rd_dev->data_ready);
+	if (ret)
+		return ret;
+
+	if (*pos < rd_dev->elfcore_size) {
+		copy_size = min(rd_dev->elfcore_size, count);
+
+		if (copy_to_user(buf, rd_dev->elfcore_buf, copy_size)) {
+			ret = -EFAULT;
+			goto ramdump_done;
+		}
+		*pos += copy_size;
+		count -= copy_size;
+		buf += copy_size;
+		if (count == 0)
+			return copy_size;
 	}
 
-	addr = offset_translate(*pos, rd_dev, &data_left);
+	addr = offset_translate(*pos - rd_dev->elfcore_size, rd_dev,
+				&data_left);
 
 	/* EOF check */
 	if (data_left == 0) {
@@ -174,7 +188,7 @@
 	return mask;
 }
 
-const struct file_operations ramdump_file_ops = {
+static const struct file_operations ramdump_file_ops = {
 	.open = ramdump_open,
 	.release = ramdump_release,
 	.read = ramdump_read,
@@ -234,11 +248,14 @@
 	kfree(rd_dev);
 }
 
-int do_ramdump(void *handle, struct ramdump_segment *segments,
-		int nsegments)
+static int _do_ramdump(void *handle, struct ramdump_segment *segments,
+		int nsegments, bool use_elf)
 {
 	int ret, i;
 	struct ramdump_device *rd_dev = (struct ramdump_device *)handle;
+	Elf32_Phdr *phdr;
+	Elf32_Ehdr *ehdr;
+	unsigned long offset;
 
 	if (!rd_dev->consumer_present) {
 		pr_err("Ramdump(%s): No consumers. Aborting..\n", rd_dev->name);
@@ -251,6 +268,38 @@
 	rd_dev->segments = segments;
 	rd_dev->nsegments = nsegments;
 
+	if (use_elf) {
+		rd_dev->elfcore_size = sizeof(*ehdr) +
+				       sizeof(*phdr) * nsegments;
+		ehdr = kzalloc(rd_dev->elfcore_size, GFP_KERNEL);
+		rd_dev->elfcore_buf = (char *)ehdr;
+		if (!rd_dev->elfcore_buf)
+			return -ENOMEM;
+
+		memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+		ehdr->e_ident[EI_CLASS] = ELFCLASS32;
+		ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+		ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+		ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
+		ehdr->e_type = ET_CORE;
+		ehdr->e_version = EV_CURRENT;
+		ehdr->e_phoff = sizeof(*ehdr);
+		ehdr->e_ehsize = sizeof(*ehdr);
+		ehdr->e_phentsize = sizeof(*phdr);
+		ehdr->e_phnum = nsegments;
+
+		offset = rd_dev->elfcore_size;
+		phdr = (Elf32_Phdr *)(ehdr + 1);
+		for (i = 0; i < nsegments; i++, phdr++) {
+			phdr->p_type = PT_LOAD;
+			phdr->p_offset = offset;
+			phdr->p_vaddr = phdr->p_paddr = segments[i].address;
+			phdr->p_filesz = phdr->p_memsz = segments[i].size;
+			phdr->p_flags = PF_R | PF_W | PF_X;
+			offset += phdr->p_filesz;
+		}
+	}
+
 	rd_dev->data_ready = 1;
 	rd_dev->ramdump_status = -1;
 
@@ -271,5 +320,20 @@
 		ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE;
 
 	rd_dev->data_ready = 0;
+	rd_dev->elfcore_size = 0;
+	kfree(rd_dev->elfcore_buf);
+	rd_dev->elfcore_buf = NULL;
 	return ret;
+
+}
+
+int do_ramdump(void *handle, struct ramdump_segment *segments, int nsegments)
+{
+	return _do_ramdump(handle, segments, nsegments, false);
+}
+
+int
+do_elf_ramdump(void *handle, struct ramdump_segment *segments, int nsegments)
+{
+	return _do_ramdump(handle, segments, nsegments, true);
 }
diff --git a/arch/arm/mach-msm/ramdump.h b/arch/arm/mach-msm/ramdump.h
index 3e5bfaf..5fb41ec 100644
--- a/arch/arm/mach-msm/ramdump.h
+++ b/arch/arm/mach-msm/ramdump.h
@@ -24,5 +24,7 @@
 void destroy_ramdump_device(void *dev);
 int do_ramdump(void *handle, struct ramdump_segment *segments,
 		int nsegments);
+int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
+		int nsegments);
 
 #endif
diff --git a/arch/arm/mach-msm/rpc_server_handset.c b/arch/arm/mach-msm/rpc_server_handset.c
index 6d173fb..3a458c8 100644
--- a/arch/arm/mach-msm/rpc_server_handset.c
+++ b/arch/arm/mach-msm/rpc_server_handset.c
@@ -280,6 +280,13 @@
 	switch (key) {
 	case KEY_POWER:
 	case KEY_END:
+		if (hs->hs_pdata->ignore_end_key)
+			input_report_key(hs->ipdev, KEY_POWER,
+						(key_code != HS_REL_K));
+		else
+			input_report_key(hs->ipdev, key,
+						(key_code != HS_REL_K));
+		break;
 	case KEY_MEDIA:
 	case KEY_VOLUMEUP:
 	case KEY_VOLUMEDOWN:
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/sensors_adsp.c b/arch/arm/mach-msm/sensors_adsp.c
new file mode 100644
index 0000000..0683bc5
--- /dev/null
+++ b/arch/arm/mach-msm/sensors_adsp.c
@@ -0,0 +1,1249 @@
+/* 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/workqueue.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ctype.h>
+#include <linux/of_device.h>
+#include <linux/msm_dsps.h>
+#include <linux/uaccess.h>
+#include <asm/mach-types.h>
+#include <asm/arch_timer.h>
+#include <mach/subsystem_restart.h>
+#include <mach/ocmem.h>
+#include <mach/msm_smd.h>
+#include <mach/sensors_adsp.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+#define DRV_NAME	"sensors"
+#define DRV_VERSION	"1.00"
+
+#define SNS_OCMEM_SMD_CHANNEL	"SENSOR"
+#define SNS_OCMEM_CLIENT_ID     OCMEM_SENSORS
+#define SNS_OCMEM_SIZE          SZ_256K
+#define SMD_BUF_SIZE		2048
+#define SNS_TIMEOUT_MS    1000
+
+#define SNS_OCMEM_ALLOC_GROW    0x00000001
+#define SNS_OCMEM_ALLOC_SHRINK  0x00000002
+#define SNS_OCMEM_MAP_DONE      0x00000004
+#define SNS_OCMEM_MAP_FAIL      0x00000008
+#define SNS_OCMEM_UNMAP_DONE    0x00000010
+#define SNS_OCMEM_UNMAP_FAIL    0x00000020
+
+#define DSPS_HAS_CLIENT         0x00000100
+#define DSPS_HAS_NO_CLIENT      0x00000200
+#define DSPS_BW_VOTE_ON         0x00000400
+#define DSPS_BW_VOTE_OFF        0x00000800
+#define DSPS_PHYS_ADDR_SET      0x00001000
+
+/**
+ *  Structure contains all state used by the sensors driver
+ */
+struct sns_adsp_control_s {
+	wait_queue_head_t sns_wait;
+	spinlock_t sns_lock;
+	struct workqueue_struct *sns_workqueue;
+	struct work_struct sns_work;
+	smd_channel_t *smd_ch;
+	uint32_t sns_ocmem_status;
+	uint32_t mem_segments_size;
+	struct sns_mem_segment_s_v01 mem_segments[SNS_OCMEM_MAX_NUM_SEG_V01];
+	struct ocmem_buf *buf;
+	struct ocmem_map_list map_list;
+	struct ocmem_notifier *ocmem_handle;
+	bool ocmem_enabled;
+	struct notifier_block ocmem_nb;
+	uint32_t sns_ocmem_bus_client;
+	struct platform_device *pdev;
+	void *pil;
+	struct class *dev_class;
+	dev_t dev_num;
+	struct device *dev;
+	struct cdev *cdev;
+};
+
+static struct sns_adsp_control_s sns_ctl;
+
+/* All asynchronous responses from the OCMEM driver are received
+by this function */
+int sns_ocmem_drv_cb(struct notifier_block *self,
+			unsigned long action,
+			void *dev)
+{
+	unsigned long flags;
+	pr_debug("%s\n", __func__);
+
+	spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+
+	pr_debug("%s: Received OCMEM callback: action=%li\n",
+		__func__, action);
+
+	switch (action) {
+	case OCMEM_MAP_DONE:
+		sns_ctl.sns_ocmem_status |= SNS_OCMEM_MAP_DONE;
+		sns_ctl.sns_ocmem_status &= (~OCMEM_MAP_FAIL &
+						~SNS_OCMEM_UNMAP_DONE &
+						~SNS_OCMEM_UNMAP_FAIL);
+		break;
+	case OCMEM_MAP_FAIL:
+		sns_ctl.sns_ocmem_status |= SNS_OCMEM_MAP_FAIL;
+		sns_ctl.sns_ocmem_status &= (~OCMEM_MAP_DONE &
+						~SNS_OCMEM_UNMAP_DONE &
+						~SNS_OCMEM_UNMAP_FAIL);
+		break;
+	case OCMEM_UNMAP_DONE:
+		sns_ctl.sns_ocmem_status |= SNS_OCMEM_UNMAP_DONE;
+		sns_ctl.sns_ocmem_status &= (~SNS_OCMEM_UNMAP_FAIL &
+						~SNS_OCMEM_MAP_DONE &
+						~OCMEM_MAP_FAIL);
+		break;
+	case OCMEM_UNMAP_FAIL:
+		sns_ctl.sns_ocmem_status |= SNS_OCMEM_UNMAP_FAIL;
+		sns_ctl.sns_ocmem_status &= (~SNS_OCMEM_UNMAP_DONE &
+						~SNS_OCMEM_MAP_DONE &
+						~OCMEM_MAP_FAIL);
+		break;
+	case OCMEM_ALLOC_GROW:
+		sns_ctl.sns_ocmem_status |= SNS_OCMEM_ALLOC_GROW;
+		sns_ctl.sns_ocmem_status &= ~SNS_OCMEM_ALLOC_SHRINK;
+		break;
+	case OCMEM_ALLOC_SHRINK:
+		sns_ctl.sns_ocmem_status |= SNS_OCMEM_ALLOC_SHRINK;
+		sns_ctl.sns_ocmem_status &= ~SNS_OCMEM_ALLOC_GROW;
+		break;
+	default:
+		pr_err("%s: Unknown action received in OCMEM callback %lu\n",
+						__func__, action);
+		break;
+	}
+
+	pr_debug("%s: sns_ocmem_status: 0x%x\n", __func__,
+					sns_ctl.sns_ocmem_status);
+	spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+
+	wake_up(&sns_ctl.sns_wait);
+
+	return 0;
+}
+
+/**
+ * Processes messages received through SMD from the ADSP
+ *
+ * @param hdr The message header
+ * @param msg Message pointer
+ *
+ * */
+void sns_ocmem_smd_process(struct sns_ocmem_hdr_s *hdr, void *msg)
+{
+	unsigned long flags;
+	pr_debug("%s\n", __func__);
+
+	spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+
+	pr_debug("%s: Received message from ADSP; id: %i type: %i (%08x)\n",
+		__func__, hdr->msg_id, hdr->msg_type,
+		sns_ctl.sns_ocmem_status);
+
+	if (hdr->msg_id == SNS_OCMEM_PHYS_ADDR_RESP_V01 &&
+	    hdr->msg_type == SNS_OCMEM_MSG_TYPE_RESP) {
+		struct sns_ocmem_phys_addr_resp_msg_v01 *msg_ptr =
+				(struct sns_ocmem_phys_addr_resp_msg_v01 *)msg;
+		pr_debug("%s: Received SNS_OCMEM_PHYS_ADDR_RESP_V01\n",
+			__func__);
+		pr_debug("%s: segments_valid=%d, segments_len=%d\n", __func__,
+				msg_ptr->segments_valid, msg_ptr->segments_len);
+
+		if (msg_ptr->segments_valid) {
+			sns_ctl.mem_segments_size = msg_ptr->segments_len;
+			memcpy(sns_ctl.mem_segments, msg_ptr->segments,
+				sizeof(struct sns_mem_segment_s_v01) *
+				msg_ptr->segments_len);
+
+			sns_ctl.sns_ocmem_status |= DSPS_PHYS_ADDR_SET;
+		} else {
+			pr_err("%s: Received invalid segment list\n", __func__);
+		}
+	} else if (hdr->msg_id == SNS_OCMEM_HAS_CLIENT_IND_V01  &&
+		   hdr->msg_type == SNS_OCMEM_MSG_TYPE_IND) {
+		struct sns_ocmem_has_client_ind_msg_v01 *msg_ptr =
+				(struct sns_ocmem_has_client_ind_msg_v01 *)msg;
+
+		pr_debug("%s: Received SNS_OCMEM_HAS_CLIENT_IND_V01\n",
+			__func__);
+		pr_debug("%s: ADSP has %i client(s)\n", __func__,
+			msg_ptr->num_clients);
+		if (msg_ptr->num_clients > 0) {
+			sns_ctl.sns_ocmem_status |= DSPS_HAS_CLIENT;
+			sns_ctl.sns_ocmem_status &= ~DSPS_HAS_NO_CLIENT;
+		} else {
+			sns_ctl.sns_ocmem_status |= DSPS_HAS_NO_CLIENT;
+			sns_ctl.sns_ocmem_status &= ~DSPS_HAS_CLIENT;
+		}
+	} else if (hdr->msg_id == SNS_OCMEM_BW_VOTE_RESP_V01 &&
+		   hdr->msg_type == SNS_OCMEM_MSG_TYPE_RESP) {
+		/* no need to handle this response msg, just return */
+		pr_debug("%s: Received SNS_OCMEM_BW_VOTE_RESP_V01\n", __func__);
+		spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+		return;
+	} else if (hdr->msg_id == SNS_OCMEM_BW_VOTE_IND_V01 &&
+		   hdr->msg_type == SNS_OCMEM_MSG_TYPE_IND) {
+		struct sns_ocmem_bw_vote_ind_msg_v01 *msg_ptr =
+			(struct sns_ocmem_bw_vote_ind_msg_v01 *)msg;
+		pr_debug("%s: Received BW_VOTE_IND_V01, is_vote_on=%d\n",
+						__func__, msg_ptr->is_vote_on);
+
+		if (msg_ptr->is_vote_on) {
+			sns_ctl.sns_ocmem_status |= DSPS_BW_VOTE_ON;
+			sns_ctl.sns_ocmem_status &= ~DSPS_BW_VOTE_OFF;
+		} else {
+			sns_ctl.sns_ocmem_status |= DSPS_BW_VOTE_OFF;
+			sns_ctl.sns_ocmem_status &= ~DSPS_BW_VOTE_ON;
+		}
+	} else {
+		pr_err("%s: Unknown message type received. id: %i; type: %i\n",
+					__func__, hdr->msg_id, hdr->msg_type);
+	}
+
+	pr_debug("%s: sns_ocmem_status: 0x%x\n",
+		__func__, sns_ctl.sns_ocmem_status);
+
+	spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+
+	wake_up(&sns_ctl.sns_wait);
+}
+
+/**
+ * All SMD notifications and messages from Sensors on ADSP are
+ * received by this function
+ *
+ * */
+
+void sns_ocmem_smd_notify_data(void *data, unsigned int event)
+{
+	pr_debug("%s:\n", __func__);
+
+	if (event == SMD_EVENT_DATA) {
+		int len;
+		pr_debug("%s: Received SMD event Data\n", __func__);
+		len = smd_read_avail(sns_ctl.smd_ch);
+		pr_debug("%s: len=%d\n", __func__, len);
+		if (len > 0) {
+			data = kzalloc(SMD_BUF_SIZE, GFP_ATOMIC);
+			if (data == NULL) {
+				pr_err("%s: malloc failed", __func__);
+				return;
+			}
+
+			len = smd_read_from_cb(sns_ctl.smd_ch,
+						data, SMD_BUF_SIZE);
+			if (len > 0) {
+				sns_ocmem_smd_process(
+					(struct sns_ocmem_hdr_s *) data,
+					(void *)((char *)data +
+					sizeof(struct sns_ocmem_hdr_s)));
+			} else {
+				pr_err("Failed to read event from smd %i", len);
+			}
+			kfree(data);
+		} else if (len < 0) {
+			pr_err("Failed to read event from smd %i", len);
+		}
+	} else if (event == SMD_EVENT_OPEN) {
+		pr_debug("%s: Received SMD event Open\n", __func__);
+	} else if (event == SMD_EVENT_CLOSE) {
+		pr_debug("%s: Received SMD event Close\n", __func__);
+	}
+}
+
+static bool sns_ocmem_is_status_set(uint32_t sns_ocmem_status)
+{
+	unsigned long flags;
+	bool is_set;
+	pr_debug("%s: status=0x%x\n", __func__, sns_ocmem_status);
+
+	spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+	is_set = sns_ctl.sns_ocmem_status & sns_ocmem_status;
+	spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+	pr_debug("%s: is_set=%d\n", __func__, is_set);
+	return is_set;
+}
+
+/**
+ * Wait for a response from ADSP or OCMEM Driver, timeout if necessary
+ *
+ * @param sns_ocmem_status Status flags to wait for.
+ * @param timeout_sec Seconds to wait before timeout
+ * @param timeout_nsec Nanoseconds to wait.  Total timeout = nsec + sec
+ *
+ * @return 0 If any status flag is set at any time prior to a timeout.
+ *	0 if success or timedout ; <0 for failures
+ *
+ */
+static int sns_ocmem_wait(uint32_t sns_ocmem_status,
+			  uint32_t timeout_ms)
+{
+	int err;
+	pr_debug("%s: status=0x%x, timeout_ms=%d\n", __func__,
+						sns_ocmem_status, timeout_ms);
+	if (timeout_ms) {
+		err = wait_event_interruptible_timeout(sns_ctl.sns_wait,
+			sns_ocmem_is_status_set(sns_ocmem_status),
+			msecs_to_jiffies(timeout_ms));
+
+		if (err == 0)
+			pr_err("%s: interruptible_timeout timeout err=%i\n",
+							__func__, err);
+		else if (err < 0)
+			pr_err("%s: interruptible_timeout failed err=%i\n",
+							__func__, err);
+	} else { /* no timeout */
+		err = wait_event_interruptible(sns_ctl.sns_wait,
+			sns_ocmem_is_status_set(sns_ocmem_status));
+		if (err < 0)
+			pr_err("%s: wait_event_interruptible failed err=%i\n",
+						__func__, err);
+	}
+
+	return err;
+}
+
+/**
+ * Sends a message to the ADSP via SMD.
+ *
+ * @param hdr Specifies message type and other meta data
+ * @param msg_ptr Pointer to the message contents.
+ *                Must be freed within this function if no error is returned.
+ *
+ * @return 0 upon success; < 0 upon error
+ */
+static int
+sns_ocmem_send_msg(struct sns_ocmem_hdr_s *hdr, void const *msg_ptr)
+{
+	int rv = 0;
+	int err = 0;
+	void *temp = NULL;
+	int size = sizeof(struct sns_ocmem_hdr_s) + hdr->msg_size;
+
+	temp = kzalloc(sizeof(struct sns_ocmem_hdr_s) + hdr->msg_size,
+			GFP_KERNEL);
+	pr_debug("%s size=%d\n", __func__, size);
+
+	if (temp == NULL) {
+		pr_err("%s: allocation failure\n", __func__);
+		rv = -ENOMEM;
+	}
+
+	hdr->dst_module = SNS_OCMEM_MODULE_ADSP;
+	hdr->src_module = SNS_OCMEM_MODULE_KERNEL;
+
+	memcpy(temp, hdr, sizeof(struct sns_ocmem_hdr_s));
+	memcpy((char *)temp + sizeof(struct sns_ocmem_hdr_s),
+		msg_ptr, hdr->msg_size);
+	pr_debug("%s: send msg type: %i size: %i id: %i dst: %i src: %i\n",
+				__func__, hdr->msg_type, hdr->msg_size,
+				hdr->msg_id, hdr->dst_module, hdr->src_module);
+
+	if (hdr == NULL) {
+		pr_err("%s: NULL message header\n", __func__);
+		rv = -EINVAL;
+	} else {
+		if (sns_ctl.smd_ch == NULL) {
+			pr_err("%s: null smd_ch\n", __func__);
+			rv = -EINVAL;
+		}
+		err = smd_write(sns_ctl.smd_ch, temp, size);
+		if (err < 0) {
+			pr_err("%s: smd_write failed %i\n", __func__, err);
+			rv = -ECOMM;
+		} else {
+			pr_debug("%s smd_write successful ret=%d\n",
+				__func__, err);
+		}
+	}
+
+	kfree(temp);
+
+	return rv;
+}
+
+/**
+ *  Load ADSP Firmware.
+ */
+
+static int sns_load_adsp(void)
+{
+	pr_debug("%s.\n", __func__);
+
+	sns_ctl.pil = subsystem_get("adsp");
+	if (IS_ERR(sns_ctl.pil)) {
+		pr_err("%s: fail to load ADSP firmware\n", __func__);
+		return -ENODEV;
+	}
+
+	pr_debug("%s: Q6/ADSP image is loaded\n", __func__);
+
+	return 0;
+}
+
+static int sns_ocmem_platform_data_populate(struct platform_device *pdev)
+{
+	int ret;
+	struct msm_bus_scale_pdata *sns_ocmem_bus_scale_pdata = NULL;
+	struct msm_bus_vectors *sns_ocmem_bus_vectors = NULL;
+	struct msm_bus_paths *ocmem_sns_bus_paths = NULL;
+	u32 val;
+
+	if (!pdev->dev.of_node) {
+		pr_err("%s: device tree information missing\n", __func__);
+		return -ENODEV;
+	}
+
+	sns_ocmem_bus_vectors = kzalloc(sizeof(struct msm_bus_vectors),
+					GFP_KERNEL);
+	if (!sns_ocmem_bus_vectors) {
+		dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
+		return -ENOMEM;
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node,
+				"qcom,src-id", &val);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: qcom,src-id missing in DT node\n",
+				__func__);
+		goto fail1;
+	}
+	sns_ocmem_bus_vectors->src = val;
+	ret = of_property_read_u32(pdev->dev.of_node,
+				"qcom,dst-id", &val);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: qcom,dst-id missing in DT node\n",
+				__func__);
+		goto fail1;
+	}
+	sns_ocmem_bus_vectors->dst = val;
+	ret = of_property_read_u32(pdev->dev.of_node,
+				"qcom,ab", &val);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: qcom,ab missing in DT node\n",
+					__func__);
+		goto fail1;
+	}
+	sns_ocmem_bus_vectors->ab = val;
+	ret = of_property_read_u32(pdev->dev.of_node,
+				"qcom,ib", &val);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: qcom,ib missing in DT node\n",
+					__func__);
+		goto fail1;
+	}
+	sns_ocmem_bus_vectors->ib = val;
+	ocmem_sns_bus_paths = kzalloc(sizeof(struct msm_bus_paths),
+					GFP_KERNEL);
+
+	if (!ocmem_sns_bus_paths) {
+		dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
+		goto fail1;
+	}
+	ocmem_sns_bus_paths->num_paths = 1;
+	ocmem_sns_bus_paths->vectors = sns_ocmem_bus_vectors;
+
+	sns_ocmem_bus_scale_pdata =
+			kzalloc(sizeof(struct msm_bus_scale_pdata), GFP_KERNEL);
+	if (!sns_ocmem_bus_scale_pdata) {
+		dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
+		goto fail2;
+	}
+
+	sns_ocmem_bus_scale_pdata->usecase = ocmem_sns_bus_paths;
+	sns_ocmem_bus_scale_pdata->num_usecases = 1;
+	sns_ocmem_bus_scale_pdata->name = "sensors-ocmem";
+
+	dev_set_drvdata(&pdev->dev, sns_ocmem_bus_scale_pdata);
+	return ret;
+
+fail2:
+	kfree(ocmem_sns_bus_paths);
+fail1:
+	kfree(sns_ocmem_bus_vectors);
+	return ret;
+}
+
+
+/**
+ * Initialize all sensors ocmem driver data fields and register with the
+ * ocmem driver.
+ *
+ * @return 0 upon success; < 0 upon error
+ */
+static int sns_ocmem_init(void)
+{
+	int i, err, ret;
+	struct sns_ocmem_hdr_s addr_req_hdr;
+	struct msm_bus_scale_pdata *sns_ocmem_bus_scale_pdata = NULL;
+
+	pr_debug("%s\n", __func__);
+
+	/* register from OCMEM callack */
+	sns_ctl.ocmem_handle =
+		ocmem_notifier_register(SNS_OCMEM_CLIENT_ID,
+		&sns_ctl.ocmem_nb);
+	if (sns_ctl.ocmem_handle == NULL) {
+		pr_err("OCMEM notifier registration failed\n");
+		return -EFAULT;
+	}
+
+	/* populate platform data */
+	ret = sns_ocmem_platform_data_populate(sns_ctl.pdev);
+	if (ret) {
+		dev_err(&sns_ctl.pdev->dev,
+			"%s: failed to populate platform data, rc = %d\n",
+			__func__, ret);
+		return -ENODEV;
+	}
+	sns_ocmem_bus_scale_pdata = dev_get_drvdata(&sns_ctl.pdev->dev);
+
+	sns_ctl.sns_ocmem_bus_client =
+		msm_bus_scale_register_client(sns_ocmem_bus_scale_pdata);
+
+	if (!sns_ctl.sns_ocmem_bus_client) {
+		pr_err("%s: msm_bus_scale_register_client() failed\n",
+			__func__);
+		return -EFAULT;
+	}
+
+	/* load ADSP first */
+	if (sns_load_adsp() != 0) {
+		pr_err("%s: sns_load_adsp failed\n", __func__);
+		return -EFAULT;
+	}
+
+	/* wait before open SMD channel from kernel to ensure
+	channel has been openned already from ADSP side */
+	pr_debug("%s: sleep for 1000 ms\n", __func__);
+	msleep(1000);
+
+	err = smd_named_open_on_edge(SNS_OCMEM_SMD_CHANNEL,
+					SMD_APPS_QDSP,
+					&sns_ctl.smd_ch,
+					NULL,
+					sns_ocmem_smd_notify_data);
+	if (err != 0) {
+		pr_err("%s: smd_named_open_on_edge failed %i\n", __func__, err);
+		return -EFAULT;
+	}
+
+	pr_debug("%s: SMD channel openned successfuly!\n", __func__);
+	/* wait for the channel ready before writing data */
+	pr_debug("%s: sleep for 1000 ms\n", __func__);
+	msleep(1000);
+	pr_debug("%s sending PHYS_ADDR_REQ\n", __func__);
+	addr_req_hdr.msg_id = SNS_OCMEM_PHYS_ADDR_REQ_V01;
+	addr_req_hdr.msg_type = SNS_OCMEM_MSG_TYPE_REQ;
+	addr_req_hdr.msg_size = 0;
+
+	err = sns_ocmem_send_msg(&addr_req_hdr, NULL);
+	if (err != 0) {
+		pr_err("%s: sns_ocmem_send_msg failed %i\n", __func__, err);
+		return -ECOMM;
+	}
+
+	err = sns_ocmem_wait(DSPS_PHYS_ADDR_SET, 0);
+	if (err != 0) {
+		pr_err("%s: sns_ocmem_wait failed %i\n", __func__, err);
+		return -EFAULT;
+	}
+
+	sns_ctl.map_list.num_chunks = sns_ctl.mem_segments_size;
+	for (i = 0; i < sns_ctl.mem_segments_size; i++) {
+		sns_ctl.map_list.chunks[i].ro =
+			sns_ctl.mem_segments[i].type == 1 ? true : false;
+		sns_ctl.map_list.chunks[i].ddr_paddr =
+			sns_ctl.mem_segments[i].start_address;
+		sns_ctl.map_list.chunks[i].size =
+			sns_ctl.mem_segments[i].size;
+
+		pr_debug("%s: chunks[%d]: ro=%d, ddr_paddr=0x%lx, size=%li",
+				__func__, i,
+				sns_ctl.map_list.chunks[i].ro,
+				sns_ctl.map_list.chunks[i].ddr_paddr,
+				sns_ctl.map_list.chunks[i].size);
+	}
+
+	return 0;
+}
+
+/**
+ *  Unmaps memory in ocmem back to DDR, indicates to the ADSP its completion,
+ *  and waits for it to finish removing its bandwidth vote.
+ *
+ */
+static void sns_ocmem_unmap(void)
+{
+	unsigned long flags;
+	int err = 0;
+	pr_debug("%s\n", __func__);
+
+	ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+				sns_ctl.buf, OCMEM_ON);
+
+	spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+	sns_ctl.sns_ocmem_status &= (~SNS_OCMEM_UNMAP_FAIL &
+					~SNS_OCMEM_UNMAP_DONE);
+	spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+
+	err = ocmem_unmap(SNS_OCMEM_CLIENT_ID,
+				sns_ctl.buf,
+				&sns_ctl.map_list);
+
+	if (err != 0) {
+		pr_err("ocmem_unmap failed %i\n", err);
+	} else {
+		err = sns_ocmem_wait(SNS_OCMEM_UNMAP_DONE |
+					SNS_OCMEM_UNMAP_FAIL, 0);
+
+		if (err == 0) {
+			if (sns_ocmem_is_status_set(SNS_OCMEM_UNMAP_DONE))
+				pr_debug("%s: OCMEM_UNMAP_DONE\n", __func__);
+			else if (sns_ocmem_is_status_set(
+							SNS_OCMEM_UNMAP_FAIL)) {
+				pr_err("%s: OCMEM_UNMAP_FAIL\n", __func__);
+				BUG_ON(true);
+			} else
+				pr_err("%s: status flag not set\n", __func__);
+		} else {
+			pr_err("%s: sns_ocmem_wait failed %i\n",
+					__func__, err);
+		}
+	}
+
+	ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+				sns_ctl.buf, OCMEM_OFF);
+}
+
+/**
+ * Waits for allocation to succeed.  This may take considerable time if the device
+ * is presently in a high-power use case.
+ *
+ * @return 0 on success; < 0 upon error
+ */
+static int sns_ocmem_wait_for_alloc(void)
+{
+	int err = 0;
+	pr_debug("%s\n", __func__);
+
+	err = sns_ocmem_wait(SNS_OCMEM_ALLOC_GROW |
+				DSPS_HAS_NO_CLIENT, 0);
+
+	if (err == 0) {
+		if (sns_ocmem_is_status_set(DSPS_HAS_NO_CLIENT)) {
+			pr_debug("%s: Lost client while waiting for GROW\n",
+				__func__);
+			ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
+			sns_ctl.buf = NULL;
+			return -EPIPE;
+		}
+	} else {
+		pr_err("sns_ocmem_wait failed %i\n", err);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/**
+ * Kicks-off the mapping of memory from DDR to ocmem.  Waits for the process
+ * to complete, then indicates so to the ADSP.
+ *
+ * @return 0: Success; < 0: Other error
+ */
+static int sns_ocmem_map(void)
+{
+	int err = 0;
+	unsigned long flags;
+	pr_debug("%s\n", __func__);
+
+	spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+	sns_ctl.sns_ocmem_status &=
+			(~SNS_OCMEM_MAP_FAIL & ~SNS_OCMEM_MAP_DONE);
+	spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+
+	/* vote for ocmem bus bandwidth */
+	err = msm_bus_scale_client_update_request(
+				sns_ctl.sns_ocmem_bus_client,
+				0);
+	if (err)
+		pr_err("%s: failed to vote for bus bandwidth\n", __func__);
+
+	err = ocmem_map(SNS_OCMEM_CLIENT_ID,
+			sns_ctl.buf,
+			&sns_ctl.map_list);
+
+	if (err != 0) {
+		pr_debug("ocmem_map failed %i\n", err);
+		ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+					sns_ctl.buf, OCMEM_OFF);
+		ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
+		sns_ctl.buf = NULL;
+	} else {
+		err = sns_ocmem_wait(SNS_OCMEM_ALLOC_SHRINK |
+					DSPS_HAS_NO_CLIENT |
+					SNS_OCMEM_MAP_DONE |
+					SNS_OCMEM_MAP_FAIL, 0);
+
+		if (err == 0) {
+			if (sns_ocmem_is_status_set(SNS_OCMEM_MAP_DONE))
+				pr_debug("%s: OCMEM mapping DONE\n", __func__);
+			else if (sns_ocmem_is_status_set(DSPS_HAS_NO_CLIENT)) {
+				pr_debug("%s: Lost client while waiting for MAP\n",
+					__func__);
+				sns_ocmem_unmap();
+				ocmem_free(SNS_OCMEM_CLIENT_ID,
+						sns_ctl.buf);
+				sns_ctl.buf = NULL;
+				err = -EPIPE;
+			} else if (sns_ocmem_is_status_set(
+						SNS_OCMEM_ALLOC_SHRINK)) {
+				pr_debug("%s: SHRINK while wait for MAP\n",
+					__func__);
+				sns_ocmem_unmap();
+				err = ocmem_shrink(SNS_OCMEM_CLIENT_ID,
+						sns_ctl.buf, 0);
+				BUG_ON(err != 0);
+				err = -EFAULT;
+			} else if (sns_ocmem_is_status_set(
+						SNS_OCMEM_MAP_FAIL)) {
+				pr_err("%s: OCMEM mapping fails\n", __func__);
+				ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+							sns_ctl.buf,
+							OCMEM_OFF);
+				ocmem_free(SNS_OCMEM_CLIENT_ID,
+						sns_ctl.buf);
+				sns_ctl.buf = NULL;
+			} else
+				pr_err("%s: status flag not set\n", __func__);
+		} else {
+			pr_err("sns_ocmem_wait failed %i\n", err);
+		}
+	}
+
+	return err;
+}
+
+/**
+ * Allocates memory in ocmem and maps to it from DDR.
+ *
+ * @return 0 upon success; <0 upon failure;
+ */
+static int sns_ocmem_alloc(void)
+{
+	int err = 0;
+	unsigned long flags;
+	pr_debug("%s\n", __func__);
+
+	if (sns_ctl.buf == NULL) {
+		spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+		sns_ctl.sns_ocmem_status &= ~SNS_OCMEM_ALLOC_GROW &
+						~SNS_OCMEM_ALLOC_SHRINK;
+		spin_unlock_irqrestore(&sns_ctl.sns_lock, flags);
+		sns_ctl.buf = ocmem_allocate_nb(SNS_OCMEM_CLIENT_ID,
+						SNS_OCMEM_SIZE);
+
+		if (sns_ctl.buf == NULL) {
+			pr_err("ocmem_allocate_nb returned NULL\n");
+			sns_ctl.ocmem_enabled = false;
+			err = -EFAULT;
+		} else if (sns_ctl.buf->len != 0 &&
+			SNS_OCMEM_SIZE > sns_ctl.buf->len) {
+			pr_err("ocmem_allocate_nb: invalid len %li, Req: %i)\n",
+				sns_ctl.buf->len, SNS_OCMEM_SIZE);
+			sns_ctl.ocmem_enabled = false;
+			err = -EFAULT;
+		}
+	}
+
+	pr_debug("%s OCMEM buf=%lx, buffer len=%li\n", __func__,
+			sns_ctl.buf->addr, sns_ctl.buf->len);
+
+	while (sns_ctl.ocmem_enabled) {
+		if (sns_ctl.buf->len == 0) {
+			pr_debug("%s: Waiting for memory allocation\n",
+				__func__);
+			err = sns_ocmem_wait_for_alloc();
+			if (err == -EPIPE) {
+				pr_debug("%s:Lost client while wait for alloc\n",
+					__func__);
+				break;
+			} else if (err != 0) {
+				pr_err("sns_ocmem_wait_for_alloc failed %i\n",
+					err);
+				break;
+			}
+		}
+
+		ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+					sns_ctl.buf,
+					OCMEM_ON);
+
+		err = sns_ocmem_map();
+
+		if (err == -EPIPE) {
+			pr_debug("%s: Lost client while waiting for mapping\n",
+				__func__);
+			break;
+		} else if (err < 0) {
+			pr_debug("%s: Mapping failed, will try again\n",
+				__func__);
+			break;
+		} else if (err == 0) {
+			pr_debug("%s: Mapping finished\n", __func__);
+			break;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * Indicate to the ADSP that unmapping has completed, and wait for the response
+ * that its bandwidth vote has been removed.
+ *
+ * @return 0 Upon success; < 0 upon error
+ */
+static int sns_ocmem_unmap_send(void)
+{
+	int err;
+	struct sns_ocmem_hdr_s msg_hdr;
+	struct sns_ocmem_bw_vote_req_msg_v01 msg;
+	pr_debug("%s\n", __func__);
+
+	memset(&msg, 0, sizeof(struct sns_ocmem_bw_vote_req_msg_v01));
+
+	msg_hdr.msg_id = SNS_OCMEM_BW_VOTE_REQ_V01;
+	msg_hdr.msg_type = SNS_OCMEM_MSG_TYPE_REQ;
+	msg_hdr.msg_size = sizeof(struct sns_ocmem_bw_vote_req_msg_v01);
+	msg.is_map = 0;
+	msg.vectors_valid = 0;
+	msg.vectors_len = 0;
+
+	pr_debug("%s: send bw_vote OFF\n", __func__);
+	err = sns_ocmem_send_msg(&msg_hdr, &msg);
+	if (err != 0) {
+		pr_err("%s: sns_ocmem_send_msg failed %i\n",
+				__func__, err);
+	} else {
+		err = sns_ocmem_wait(DSPS_BW_VOTE_OFF, 0);
+		if (err != 0)
+			pr_err("%s: sns_ocmem_wait failed %i\n", __func__, err);
+	}
+
+	return err;
+}
+
+/**
+ * Indicate to the ADSP that mapping has completed, and wait for the response
+ * that its bandwidth vote has been made.
+ *
+ * @return 0 Upon success; < 0 upon error
+ */
+static int sns_ocmem_map_send(void)
+{
+	int err;
+	struct sns_ocmem_hdr_s msg_hdr;
+	struct sns_ocmem_bw_vote_req_msg_v01 msg;
+	struct ocmem_vectors *vectors;
+	pr_debug("%s\n", __func__);
+
+	memset(&msg, 0, sizeof(struct sns_ocmem_bw_vote_req_msg_v01));
+
+	msg_hdr.msg_id = SNS_OCMEM_BW_VOTE_REQ_V01;
+	msg_hdr.msg_type = SNS_OCMEM_MSG_TYPE_REQ;
+	msg_hdr.msg_size = sizeof(struct sns_ocmem_bw_vote_req_msg_v01);
+	msg.is_map = 1;
+
+	vectors = ocmem_get_vectors(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
+	if ((vectors != NULL)) {
+		memcpy(&msg.vectors, vectors, sizeof(vectors));
+		/* TODO: set vectors_len */
+		msg.vectors_valid = true;
+		msg.vectors_len = 0;
+	}
+
+	pr_debug("%s: send bw_vote ON\n", __func__);
+	err = sns_ocmem_send_msg(&msg_hdr, &msg);
+	if (err != 0) {
+		pr_err("%s: sns_ocmem_send_msg failed %i\n", __func__, err);
+	} else {
+		err = sns_ocmem_wait(DSPS_BW_VOTE_ON |
+					SNS_OCMEM_ALLOC_SHRINK, 0);
+		if (err != 0)
+			pr_err("%s: sns_ocmem_wait failed %i\n", __func__, err);
+	}
+
+	return err;
+}
+
+/**
+ * Perform the encessary operations to clean-up OCMEM after being notified that
+ * there is no longer a client; if sensors was evicted; or if some error
+ * has occurred.
+ *
+ * @param[i] do_free Whether the memory should be freed (true) or if shrink
+ *                   should be called instead (false).
+ */
+static void sns_ocmem_evicted(bool do_free)
+{
+	int err = 0;
+	pr_debug("%s\n", __func__);
+
+	sns_ocmem_unmap();
+	if (do_free) {
+		ocmem_free(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
+		sns_ctl.buf = NULL;
+	} else {
+		err = ocmem_shrink(SNS_OCMEM_CLIENT_ID, sns_ctl.buf, 0);
+		BUG_ON(err != 0);
+	}
+
+	err = sns_ocmem_unmap_send();
+	if (err != 0)
+		pr_err("sns_ocmem_unmap_send failed %i\n", err);
+}
+
+/**
+ * After mapping has completed and the ADSP has reacted appropriately, wait
+ * for a shrink command or word from the ADSP that it no longer has a client.
+ *
+ * @return 0 If no clients; < 0 upon error;
+ */
+static int sns_ocmem_map_done(void)
+{
+	int err = 0;
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+
+	err = sns_ocmem_map_send();
+	if (err != 0) {
+		pr_err("sns_ocmem_map_send failed %i\n", err);
+		sns_ocmem_evicted(true);
+	} else {
+		ocmem_set_power_state(SNS_OCMEM_CLIENT_ID,
+					sns_ctl.buf, OCMEM_OFF);
+
+		pr_debug("%s: Waiting for shrink or 'no client' updates\n",
+			__func__);
+		err = sns_ocmem_wait(DSPS_HAS_NO_CLIENT |
+					SNS_OCMEM_ALLOC_SHRINK, 0);
+		if (err == 0) {
+			if (sns_ocmem_is_status_set(DSPS_HAS_NO_CLIENT)) {
+				pr_debug("%s: No longer have a client\n",
+					__func__);
+				sns_ocmem_evicted(true);
+			} else if (sns_ocmem_is_status_set(
+						SNS_OCMEM_ALLOC_SHRINK)) {
+				pr_debug("%s: Received SHRINK\n", __func__);
+				sns_ocmem_evicted(false);
+
+				spin_lock_irqsave(&sns_ctl.sns_lock, flags);
+				sns_ctl.sns_ocmem_status &=
+						~SNS_OCMEM_ALLOC_SHRINK;
+				spin_unlock_irqrestore(&sns_ctl.sns_lock,
+							flags);
+				err = -EFAULT;
+			}
+		} else {
+			pr_err("sns_ocmem_wait failed %i\n", err);
+		}
+	}
+
+	return err;
+}
+
+/**
+ * Main function.
+ * Initializes sensors ocmem feature, and waits for an ADSP client.
+ *
+ */
+static void sns_ocmem_main(struct work_struct *work)
+{
+	int err = 0;
+	pr_debug("%s\n", __func__);
+
+	err = sns_ocmem_init();
+	if (err != 0) {
+		pr_err("%s: sns_ocmem_init failed %i\n", __func__, err);
+		return;
+	}
+
+	while (true) {
+		pr_debug("%s: Waiting for sensor client\n", __func__);
+		if (sns_ocmem_is_status_set(DSPS_HAS_CLIENT) ||
+			!sns_ocmem_wait(DSPS_HAS_CLIENT, 0)) {
+			pr_debug("%s: DSPS_HAS_CLIENT\n", __func__);
+
+			err = sns_ocmem_alloc();
+			if (err != 0) {
+				pr_err("sns_ocmem_alloc failed %i\n", err);
+				return;
+			} else {
+				err = sns_ocmem_map_done();
+				if (err != 0) {
+					pr_err("sns_ocmem_map_done failed %i",
+						err);
+					return;
+				}
+			}
+		}
+	}
+
+	ocmem_notifier_unregister(sns_ctl.ocmem_handle,
+					&sns_ctl.ocmem_nb);
+}
+
+static int sensors_adsp_open(struct inode *ip, struct file *fp)
+{
+	int ret = 0;
+	pr_debug("%s\n", __func__);
+	return ret;
+}
+
+static int sensors_adsp_release(struct inode *inode, struct file *file)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+/**
+ * Read QTimer clock ticks and scale down to 32KHz clock as used
+ * in DSPS
+ */
+static u32 sns_read_qtimer(void)
+{
+	u64 val;
+	val = arch_counter_get_cntpct();
+	/*
+	 * To convert ticks from 19.2 Mhz clock to 32768 Hz clock:
+	 * x = (value * 32768) / 19200000
+	 * This is same as first left shift the value by 4 bits, i.e. mutiply
+	 * by 16, and then divide by 9375. The latter is preferable since
+	 * QTimer tick (value) is 56-bit, so (value * 32768) could overflow,
+	 * while (value * 16) will never do
+	 */
+	val <<= 4;
+	do_div(val, 9375);
+
+	pr_debug("%s.count=%llu\n", __func__, val);
+	return (u32)val;
+}
+
+/**
+ * IO Control - handle commands from client.
+ *
+ */
+static long sensors_adsp_ioctl(struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	int ret = 0;
+	u32 val = 0;
+	pr_debug("%s\n", __func__);
+
+	switch (cmd) {
+	case DSPS_IOCTL_READ_SLOW_TIMER:
+		val = sns_read_qtimer();
+		ret = put_user(val, (u32 __user *) arg);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * platform driver
+ *
+ */
+const struct file_operations sensors_adsp_fops = {
+	.owner = THIS_MODULE,
+	.open = sensors_adsp_open,
+	.release = sensors_adsp_release,
+	.unlocked_ioctl = sensors_adsp_ioctl,
+};
+
+static int sensors_adsp_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	pr_debug("%s.\n", __func__);
+	sns_ctl.dev_class = class_create(THIS_MODULE, DRV_NAME);
+	if (sns_ctl.dev_class == NULL) {
+		pr_err("%s: class_create fail.\n", __func__);
+		goto res_err;
+	}
+
+	ret = alloc_chrdev_region(&sns_ctl.dev_num, 0, 1, DRV_NAME);
+	if (ret) {
+		pr_err("%s: alloc_chrdev_region fail.\n", __func__);
+		goto alloc_chrdev_region_err;
+	}
+
+	sns_ctl.dev = device_create(sns_ctl.dev_class, NULL,
+				     sns_ctl.dev_num,
+				     &sns_ctl, DRV_NAME);
+	if (IS_ERR(sns_ctl.dev)) {
+		pr_err("%s: device_create fail.\n", __func__);
+		goto device_create_err;
+	}
+
+	sns_ctl.cdev = cdev_alloc();
+	if (sns_ctl.cdev == NULL) {
+		pr_err("%s: cdev_alloc fail.\n", __func__);
+		goto cdev_alloc_err;
+	}
+	cdev_init(sns_ctl.cdev, &sensors_adsp_fops);
+	sns_ctl.cdev->owner = THIS_MODULE;
+
+	ret = cdev_add(sns_ctl.cdev, sns_ctl.dev_num, 1);
+	if (ret) {
+		pr_err("%s: cdev_add fail.\n", __func__);
+		goto cdev_add_err;
+	}
+
+	sns_ctl.sns_workqueue =
+			alloc_workqueue("sns_ocmem", WQ_NON_REENTRANT, 0);
+	if (!sns_ctl.sns_workqueue) {
+		pr_err("%s: Failed to create work queue\n",
+			__func__);
+		goto cdev_add_err;
+	}
+
+	init_waitqueue_head(&sns_ctl.sns_wait);
+	spin_lock_init(&sns_ctl.sns_lock);
+
+	sns_ctl.ocmem_handle = NULL;
+	sns_ctl.buf = NULL;
+	sns_ctl.sns_ocmem_status = 0;
+	sns_ctl.ocmem_enabled = true;
+	sns_ctl.ocmem_nb.notifier_call = sns_ocmem_drv_cb;
+	sns_ctl.smd_ch = NULL;
+	sns_ctl.pdev = pdev;
+
+	INIT_WORK(&sns_ctl.sns_work, sns_ocmem_main);
+	queue_work(sns_ctl.sns_workqueue, &sns_ctl.sns_work);
+
+	return 0;
+
+cdev_add_err:
+	kfree(sns_ctl.cdev);
+cdev_alloc_err:
+	device_destroy(sns_ctl.dev_class, sns_ctl.dev_num);
+device_create_err:
+	unregister_chrdev_region(sns_ctl.dev_num, 1);
+alloc_chrdev_region_err:
+	class_destroy(sns_ctl.dev_class);
+res_err:
+	return -ENODEV;
+}
+
+static int sensors_adsp_remove(struct platform_device *pdev)
+{
+	struct msm_bus_scale_pdata *sns_ocmem_bus_scale_pdata = NULL;
+	pr_debug("%s.\n", __func__);
+
+	sns_ocmem_bus_scale_pdata = (struct msm_bus_scale_pdata *)
+					dev_get_drvdata(&pdev->dev);
+
+	kfree(sns_ocmem_bus_scale_pdata->usecase->vectors);
+	kfree(sns_ocmem_bus_scale_pdata->usecase);
+	kfree(sns_ocmem_bus_scale_pdata);
+
+	ocmem_notifier_unregister(sns_ctl.ocmem_handle,
+					&sns_ctl.ocmem_nb);
+	destroy_workqueue(sns_ctl.sns_workqueue);
+
+	cdev_del(sns_ctl.cdev);
+	kfree(sns_ctl.cdev);
+	sns_ctl.cdev = NULL;
+	device_destroy(sns_ctl.dev_class, sns_ctl.dev_num);
+	unregister_chrdev_region(sns_ctl.dev_num, 1);
+	class_destroy(sns_ctl.dev_class);
+
+	return 0;
+}
+
+static const struct of_device_id msm_adsp_sensors_dt_match[] = {
+	{.compatible = "qcom,msm-adsp-sensors"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, msm_adsp_sensors_dt_match);
+
+
+static struct platform_driver sensors_adsp_driver = {
+	.driver = {
+		.name = "sensors-adsp",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_adsp_sensors_dt_match,
+	},
+	.probe = sensors_adsp_probe,
+	.remove = sensors_adsp_remove,
+};
+
+/**
+ * Module Init.
+ */
+static int sensors_adsp_init(void)
+{
+	int rc;
+	pr_debug("%s.\n", __func__);
+	pr_debug("%s driver version %s.\n", DRV_NAME, DRV_VERSION);
+
+	rc = platform_driver_register(&sensors_adsp_driver);
+
+	if (rc) {
+		pr_err("%s: Failed to register sensors adsp driver\n",
+			__func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Module Exit.
+ */
+static void sensors_adsp_exit(void)
+{
+	pr_debug("%s.\n", __func__);
+	platform_driver_unregister(&sensors_adsp_driver);
+}
+
+module_init(sensors_adsp_init);
+module_exit(sensors_adsp_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Sensors ADSP driver");
diff --git a/arch/arm/mach-msm/smcmod.c b/arch/arm/mach-msm/smcmod.c
new file mode 100644
index 0000000..705bab5
--- /dev/null
+++ b/arch/arm/mach-msm/smcmod.c
@@ -0,0 +1,727 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define KMSG_COMPONENT "SMCMOD"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/printk.h>
+#include <linux/msm_ion.h>
+#include <asm/smcmod.h>
+#include <mach/scm.h>
+
+static DEFINE_MUTEX(ioctl_lock);
+
+#define SMCMOD_SVC_DEFAULT (0)
+#define SMCMOD_SVC_CRYPTO (1)
+#define SMCMOD_CRYPTO_CMD_CIPHER (1)
+#define SMCMOD_CRYPTO_CMD_MSG_DIGEST_FIXED (2)
+#define SMCMOD_CRYPTO_CMD_MSG_DIGEST (3)
+
+/**
+ * struct smcmod_cipher_scm_req - structure for sending the cipher cmd to
+ * scm_call.
+ *
+ * @algorithm - specifies cipher algorithm
+ * @operation - specifies encryption or decryption.
+ * @mode - specifies cipher mode.
+ * @key_phys_addr - physical address for key buffer.
+ * @key_size - key size in bytes.
+ * @plain_text_phys_addr - physical address for plain text buffer.
+ * @plain_text_size - size of plain text in bytes.
+ * @cipher_text_phys_addr - physical address for cipher text buffer.
+ * @cipher_text_size - cipher text size in bytes.
+ * @init_vector_phys_addr - physical address for init vector buffer.
+ * @init_vector_size - size of initialization vector in bytes.
+ */
+struct smcmod_cipher_scm_req {
+	uint32_t algorithm;
+	uint32_t operation;
+	uint32_t mode;
+	uint32_t key_phys_addr;
+	uint32_t key_size;
+	uint32_t plain_text_phys_addr;
+	uint32_t plain_text_size;
+	uint32_t cipher_text_phys_addr;
+	uint32_t cipher_text_size;
+	uint32_t init_vector_phys_addr;
+	uint32_t init_vector_size;
+};
+
+/**
+ * struct smcmod_msg_digest_scm_req - structure for sending message digest
+ * to scm_call.
+ *
+ * @algorithm - specifies the cipher algorithm.
+ * @key_phys_addr - physical address of key buffer.
+ * @key_size - hash key size in bytes.
+ * @input_phys_addr - physical address of input buffer.
+ * @input_size - input data size in bytes.
+ * @output_phys_addr - physical address of output buffer.
+ * @output_size - size of output buffer in bytes.
+ * @verify - indicates whether to verify the hash value.
+ */
+struct smcmod_msg_digest_scm_req {
+	uint32_t algorithm;
+	uint32_t key_phys_addr;
+	uint32_t key_size;
+	uint32_t input_phys_addr;
+	uint32_t input_size;
+	uint32_t output_phys_addr;
+	uint32_t output_size;
+	uint8_t verify;
+} __packed;
+
+static void smcmod_inv_range(unsigned long start, unsigned long end)
+{
+	uint32_t cacheline_size;
+	uint32_t ctr;
+
+	/* get cache line size */
+	asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
+	cacheline_size =  4 << ((ctr >> 16) & 0xf);
+
+	/* invalidate the range */
+	start = round_down(start, cacheline_size);
+	end = round_up(end, cacheline_size);
+	while (start < end) {
+		asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
+			 : "memory");
+		start += cacheline_size;
+	}
+	mb();
+	isb();
+}
+
+static int smcmod_ion_fd_to_phys(int32_t fd, struct ion_client *ion_clientp,
+	struct ion_handle **ion_handlep, uint32_t *phys_addrp, size_t *sizep)
+{
+	int ret = 0;
+
+	/* sanity check args */
+	if ((fd < 0) || IS_ERR_OR_NULL(ion_clientp) ||
+		IS_ERR_OR_NULL(ion_handlep) || IS_ERR_OR_NULL(phys_addrp) ||
+		IS_ERR_OR_NULL(sizep))
+		return -EINVAL;
+
+	/* import the buffer fd */
+	*ion_handlep = ion_import_dma_buf(ion_clientp, fd);
+
+	/* sanity check the handle */
+	if (IS_ERR_OR_NULL(*ion_handlep))
+		return -EINVAL;
+
+	/* get the physical address */
+	ret = ion_phys(ion_clientp, *ion_handlep, (ion_phys_addr_t *)phys_addrp,
+		sizep);
+
+	return ret;
+}
+
+static int smcmod_send_buf_cmd(struct smcmod_buf_req *reqp)
+{
+	int ret = 0;
+	struct ion_client *ion_clientp = NULL;
+	struct ion_handle *ion_cmd_handlep = NULL;
+	struct ion_handle *ion_resp_handlep = NULL;
+	void *cmd_vaddrp = NULL;
+	void *resp_vaddrp = NULL;
+	unsigned long cmd_buf_size = 0;
+	unsigned long resp_buf_size = 0;
+
+	/* sanity check the argument */
+	if (IS_ERR_OR_NULL(reqp))
+		return -EINVAL;
+
+	/* sanity check the fds */
+	if (reqp->ion_cmd_fd < 0)
+		return -EINVAL;
+
+	/* create an ion client */
+	ion_clientp = msm_ion_client_create(UINT_MAX, "smcmod");
+
+	/* check for errors */
+	if (IS_ERR_OR_NULL(ion_clientp))
+		return -EINVAL;
+
+	/* import the command buffer fd */
+	ion_cmd_handlep = ion_import_dma_buf(ion_clientp, reqp->ion_cmd_fd);
+
+	/* sanity check the handle */
+	if (IS_ERR_OR_NULL(ion_cmd_handlep)) {
+		ret = -EINVAL;
+		goto buf_cleanup;
+	}
+
+	/* retrieve the size of the buffer */
+	if (ion_handle_get_size(ion_clientp, ion_cmd_handlep,
+		&cmd_buf_size) < 0) {
+		ret = -EINVAL;
+		goto buf_cleanup;
+	}
+
+	/* ensure that the command buffer size is not
+	 * greater than the size of the buffer.
+	 */
+	if (reqp->cmd_len > cmd_buf_size) {
+		ret = -EINVAL;
+		goto buf_cleanup;
+	}
+
+	/* map the area to get a virtual address */
+	cmd_vaddrp = ion_map_kernel(ion_clientp, ion_cmd_handlep);
+
+	/* sanity check the address */
+	if (IS_ERR_OR_NULL(cmd_vaddrp)) {
+		ret = -EINVAL;
+		goto buf_cleanup;
+	}
+
+	/* check if there is a response buffer */
+	if (reqp->ion_resp_fd >= 0) {
+		/* import the handle */
+		ion_resp_handlep =
+			ion_import_dma_buf(ion_clientp, reqp->ion_resp_fd);
+
+		/* sanity check the handle */
+		if (IS_ERR_OR_NULL(ion_resp_handlep)) {
+			ret = -EINVAL;
+			goto buf_cleanup;
+		}
+
+		/* retrieve the size of the buffer */
+		if (ion_handle_get_size(ion_clientp, ion_resp_handlep,
+			&resp_buf_size) < 0) {
+			ret = -EINVAL;
+			goto buf_cleanup;
+		}
+
+		/* ensure that the command buffer size is not
+		 * greater than the size of the buffer.
+		 */
+		if (reqp->resp_len > resp_buf_size) {
+			ret = -EINVAL;
+			goto buf_cleanup;
+		}
+
+		/* map the area to get a virtual address */
+		resp_vaddrp = ion_map_kernel(ion_clientp, ion_resp_handlep);
+
+		/* sanity check the address */
+		if (IS_ERR_OR_NULL(resp_vaddrp)) {
+			ret = -EINVAL;
+			goto buf_cleanup;
+		}
+	}
+
+	/* call scm function to switch to secure world */
+	reqp->return_val = scm_call(reqp->service_id, reqp->command_id,
+		cmd_vaddrp, reqp->cmd_len, resp_vaddrp, reqp->resp_len);
+
+buf_cleanup:
+	/* if the client and handle(s) are valid, free them */
+	if (!IS_ERR_OR_NULL(ion_clientp)) {
+		if (!IS_ERR_OR_NULL(ion_cmd_handlep)) {
+			if (!IS_ERR_OR_NULL(cmd_vaddrp))
+				ion_unmap_kernel(ion_clientp, ion_cmd_handlep);
+			ion_free(ion_clientp, ion_cmd_handlep);
+		}
+
+		if (!IS_ERR_OR_NULL(ion_resp_handlep)) {
+			if (!IS_ERR_OR_NULL(resp_vaddrp))
+				ion_unmap_kernel(ion_clientp, ion_resp_handlep);
+			ion_free(ion_clientp, ion_resp_handlep);
+		}
+
+		ion_client_destroy(ion_clientp);
+	}
+
+	return ret;
+}
+
+static int smcmod_send_cipher_cmd(struct smcmod_cipher_req *reqp)
+{
+	int ret = 0;
+	struct smcmod_cipher_scm_req scm_req;
+	struct ion_client *ion_clientp = NULL;
+	struct ion_handle *ion_key_handlep = NULL;
+	struct ion_handle *ion_plain_handlep = NULL;
+	struct ion_handle *ion_cipher_handlep = NULL;
+	struct ion_handle *ion_iv_handlep = NULL;
+	size_t size = 0;
+
+	if (IS_ERR_OR_NULL(reqp))
+		return -EINVAL;
+
+	/* sanity check the fds */
+	if ((reqp->ion_plain_text_fd < 0) ||
+		(reqp->ion_cipher_text_fd < 0) ||
+		(reqp->ion_init_vector_fd < 0))
+		return -EINVAL;
+
+	/* create an ion client */
+	ion_clientp = msm_ion_client_create(UINT_MAX, "smcmod");
+
+	/* check for errors */
+	if (IS_ERR_OR_NULL(ion_clientp))
+		return -EINVAL;
+
+	/* fill in the scm request structure */
+	scm_req.algorithm = reqp->algorithm;
+	scm_req.operation = reqp->operation;
+	scm_req.mode = reqp->mode;
+	scm_req.key_phys_addr = 0;
+	scm_req.key_size = reqp->key_size;
+	scm_req.plain_text_size = reqp->plain_text_size;
+	scm_req.cipher_text_size = reqp->cipher_text_size;
+	scm_req.init_vector_size = reqp->init_vector_size;
+
+	if (!reqp->key_is_null) {
+		/* import the key buffer and get the physical address */
+		ret = smcmod_ion_fd_to_phys(reqp->ion_key_fd, ion_clientp,
+			&ion_key_handlep, &scm_req.key_phys_addr, &size);
+		if (ret < 0)
+			goto buf_cleanup;
+
+		/* ensure that the key size is not
+		 * greater than the size of the buffer.
+		 */
+		if (reqp->key_size > size) {
+			ret = -EINVAL;
+			goto buf_cleanup;
+		}
+	}
+
+	/* import the plain text buffer and get the physical address */
+	ret = smcmod_ion_fd_to_phys(reqp->ion_plain_text_fd, ion_clientp,
+		&ion_plain_handlep, &scm_req.plain_text_phys_addr, &size);
+
+	if (ret < 0)
+		goto buf_cleanup;
+
+	/* ensure that the plain text size is not
+	 * greater than the size of the buffer.
+	 */
+	if (reqp->plain_text_size > size) {
+		ret = -EINVAL;
+		goto buf_cleanup;
+	}
+
+	/* import the cipher text buffer and get the physical address */
+	ret = smcmod_ion_fd_to_phys(reqp->ion_cipher_text_fd, ion_clientp,
+		&ion_cipher_handlep, &scm_req.cipher_text_phys_addr, &size);
+	if (ret < 0)
+		goto buf_cleanup;
+
+	/* ensure that the cipher text size is not
+	 * greater than the size of the buffer.
+	 */
+	if (reqp->cipher_text_size > size) {
+		ret = -EINVAL;
+		goto buf_cleanup;
+	}
+
+	/* import the init vector buffer and get the physical address */
+	ret = smcmod_ion_fd_to_phys(reqp->ion_init_vector_fd, ion_clientp,
+		&ion_iv_handlep, &scm_req.init_vector_phys_addr, &size);
+	if (ret < 0)
+		goto buf_cleanup;
+
+	/* ensure that the init vector size is not
+	 * greater than the size of the buffer.
+	 */
+	if (reqp->init_vector_size > size) {
+		ret = -EINVAL;
+		goto buf_cleanup;
+	}
+
+	/* call scm function to switch to secure world */
+	reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO,
+		SMCMOD_CRYPTO_CMD_CIPHER, &scm_req,
+		sizeof(scm_req), NULL, 0);
+
+	/* for decrypt, plain text is the output, otherwise it's cipher text */
+	if (reqp->operation) {
+		void *vaddrp = NULL;
+
+		/* map the plain text region to get the virtual address */
+		vaddrp = ion_map_kernel(ion_clientp, ion_plain_handlep);
+		if (IS_ERR_OR_NULL(vaddrp)) {
+			ret = -EINVAL;
+			goto buf_cleanup;
+		}
+
+		/* invalidate the range */
+		smcmod_inv_range((unsigned long)vaddrp,
+			(unsigned long)(vaddrp + scm_req.plain_text_size));
+
+		/* unmap the mapped area */
+		ion_unmap_kernel(ion_clientp, ion_plain_handlep);
+	} else {
+		void *vaddrp = NULL;
+
+		/* map the cipher text region to get the virtual address */
+		vaddrp = ion_map_kernel(ion_clientp, ion_cipher_handlep);
+		if (IS_ERR_OR_NULL(vaddrp)) {
+			ret = -EINVAL;
+			goto buf_cleanup;
+		}
+
+		/* invalidate the range */
+		smcmod_inv_range((unsigned long)vaddrp,
+			(unsigned long)(vaddrp + scm_req.cipher_text_size));
+
+		/* unmap the mapped area */
+		ion_unmap_kernel(ion_clientp, ion_cipher_handlep);
+	}
+
+buf_cleanup:
+	/* if the client and handles are valid, free them */
+	if (!IS_ERR_OR_NULL(ion_clientp)) {
+		if (!IS_ERR_OR_NULL(ion_key_handlep))
+			ion_free(ion_clientp, ion_key_handlep);
+
+		if (!IS_ERR_OR_NULL(ion_plain_handlep))
+			ion_free(ion_clientp, ion_plain_handlep);
+
+		if (!IS_ERR_OR_NULL(ion_cipher_handlep))
+			ion_free(ion_clientp, ion_cipher_handlep);
+
+		if (!IS_ERR_OR_NULL(ion_iv_handlep))
+			ion_free(ion_clientp, ion_iv_handlep);
+
+		ion_client_destroy(ion_clientp);
+	}
+
+	return ret;
+}
+static int smcmod_send_msg_digest_cmd(struct smcmod_msg_digest_req *reqp)
+{
+	int ret = 0;
+	struct smcmod_msg_digest_scm_req scm_req;
+	struct ion_client *ion_clientp = NULL;
+	struct ion_handle *ion_key_handlep = NULL;
+	struct ion_handle *ion_input_handlep = NULL;
+	struct ion_handle *ion_output_handlep = NULL;
+	size_t size = 0;
+	void *vaddrp = NULL;
+
+	if (IS_ERR_OR_NULL(reqp))
+		return -EINVAL;
+
+	/* sanity check the fds */
+	if ((reqp->ion_input_fd < 0) || (reqp->ion_output_fd < 0))
+		return -EINVAL;
+
+	/* create an ion client */
+	ion_clientp = msm_ion_client_create(UINT_MAX, "smcmod");
+
+	/* check for errors */
+	if (IS_ERR_OR_NULL(ion_clientp))
+		return -EINVAL;
+
+	/* fill in the scm request structure */
+	scm_req.algorithm = reqp->algorithm;
+	scm_req.key_phys_addr = 0;
+	scm_req.key_size = reqp->key_size;
+	scm_req.input_size = reqp->input_size;
+	scm_req.output_size = reqp->output_size;
+	scm_req.verify = 0;
+
+	if (!reqp->key_is_null) {
+		/* import the key buffer and get the physical address */
+		ret = smcmod_ion_fd_to_phys(reqp->ion_key_fd, ion_clientp,
+			&ion_key_handlep, &scm_req.key_phys_addr, &size);
+		if (ret < 0)
+			goto buf_cleanup;
+
+		/* ensure that the key size is not
+		 * greater than the size of the buffer.
+		 */
+		if (reqp->key_size > size) {
+			ret = -EINVAL;
+			goto buf_cleanup;
+		}
+	}
+
+	/* import the input buffer and get the physical address */
+	ret = smcmod_ion_fd_to_phys(reqp->ion_input_fd, ion_clientp,
+		&ion_input_handlep, &scm_req.input_phys_addr, &size);
+	if (ret < 0)
+		goto buf_cleanup;
+
+	/* ensure that the input size is not
+	 * greater than the size of the buffer.
+	 */
+	if (reqp->input_size > size) {
+		ret = -EINVAL;
+		goto buf_cleanup;
+	}
+
+	/* import the output buffer and get the physical address */
+	ret = smcmod_ion_fd_to_phys(reqp->ion_output_fd, ion_clientp,
+		&ion_output_handlep, &scm_req.output_phys_addr, &size);
+	if (ret < 0)
+		goto buf_cleanup;
+
+	/* ensure that the output size is not
+	 * greater than the size of the buffer.
+	 */
+	if (reqp->output_size > size) {
+		ret = -EINVAL;
+		goto buf_cleanup;
+	}
+
+	/* call scm function to switch to secure world */
+	if (reqp->fixed_block)
+		reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO,
+			SMCMOD_CRYPTO_CMD_MSG_DIGEST_FIXED,
+			&scm_req,
+			sizeof(scm_req),
+			NULL, 0);
+	else
+		reqp->return_val = scm_call(SMCMOD_SVC_CRYPTO,
+			SMCMOD_CRYPTO_CMD_MSG_DIGEST,
+			&scm_req,
+			sizeof(scm_req),
+			NULL, 0);
+
+
+	/* map the output region to get the virtual address */
+	vaddrp = ion_map_kernel(ion_clientp, ion_output_handlep);
+	if (IS_ERR_OR_NULL(vaddrp)) {
+		ret = -EINVAL;
+		goto buf_cleanup;
+	}
+
+	/* invalidate the range */
+	smcmod_inv_range((unsigned long)vaddrp,
+		(unsigned long)(vaddrp + scm_req.output_size));
+
+	/* unmap the mapped area */
+	ion_unmap_kernel(ion_clientp, ion_output_handlep);
+
+buf_cleanup:
+	/* if the client and handles are valid, free them */
+	if (!IS_ERR_OR_NULL(ion_clientp)) {
+		if (!IS_ERR_OR_NULL(ion_key_handlep))
+			ion_free(ion_clientp, ion_key_handlep);
+
+		if (!IS_ERR_OR_NULL(ion_input_handlep))
+			ion_free(ion_clientp, ion_input_handlep);
+
+		if (!IS_ERR_OR_NULL(ion_output_handlep))
+			ion_free(ion_clientp, ion_output_handlep);
+
+		ion_client_destroy(ion_clientp);
+	}
+
+	return ret;
+}
+
+static long smcmod_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int ret = 0;
+
+	/* sanity check */
+	if (!argp)
+		return -EINVAL;
+
+	/*
+	 * The SMC instruction should only be initiated by one process
+	 * at a time, hence the critical section here. Note that this
+	 * does not prevent user space from modifying the
+	 * allocated buffer contents.  Extra steps are needed to
+	 * prevent that from happening.
+	 */
+	mutex_lock(&ioctl_lock);
+
+	switch (cmd) {
+	case SMCMOD_IOCTL_SEND_REG_CMD:
+		{
+			struct smcmod_reg_req req;
+
+			/* copy struct from user */
+			if (copy_from_user((void *)&req, argp, sizeof(req))) {
+				ret = -EFAULT;
+				goto cleanup;
+			}
+
+			/* call the correct scm function to switch to secure
+			 * world
+			 */
+			if (req.num_args == 1) {
+				req.return_val =
+					scm_call_atomic1(req.service_id,
+					req.command_id, req.args[0]);
+			} else if (req.num_args == 2) {
+				req.return_val =
+					scm_call_atomic2(req.service_id,
+					req.command_id, req.args[0],
+					req.args[1]);
+			} else {
+				ret = -EINVAL;
+				goto cleanup;
+			}
+
+			/* copy result back to user */
+			if (copy_to_user(argp, (void *)&req, sizeof(req))) {
+				ret = -EFAULT;
+				goto cleanup;
+			}
+		}
+		break;
+
+	/* This is an example of how to pass buffers to/from the secure
+	 * side using the ion driver.
+	 */
+	case SMCMOD_IOCTL_SEND_BUF_CMD:
+		{
+			struct smcmod_buf_req req;
+
+			/* copy struct from user */
+			if (copy_from_user((void *)&req, argp, sizeof(req))) {
+				ret = -EFAULT;
+				goto cleanup;
+			}
+
+			/* send the command */
+			ret = smcmod_send_buf_cmd(&req);
+			if (ret < 0)
+				goto cleanup;
+
+			/* copy result back to user */
+			if (copy_to_user(argp, (void *)&req, sizeof(req))) {
+				ret = -EFAULT;
+				goto cleanup;
+			}
+		}
+		break;
+
+	case SMCMOD_IOCTL_SEND_CIPHER_CMD:
+		{
+			struct smcmod_cipher_req req;
+
+			/* copy struct from user */
+			if (copy_from_user((void *)&req, argp, sizeof(req))) {
+				ret = -EFAULT;
+				goto cleanup;
+			}
+
+			ret = smcmod_send_cipher_cmd(&req);
+			if (ret < 0)
+				goto cleanup;
+
+			/* copy result back to user */
+			if (copy_to_user(argp, (void *)&req, sizeof(req))) {
+				ret = -EFAULT;
+				goto cleanup;
+			}
+		}
+		break;
+
+	case SMCMOD_IOCTL_SEND_MSG_DIGEST_CMD:
+		{
+			struct smcmod_msg_digest_req req;
+
+			/* copy struct from user */
+			if (copy_from_user((void *)&req, argp, sizeof(req))) {
+				ret = -EFAULT;
+				goto cleanup;
+			}
+
+			ret = smcmod_send_msg_digest_cmd(&req);
+			if (ret < 0)
+				goto cleanup;
+
+			/* copy result back to user */
+			if (copy_to_user(argp, (void *)&req, sizeof(req))) {
+				ret = -EFAULT;
+				goto cleanup;
+			}
+		}
+		break;
+
+	case SMCMOD_IOCTL_GET_VERSION:
+		{
+			uint32_t req;
+
+			/* call scm function to switch to secure world */
+			req = scm_get_version();
+
+			/* copy result back to user */
+			if (copy_to_user(argp, (void *)&req, sizeof(req))) {
+				ret = -EFAULT;
+				goto cleanup;
+			}
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+cleanup:
+	mutex_unlock(&ioctl_lock);
+	return ret;
+}
+
+static int smcmod_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int smcmod_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations smcmod_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = smcmod_ioctl,
+	.open = smcmod_open,
+	.release = smcmod_release,
+};
+
+static struct miscdevice smcmod_misc_dev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = SMCMOD_DEV,
+	.fops = &smcmod_fops
+};
+
+static int __init smcmod_init(void)
+{
+	return misc_register(&smcmod_misc_dev);
+}
+
+static void __exit smcmod_exit(void)
+{
+	misc_deregister(&smcmod_misc_dev);
+}
+
+MODULE_DESCRIPTION("Qualcomm SMC Module");
+MODULE_LICENSE("GPL v2");
+
+module_init(smcmod_init);
+module_exit(smcmod_exit);
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index a353ce0..01f6787 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -130,7 +130,14 @@
 int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm);
 int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel);
 unsigned int msm_spm_get_vdd(unsigned int cpu);
+#if defined(CONFIG_MSM_SPM_V2)
 int msm_spm_turn_on_cpu_rail(unsigned int cpu);
+#else
+static inline int msm_spm_turn_on_cpu_rail(unsigned int cpu)
+{
+	return -ENOSYS;
+}
+#endif
 
 /* Internal low power management specific functions */
 
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index b378d3b..e77a7ac 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -374,7 +374,7 @@
 	};
 
 	struct mode_of of_l2_modes[] = {
-		{"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 1},
+		{"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 0},
 		{"qcom,saw2-spm-cmd-gdhs", MSM_SPM_L2_MODE_GDHS, 1},
 		{"qcom,saw2-spm-cmd-pc", MSM_SPM_L2_MODE_POWER_COLLAPSE, 1},
 	};
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 3af066d..e360906 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;
@@ -1022,7 +1035,8 @@
 
 	if (cpu_is_msm7x01() || cpu_is_msm7x25() || cpu_is_msm7x27() ||
 	    cpu_is_msm7x25a() || cpu_is_msm7x27a() || cpu_is_msm7x25aa() ||
-	    cpu_is_msm7x27aa() || cpu_is_msm8625() || cpu_is_msm7x25ab()) {
+	    cpu_is_msm7x27aa() || cpu_is_msm8625() || cpu_is_msm7x25ab() ||
+	    cpu_is_msm8625q()) {
 		dgt->shift = MSM_DGT_SHIFT;
 		dgt->freq = 19200000 >> MSM_DGT_SHIFT;
 		dgt->clockevent.shift = 32 + MSM_DGT_SHIFT;
@@ -1032,11 +1046,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() || cpu_is_msm8625q())
+			fixup_msm8625_timer();
 	} else if (cpu_is_qsd8x50()) {
 		dgt->freq = 4800000;
 		gpt->regbase = MSM_TMR_BASE;
@@ -1124,8 +1135,8 @@
 
 		ce->irq = clock->irq;
 		if (cpu_is_msm8x60() || cpu_is_msm9615() || cpu_is_msm8625() ||
-		    soc_class_is_msm8960() || soc_class_is_apq8064() ||
-		    soc_class_is_msm8930()) {
+		    cpu_is_msm8625q() || soc_class_is_msm8960() ||
+		    soc_class_is_apq8064() || soc_class_is_msm8930()) {
 			clock->percpu_evt = alloc_percpu(struct clock_event_device *);
 			if (!clock->percpu_evt) {
 				pr_err("msm_timer_init: memory allocation "
diff --git a/block/blk-core.c b/block/blk-core.c
index 68d7158..fe1c7e0 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -297,13 +297,26 @@
  * Description:
  *    See @blk_run_queue. This variant must be called with the queue lock
  *    held and interrupts disabled.
+ *    Device driver will be notified of an urgent request
+ *    pending under the following conditions:
+ *    1. The driver and the current scheduler support urgent reques handling
+ *    2. There is an urgent request pending in the scheduler
+ *    3. There isn't already an urgent request in flight, meaning previously
+ *       notified urgent request completed (!q->notified_urgent)
  */
 void __blk_run_queue(struct request_queue *q)
 {
 	if (unlikely(blk_queue_stopped(q)))
 		return;
 
-	q->request_fn(q);
+	if (!q->notified_urgent &&
+		q->elevator->type->ops.elevator_is_urgent_fn &&
+		q->urgent_request_fn &&
+		q->elevator->type->ops.elevator_is_urgent_fn(q)) {
+		q->notified_urgent = true;
+		q->urgent_request_fn(q);
+	} else
+		q->request_fn(q);
 }
 EXPORT_SYMBOL(__blk_run_queue);
 
@@ -1070,6 +1083,50 @@
 }
 EXPORT_SYMBOL(blk_requeue_request);
 
+/**
+ * blk_reinsert_request() - Insert a request back to the scheduler
+ * @q:		request queue
+ * @rq:		request to be inserted
+ *
+ * This function inserts the request back to the scheduler as if
+ * it was never dispatched.
+ *
+ * Return: 0 on success, error code on fail
+ */
+int blk_reinsert_request(struct request_queue *q, struct request *rq)
+{
+	if (unlikely(!rq) || unlikely(!q))
+		return -EIO;
+
+	blk_delete_timer(rq);
+	blk_clear_rq_complete(rq);
+	trace_block_rq_requeue(q, rq);
+
+	if (blk_rq_tagged(rq))
+		blk_queue_end_tag(q, rq);
+
+	BUG_ON(blk_queued_rq(rq));
+
+	return elv_reinsert_request(q, rq);
+}
+EXPORT_SYMBOL(blk_reinsert_request);
+
+/**
+ * blk_reinsert_req_sup() - check whether the scheduler supports
+ *          reinsertion of requests
+ * @q:		request queue
+ *
+ * Returns true if the current scheduler supports reinserting
+ * request. False otherwise
+ */
+bool blk_reinsert_req_sup(struct request_queue *q)
+{
+	if (unlikely(!q))
+		return false;
+	return q->elevator->type->ops.elevator_reinsert_req_fn ? true : false;
+}
+EXPORT_SYMBOL(blk_reinsert_req_sup);
+
 static void add_acct_request(struct request_queue *q, struct request *rq,
 			     int where)
 {
@@ -2073,8 +2130,17 @@
 	struct request *rq;
 
 	rq = blk_peek_request(q);
-	if (rq)
+	if (rq) {
+		/*
+		 * Assumption: the next request fetched from scheduler after we
+		 * notified "urgent request pending" - will be the urgent one
+		 */
+		if (q->notified_urgent && !q->dispatched_urgent) {
+			q->dispatched_urgent = true;
+			(void)blk_mark_rq_urgent(rq);
+		}
 		blk_start_request(rq);
+	}
 	return rq;
 }
 EXPORT_SYMBOL(blk_fetch_request);
diff --git a/block/blk-settings.c b/block/blk-settings.c
index d3234fc..579328c 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -100,6 +100,18 @@
 EXPORT_SYMBOL_GPL(blk_queue_lld_busy);
 
 /**
+ * blk_urgent_request() - Set an urgent_request handler function for queue
+ * @q:		queue
+ * @fn:		handler for urgent requests
+ *
+ */
+void blk_urgent_request(struct request_queue *q, request_fn_proc *fn)
+{
+	q->urgent_request_fn = fn;
+}
+EXPORT_SYMBOL(blk_urgent_request);
+
+/**
  * blk_set_default_limits - reset limits to default values
  * @lim:  the queue_limits structure to reset
  *
diff --git a/block/blk.h b/block/blk.h
index d45be87..a52209f 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -39,6 +39,7 @@
  */
 enum rq_atomic_flags {
 	REQ_ATOM_COMPLETE = 0,
+	REQ_ATOM_URGENT = 1,
 };
 
 /*
@@ -55,6 +56,16 @@
 	clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags);
 }
 
+static inline int blk_mark_rq_urgent(struct request *rq)
+{
+	return test_and_set_bit(REQ_ATOM_URGENT, &rq->atomic_flags);
+}
+
+static inline void blk_clear_rq_urgent(struct request *rq)
+{
+	clear_bit(REQ_ATOM_URGENT, &rq->atomic_flags);
+}
+
 /*
  * Internal elevator interface
  */
diff --git a/block/elevator.c b/block/elevator.c
index 74fd51b..efec457 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -585,6 +585,41 @@
 	__elv_add_request(q, rq, ELEVATOR_INSERT_REQUEUE);
 }
 
+/**
+ * elv_reinsert_request() - Insert a request back to the scheduler
+ * @q:		request queue where request should be inserted
+ * @rq:		request to be inserted
+ *
+ * This function returns the request back to the scheduler to be
+ * inserted as if it was never dispatched
+ *
+ * Return: 0 on success, error code on failure
+ */
+int elv_reinsert_request(struct request_queue *q, struct request *rq)
+{
+	int res;
+
+	if (!q->elevator->type->ops.elevator_reinsert_req_fn)
+		return -EPERM;
+
+	res = q->elevator->type->ops.elevator_reinsert_req_fn(q, rq);
+	if (!res) {
+		/*
+		 * it already went through dequeue, we need to decrement the
+		 * in_flight count again
+		 */
+		if (blk_account_rq(rq)) {
+			q->in_flight[rq_is_sync(rq)]--;
+			if (rq->cmd_flags & REQ_SORTED)
+				elv_deactivate_rq(q, rq);
+		}
+		rq->cmd_flags &= ~REQ_STARTED;
+		q->nr_sorted++;
+	}
+
+	return res;
+}
+
 void elv_drain_elevator(struct request_queue *q)
 {
 	static int printed;
@@ -779,6 +814,11 @@
 {
 	struct elevator_queue *e = q->elevator;
 
+	if (test_bit(REQ_ATOM_URGENT, &rq->atomic_flags)) {
+		q->notified_urgent = false;
+		q->dispatched_urgent = false;
+		blk_clear_rq_urgent(rq);
+	}
 	/*
 	 * request is released from the driver, io must be done
 	 */
diff --git a/block/row-iosched.c b/block/row-iosched.c
index b7965c6..483d97f 100644
--- a/block/row-iosched.c
+++ b/block/row-iosched.c
@@ -69,20 +69,19 @@
 	1	/* ROWQ_PRIO_LOW_SWRITE */
 };
 
-/* Default values for idling on read queues */
-#define ROW_IDLE_TIME 50	/* 5 msec */
-#define ROW_READ_FREQ 70	/* 7 msec */
+/* Default values for idling on read queues (in msec) */
+#define ROW_IDLE_TIME_MSEC 5
+#define ROW_READ_FREQ_MSEC 20
 
 /**
  * struct rowq_idling_data -  parameters for idling on the queue
- * @idle_trigger_time:	time (in jiffies). If a new request was
- *			inserted before this time value, idling
- *			will be enabled.
+ * @last_insert_time:	time the last request was inserted
+ *			to the queue
  * @begin_idling:	flag indicating wether we should idle
  *
  */
 struct rowq_idling_data {
-	unsigned long		idle_trigger_time;
+	ktime_t			last_insert_time;
 	bool			begin_idling;
 };
 
@@ -111,7 +110,7 @@
 
 /**
  * struct idling_data - data for idling on empty rqueue
- * @idle_time:		idling duration (msec)
+ * @idle_time:		idling duration (jiffies)
  * @freq:		min time between two requests that
  *			triger idling (msec)
  * @idle_work:		pointer to struct delayed_work
@@ -119,7 +118,7 @@
  */
 struct idling_data {
 	unsigned long			idle_time;
-	unsigned long			freq;
+	u32				freq;
 
 	struct workqueue_struct	*idle_workqueue;
 	struct delayed_work		idle_work;
@@ -260,14 +259,17 @@
 		if (delayed_work_pending(&rd->read_idle.idle_work))
 			(void)cancel_delayed_work(
 				&rd->read_idle.idle_work);
-		if (time_before(jiffies, rqueue->idle_data.idle_trigger_time)) {
+		if (ktime_to_ms(ktime_sub(ktime_get(),
+				rqueue->idle_data.last_insert_time)) <
+				rd->read_idle.freq) {
 			rqueue->idle_data.begin_idling = true;
 			row_log_rowq(rd, rqueue->prio, "Enable idling");
-		} else
+		} else {
 			rqueue->idle_data.begin_idling = false;
+			row_log_rowq(rd, rqueue->prio, "Disable idling");
+		}
 
-		rqueue->idle_data.idle_trigger_time =
-			jiffies + msecs_to_jiffies(rd->read_idle.freq);
+		rqueue->idle_data.last_insert_time = ktime_get();
 	}
 	row_log_rowq(rd, rqueue->prio, "added request");
 }
@@ -402,9 +404,8 @@
 		if (!force && queue_idling_enabled[currq] &&
 		    rd->row_queues[currq].rqueue.idle_data.begin_idling) {
 			if (!queue_delayed_work(rd->read_idle.idle_workqueue,
-			    &rd->read_idle.idle_work,
-			    jiffies +
-			    msecs_to_jiffies(rd->read_idle.idle_time))) {
+						&rd->read_idle.idle_work,
+						rd->read_idle.idle_time)) {
 				row_log_rowq(rd, currq,
 					     "Work already on queue!");
 				pr_err("ROW_BUG: Work already on queue!");
@@ -453,6 +454,8 @@
 		rdata->row_queues[i].rqueue.rdata = rdata;
 		rdata->row_queues[i].rqueue.prio = i;
 		rdata->row_queues[i].rqueue.idle_data.begin_idling = false;
+		rdata->row_queues[i].rqueue.idle_data.last_insert_time =
+			ktime_set(0, 0);
 	}
 
 	/*
@@ -460,8 +463,11 @@
 	 * enable it for write queues also, note that idling frequency will
 	 * be the same in both cases
 	 */
-	rdata->read_idle.idle_time = ROW_IDLE_TIME;
-	rdata->read_idle.freq = ROW_READ_FREQ;
+	rdata->read_idle.idle_time = msecs_to_jiffies(ROW_IDLE_TIME_MSEC);
+	/* Maybe 0 on some platforms */
+	if (!rdata->read_idle.idle_time)
+		rdata->read_idle.idle_time = 1;
+	rdata->read_idle.freq = ROW_READ_FREQ_MSEC;
 	rdata->read_idle.idle_workqueue = alloc_workqueue("row_idle_work",
 					    WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
 	if (!rdata->read_idle.idle_workqueue)
@@ -489,6 +495,8 @@
 	for (i = 0; i < ROWQ_MAX_PRIO; i++)
 		BUG_ON(!list_empty(&rd->row_queues[i].rqueue.fifo));
 	(void)cancel_delayed_work_sync(&rd->read_idle.idle_work);
+	BUG_ON(delayed_work_pending(&rd->read_idle.idle_work));
+	destroy_workqueue(rd->read_idle.idle_workqueue);
 	kfree(rd);
 }
 
@@ -590,7 +598,7 @@
 SHOW_FUNCTION(row_lp_swrite_quantum_show,
 	rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, 0);
 SHOW_FUNCTION(row_read_idle_show, rowd->read_idle.idle_time, 1);
-SHOW_FUNCTION(row_read_idle_freq_show, rowd->read_idle.freq, 1);
+SHOW_FUNCTION(row_read_idle_freq_show, rowd->read_idle.freq, 0);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)			\
@@ -630,7 +638,7 @@
 			&rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum,
 			1, INT_MAX, 1);
 STORE_FUNCTION(row_read_idle_store, &rowd->read_idle.idle_time, 1, INT_MAX, 1);
-STORE_FUNCTION(row_read_idle_freq_store, &rowd->read_idle.freq, 1, INT_MAX, 1);
+STORE_FUNCTION(row_read_idle_freq_store, &rowd->read_idle.freq, 1, INT_MAX, 0);
 
 #undef STORE_FUNCTION
 
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 9e419e1..82d19e0 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -281,6 +281,7 @@
 static const struct of_device_id ahci_of_match[] = {
 	{ .compatible = "calxeda,hb-ahci", },
 	{ .compatible = "snps,spear-ahci", },
+	{ .compatible = "qcom,msm-ahci", },
 	{},
 };
 MODULE_DEVICE_TABLE(of, ahci_of_match);
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..f2f4f0c 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -41,68 +41,45 @@
 #define DCI_CHK_CAPACITY(entry, new_data_len)				\
 ((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0)	\
 
-static void diag_smd_dci_send_req(int proc_num)
+/* Process the data read from the smd dci channel */
+int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
+								int recd_bytes)
 {
-	void *buf = NULL;
-	smd_channel_t *smd_ch = NULL;
-	int recd_bytes, read_bytes, dci_pkt_len, i;
+	int read_bytes, dci_pkt_len, i;
 	uint8_t recv_pkt_cmd_code;
 
-	if (driver->in_busy_dci)
-		return;
-
-	if (proc_num == MODEM_PROC) {
-		buf = driver->buf_in_dci;
-		smd_ch = driver->ch_dci;
+	/* Each SMD read can have multiple DCI packets */
+	read_bytes = 0;
+	while (read_bytes < recd_bytes) {
+		/* read actual length of dci pkt */
+		dci_pkt_len = *(uint16_t *)(buf+2);
+		/* process one dci packet */
+		pr_debug("diag: bytes read = %d, single dci pkt len = %d\n",
+			read_bytes, dci_pkt_len);
+		/* print_hex_dump(KERN_DEBUG, "Single DCI packet :",
+		 DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1);*/
+		recv_pkt_cmd_code = *(uint8_t *)(buf+4);
+		if (recv_pkt_cmd_code == LOG_CMD_CODE)
+			extract_dci_log(buf+4);
+		else if (recv_pkt_cmd_code == EVENT_CMD_CODE)
+			extract_dci_events(buf+4);
+		else
+			extract_dci_pkt_rsp(buf); /* pkt response */
+		read_bytes += 5 + dci_pkt_len;
+		buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
 	}
-
-	if (!smd_ch || !buf)
-		return;
-
-	recd_bytes = smd_read_avail(smd_ch);
-	if (recd_bytes > IN_BUF_SIZE) {
-		if (recd_bytes < MAX_IN_BUF_SIZE) {
-			pr_err("diag: SMD DCI sending pkt upto %d bytes",
-				recd_bytes);
-			buf = krealloc(buf, recd_bytes, GFP_KERNEL);
-		} else {
-			pr_err("diag: DCI pkt > %d bytes", MAX_IN_BUF_SIZE);
-			return;
+	/* wake up all sleeping DCI clients which have some data */
+	for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+		if (driver->dci_client_tbl[i].client &&
+			driver->dci_client_tbl[i].data_len) {
+			smd_info->in_busy_1 = 1;
+			diag_update_sleeping_process(
+				driver->dci_client_tbl[i].client->tgid,
+					 DCI_DATA_TYPE);
 		}
 	}
-	if (buf && recd_bytes > 0) {
-		smd_read(smd_ch, buf, recd_bytes);
-		pr_debug("diag: data received %d bytes\n", recd_bytes);
-		/* Each SMD read can have multiple DCI packets */
-		read_bytes = 0;
-		while (read_bytes < recd_bytes) {
-			/* read actual length of dci pkt */
-			dci_pkt_len = *(uint16_t *)(buf+2);
-			/* process one dci packet */
-			pr_debug("diag: bytes read = %d, single dci pkt len = %d\n",
-				read_bytes, dci_pkt_len);
-			/* print_hex_dump(KERN_DEBUG, "Single DCI packet :",
-			 DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1);*/
-			recv_pkt_cmd_code = *(uint8_t *)(buf+4);
-			if (recv_pkt_cmd_code == LOG_CMD_CODE)
-				extract_dci_log(buf+4);
-			else if (recv_pkt_cmd_code == EVENT_CMD_CODE)
-				extract_dci_events(buf+4);
-			else
-				extract_dci_pkt_rsp(buf); /* pkt response */
-			read_bytes += 5 + dci_pkt_len;
-			buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
-		}
-		/* wake up all sleeping DCI clients which have some data */
-		for (i = 0; i < MAX_DCI_CLIENTS; i++)
-			if (driver->dci_client_tbl[i].client &&
-				driver->dci_client_tbl[i].data_len) {
-				driver->in_busy_dci = 1;
-				diag_update_sleeping_process(
-					driver->dci_client_tbl[i].client->tgid,
-						 DCI_DATA_TYPE);
-			}
-	}
+
+	return 0;
 }
 
 void extract_dci_pkt_rsp(unsigned char *buf)
@@ -161,7 +138,8 @@
 					buf+4+cmd_code_len, write_len);
 				entry->data_len += write_len;
 				/* delete immediate response entry */
-				if (driver->buf_in_dci[8+cmd_code_len] != 0x80)
+				if (driver->smd_dci[SMD_MODEM_INDEX].
+					buf_in_1[8+cmd_code_len] != 0x80)
 					driver->req_tracking_tbl[index].pid = 0;
 				break;
 			}
@@ -301,28 +279,95 @@
 	}
 }
 
-void diag_read_smd_dci_work_fn(struct work_struct *work)
+void diag_update_smd_dci_work_fn(struct work_struct *work)
 {
-	diag_smd_dci_send_req(MODEM_PROC);
+	struct diag_smd_info *smd_info = container_of(work,
+						struct diag_smd_info,
+						diag_notify_update_smd_work);
+	int i, j;
+	char dirty_bits[16];
+	uint8_t *client_log_mask_ptr;
+	uint8_t *log_mask_ptr;
+	int ret;
+	int index;
+
+	switch (smd_info->peripheral) {
+	case MODEM_PROC:
+		index = SMD_MODEM_INDEX;
+		break;
+	case LPASS_PROC:
+		index = SMD_LPASS_INDEX;
+		break;
+	case WCNSS_PROC:
+		index = SMD_WCNSS_INDEX;
+		break;
+	default:
+		pr_err("diag: In %s, unknown peripheral: %d\n",
+			__func__, smd_info->peripheral);
+		return;
+	}
+
+	/* 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->smd_cntl[index].ch)
+		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->smd_cntl[index].ch);
+
+	ret = diag_send_dci_event_mask(driver->smd_cntl[index].ch);
+
+	smd_info->notify_context = 0;
 }
 
-static void diag_smd_dci_notify(void *ctxt, unsigned event)
-{
-	queue_work(driver->diag_dci_wq, &(driver->diag_read_smd_dci_work));
-}
-
-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 */
@@ -331,20 +376,23 @@
 static int diag_dci_probe(struct platform_device *pdev)
 {
 	int err = 0;
+	int index;
 
 	if (pdev->id == SMD_APPS_MODEM) {
-		err = smd_open("DIAG_2", &driver->ch_dci, driver,
-						diag_smd_dci_notify);
+		index = SMD_MODEM_INDEX;
+		err = smd_open("DIAG_2", &driver->smd_dci[index].ch,
+					&driver->smd_dci[index],
+					diag_smd_notify);
+		driver->smd_dci[index].ch_save =
+					driver->smd_dci[index].ch;
 		if (err)
-			pr_err("diag: cannot open DCI port, Id = %d, err ="
-				" %d\n", pdev->id, err);
-		else
-			diag_dci_notify_client(DIAG_CON_MPSS);
+			pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
+				__func__, pdev->id, err);
 	}
+
 	return err;
 }
 
-
 int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
 					 int len, int index)
 {
@@ -366,8 +414,10 @@
 
 	driver->apps_dci_buf[9+len] = CONTROL_CHAR; /* end */
 
-	if (entry.client_id == MODEM_PROC && driver->ch_dci) {
-		smd_write(driver->ch_dci, driver->apps_dci_buf, len + 10);
+	if (entry.client_id == MODEM_PROC &&
+					driver->smd_dci[SMD_MODEM_INDEX].ch) {
+		smd_write(driver->smd_dci[SMD_MODEM_INDEX].ch,
+					driver->apps_dci_buf, len + 10);
 		i = DIAG_DCI_NO_ERROR;
 	} else {
 		pr_alert("diag: check DCI channel\n");
@@ -414,6 +464,12 @@
 	uint8_t *event_mask_ptr;
 	int offset = 0;
 
+	if (!driver->smd_dci[SMD_MODEM_INDEX].ch) {
+		pr_err("diag: DCI smd channel for peripheral %d not valid for dci updates\n",
+			driver->smd_dci[SMD_MODEM_INDEX].peripheral);
+		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 +591,8 @@
 			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->
+						smd_cntl[SMD_MODEM_INDEX].ch);
 	} else if (*(int *)temp == DCI_EVENT_TYPE) {
 		/* find client id and table */
 		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
@@ -581,7 +638,8 @@
 			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->
+						smd_cntl[SMD_MODEM_INDEX].ch);
 	} else {
 		pr_alert("diag: Incorrect DCI transaction\n");
 	}
@@ -614,11 +672,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 +701,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 +751,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 +786,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 +800,8 @@
 		log_mask_ptr += 514;
 	}
 	mutex_unlock(&driver->diag_cntl_mutex);
+
+	return ret;
 }
 
 void create_dci_log_mask_tbl(unsigned char *tbl_buf)
@@ -777,25 +852,19 @@
 int diag_dci_init(void)
 {
 	int success = 0;
+	int i;
 
 	driver->dci_tag = 0;
 	driver->dci_client_id = 0;
 	driver->num_dci_client = 0;
-	driver->in_busy_dci = 0;
 	mutex_init(&driver->dci_mutex);
 	mutex_init(&dci_log_mask_mutex);
 	mutex_init(&dci_event_mask_mutex);
-	if (driver->buf_in_dci == NULL) {
-		driver->buf_in_dci = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_dci == NULL)
-			goto err;
-	}
-	if (driver->write_ptr_dci == NULL) {
-		driver->write_ptr_dci = kzalloc(
-			sizeof(struct diag_write_device), GFP_KERNEL);
-		if (driver->write_ptr_dci == NULL)
-			goto err;
-	}
+	success = diag_smd_constructor(&driver->smd_dci[SMD_MODEM_INDEX],
+				MODEM_PROC, SMD_DCI_TYPE, DIAG_CON_MPSS);
+	if (!success)
+		goto err;
+
 	if (driver->req_tracking_tbl == NULL) {
 		driver->req_tracking_tbl = kzalloc(dci_max_reg *
 			sizeof(struct dci_pkt_req_tracking_tbl), GFP_KERNEL);
@@ -825,8 +894,8 @@
 	kfree(driver->req_tracking_tbl);
 	kfree(driver->dci_client_tbl);
 	kfree(driver->apps_dci_buf);
-	kfree(driver->buf_in_dci);
-	kfree(driver->write_ptr_dci);
+	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
+		diag_smd_destructor(&driver->smd_dci[i]);
 	if (driver->diag_dci_wq)
 		destroy_workqueue(driver->diag_dci_wq);
 	return DIAG_DCI_NO_REG;
@@ -834,13 +903,14 @@
 
 void diag_dci_exit(void)
 {
-	smd_close(driver->ch_dci);
-	driver->ch_dci = 0;
+	int i;
+
+	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
+		diag_smd_destructor(&driver->smd_dci[i]);
+
 	platform_driver_unregister(&msm_diag_dci_driver);
 	kfree(driver->req_tracking_tbl);
 	kfree(driver->dci_client_tbl);
 	kfree(driver->apps_dci_buf);
-	kfree(driver->buf_in_dci);
-	kfree(driver->write_ptr_dci);
 	destroy_workqueue(driver->diag_dci_wq);
 }
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 435c750..af89ac8 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -78,7 +78,10 @@
 
 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 *);
+void diag_dci_notify_client(int peripheral_mask, int data);
+int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
+								int recd_bytes);
 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 +90,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..8badc55 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -48,34 +48,34 @@
 		"Check Polling Response: %d\n"
 		"polling_reg_flag: %d\n"
 		"uses device tree: %d\n"
-		"in_busy_1: %d\n"
-		"in_busy_2: %d\n"
-		"in_busy_lpass_1: %d\n"
-		"in_busy_lpass_2: %d\n"
-		"in_busy_wcnss_1: %d\n"
-		"in_busy_wcnss_2: %d\n"
-		"in_busy_dci: %d\n"
+		"Modem in_busy_1: %d\n"
+		"Modem in_busy_2: %d\n"
+		"LPASS in_busy_1: %d\n"
+		"LPASS in_busy_2: %d\n"
+		"RIVA in_busy_1: %d\n"
+		"RIVA in_busy_2: %d\n"
+		"DCI Modem in_busy_1: %d\n"
 		"logging_mode: %d\n",
-		(unsigned int)driver->ch,
-		(unsigned int)driver->chlpass,
-		(unsigned int)driver->ch_wcnss,
-		(unsigned int)driver->ch_dci,
-		(unsigned int)driver->ch_cntl,
-		(unsigned int)driver->chlpass_cntl,
-		(unsigned int)driver->ch_wcnss_cntl,
+		(unsigned int)driver->smd_data[SMD_MODEM_INDEX].ch,
+		(unsigned int)driver->smd_data[SMD_LPASS_INDEX].ch,
+		(unsigned int)driver->smd_data[SMD_WCNSS_INDEX].ch,
+		(unsigned int)driver->smd_dci[SMD_MODEM_INDEX].ch,
+		(unsigned int)driver->smd_cntl[SMD_MODEM_INDEX].ch,
+		(unsigned int)driver->smd_cntl[SMD_LPASS_INDEX].ch,
+		(unsigned int)driver->smd_cntl[SMD_WCNSS_INDEX].ch,
 		chk_config_get_id(),
 		chk_apps_only(),
 		chk_apps_master(),
 		chk_polling_response(),
 		driver->polling_reg_flag,
 		driver->use_device_tree,
-		driver->in_busy_1,
-		driver->in_busy_2,
-		driver->in_busy_lpass_1,
-		driver->in_busy_lpass_2,
-		driver->in_busy_wcnss_1,
-		driver->in_busy_wcnss_2,
-		driver->in_busy_dci,
+		driver->smd_data[SMD_MODEM_INDEX].in_busy_1,
+		driver->smd_data[SMD_MODEM_INDEX].in_busy_2,
+		driver->smd_data[SMD_LPASS_INDEX].in_busy_1,
+		driver->smd_data[SMD_LPASS_INDEX].in_busy_2,
+		driver->smd_data[SMD_WCNSS_INDEX].in_busy_1,
+		driver->smd_data[SMD_WCNSS_INDEX].in_busy_2,
+		driver->smd_dci[SMD_MODEM_INDEX].in_busy_1,
 		driver->logging_mode);
 
 #ifdef CONFIG_DIAG_OVER_USB
@@ -104,27 +104,49 @@
 	ret = scnprintf(buf, DEBUG_BUF_SIZE,
 		"Pending status for work_stucts:\n"
 		"diag_drain_work: %d\n"
-		"diag_read_smd_work: %d\n"
-		"diag_read_smd_cntl_work: %d\n"
-		"diag_read_smd_lpass_work: %d\n"
-		"diag_read_smd_lpass_cntl_work: %d\n"
-		"diag_read_smd_wcnss_work: %d\n"
-		"diag_read_smd_wcnss_cntl_work: %d\n"
-		"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",
+		"Modem data diag_read_smd_work: %d\n"
+		"LPASS data diag_read_smd_work: %d\n"
+		"RIVA data diag_read_smd_work: %d\n"
+		"Modem cntl diag_read_smd_work: %d\n"
+		"LPASS cntl diag_read_smd_work: %d\n"
+		"RIVA cntl diag_read_smd_work: %d\n"
+		"Modem dci diag_read_smd_work: %d\n"
+		"Modem data diag_notify_update_smd_work: %d\n"
+		"LPASS data diag_notify_update_smd_work: %d\n"
+		"RIVA data diag_notify_update_smd_work: %d\n"
+		"Modem cntl diag_notify_update_smd_work: %d\n"
+		"LPASS cntl diag_notify_update_smd_work: %d\n"
+		"RIVA cntl diag_notify_update_smd_work: %d\n"
+		"Modem dci diag_notify_update_smd_work: %d\n",
 		work_pending(&(driver->diag_drain_work)),
-		work_pending(&(driver->diag_read_smd_work)),
-		work_pending(&(driver->diag_read_smd_cntl_work)),
-		work_pending(&(driver->diag_read_smd_lpass_work)),
-		work_pending(&(driver->diag_read_smd_lpass_cntl_work)),
-		work_pending(&(driver->diag_read_smd_wcnss_work)),
-		work_pending(&(driver->diag_read_smd_wcnss_cntl_work)),
-		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->smd_data[SMD_MODEM_INDEX].
+							diag_read_smd_work)),
+		work_pending(&(driver->smd_data[SMD_LPASS_INDEX].
+							diag_read_smd_work)),
+		work_pending(&(driver->smd_data[SMD_WCNSS_INDEX].
+							diag_read_smd_work)),
+		work_pending(&(driver->smd_cntl[SMD_MODEM_INDEX].
+							diag_read_smd_work)),
+		work_pending(&(driver->smd_cntl[SMD_LPASS_INDEX].
+							diag_read_smd_work)),
+		work_pending(&(driver->smd_cntl[SMD_WCNSS_INDEX].
+							diag_read_smd_work)),
+		work_pending(&(driver->smd_dci[SMD_MODEM_INDEX].
+							diag_read_smd_work)),
+		work_pending(&(driver->smd_data[SMD_MODEM_INDEX].
+						diag_notify_update_smd_work)),
+		work_pending(&(driver->smd_data[SMD_LPASS_INDEX].
+						diag_notify_update_smd_work)),
+		work_pending(&(driver->smd_data[SMD_WCNSS_INDEX].
+						diag_notify_update_smd_work)),
+		work_pending(&(driver->smd_cntl[SMD_MODEM_INDEX].
+						diag_notify_update_smd_work)),
+		work_pending(&(driver->smd_cntl[SMD_LPASS_INDEX].
+						diag_notify_update_smd_work)),
+		work_pending(&(driver->smd_cntl[SMD_WCNSS_INDEX].
+						diag_notify_update_smd_work)),
+		work_pending(&(driver->smd_dci[SMD_MODEM_INDEX].
+						diag_notify_update_smd_work)));
 
 #ifdef CONFIG_DIAG_OVER_USB
 	ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
@@ -187,7 +209,7 @@
 		if (bytes_remaining < bytes_written)
 			break;
 	}
-	diag_dbgfs_table_index = i;
+	diag_dbgfs_table_index = i+1;
 
 	*ppos = 0;
 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
@@ -228,10 +250,10 @@
 		"diag_read_hsic_work: %d\n"
 		"diag_disconnect_work: %d\n"
 		"diag_usb_read_complete_work: %d\n"
-		"smux ch: %d"
-		"smux enabled %d"
-		"smux in busy %d"
-		"smux connected %d",
+		"smux ch: %d\n"
+		"smux enabled %d\n"
+		"smux in busy %d\n"
+		"smux connected %d\n",
 		driver->hsic_ch,
 		driver->hsic_inited,
 		driver->hsic_device_enabled,
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 5316548..b2952f2 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -294,29 +294,23 @@
 	mutex_unlock(&driver->diagchar_mutex);
 }
 
-void diag_modem_mask_update_fn(struct work_struct *work)
+void diag_mask_update_fn(struct work_struct *work)
 {
-	diag_send_msg_mask_update(driver->ch_cntl, ALL_SSID,
-					   ALL_SSID, MODEM_PROC);
-	diag_send_log_mask_update(driver->ch_cntl, ALL_EQUIP_ID);
-	diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
-}
+	struct diag_smd_info *smd_info = container_of(work,
+						struct diag_smd_info,
+						diag_notify_update_smd_work);
+	if (!smd_info) {
+		pr_err("diag: In %s, smd info is null, cannot update masks for the peripheral\n",
+			__func__);
+		return;
+	}
 
-void diag_lpass_mask_update_fn(struct work_struct *work)
-{
-	diag_send_msg_mask_update(driver->chlpass_cntl, ALL_SSID,
-						   ALL_SSID, LPASS_PROC);
-	diag_send_log_mask_update(driver->chlpass_cntl, ALL_EQUIP_ID);
-	diag_send_event_mask_update(driver->chlpass_cntl, diag_event_num_bytes);
-}
+	diag_send_msg_mask_update(smd_info->ch, ALL_SSID, ALL_SSID,
+						smd_info->peripheral);
+	diag_send_log_mask_update(smd_info->ch, ALL_EQUIP_ID);
+	diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
 
-void diag_wcnss_mask_update_fn(struct work_struct *work)
-{
-	diag_send_msg_mask_update(driver->ch_wcnss_cntl, ALL_SSID,
-						   ALL_SSID, WCNSS_PROC);
-	diag_send_log_mask_update(driver->ch_wcnss_cntl, ALL_EQUIP_ID);
-	diag_send_event_mask_update(driver->ch_wcnss_cntl,
-						 diag_event_num_bytes);
+	smd_info->notify_context = 0;
 }
 
 void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
@@ -493,15 +487,13 @@
 			payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
 			for (i = 0; i < payload_length; i++)
 				*(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
-			if (driver->ch_cntl)
-				diag_send_log_mask_update(driver->ch_cntl,
-				*(int *)buf);
-			if (driver->chlpass_cntl)
-				diag_send_log_mask_update(driver->chlpass_cntl,
-				*(int *)buf);
-			if (driver->ch_wcnss_cntl)
-				diag_send_log_mask_update(driver->ch_wcnss_cntl,
-				*(int *)buf);
+
+			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+				if (driver->smd_cntl[i].ch)
+					diag_send_log_mask_update(
+						driver->smd_cntl[i].ch,
+						*(int *)buf);
+			}
 			encode_rsp_and_send(12 + payload_length - 1);
 			return 0;
 		}
@@ -509,7 +501,8 @@
 	} /* Get log masks */
 	else if (*buf == 0x73 && *(int *)(buf+4) == 4) {
 #if defined(CONFIG_DIAG_OVER_USB)
-		if (!(driver->ch) && chk_apps_only()) {
+		if (!(driver->smd_data[SMD_MODEM_INDEX].ch) &&
+						chk_apps_only()) {
 			equip_id = *(int *)(buf + 8);
 			num_items = *(int *)(buf + 12);
 			driver->apps_rsp_buf[0] = 0x73;
@@ -541,15 +534,13 @@
 			driver->apps_rsp_buf[3] = 0x0;
 			*(int *)(driver->apps_rsp_buf + 4) = 0x0;
 			*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* status */
-			if (driver->ch_cntl)
-				diag_send_log_mask_update(driver->ch_cntl,
-				ALL_EQUIP_ID);
-			if (driver->chlpass_cntl)
-				diag_send_log_mask_update(driver->chlpass_cntl,
-				ALL_EQUIP_ID);
-			if (driver->ch_wcnss_cntl)
-				diag_send_log_mask_update(driver->ch_wcnss_cntl,
-				ALL_EQUIP_ID);
+			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+				if (driver->smd_cntl[i].ch)
+					diag_send_log_mask_update(
+						driver->smd_cntl[i].ch,
+						ALL_EQUIP_ID);
+
+			}
 			encode_rsp_and_send(11);
 			return 0;
 		}
@@ -559,7 +550,8 @@
 		ssid_first = *(uint16_t *)(buf + 2);
 		ssid_last = *(uint16_t *)(buf + 4);
 #if defined(CONFIG_DIAG_OVER_USB)
-		if (!(driver->ch) && chk_apps_only()) {
+		if (!(driver->smd_data[SMD_MODEM_INDEX].ch) &&
+						chk_apps_only()) {
 			driver->apps_rsp_buf[0] = 0x7d;
 			driver->apps_rsp_buf[1] = 0x3;
 			*(uint16_t *)(driver->apps_rsp_buf+2) = ssid_first;
@@ -599,15 +591,14 @@
 			for (i = 0; i < 8 + ssid_range; i++)
 				*(driver->apps_rsp_buf + i) = *(buf+i);
 			*(driver->apps_rsp_buf + 6) = 0x1;
-			if (driver->ch_cntl)
-				diag_send_msg_mask_update(driver->ch_cntl,
-				ssid_first, ssid_last, MODEM_PROC);
-			if (driver->chlpass_cntl)
-				diag_send_msg_mask_update(driver->chlpass_cntl,
-				ssid_first, ssid_last, LPASS_PROC);
-			if (driver->ch_wcnss_cntl)
-				diag_send_msg_mask_update(driver->ch_wcnss_cntl,
-				ssid_first, ssid_last, WCNSS_PROC);
+			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+				if (driver->smd_cntl[i].ch)
+					diag_send_msg_mask_update(
+						driver->smd_cntl[i].ch,
+						ssid_first, ssid_last,
+						driver->smd_cntl[i].peripheral);
+
+			}
 			encode_rsp_and_send(8 + ssid_range - 1);
 			return 0;
 		}
@@ -625,15 +616,14 @@
 			driver->apps_rsp_buf[3] = 0; /* rsvd */
 			*(int *)(driver->apps_rsp_buf + 4) = rt_mask;
 			/* send msg mask update to peripheral */
-			if (driver->ch_cntl)
-				diag_send_msg_mask_update(driver->ch_cntl,
-				ALL_SSID, ALL_SSID, MODEM_PROC);
-			if (driver->chlpass_cntl)
-				diag_send_msg_mask_update(driver->chlpass_cntl,
-				ALL_SSID, ALL_SSID, LPASS_PROC);
-			if (driver->ch_wcnss_cntl)
-				diag_send_msg_mask_update(driver->ch_wcnss_cntl,
-				ALL_SSID, ALL_SSID, WCNSS_PROC);
+			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+				if (driver->smd_cntl[i].ch)
+					diag_send_msg_mask_update(
+						driver->smd_cntl[i].ch,
+						ALL_SSID, ALL_SSID,
+						driver->smd_cntl[i].peripheral);
+
+			}
 			encode_rsp_and_send(7);
 			return 0;
 		}
@@ -652,16 +642,12 @@
 				EVENT_LAST_ID + 1;
 			memcpy(driver->apps_rsp_buf+6, driver->event_masks,
 				EVENT_LAST_ID/8+1);
-			if (driver->ch_cntl)
-				diag_send_event_mask_update(driver->ch_cntl,
-				diag_event_num_bytes);
-			if (driver->chlpass_cntl)
-				diag_send_event_mask_update(
-				driver->chlpass_cntl,
-				diag_event_num_bytes);
-			if (driver->ch_wcnss_cntl)
-				diag_send_event_mask_update(
-				driver->ch_wcnss_cntl, diag_event_num_bytes);
+			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+				if (driver->smd_cntl[i].ch)
+					diag_send_event_mask_update(
+						driver->smd_cntl[i].ch,
+						diag_event_num_bytes);
+			}
 			encode_rsp_and_send(6 + EVENT_LAST_ID/8);
 			return 0;
 		}
@@ -675,16 +661,12 @@
 			driver->apps_rsp_buf[0] = 0x60;
 			driver->apps_rsp_buf[1] = 0x0;
 			driver->apps_rsp_buf[2] = 0x0;
-			if (driver->ch_cntl)
-				diag_send_event_mask_update(driver->ch_cntl,
-				diag_event_num_bytes);
-			if (driver->chlpass_cntl)
-				diag_send_event_mask_update(
-				driver->chlpass_cntl,
-				diag_event_num_bytes);
-			if (driver->ch_wcnss_cntl)
-				diag_send_event_mask_update(
-				driver->ch_wcnss_cntl, diag_event_num_bytes);
+			for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+				if (driver->smd_cntl[i].ch)
+					diag_send_event_mask_update(
+						driver->smd_cntl[i].ch,
+						diag_event_num_bytes);
+			}
 			encode_rsp_and_send(2);
 			return 0;
 		}
@@ -760,14 +742,6 @@
 			goto err;
 		kmemleak_not_leak(driver->event_masks);
 	}
-#ifdef CONFIG_DIAG_OVER_USB
-	INIT_WORK(&(driver->diag_modem_mask_update_work),
-						 diag_modem_mask_update_fn);
-	INIT_WORK(&(driver->diag_lpass_mask_update_work),
-						 diag_lpass_mask_update_fn);
-	INIT_WORK(&(driver->diag_wcnss_mask_update_work),
-						 diag_wcnss_mask_update_fn);
-#endif
 	return;
 err:
 	pr_err("diag: Could not initialize diag mask buffers");
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index bcf5bc2..f144774 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -20,6 +20,7 @@
 void diag_send_msg_mask_update(smd_channel_t *, int ssid_first,
 					 int ssid_last, int proc);
 void diag_send_log_mask_update(smd_channel_t *, int);
+void diag_mask_update_fn(struct work_struct *work);
 int diag_process_apps_masks(unsigned char *buf, int len);
 void diag_masks_init(void);
 void diag_masks_exit(void);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index d1ec5f2..fe63a3c 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -23,6 +23,7 @@
 #include <mach/msm_smd.h>
 #include <asm/atomic.h>
 #include <asm/mach-types.h>
+
 /* Size of the USB buffers used for read and write*/
 #define USB_MAX_OUT_BUF 4096
 #define APPS_BUF_SIZE	2000
@@ -67,6 +68,27 @@
 #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 */
+
+#define NUM_SMD_DATA_CHANNELS 3
+#define NUM_SMD_CONTROL_CHANNELS 3
+#define NUM_SMD_DCI_CHANNELS 1
+
+#define SMD_DATA_TYPE 0
+#define SMD_CNTL_TYPE 1
+#define SMD_DCI_TYPE 2
+
+#define SMD_MODEM_INDEX 0
+#define SMD_LPASS_INDEX 1
+#define SMD_WCNSS_INDEX 2
+
 /* Maximum number of pkt reg supported at initialization*/
 extern unsigned int diag_max_reg;
 extern unsigned int diag_threshold_reg;
@@ -128,6 +150,35 @@
 };
 #endif
 
+struct diag_smd_info {
+	int peripheral;	/* The peripheral this smd channel communicates with */
+	int type;	/* The type of smd channel (data, control, dci) */
+	uint16_t peripheral_mask;
+
+	smd_channel_t *ch;
+	smd_channel_t *ch_save;
+
+	int in_busy_1;
+	int in_busy_2;
+
+	unsigned char *buf_in_1;
+	unsigned char *buf_in_2;
+
+	struct diag_request *write_ptr_1;
+	struct diag_request *write_ptr_2;
+
+	struct work_struct diag_read_smd_work;
+	struct work_struct diag_notify_update_smd_work;
+	int notify_context;
+
+	/*
+	 * Function ptr for function to call to process the data that
+	 * was just read from the smd channel
+	 */
+	int (*process_smd_read_data)(struct diag_smd_info *smd_info,
+						void *buf, int num_bytes);
+};
+
 struct diagchar_dev {
 
 	/* State for the char driver */
@@ -181,16 +232,9 @@
 	struct diag_ctrl_log_mask *log_mask;
 	struct diag_ctrl_msg_mask *msg_mask;
 	/* State for diag forwarding */
-	unsigned char *buf_in_1;
-	unsigned char *buf_in_2;
-	unsigned char *buf_in_cntl;
-	unsigned char *buf_in_lpass_1;
-	unsigned char *buf_in_lpass_2;
-	unsigned char *buf_in_lpass_cntl;
-	unsigned char *buf_in_wcnss_1;
-	unsigned char *buf_in_wcnss_2;
-	unsigned char *buf_in_wcnss_cntl;
-	unsigned char *buf_in_dci;
+	struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
+	struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
+	struct diag_smd_info smd_dci[NUM_SMD_DCI_CHANNELS];
 	unsigned char *usb_buf_out;
 	unsigned char *apps_rsp_buf;
 	unsigned char *user_space_data;
@@ -198,20 +242,6 @@
 	unsigned char *buf_msg_mask_update;
 	unsigned char *buf_log_mask_update;
 	unsigned char *buf_event_mask_update;
-	smd_channel_t *ch;
-	smd_channel_t *ch_cntl;
-	smd_channel_t *ch_dci;
-	smd_channel_t *chlpass;
-	smd_channel_t *chlpass_cntl;
-	smd_channel_t *ch_wcnss;
-	smd_channel_t *ch_wcnss_cntl;
-	int in_busy_1;
-	int in_busy_2;
-	int in_busy_lpass_1;
-	int in_busy_lpass_2;
-	int in_busy_wcnss_1;
-	int in_busy_wcnss_2;
-	int in_busy_dci;
 	int read_len_legacy;
 	unsigned char *hdlc_buf;
 	unsigned hdlc_count;
@@ -224,20 +254,7 @@
 #endif
 	struct workqueue_struct *diag_wq;
 	struct work_struct diag_drain_work;
-	struct work_struct diag_read_smd_work;
-	struct work_struct diag_read_smd_cntl_work;
-	struct work_struct diag_read_smd_lpass_work;
-	struct work_struct diag_read_smd_lpass_cntl_work;
-	struct work_struct diag_read_smd_wcnss_work;
-	struct work_struct diag_read_smd_wcnss_cntl_work;
 	struct workqueue_struct *diag_cntl_wq;
-	struct work_struct diag_modem_mask_update_work;
-	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_clean_modem_reg_work;
-	struct work_struct diag_clean_lpass_reg_work;
-	struct work_struct diag_clean_wcnss_reg_work;
 	uint8_t *msg_masks;
 	uint8_t *log_masks;
 	int log_masks_length;
@@ -245,15 +262,8 @@
 	struct diag_master_table *table;
 	uint8_t *pkt_buf;
 	int pkt_length;
-	struct diag_request *write_ptr_1;
-	struct diag_request *write_ptr_2;
 	struct diag_request *usb_read_ptr;
 	struct diag_request *write_ptr_svc;
-	struct diag_request *write_ptr_lpass_1;
-	struct diag_request *write_ptr_lpass_2;
-	struct diag_request *write_ptr_wcnss_1;
-	struct diag_request *write_ptr_wcnss_2;
-	struct diag_write_device *write_ptr_dci;
 	int logging_mode;
 	int mask_check;
 	int logging_process_id;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 645d916..47ba97f2 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -149,21 +149,6 @@
 void diag_clear_hsic_tbl(void) { }
 #endif
 
-void diag_read_smd_work_fn(struct work_struct *work)
-{
-	__diag_smd_send_req();
-}
-
-void diag_read_smd_lpass_work_fn(struct work_struct *work)
-{
-	__diag_smd_lpass_send_req();
-}
-
-void diag_read_smd_wcnss_work_fn(struct work_struct *work)
-{
-	__diag_smd_wcnss_send_req();
-}
-
 void diag_add_client(int i, struct file *file)
 {
 	struct diagchar_priv *diagpriv_data;
@@ -565,9 +550,10 @@
 			return -EFAULT;
 		mutex_lock(&driver->dci_mutex);
 		if (!(driver->num_dci_client))
-			driver->in_busy_dci = 0;
+			driver->smd_dci[SMD_MODEM_INDEX].in_busy_1 = 0;
 		driver->num_dci_client++;
-		pr_debug("diag: id = %d\n", driver->dci_client_id);
+		pr_debug("diag: In %s, id = %d\n",
+				__func__, driver->dci_client_id);
 		driver->dci_client_id++;
 		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
 			if (driver->dci_client_tbl[i].client == NULL) {
@@ -616,8 +602,9 @@
 		mutex_unlock(&driver->dci_mutex);
 		return success;
 	} else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
-		if (driver->ch_dci)
-			support_list = support_list | DIAG_CON_MPSS;
+		if (driver->smd_dci[SMD_MODEM_INDEX].ch)
+			support_list |=
+			driver->smd_dci[SMD_MODEM_INDEX].peripheral_mask;
 		if (copy_to_user((void *)ioarg, &support_list,
 							 sizeof(uint16_t)))
 			return -EFAULT;
@@ -700,12 +687,10 @@
 		mutex_unlock(&driver->diagchar_mutex);
 		if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
 							== NO_LOGGING_MODE) {
-			driver->in_busy_1 = 1;
-			driver->in_busy_2 = 1;
-			driver->in_busy_lpass_1 = 1;
-			driver->in_busy_lpass_2 = 1;
-			driver->in_busy_wcnss_1 = 1;
-			driver->in_busy_wcnss_2 = 1;
+			for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+				driver->smd_data[i].in_busy_1 = 0;
+				driver->smd_data[i].in_busy_2 = 0;
+			}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 			driver->in_busy_sdio = 1;
 #endif
@@ -715,22 +700,15 @@
 #endif
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
-			driver->in_busy_1 = 0;
-			driver->in_busy_2 = 0;
-			driver->in_busy_lpass_1 = 0;
-			driver->in_busy_lpass_2 = 0;
-			driver->in_busy_wcnss_1 = 0;
-			driver->in_busy_wcnss_2 = 0;
-			/* Poll SMD channels to check for data*/
-			if (driver->ch)
-				queue_work(driver->diag_wq,
-					&(driver->diag_read_smd_work));
-			if (driver->chlpass)
-				queue_work(driver->diag_wq,
-					&(driver->diag_read_smd_lpass_work));
-			if (driver->ch_wcnss)
-				queue_work(driver->diag_wq,
-					&(driver->diag_read_smd_wcnss_work));
+			for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+				driver->smd_data[i].in_busy_1 = 0;
+				driver->smd_data[i].in_busy_2 = 0;
+				/* Poll SMD channels to check for data*/
+				if (driver->smd_data[i].ch)
+					queue_work(driver->diag_wq,
+						&(driver->smd_data[i].
+							diag_read_smd_work));
+			}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 			driver->in_busy_sdio = 0;
 			/* Poll SDIO channel to check for data */
@@ -758,23 +736,15 @@
 		} else if (temp == USB_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
 			diagfwd_disconnect();
-			driver->in_busy_1 = 0;
-			driver->in_busy_2 = 0;
-			driver->in_busy_lpass_1 = 0;
-			driver->in_busy_lpass_2 = 0;
-			driver->in_busy_wcnss_1 = 0;
-			driver->in_busy_wcnss_2 = 0;
-
-			/* Poll SMD channels to check for data*/
-			if (driver->ch)
-				queue_work(driver->diag_wq,
-					 &(driver->diag_read_smd_work));
-			if (driver->chlpass)
-				queue_work(driver->diag_wq,
-					&(driver->diag_read_smd_lpass_work));
-			if (driver->ch_wcnss)
-				queue_work(driver->diag_wq,
-					&(driver->diag_read_smd_wcnss_work));
+			for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+				driver->smd_data[i].in_busy_1 = 0;
+				driver->smd_data[i].in_busy_2 = 0;
+				/* Poll SMD channels to check for data*/
+				if (driver->smd_data[i].ch)
+					queue_work(driver->diag_wq,
+						&(driver->smd_data[i].
+							diag_read_smd_work));
+			}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 			driver->in_busy_sdio = 0;
 			/* Poll SDIO channel to check for data */
@@ -886,73 +856,30 @@
 		}
 
 		/* copy modem data */
-		if (driver->in_busy_1 == 1) {
-			num_data++;
-			/*Copy the length of data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-					 (driver->write_ptr_1->length), 4);
-			/*Copy the actual data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-					*(driver->buf_in_1),
-					 driver->write_ptr_1->length);
-			driver->in_busy_1 = 0;
-		}
-		if (driver->in_busy_2 == 1) {
-			num_data++;
-			/*Copy the length of data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-					 (driver->write_ptr_2->length), 4);
-			/*Copy the actual data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-					 *(driver->buf_in_2),
-					 driver->write_ptr_2->length);
-			driver->in_busy_2 = 0;
-		}
-		/* copy lpass data */
-		if (driver->in_busy_lpass_1 == 1) {
-			num_data++;
-			/*Copy the length of data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-				 (driver->write_ptr_lpass_1->length), 4);
-			/*Copy the actual data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
-							buf_in_lpass_1),
-					 driver->write_ptr_lpass_1->length);
-			driver->in_busy_lpass_1 = 0;
-		}
-		if (driver->in_busy_lpass_2 == 1) {
-			num_data++;
-			/*Copy the length of data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-				 (driver->write_ptr_lpass_2->length), 4);
-			/*Copy the actual data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
-				buf_in_lpass_2), driver->
-					write_ptr_lpass_2->length);
-			driver->in_busy_lpass_2 = 0;
-		}
-		/* copy wncss data */
-		if (driver->in_busy_wcnss_1 == 1) {
-			num_data++;
-			/*Copy the length of data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-				 (driver->write_ptr_wcnss_1->length), 4);
-			/*Copy the actual data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
-							buf_in_wcnss_1),
-					 driver->write_ptr_wcnss_1->length);
-			driver->in_busy_wcnss_1 = 0;
-		}
-		if (driver->in_busy_wcnss_2 == 1) {
-			num_data++;
-			/*Copy the length of data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret,
-				 (driver->write_ptr_wcnss_2->length), 4);
-			/*Copy the actual data being passed*/
-			COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
-							buf_in_wcnss_2),
-					 driver->write_ptr_wcnss_2->length);
-			driver->in_busy_wcnss_2 = 0;
+		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+			struct diag_smd_info *data = &driver->smd_data[i];
+			if (data->in_busy_1 == 1) {
+				num_data++;
+				/*Copy the length of data being passed*/
+				COPY_USER_SPACE_OR_EXIT(buf+ret,
+					(data->write_ptr_1->length), 4);
+				/*Copy the actual data being passed*/
+				COPY_USER_SPACE_OR_EXIT(buf+ret,
+					*(data->buf_in_1),
+					data->write_ptr_1->length);
+				data->in_busy_1 = 0;
+			}
+			if (data->in_busy_2 == 1) {
+				num_data++;
+				/*Copy the length of data being passed*/
+				COPY_USER_SPACE_OR_EXIT(buf+ret,
+					(data->write_ptr_2->length), 4);
+				/*Copy the actual data being passed*/
+				COPY_USER_SPACE_OR_EXIT(buf+ret,
+					*(data->buf_in_2),
+					data->write_ptr_2->length);
+				data->in_busy_2 = 0;
+			}
 		}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		/* copy 9K data over SDIO */
@@ -1045,15 +972,11 @@
 		COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
 		ret -= 4;
 		driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
-		if (driver->ch)
-			queue_work(driver->diag_wq,
-					 &(driver->diag_read_smd_work));
-		if (driver->chlpass)
-			queue_work(driver->diag_wq,
-					 &(driver->diag_read_smd_lpass_work));
-		if (driver->ch_wcnss)
-			queue_work(driver->diag_wq,
-					 &(driver->diag_read_smd_wcnss_work));
+		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+			if (driver->smd_data[i].ch)
+				queue_work(driver->diag_wq,
+				&(driver->smd_data[i].diag_read_smd_work));
+		}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		if (driver->sdio_ch)
 			queue_work(driver->diag_sdio_wq,
@@ -1135,10 +1058,11 @@
 			}
 		}
 		driver->data_ready[index] ^= DCI_DATA_TYPE;
-		driver->in_busy_dci = 0;
-		if (driver->ch_dci)
+		driver->smd_dci[SMD_MODEM_INDEX].in_busy_1 = 0;
+		if (driver->smd_dci[SMD_MODEM_INDEX].ch)
 			queue_work(driver->diag_dci_wq,
-				&(driver->diag_read_smd_dci_work));
+				&(driver->smd_dci[SMD_MODEM_INDEX].
+						diag_read_smd_work));
 		goto exit;
 	}
 exit:
@@ -1601,25 +1525,6 @@
 		init_waitqueue_head(&driver->wait_q);
 		init_waitqueue_head(&driver->smd_wait_q);
 		INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn);
-		INIT_WORK(&(driver->diag_read_smd_work), diag_read_smd_work_fn);
-		INIT_WORK(&(driver->diag_read_smd_cntl_work),
-						 diag_read_smd_cntl_work_fn);
-		INIT_WORK(&(driver->diag_read_smd_lpass_work),
-			   diag_read_smd_lpass_work_fn);
-		INIT_WORK(&(driver->diag_read_smd_lpass_cntl_work),
-			   diag_read_smd_lpass_cntl_work_fn);
-		INIT_WORK(&(driver->diag_read_smd_wcnss_work),
-			diag_read_smd_wcnss_work_fn);
-		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);
-		INIT_WORK(&(driver->diag_clean_modem_reg_work),
-						 diag_clean_modem_reg_fn);
-		INIT_WORK(&(driver->diag_clean_lpass_reg_work),
-						 diag_clean_lpass_reg_fn);
-		INIT_WORK(&(driver->diag_clean_wcnss_reg_work),
-						 diag_clean_wcnss_reg_fn);
 		diag_debugfs_init();
 		diag_masks_init();
 		diagfwd_init();
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index cee4c96..bc9d3fa 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -49,26 +49,26 @@
 unsigned char diag_debug_buf[1024];
 static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
 struct diag_master_table entry;
-smd_channel_t *ch_temp = NULL, *chlpass_temp = NULL, *ch_wcnss_temp = NULL;
 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
 
 void encode_rsp_and_send(int buf_length)
 {
+	struct diag_smd_info *data = &(driver->smd_data[SMD_MODEM_INDEX]);
 	send.state = DIAG_STATE_START;
 	send.pkt = driver->apps_rsp_buf;
 	send.last = (void *)(driver->apps_rsp_buf + buf_length);
 	send.terminate = 1;
-	if (!driver->in_busy_1) {
-		enc.dest = driver->buf_in_1;
-		enc.dest_last = (void *)(driver->buf_in_1 + APPS_BUF_SIZE - 1);
+	if (!data->in_busy_1) {
+		enc.dest = data->buf_in_1;
+		enc.dest_last = (void *)(data->buf_in_1 + APPS_BUF_SIZE - 1);
 		diag_hdlc_encode(&send, &enc);
-		driver->write_ptr_1->buf = driver->buf_in_1;
-		driver->write_ptr_1->length = (int)(enc.dest -
-						(void *)(driver->buf_in_1));
-		driver->in_busy_1 = 1;
-		diag_device_write(driver->buf_in_1, MODEM_DATA,
-					driver->write_ptr_1);
+		data->write_ptr_1->buf = data->buf_in_1;
+		data->write_ptr_1->length = (int)(enc.dest -
+						(void *)(data->buf_in_1));
+		data->in_busy_1 = 1;
+		diag_device_write(data->buf_in_1, MODEM_DATA,
+					data->write_ptr_1);
 		memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
 	}
 }
@@ -178,7 +178,8 @@
 		 * has registered to respond for polling
 		 */
 		return 1;
-	else if (!(driver->ch) && !(chk_apps_master()))
+	else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) &&
+					!(chk_apps_master()))
 		/*
 		 * If the apps processor is not the master and the modem
 		 * is not up
@@ -221,39 +222,82 @@
 	}
 }
 
-void __diag_smd_send_req(void)
+/* Process the data read from the smd data channel */
+int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
+								int total_recd)
 {
-	void *buf = NULL, *temp_buf = NULL;
-	int total_recd = 0, r = 0, pkt_len, *in_busy_ptr = NULL;
-	int loop_count = 0;
 	struct diag_request *write_ptr_modem = NULL;
+	int *in_busy_ptr = 0;
 
-	if (!driver->in_busy_1) {
-		buf = driver->buf_in_1;
-		write_ptr_modem = driver->write_ptr_1;
-		in_busy_ptr = &(driver->in_busy_1);
-	} else if (!driver->in_busy_2) {
-		buf = driver->buf_in_2;
-		write_ptr_modem = driver->write_ptr_2;
-		in_busy_ptr = &(driver->in_busy_2);
+	if (smd_info->buf_in_1 == buf) {
+		write_ptr_modem = smd_info->write_ptr_1;
+		in_busy_ptr = &smd_info->in_busy_1;
+	} else if (smd_info->buf_in_2 == buf) {
+		write_ptr_modem = smd_info->write_ptr_2;
+		in_busy_ptr = &smd_info->in_busy_2;
+	} else {
+		pr_err("diag: In %s, no match for in_busy_1\n", __func__);
 	}
 
-	if (driver->ch && buf) {
+	if (write_ptr_modem) {
+		int data_type;
+		switch (smd_info->peripheral) {
+		case MODEM_PROC:
+			data_type = MODEM_DATA;
+			break;
+		case LPASS_PROC:
+			data_type = LPASS_DATA;
+			break;
+		case WCNSS_PROC:
+			data_type = WCNSS_DATA;
+			break;
+		default:
+			pr_err("diag: In %s, unknown peripheral type: %d\n",
+				__func__, smd_info->peripheral);
+			return 0;
+		}
+		write_ptr_modem->length = total_recd;
+		*in_busy_ptr = 1;
+		diag_device_write(buf, data_type, write_ptr_modem);
+	}
+
+	return 0;
+}
+
+void diag_smd_send_req(struct diag_smd_info *smd_info)
+{
+	void *buf = NULL, *temp_buf = NULL;
+	int total_recd = 0, r = 0, pkt_len;
+	int loop_count = 0;
+	int notify = 0;
+
+	if (!smd_info) {
+		pr_err("diag: In %s, no smd info. Not able to read.\n",
+			__func__);
+		return;
+	}
+
+	if (!smd_info->in_busy_1)
+		buf = smd_info->buf_in_1;
+	else if ((smd_info->type == SMD_DATA_TYPE) && !smd_info->in_busy_2)
+		buf = smd_info->buf_in_2;
+
+	if (smd_info->ch && buf) {
 		temp_buf = buf;
-		pkt_len = smd_cur_packet_size(driver->ch);
+		pkt_len = smd_cur_packet_size(smd_info->ch);
 
 		while (pkt_len && (pkt_len != total_recd)) {
 			loop_count++;
-			r = smd_read_avail(driver->ch);
+			r = smd_read_avail(smd_info->ch);
 			pr_debug("diag: In %s, received pkt %d %d\n",
 				__func__, r, total_recd);
 			if (!r) {
 				/* Nothing to read from SMD */
 				wait_event(driver->smd_wait_q,
-					((driver->ch == 0) ||
-					smd_read_avail(driver->ch)));
+					((smd_info->ch == 0) ||
+					smd_read_avail(smd_info->ch)));
 				/* If the smd channel is open */
-				if (driver->ch) {
+				if (smd_info->ch) {
 					pr_debug("diag: In %s, return from wait_event\n",
 						__func__);
 					continue;
@@ -269,7 +313,7 @@
 					pr_err("diag: In %s, SMD sending in packets up to %d bytes\n",
 						__func__, total_recd);
 					buf = krealloc(buf, total_recd,
-							GFP_KERNEL);
+						GFP_KERNEL);
 				} else {
 					pr_err("diag: In %s, SMD sending in packets more than %d bytes\n",
 						__func__, MAX_IN_BUF_SIZE);
@@ -281,32 +325,43 @@
 					__func__);
 				return;
 			}
-			if (pkt_len > r)
-				pr_debug("diag: In %s, SMD sending partial pkt %d %d %d %d\n",
-					__func__, pkt_len, r, total_recd,
-					loop_count);
+			if (pkt_len > r) {
+				pr_err("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
+				__func__, pkt_len, r, total_recd, loop_count,
+				smd_info->peripheral, smd_info->type);
+			}
+
 			/* keep reading for complete packet */
-			smd_read(driver->ch, temp_buf, r);
+			smd_read(smd_info->ch, temp_buf, r);
 			temp_buf += r;
 		}
 
 		if (total_recd > 0) {
-			if (!buf)
+			if (!buf) {
 				pr_err("diag: Out of diagmem for Modem\n");
-			else {
-				APPEND_DEBUG('j');
-				write_ptr_modem->length = total_recd;
-				*in_busy_ptr = 1;
-				diag_device_write(buf, MODEM_DATA,
-							 write_ptr_modem);
+			} else if (smd_info->process_smd_read_data) {
+				notify = smd_info->process_smd_read_data(
+						smd_info, buf, total_recd);
+				/* Poll SMD channels to check for data */
+				if (notify)
+					diag_smd_notify(smd_info,
+							SMD_EVENT_DATA);
 			}
 		}
-	} else if (driver->ch && !buf &&
+	} else if (smd_info->ch && !buf &&
 		(driver->logging_mode == MEMORY_DEVICE_MODE)) {
-		chk_logging_wakeup();
+			chk_logging_wakeup();
 	}
 }
 
+void diag_read_smd_work_fn(struct work_struct *work)
+{
+	struct diag_smd_info *smd_info = container_of(work,
+							struct diag_smd_info,
+							diag_read_smd_work);
+	diag_smd_send_req(smd_info);
+}
+
 int diag_device_write(void *buf, int proc_num, struct diag_request *write_ptr)
 {
 	int i, err = 0;
@@ -365,20 +420,23 @@
 			return -EINVAL;
 	} else if (driver->logging_mode == NO_LOGGING_MODE) {
 		if (proc_num == MODEM_DATA) {
-			driver->in_busy_1 = 0;
-			driver->in_busy_2 = 0;
-			queue_work(driver->diag_wq, &(driver->
+			driver->smd_data[SMD_MODEM_INDEX].in_busy_1 = 0;
+			driver->smd_data[SMD_MODEM_INDEX].in_busy_2 = 0;
+			queue_work(driver->diag_wq,
+				&(driver->smd_data[SMD_MODEM_INDEX].
 							diag_read_smd_work));
 		} else if (proc_num == LPASS_DATA) {
-			driver->in_busy_lpass_1 = 0;
-			driver->in_busy_lpass_2 = 0;
-			queue_work(driver->diag_wq, &(driver->
-						diag_read_smd_lpass_work));
+			driver->smd_data[SMD_LPASS_INDEX].in_busy_1 = 0;
+			driver->smd_data[SMD_LPASS_INDEX].in_busy_2 = 0;
+			queue_work(driver->diag_wq,
+				&(driver->smd_data[SMD_LPASS_INDEX].
+							diag_read_smd_work));
 		}  else if (proc_num == WCNSS_DATA) {
-			driver->in_busy_wcnss_1 = 0;
-			driver->in_busy_wcnss_2 = 0;
-			queue_work(driver->diag_wq, &(driver->
-				diag_read_smd_wcnss_work));
+			driver->smd_data[SMD_WCNSS_INDEX].in_busy_1 = 0;
+			driver->smd_data[SMD_WCNSS_INDEX].in_busy_2 = 0;
+			queue_work(driver->diag_wq,
+				&(driver->smd_data[SMD_WCNSS_INDEX].
+							diag_read_smd_work));
 		}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		else if (proc_num == SDIO_DATA) {
@@ -483,179 +541,6 @@
     return err;
 }
 
-void __diag_smd_wcnss_send_req(void)
-{
-	void *buf = NULL, *temp_buf = NULL;
-	int total_recd = 0, r = 0, pkt_len, *in_busy_wcnss_ptr = NULL;
-	struct diag_request *write_ptr_wcnss = NULL;
-	int loop_count = 0;
-
-	if (!driver->in_busy_wcnss_1) {
-		buf = driver->buf_in_wcnss_1;
-		write_ptr_wcnss = driver->write_ptr_wcnss_1;
-		in_busy_wcnss_ptr = &(driver->in_busy_wcnss_1);
-	} else if (!driver->in_busy_wcnss_2) {
-		buf = driver->buf_in_wcnss_2;
-		write_ptr_wcnss = driver->write_ptr_wcnss_2;
-		in_busy_wcnss_ptr = &(driver->in_busy_wcnss_2);
-	}
-
-	if (driver->ch_wcnss && buf) {
-		temp_buf = buf;
-		pkt_len = smd_cur_packet_size(driver->ch_wcnss);
-
-		while (pkt_len && (pkt_len != total_recd)) {
-			loop_count++;
-			r = smd_read_avail(driver->ch_wcnss);
-			pr_debug("diag: In %s, received pkt %d %d\n",
-				__func__, r, total_recd);
-			if (!r) {
-				/* Nothing to read from SMD */
-				wait_event(driver->smd_wait_q,
-					((driver->ch_wcnss == 0) ||
-					smd_read_avail(driver->ch_wcnss)));
-				/* If the smd channel is open */
-				if (driver->ch_wcnss) {
-					pr_debug("diag: In %s, return from wait_event\n",
-						__func__);
-					continue;
-				} else {
-					pr_debug("diag: In %s, return from wait_event ch_wcnss closed\n",
-						__func__);
-					return;
-				}
-			}
-			total_recd += r;
-			if (total_recd > IN_BUF_SIZE) {
-				if (total_recd < MAX_IN_BUF_SIZE) {
-					pr_err("diag: In %s, SMD sending in packets up to %d bytes\n",
-						__func__, total_recd);
-					buf = krealloc(buf, total_recd,
-								 GFP_KERNEL);
-				} else {
-					pr_err("diag: In %s, SMD sending in packets more than %d bytes\n",
-						__func__, MAX_IN_BUF_SIZE);
-					return;
-				}
-			}
-			if (pkt_len < r) {
-				pr_err("diag: In %s, SMD sending incorrect pkt\n",
-					__func__);
-				return;
-			}
-			if (pkt_len > r) {
-				pr_debug("diag: In %s, SMD sending partial pkt %d %d %d %d\n",
-					__func__, pkt_len, r, total_recd,
-					loop_count);
-			}
-			/* keep reading for complete packet */
-			smd_read(driver->ch_wcnss, temp_buf, r);
-			temp_buf += r;
-		}
-
-		if (total_recd > 0) {
-			if (!buf) {
-				pr_err("diag: Out of diagmem for wcnss\n");
-			} else {
-				APPEND_DEBUG('j');
-				write_ptr_wcnss->length = total_recd;
-				*in_busy_wcnss_ptr = 1;
-				diag_device_write(buf, WCNSS_DATA,
-					 write_ptr_wcnss);
-			}
-		}
-	} else if (driver->ch_wcnss && !buf &&
-		(driver->logging_mode == MEMORY_DEVICE_MODE)) {
-		chk_logging_wakeup();
-	}
-}
-
-void __diag_smd_lpass_send_req(void)
-{
-	void *buf = NULL, *temp_buf = NULL;
-	int total_recd = 0, r = 0, pkt_len, *in_busy_lpass_ptr = NULL;
-	struct diag_request *write_ptr_lpass = NULL;
-	int loop_count = 0;
-
-	if (!driver->in_busy_lpass_1) {
-		buf = driver->buf_in_lpass_1;
-		write_ptr_lpass = driver->write_ptr_lpass_1;
-		in_busy_lpass_ptr = &(driver->in_busy_lpass_1);
-	} else if (!driver->in_busy_lpass_2) {
-		buf = driver->buf_in_lpass_2;
-		write_ptr_lpass = driver->write_ptr_lpass_2;
-		in_busy_lpass_ptr = &(driver->in_busy_lpass_2);
-	}
-
-	if (driver->chlpass && buf) {
-		temp_buf = buf;
-		pkt_len = smd_cur_packet_size(driver->chlpass);
-
-		while (pkt_len && (pkt_len != total_recd)) {
-			loop_count++;
-			r = smd_read_avail(driver->chlpass);
-			pr_debug("diag: In %s, received pkt %d %d\n",
-				__func__, r, total_recd);
-			if (!r) {
-				/* Nothing to read from SMD */
-				wait_event(driver->smd_wait_q,
-					((driver->chlpass == 0) ||
-					smd_read_avail(driver->chlpass)));
-				/* If the smd channel is open */
-				if (driver->chlpass) {
-					pr_debug("diag: In %s, return from wait_event\n",
-						__func__);
-					continue;
-				} else {
-					pr_debug("diag: In %s, return from wait_event chlpass closed\n",
-						__func__);
-					return;
-				}
-			}
-			total_recd += r;
-			if (total_recd > IN_BUF_SIZE) {
-				if (total_recd < MAX_IN_BUF_SIZE) {
-					pr_err("diag: In %s, SMD sending in packets up to %d bytes\n",
-						__func__, total_recd);
-					buf = krealloc(buf, total_recd,
-								 GFP_KERNEL);
-				} else {
-					pr_err("diag: In %s, SMD sending in packets more than %d bytes\n",
-						__func__, MAX_IN_BUF_SIZE);
-					return;
-				}
-			}
-			if (pkt_len < r) {
-				pr_err("diag: In %s, SMD sending incorrect pkt\n",
-					__func__);
-				return;
-			}
-			if (pkt_len > r)
-				pr_debug("diag: In %s, SMD sending partial pkt %d %d %d %d\n",
-					__func__, pkt_len, r, total_recd,
-					loop_count);
-			/* keep reading for complete packet */
-			smd_read(driver->chlpass, temp_buf, r);
-			temp_buf += r;
-		}
-
-		if (total_recd > 0) {
-			if (!buf)
-				pr_err("diag: Out of diagmem for LPASS\n");
-			else {
-				APPEND_DEBUG('j');
-				write_ptr_lpass->length = total_recd;
-				*in_busy_lpass_ptr = 1;
-				diag_device_write(buf, LPASS_DATA,
-							 write_ptr_lpass);
-			}
-		}
-	} else if (driver->chlpass && !buf &&
-		(driver->logging_mode == MEMORY_DEVICE_MODE)) {
-		chk_logging_wakeup();
-	}
-}
-
 static void diag_update_pkt_buffer(unsigned char *buf)
 {
 	unsigned char *ptr = driver->pkt_buf;
@@ -704,19 +589,23 @@
 		diag_update_sleeping_process(entry.process_id, PKT_TYPE);
 	} else {
 		if (len > 0) {
-			if (entry.client_id == MODEM_PROC && driver->ch) {
+			if (entry.client_id == MODEM_PROC &&
+					driver->smd_data[SMD_MODEM_INDEX].ch) {
 				if (chk_apps_master() &&
 					 (int)(*(char *)buf) == MODE_CMD)
 					if ((int)(*(char *)(buf+1)) ==
 						RESET_ID)
 						return;
-				smd_write(driver->ch, buf, len);
+				smd_write(driver->smd_data[SMD_MODEM_INDEX].ch,
+								buf, len);
 			} else if (entry.client_id == LPASS_PROC &&
-							 driver->chlpass) {
-				smd_write(driver->chlpass, buf, len);
+					driver->smd_data[SMD_LPASS_INDEX].ch) {
+				smd_write(driver->smd_data[SMD_LPASS_INDEX].ch,
+								buf, len);
 			} else if (entry.client_id == WCNSS_PROC &&
-							 driver->ch_wcnss) {
-				smd_write(driver->ch_wcnss, buf, len);
+					driver->smd_data[SMD_WCNSS_INDEX].ch) {
+				smd_write(driver->smd_data[SMD_WCNSS_INDEX].ch,
+								buf, len);
 			} else {
 				pr_alert("diag: incorrect channel");
 			}
@@ -799,7 +688,8 @@
 		return 0;
 	}
 	/* Check for Apps Only & get event mask request */
-	else if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
+	else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only() &&
+								*buf == 0x81) {
 		driver->apps_rsp_buf[0] = 0x81;
 		driver->apps_rsp_buf[1] = 0x0;
 		*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
@@ -810,7 +700,7 @@
 		return 0;
 	}
 	/* Get log ID range & Check for Apps Only */
-	else if (!(driver->ch) && chk_apps_only()
+	else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only()
 			  && (*buf == 0x73) && *(int *)(buf+4) == 1) {
 		driver->apps_rsp_buf[0] = 0x73;
 		*(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
@@ -835,7 +725,7 @@
 		return 0;
 	}
 	/* Respond to Get SSID Range request message */
-	else if (!(driver->ch) && chk_apps_only()
+	else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only()
 			 && (*buf == 0x7d) && (*(buf+1) == 0x1)) {
 		driver->apps_rsp_buf[0] = 0x7d;
 		driver->apps_rsp_buf[1] = 0x1;
@@ -893,7 +783,7 @@
 		return 0;
 	}
 	/* Check for Apps Only Respond to Get Subsys Build mask */
-	else if (!(driver->ch) && chk_apps_only()
+	else if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && chk_apps_only()
 			 && (*buf == 0x7d) && (*(buf+1) == 0x2)) {
 		ssid_first = *(uint16_t *)(buf + 2);
 		ssid_last = *(uint16_t *)(buf + 4);
@@ -1110,13 +1000,14 @@
 		type = 0;
 	}
 	/* implies this packet is NOT meant for apps */
-	if (!(driver->ch) && type == 1) {
+	if (!(driver->smd_data[SMD_MODEM_INDEX].ch) && type == 1) {
 		if (chk_apps_only()) {
 			diag_send_error_rsp(hdlc.dest_idx);
 		} else { /* APQ 8060, Let Q6 respond */
-			if (driver->chlpass)
-				smd_write(driver->chlpass, driver->hdlc_buf,
-						  hdlc.dest_idx - 3);
+			if (driver->smd_data[SMD_LPASS_INDEX].ch)
+				smd_write(driver->smd_data[SMD_LPASS_INDEX].ch,
+						driver->hdlc_buf,
+						hdlc.dest_idx - 3);
 		}
 		type = 0;
 	}
@@ -1128,9 +1019,11 @@
 							driver->hdlc_buf)+i));
 #endif /* DIAG DEBUG */
 	/* ignore 2 bytes for CRC, one for 7E and send */
-	if ((driver->ch) && (ret) && (type) && (hdlc.dest_idx > 3)) {
+	if ((driver->smd_data[SMD_MODEM_INDEX].ch) && (ret) && (type) &&
+						(hdlc.dest_idx > 3)) {
 		APPEND_DEBUG('g');
-		smd_write(driver->ch, driver->hdlc_buf, hdlc.dest_idx - 3);
+		smd_write(driver->smd_data[SMD_MODEM_INDEX].ch,
+					driver->hdlc_buf, hdlc.dest_idx - 3);
 		APPEND_DEBUG('h');
 #ifdef DIAG_DEBUG
 		printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
@@ -1148,6 +1041,7 @@
 int diagfwd_connect(void)
 {
 	int err;
+	int i;
 
 	printk(KERN_DEBUG "diag: USB connected\n");
 	err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
@@ -1156,21 +1050,16 @@
 		printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
 
 	driver->usb_connected = 1;
-	driver->in_busy_1 = 0;
-	driver->in_busy_2 = 0;
-	driver->in_busy_lpass_1 = 0;
-	driver->in_busy_lpass_2 = 0;
-	driver->in_busy_wcnss_1 = 0;
-	driver->in_busy_wcnss_2 = 0;
+	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+		driver->smd_data[i].in_busy_1 = 0;
+		driver->smd_data[i].in_busy_2 = 0;
+		/* Poll SMD data channels to check for data */
+		queue_work(driver->diag_wq,
+			&(driver->smd_data[i].diag_read_smd_work));
+		/* Poll SMD CNTL channels to check for data */
+		diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
+	}
 
-	/* Poll SMD channels to check for data*/
-	queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
-	queue_work(driver->diag_wq, &(driver->diag_read_smd_lpass_work));
-	queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
-	/* Poll SMD CNTL channels to check for data */
-	diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
-	diag_smd_lpass_cntl_notify(NULL, SMD_EVENT_DATA);
-	diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
 	/* Poll USB channel to check for data*/
 	queue_work(driver->diag_wq, &(driver->diag_read_work));
 #ifdef CONFIG_DIAG_SDIO_PIPE
@@ -1186,17 +1075,17 @@
 
 int diagfwd_disconnect(void)
 {
+	int i;
+
 	printk(KERN_DEBUG "diag: USB disconnected\n");
 	driver->usb_connected = 0;
 	driver->debug_flag = 1;
 	usb_diag_free_req(driver->legacy_ch);
 	if (driver->logging_mode == USB_MODE) {
-		driver->in_busy_1 = 1;
-		driver->in_busy_2 = 1;
-		driver->in_busy_lpass_1 = 1;
-		driver->in_busy_lpass_2 = 1;
-		driver->in_busy_wcnss_1 = 1;
-		driver->in_busy_wcnss_2 = 1;
+		for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+			driver->smd_data[i].in_busy_1 = 1;
+			driver->smd_data[i].in_busy_2 = 1;
+		}
 	}
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
@@ -1210,50 +1099,44 @@
 int diagfwd_write_complete(struct diag_request *diag_write_ptr)
 {
 	unsigned char *buf = diag_write_ptr->buf;
-	/*Determine if the write complete is for data from modem/apps/q6 */
+	int found_it = 0;
+	int i;
+
+	/* Determine if the write complete is for data from modem/apps/q6 */
 	/* Need a context variable here instead */
-	if (buf == (void *)driver->buf_in_1) {
-		driver->in_busy_1 = 0;
-		APPEND_DEBUG('o');
-		queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
-	} else if (buf == (void *)driver->buf_in_2) {
-		driver->in_busy_2 = 0;
-		APPEND_DEBUG('O');
-		queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
-	} else if (buf == (void *)driver->buf_in_lpass_1) {
-		driver->in_busy_lpass_1 = 0;
-		APPEND_DEBUG('p');
-		queue_work(driver->diag_wq,
-				&(driver->diag_read_smd_lpass_work));
-	} else if (buf == (void *)driver->buf_in_lpass_2) {
-		driver->in_busy_lpass_2 = 0;
-		APPEND_DEBUG('P');
-		queue_work(driver->diag_wq,
-				&(driver->diag_read_smd_lpass_work));
-	} else if (buf == driver->buf_in_wcnss_1) {
-		driver->in_busy_wcnss_1 = 0;
-		APPEND_DEBUG('r');
-		queue_work(driver->diag_wq,
-			 &(driver->diag_read_smd_wcnss_work));
-	} else if (buf == driver->buf_in_wcnss_2) {
-		driver->in_busy_wcnss_2 = 0;
-		APPEND_DEBUG('R');
-		queue_work(driver->diag_wq,
-			 &(driver->diag_read_smd_wcnss_work));
+	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+		struct diag_smd_info *data = &(driver->smd_data[i]);
+		if (buf == (void *)data->buf_in_1) {
+			data->in_busy_1 = 0;
+			queue_work(driver->diag_wq,
+				&(data->diag_read_smd_work));
+			found_it = 1;
+			break;
+		} else if (buf == (void *)data->buf_in_2) {
+			data->in_busy_2 = 0;
+			queue_work(driver->diag_wq,
+				&(data->diag_read_smd_work));
+			found_it = 1;
+			break;
+		}
 	}
 #ifdef CONFIG_DIAG_SDIO_PIPE
-	else if (buf == (void *)driver->buf_in_sdio)
-		if (machine_is_msm8x60_fusion() ||
-			 machine_is_msm8x60_fusn_ffa())
-			diagfwd_write_complete_sdio();
-		else
-			pr_err("diag: Incorrect buffer pointer while WRITE");
+	if (!found_it) {
+		if (buf == (void *)driver->buf_in_sdio) {
+			if (machine_is_msm8x60_fusion() ||
+				 machine_is_msm8x60_fusn_ffa())
+				diagfwd_write_complete_sdio();
+			else
+				pr_err("diag: Incorrect buffer pointer while WRITE");
+			found_it = 1;
+		}
+	}
 #endif
-	else {
-		diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HDLC);
+	if (!found_it) {
+		diagmem_free(driver, (unsigned char *)buf,
+						POOL_TYPE_HDLC);
 		diagmem_free(driver, (unsigned char *)diag_write_ptr,
-						 POOL_TYPE_WRITE_STRUCT);
-		APPEND_DEBUG('q');
+						POOL_TYPE_WRITE_STRUCT);
 	}
 	return 0;
 }
@@ -1340,76 +1223,87 @@
 
 #endif /* DIAG OVER USB */
 
-static void diag_smd_notify(void *ctxt, unsigned event)
+void diag_smd_notify(void *ctxt, unsigned event)
 {
-	if (event == SMD_EVENT_CLOSE) {
-		driver->ch = 0;
-		wake_up(&driver->smd_wait_q);
-		queue_work(driver->diag_cntl_wq,
-			 &(driver->diag_clean_modem_reg_work));
+	struct diag_smd_info *smd_info = (struct diag_smd_info *)ctxt;
+	if (!smd_info)
 		return;
-	} else if (event == SMD_EVENT_OPEN) {
-		if (ch_temp)
-			driver->ch = ch_temp;
-	}
-	wake_up(&driver->smd_wait_q);
-	queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
-}
 
-#if defined(CONFIG_MSM_N_WAY_SMD)
-static void diag_smd_lpass_notify(void *ctxt, unsigned event)
-{
 	if (event == SMD_EVENT_CLOSE) {
-		driver->chlpass = 0;
+		smd_info->ch = 0;
 		wake_up(&driver->smd_wait_q);
-		queue_work(driver->diag_cntl_wq,
-			 &(driver->diag_clean_lpass_reg_work));
+		if (smd_info->type == SMD_DATA_TYPE) {
+			smd_info->notify_context = event;
+			queue_work(driver->diag_cntl_wq,
+				 &(smd_info->diag_notify_update_smd_work));
+		} else if (smd_info->type == SMD_DCI_TYPE) {
+			/* Notify the clients of the close */
+			diag_dci_notify_client(smd_info->peripheral_mask,
+							DIAG_STATUS_CLOSED);
+		}
 		return;
 	} else if (event == SMD_EVENT_OPEN) {
-		if (chlpass_temp)
-			driver->chlpass = chlpass_temp;
-	}
-	wake_up(&driver->smd_wait_q);
-	queue_work(driver->diag_wq, &(driver->diag_read_smd_lpass_work));
-}
-#endif
+		if (smd_info->ch_save)
+			smd_info->ch = smd_info->ch_save;
 
-static void diag_smd_wcnss_notify(void *ctxt, unsigned event)
-{
-	if (event == SMD_EVENT_CLOSE) {
-		driver->ch_wcnss = 0;
-		wake_up(&driver->smd_wait_q);
-		queue_work(driver->diag_cntl_wq,
-			 &(driver->diag_clean_wcnss_reg_work));
-		return;
-	} else if (event == SMD_EVENT_OPEN) {
-		if (ch_wcnss_temp)
-			driver->ch_wcnss = ch_wcnss_temp;
+		if (smd_info->type == SMD_CNTL_TYPE) {
+			smd_info->notify_context = event;
+			queue_work(driver->diag_cntl_wq,
+				&(smd_info->diag_notify_update_smd_work));
+		} else if (smd_info->type == SMD_DCI_TYPE) {
+			smd_info->notify_context = event;
+			queue_work(driver->diag_dci_wq,
+				&(smd_info->diag_notify_update_smd_work));
+			/* Notify the clients of the open */
+			diag_dci_notify_client(smd_info->peripheral_mask,
+							DIAG_STATUS_OPEN);
+		}
 	}
+
 	wake_up(&driver->smd_wait_q);
-	queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
+
+	if (smd_info->type == SMD_DCI_TYPE)
+		queue_work(driver->diag_dci_wq,
+				&(smd_info->diag_read_smd_work));
+	else
+		queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
 }
 
 static int diag_smd_probe(struct platform_device *pdev)
 {
 	int r = 0;
+	int index = -1;
 
 	if (pdev->id == SMD_APPS_MODEM) {
-		r = smd_open("DIAG", &driver->ch, driver, diag_smd_notify);
-		ch_temp = driver->ch;
+		index = SMD_MODEM_INDEX;
+		r = smd_open("DIAG", &driver->smd_data[index].ch,
+					&driver->smd_data[index],
+					diag_smd_notify);
+		driver->smd_data[index].ch_save =
+					driver->smd_data[index].ch;
 	}
 #if defined(CONFIG_MSM_N_WAY_SMD)
 	if (pdev->id == SMD_APPS_QDSP) {
+		index = SMD_LPASS_INDEX;
 		r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
-			&driver->chlpass, driver, diag_smd_lpass_notify);
-		chlpass_temp = driver->chlpass;
+					&driver->smd_data[index].ch,
+					&driver->smd_data[index],
+					diag_smd_notify);
+		driver->smd_data[index].ch_save =
+					driver->smd_data[index].ch;
 	}
 #endif
 	if (pdev->id == SMD_APPS_WCNSS) {
-		r = smd_named_open_on_edge("APPS_RIVA_DATA", SMD_APPS_WCNSS
-			, &driver->ch_wcnss, driver, diag_smd_wcnss_notify);
-		ch_wcnss_temp = driver->ch_wcnss;
+		index = SMD_WCNSS_INDEX;
+		r = smd_named_open_on_edge("APPS_RIVA_DATA",
+					SMD_APPS_WCNSS,
+					&driver->smd_data[index].ch,
+					&driver->smd_data[index],
+					diag_smd_notify);
+		driver->smd_data[index].ch_save =
+					driver->smd_data[index].ch;
 	}
+
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 	pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
@@ -1417,86 +1311,175 @@
 	return 0;
 }
 
-static int diagfwd_runtime_suspend(struct device *dev)
+static int diag_smd_runtime_suspend(struct device *dev)
 {
 	dev_dbg(dev, "pm_runtime: suspending...\n");
 	return 0;
 }
 
-static int diagfwd_runtime_resume(struct device *dev)
+static int diag_smd_runtime_resume(struct device *dev)
 {
 	dev_dbg(dev, "pm_runtime: resuming...\n");
 	return 0;
 }
 
-static const struct dev_pm_ops diagfwd_dev_pm_ops = {
-	.runtime_suspend = diagfwd_runtime_suspend,
-	.runtime_resume = diagfwd_runtime_resume,
+static const struct dev_pm_ops diag_smd_dev_pm_ops = {
+	.runtime_suspend = diag_smd_runtime_suspend,
+	.runtime_resume = diag_smd_runtime_resume,
 };
 
 static struct platform_driver msm_smd_ch1_driver = {
 
 	.probe = diag_smd_probe,
 	.driver = {
-		   .name = "DIAG",
-		   .owner = THIS_MODULE,
-		   .pm   = &diagfwd_dev_pm_ops,
-		   },
+		.name = "DIAG",
+		.owner = THIS_MODULE,
+		.pm   = &diag_smd_dev_pm_ops,
+	},
 };
 
 static struct platform_driver diag_smd_lite_driver = {
 
 	.probe = diag_smd_probe,
 	.driver = {
-		   .name = "APPS_RIVA_DATA",
-		   .owner = THIS_MODULE,
-		   .pm   = &diagfwd_dev_pm_ops,
-		   },
+		.name = "APPS_RIVA_DATA",
+		.owner = THIS_MODULE,
+		.pm   = &diag_smd_dev_pm_ops,
+	},
 };
 
+void diag_smd_destructor(struct diag_smd_info *smd_info)
+{
+	if (smd_info->ch)
+		smd_close(smd_info->ch);
+
+	smd_info->ch = 0;
+	smd_info->ch_save = 0;
+	kfree(smd_info->buf_in_1);
+	kfree(smd_info->buf_in_2);
+	kfree(smd_info->write_ptr_1);
+	kfree(smd_info->write_ptr_2);
+}
+
+int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
+			  int type, uint16_t peripheral_mask)
+{
+	smd_info->peripheral = peripheral;
+	smd_info->type = type;
+	smd_info->peripheral_mask = peripheral_mask;
+
+	smd_info->ch = 0;
+	smd_info->ch_save = 0;
+
+	if (smd_info->buf_in_1 == NULL) {
+		smd_info->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+		if (smd_info->buf_in_1 == NULL)
+			goto err;
+		kmemleak_not_leak(smd_info->buf_in_1);
+	}
+
+	if (smd_info->write_ptr_1 == NULL) {
+		smd_info->write_ptr_1 = kzalloc(sizeof(struct diag_request),
+								GFP_KERNEL);
+		if (smd_info->write_ptr_1 == NULL)
+			goto err;
+		kmemleak_not_leak(smd_info->write_ptr_1);
+	}
+
+	/* The smd data type needs two buffers */
+	if (smd_info->type == SMD_DATA_TYPE) {
+		if (smd_info->buf_in_2 == NULL) {
+			smd_info->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+			if (smd_info->buf_in_2 == NULL)
+				goto err;
+			kmemleak_not_leak(smd_info->buf_in_2);
+		}
+		if (smd_info->write_ptr_2 == NULL) {
+			smd_info->write_ptr_2 =
+				kzalloc(sizeof(struct diag_request),
+				GFP_KERNEL);
+			if (smd_info->write_ptr_2 == NULL)
+				goto err;
+			kmemleak_not_leak(smd_info->write_ptr_2);
+		}
+	}
+
+	INIT_WORK(&(smd_info->diag_read_smd_work), diag_read_smd_work_fn);
+
+	/*
+	 * The update function assigned to the diag_notify_update_smd_work
+	 * work_struct is meant to be used for updating that is not to
+	 * be done in the context of the smd notify function. The
+	 * notify_context variable can be used for passing additional
+	 * information to the update function.
+	 */
+	smd_info->notify_context = 0;
+	if (type == SMD_DATA_TYPE)
+		INIT_WORK(&(smd_info->diag_notify_update_smd_work),
+							diag_clean_reg_fn);
+	else if (type == SMD_CNTL_TYPE)
+		INIT_WORK(&(smd_info->diag_notify_update_smd_work),
+							diag_mask_update_fn);
+	else if (type == SMD_DCI_TYPE)
+		INIT_WORK(&(smd_info->diag_notify_update_smd_work),
+						diag_update_smd_dci_work_fn);
+	else {
+		pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
+		goto err;
+	}
+
+	/*
+	 * Set function ptr for function to call to process the data that
+	 * was just read from the smd channel
+	 */
+	if (type == SMD_DATA_TYPE)
+		smd_info->process_smd_read_data = diag_process_smd_read_data;
+	else if (type == SMD_CNTL_TYPE)
+		smd_info->process_smd_read_data =
+						diag_process_smd_cntl_read_data;
+	else if (type == SMD_DCI_TYPE)
+		smd_info->process_smd_read_data =
+						diag_process_smd_dci_read_data;
+	else {
+		pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
+		goto err;
+	}
+
+	return 1;
+err:
+	kfree(smd_info->buf_in_1);
+	kfree(smd_info->buf_in_2);
+	kfree(smd_info->write_ptr_1);
+	kfree(smd_info->write_ptr_2);
+
+	return 0;
+}
+
 void diagfwd_init(void)
 {
+	int success;
+	int i;
+
 	diag_debug_buf_idx = 0;
 	driver->read_len_legacy = 0;
 	driver->use_device_tree = has_device_tree();
 	mutex_init(&driver->diag_cntl_mutex);
 
-	if (driver->buf_in_1 == NULL) {
-		driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_1 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_in_1);
-	}
-	if (driver->buf_in_2 == NULL) {
-		driver->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_2 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_in_2);
-	}
-	if (driver->buf_in_lpass_1 == NULL) {
-		driver->buf_in_lpass_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_lpass_1 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_in_lpass_1);
-	}
-	if (driver->buf_in_lpass_2 == NULL) {
-		driver->buf_in_lpass_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_lpass_2 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_in_lpass_2);
-	}
-	if (driver->buf_in_wcnss_1 == NULL) {
-		driver->buf_in_wcnss_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_wcnss_1 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_in_wcnss_1);
-	}
-	if (driver->buf_in_wcnss_2 == NULL) {
-		driver->buf_in_wcnss_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_wcnss_2 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_in_wcnss_2);
-	}
+	success = diag_smd_constructor(&driver->smd_data[SMD_MODEM_INDEX],
+				MODEM_PROC, SMD_DATA_TYPE, DIAG_CON_MPSS);
+	if (!success)
+		goto err;
+
+	success = diag_smd_constructor(&driver->smd_data[SMD_LPASS_INDEX],
+				LPASS_PROC, SMD_DATA_TYPE, DIAG_CON_LPASS);
+	if (!success)
+		goto err;
+
+	success = diag_smd_constructor(&driver->smd_data[SMD_WCNSS_INDEX],
+				WCNSS_PROC, SMD_DATA_TYPE, DIAG_CON_WCNSS);
+	if (!success)
+		goto err;
+
 	if (driver->usb_buf_out  == NULL &&
 	     (driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
 					 GFP_KERNEL)) == NULL)
@@ -1534,48 +1517,6 @@
 		       GFP_KERNEL)) == NULL)
 		goto err;
 	kmemleak_not_leak(driver->table);
-	if (driver->write_ptr_1 == NULL) {
-		driver->write_ptr_1 = kzalloc(
-			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->write_ptr_1 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->write_ptr_1);
-	}
-	if (driver->write_ptr_2 == NULL) {
-		driver->write_ptr_2 = kzalloc(
-			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->write_ptr_2 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->write_ptr_2);
-	}
-	if (driver->write_ptr_lpass_1 == NULL) {
-		driver->write_ptr_lpass_1 = kzalloc(
-			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->write_ptr_lpass_1 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->write_ptr_lpass_1);
-	}
-	if (driver->write_ptr_lpass_2 == NULL) {
-		driver->write_ptr_lpass_2 = kzalloc(
-			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->write_ptr_lpass_2 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->write_ptr_lpass_2);
-	}
-	if (driver->write_ptr_wcnss_1 == NULL) {
-		driver->write_ptr_wcnss_1 = kzalloc(
-			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->write_ptr_wcnss_1 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->write_ptr_wcnss_1);
-	}
-	if (driver->write_ptr_wcnss_2 == NULL) {
-		driver->write_ptr_wcnss_2 = kzalloc(
-			sizeof(struct diag_request), GFP_KERNEL);
-		if (driver->write_ptr_wcnss_2 == NULL)
-			goto err;
-		kmemleak_not_leak(driver->write_ptr_wcnss_2);
-	}
 
 	if (driver->usb_read_ptr == NULL) {
 		driver->usb_read_ptr = kzalloc(
@@ -1608,16 +1549,13 @@
 #endif
 	platform_driver_register(&msm_smd_ch1_driver);
 	platform_driver_register(&diag_smd_lite_driver);
-
 	return;
 err:
 	pr_err("diag: Could not initialize diag buffers");
-	kfree(driver->buf_in_1);
-	kfree(driver->buf_in_2);
-	kfree(driver->buf_in_lpass_1);
-	kfree(driver->buf_in_lpass_2);
-	kfree(driver->buf_in_wcnss_1);
-	kfree(driver->buf_in_wcnss_2);
+
+	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
+		diag_smd_destructor(&driver->smd_data[i]);
+
 	kfree(driver->buf_msg_mask_update);
 	kfree(driver->buf_log_mask_update);
 	kfree(driver->buf_event_mask_update);
@@ -1628,12 +1566,6 @@
 	kfree(driver->data_ready);
 	kfree(driver->table);
 	kfree(driver->pkt_buf);
-	kfree(driver->write_ptr_1);
-	kfree(driver->write_ptr_2);
-	kfree(driver->write_ptr_lpass_1);
-	kfree(driver->write_ptr_lpass_2);
-	kfree(driver->write_ptr_wcnss_1);
-	kfree(driver->write_ptr_wcnss_2);
 	kfree(driver->usb_read_ptr);
 	kfree(driver->apps_rsp_buf);
 	kfree(driver->user_space_data);
@@ -1643,12 +1575,11 @@
 
 void diagfwd_exit(void)
 {
-	smd_close(driver->ch);
-	smd_close(driver->chlpass);
-	smd_close(driver->ch_wcnss);
-	driver->ch = 0;		/* SMD can make this NULL */
-	driver->chlpass = 0;
-	driver->ch_wcnss = 0;
+	int i;
+
+	for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
+		diag_smd_destructor(&driver->smd_data[i]);
+
 #ifdef CONFIG_DIAG_OVER_USB
 	if (driver->usb_connected)
 		usb_diag_free_req(driver->legacy_ch);
@@ -1657,12 +1588,7 @@
 	platform_driver_unregister(&msm_smd_ch1_driver);
 	platform_driver_unregister(&msm_diag_dci_driver);
 	platform_driver_unregister(&diag_smd_lite_driver);
-	kfree(driver->buf_in_1);
-	kfree(driver->buf_in_2);
-	kfree(driver->buf_in_lpass_1);
-	kfree(driver->buf_in_lpass_2);
-	kfree(driver->buf_in_wcnss_1);
-	kfree(driver->buf_in_wcnss_2);
+
 	kfree(driver->buf_msg_mask_update);
 	kfree(driver->buf_log_mask_update);
 	kfree(driver->buf_event_mask_update);
@@ -1673,12 +1599,6 @@
 	kfree(driver->data_ready);
 	kfree(driver->table);
 	kfree(driver->pkt_buf);
-	kfree(driver->write_ptr_1);
-	kfree(driver->write_ptr_2);
-	kfree(driver->write_ptr_lpass_1);
-	kfree(driver->write_ptr_lpass_2);
-	kfree(driver->write_ptr_wcnss_1);
-	kfree(driver->write_ptr_wcnss_2);
 	kfree(driver->usb_read_ptr);
 	kfree(driver->apps_rsp_buf);
 	kfree(driver->user_space_data);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index a0631d6..b7f4aba 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -22,9 +22,7 @@
 void diagfwd_init(void);
 void diagfwd_exit(void);
 void diag_process_hdlc(void *data, unsigned len);
-void __diag_smd_send_req(void);
-void __diag_smd_lpass_send_req(void);
-void __diag_smd_wcnss_send_req(void);
+void diag_smd_send_req(struct diag_smd_info *smd_info);
 void diag_usb_legacy_notifier(void *, unsigned, struct diag_request *);
 long diagchar_ioctl(struct file *, unsigned int, unsigned long);
 int diag_device_write(void *, int, struct diag_request *);
@@ -37,6 +35,10 @@
 void diag_update_userspace_clients(unsigned int type);
 void diag_update_sleeping_process(int process_id, int data_type);
 void encode_rsp_and_send(int buf_length);
+void diag_smd_notify(void *ctxt, unsigned event);
+int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
+			 int type, uint16_t peripheral_mask);
+void diag_smd_destructor(struct diag_smd_info *smd_info);
 /* State for diag forwarding */
 #ifdef CONFIG_DIAG_OVER_USB
 int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 4848a1d..0673635 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -21,253 +21,145 @@
 static uint16_t reg_dirty;
 #define HDR_SIZ 8
 
-void diag_clean_modem_reg_fn(struct work_struct *work)
+void diag_clean_reg_fn(struct work_struct *work)
 {
-	pr_debug("diag: clean modem registration\n");
-	reg_dirty |= DIAG_CON_MPSS;
-	diag_clear_reg(MODEM_PROC);
-	reg_dirty ^= DIAG_CON_MPSS;
-}
-
-void diag_clean_lpass_reg_fn(struct work_struct *work)
-{
-	pr_debug("diag: clean lpass registration\n");
-	reg_dirty |= DIAG_CON_LPASS;
-	diag_clear_reg(LPASS_PROC);
-	reg_dirty ^= DIAG_CON_LPASS;
-}
-
-void diag_clean_wcnss_reg_fn(struct work_struct *work)
-{
-	pr_debug("diag: clean wcnss registration\n");
-	reg_dirty |= DIAG_CON_WCNSS;
-	diag_clear_reg(WCNSS_PROC);
-	reg_dirty ^= DIAG_CON_WCNSS;
-}
-
-void diag_smd_cntl_notify(void *ctxt, unsigned event)
-{
-	int r1, r2;
-
-	if (!(driver->ch_cntl))
+	struct diag_smd_info *smd_info = container_of(work,
+						struct diag_smd_info,
+						diag_notify_update_smd_work);
+	if (!smd_info)
 		return;
 
-	switch (event) {
-	case SMD_EVENT_DATA:
-		r1 = smd_read_avail(driver->ch_cntl);
-		r2 = smd_cur_packet_size(driver->ch_cntl);
-		if (r1 > 0 && r1 == r2)
-			queue_work(driver->diag_wq,
-				 &(driver->diag_read_smd_cntl_work));
-		else
-			pr_debug("diag: incomplete pkt on Modem CNTL ch\n");
-		break;
-	case SMD_EVENT_OPEN:
-		queue_work(driver->diag_cntl_wq,
-			 &(driver->diag_modem_mask_update_work));
-		break;
-	}
+	pr_debug("diag: clean registration for peripheral: %d\n",
+		smd_info->peripheral);
+
+	reg_dirty |= smd_info->peripheral_mask;
+	diag_clear_reg(smd_info->peripheral);
+	reg_dirty ^= smd_info->peripheral_mask;
+
+	smd_info->notify_context = 0;
 }
 
-void diag_smd_lpass_cntl_notify(void *ctxt, unsigned event)
+/* Process the data read from the smd control channel */
+int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
+								int total_recd)
 {
-	int r1, r2;
-
-	if (!(driver->chlpass_cntl))
-		return;
-
-	switch (event) {
-	case SMD_EVENT_DATA:
-		r1 = smd_read_avail(driver->chlpass_cntl);
-		r2 = smd_cur_packet_size(driver->chlpass_cntl);
-		if (r1 > 0 && r1 == r2)
-			queue_work(driver->diag_wq,
-				 &(driver->diag_read_smd_lpass_cntl_work));
-		else
-			pr_debug("diag: incomplete pkt on LPASS CNTL ch\n");
-		break;
-	case SMD_EVENT_OPEN:
-		queue_work(driver->diag_cntl_wq,
-			 &(driver->diag_lpass_mask_update_work));
-		break;
-	}
-}
-
-void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event)
-{
-	int r1, r2;
-
-	if (!(driver->ch_wcnss_cntl))
-		return;
-
-	switch (event) {
-	case SMD_EVENT_DATA:
-		r1 = smd_read_avail(driver->ch_wcnss_cntl);
-		r2 = smd_cur_packet_size(driver->ch_wcnss_cntl);
-		if (r1 > 0 && r1 == r2)
-			queue_work(driver->diag_wq,
-				 &(driver->diag_read_smd_wcnss_cntl_work));
-		else
-			pr_debug("diag: incomplete pkt on WCNSS CNTL ch\n");
-		break;
-	case SMD_EVENT_OPEN:
-		queue_work(driver->diag_cntl_wq,
-			 &(driver->diag_wcnss_mask_update_work));
-		break;
-	}
-}
-
-static void diag_smd_cntl_send_req(int proc_num)
-{
-	int data_len = 0, type = -1, count_bytes = 0, j, r, flag = 0;
+	int data_len = 0, type = -1, count_bytes = 0, j, flag = 0;
 	struct bindpkt_params_per_process *pkt_params =
-		 kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
+		kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
 	struct diag_ctrl_msg *msg;
 	struct cmd_code_range *range;
 	struct bindpkt_params *temp;
-	void *buf = NULL;
-	smd_channel_t *smd_ch = NULL;
-	/* tracks which peripheral is sending registration */
-	uint16_t reg_mask = 0;
 
 	if (pkt_params == NULL) {
-		pr_alert("diag: Memory allocation failure\n");
-		return;
+		pr_alert("diag: In %s, Memory allocation failure\n",
+			__func__);
+		return 0;
 	}
 
-	if (proc_num == MODEM_PROC) {
-		buf = driver->buf_in_cntl;
-		smd_ch = driver->ch_cntl;
-		reg_mask = DIAG_CON_MPSS;
-	} else if (proc_num == LPASS_PROC) {
-		buf = driver->buf_in_lpass_cntl;
-		smd_ch = driver->chlpass_cntl;
-		reg_mask = DIAG_CON_LPASS;
-	} else if (proc_num == WCNSS_PROC) {
-		buf = driver->buf_in_wcnss_cntl;
-		smd_ch = driver->ch_wcnss_cntl;
-		reg_mask = DIAG_CON_WCNSS;
-	}
-
-	if (!smd_ch || !buf) {
+	if (!smd_info) {
+		pr_err("diag: In %s, No smd info. Not able to read.\n",
+			__func__);
 		kfree(pkt_params);
-		return;
+		return 0;
 	}
 
-	r = smd_read_avail(smd_ch);
-	if (r > IN_BUF_SIZE) {
-		if (r < MAX_IN_BUF_SIZE) {
-			pr_err("diag: SMD CNTL sending pkt upto %d bytes", r);
-			buf = krealloc(buf, r, GFP_KERNEL);
-		} else {
-			pr_err("diag: CNTL pkt > %d bytes", MAX_IN_BUF_SIZE);
-			kfree(pkt_params);
-			return;
+	while (count_bytes + HDR_SIZ <= total_recd) {
+		type = *(uint32_t *)(buf);
+		data_len = *(uint32_t *)(buf + 4);
+		if (type < DIAG_CTRL_MSG_REG ||
+				 type > DIAG_CTRL_MSG_F3_MASK_V2) {
+			pr_alert("diag: In %s, Invalid Msg type %d proc %d",
+				 __func__, type, smd_info->peripheral);
+			break;
 		}
-	}
-	if (buf && r > 0) {
-		smd_read(smd_ch, buf, r);
-		while (count_bytes + HDR_SIZ <= r) {
-			type = *(uint32_t *)(buf);
-			data_len = *(uint32_t *)(buf + 4);
-			if (type < DIAG_CTRL_MSG_REG ||
-					 type > DIAG_CTRL_MSG_F3_MASK_V2) {
-				pr_alert("diag: Invalid Msg type %d proc %d",
-					 type, proc_num);
-				break;
-			}
-			if (data_len < 0 || data_len > r) {
-				pr_alert("diag: Invalid data len %d proc %d",
-					 data_len, proc_num);
-				break;
-			}
-			count_bytes = count_bytes+HDR_SIZ+data_len;
-			if (type == DIAG_CTRL_MSG_REG && r >= count_bytes) {
-				msg = buf+HDR_SIZ;
-				range = buf+HDR_SIZ+
-						sizeof(struct diag_ctrl_msg);
-				pkt_params->count = msg->count_entries;
-				temp = kzalloc(pkt_params->count * sizeof(struct
-						 bindpkt_params), GFP_KERNEL);
-				if (temp == NULL) {
-					pr_alert("diag: Memory alloc fail\n");
-					kfree(pkt_params);
-					return;
-				}
-				for (j = 0; j < pkt_params->count; j++) {
-					temp->cmd_code = msg->cmd_code;
-					temp->subsys_id = msg->subsysid;
-					temp->client_id = proc_num;
-					temp->proc_id = proc_num;
-					temp->cmd_code_lo = range->cmd_code_lo;
-					temp->cmd_code_hi = range->cmd_code_hi;
-					range++;
-					temp++;
-				}
-				temp -= pkt_params->count;
-				pkt_params->params = temp;
-				flag = 1;
-				/* peripheral undergoing SSR should not
-				 * record new registration
-				 */
-				if (!(reg_dirty & reg_mask))
-					diagchar_ioctl(NULL,
-					 DIAG_IOCTL_COMMAND_REG, (unsigned long)
-								pkt_params);
-				else
-					pr_err("diag: drop reg proc %d\n",
-								 proc_num);
-				kfree(temp);
-			} else if (type != DIAG_CTRL_MSG_REG) {
-				flag = 1;
-			}
-			buf = buf + HDR_SIZ + data_len;
+		if (data_len < 0 || data_len > total_recd) {
+			pr_alert("diag: In %s, Invalid data len %d, total_recd: %d, proc %d",
+				 __func__, data_len, total_recd,
+				 smd_info->peripheral);
+			break;
 		}
+		count_bytes = count_bytes+HDR_SIZ+data_len;
+		if (type == DIAG_CTRL_MSG_REG && total_recd >= count_bytes) {
+			msg = buf+HDR_SIZ;
+			range = buf+HDR_SIZ+
+					sizeof(struct diag_ctrl_msg);
+			pkt_params->count = msg->count_entries;
+			temp = kzalloc(pkt_params->count * sizeof(struct
+					 bindpkt_params), GFP_KERNEL);
+			if (temp == NULL) {
+				pr_alert("diag: In %s, Memory alloc fail\n",
+					__func__);
+				kfree(pkt_params);
+				return flag;
+			}
+			for (j = 0; j < pkt_params->count; j++) {
+				temp->cmd_code = msg->cmd_code;
+				temp->subsys_id = msg->subsysid;
+				temp->client_id = smd_info->peripheral;
+				temp->proc_id = smd_info->peripheral;
+				temp->cmd_code_lo = range->cmd_code_lo;
+				temp->cmd_code_hi = range->cmd_code_hi;
+				range++;
+				temp++;
+			}
+			temp -= pkt_params->count;
+			pkt_params->params = temp;
+			flag = 1;
+			/* peripheral undergoing SSR should not
+			 * record new registration
+			 */
+			if (!(reg_dirty & smd_info->peripheral_mask))
+				diagchar_ioctl(NULL, DIAG_IOCTL_COMMAND_REG,
+						(unsigned long)pkt_params);
+			else
+				pr_err("diag: drop reg proc %d\n",
+						smd_info->peripheral);
+			kfree(temp);
+		} else if (type != DIAG_CTRL_MSG_REG) {
+			flag = 1;
+		}
+		buf = buf + HDR_SIZ + data_len;
 	}
 	kfree(pkt_params);
-	if (flag) {
-		/* Poll SMD CNTL channels to check for data */
-		if (proc_num == MODEM_PROC)
-			diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
-		else if (proc_num == LPASS_PROC)
-			diag_smd_lpass_cntl_notify(NULL, SMD_EVENT_DATA);
-		else if (proc_num == WCNSS_PROC)
-			diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
-	}
-}
 
-void diag_read_smd_cntl_work_fn(struct work_struct *work)
-{
-	diag_smd_cntl_send_req(MODEM_PROC);
-}
-
-void diag_read_smd_lpass_cntl_work_fn(struct work_struct *work)
-{
-	diag_smd_cntl_send_req(LPASS_PROC);
-}
-
-void diag_read_smd_wcnss_cntl_work_fn(struct work_struct *work)
-{
-	diag_smd_cntl_send_req(WCNSS_PROC);
+	return flag;
 }
 
 static int diag_smd_cntl_probe(struct platform_device *pdev)
 {
 	int r = 0;
+	int index = -1;
 
 	/* open control ports only on 8960 & newer targets */
 	if (chk_apps_only()) {
-		if (pdev->id == SMD_APPS_MODEM)
-			r = smd_open("DIAG_CNTL", &driver->ch_cntl, driver,
-							diag_smd_cntl_notify);
-		if (pdev->id == SMD_APPS_QDSP)
-			r = smd_named_open_on_edge("DIAG_CNTL", SMD_APPS_QDSP
-					, &driver->chlpass_cntl, driver,
-					diag_smd_lpass_cntl_notify);
-		if (pdev->id == SMD_APPS_WCNSS)
+		if (pdev->id == SMD_APPS_MODEM) {
+			index = SMD_MODEM_INDEX;
+			r = smd_open("DIAG_CNTL",
+					&driver->smd_cntl[index].ch,
+					&driver->smd_cntl[index],
+					diag_smd_notify);
+			driver->smd_cntl[index].ch_save =
+					driver->smd_cntl[index].ch;
+		} else if (pdev->id == SMD_APPS_QDSP) {
+			index = SMD_LPASS_INDEX;
+			r = smd_named_open_on_edge("DIAG_CNTL",
+					SMD_APPS_QDSP,
+					&driver->smd_cntl[index].ch,
+					&driver->smd_cntl[index],
+					diag_smd_notify);
+			driver->smd_cntl[index].ch_save =
+					driver->smd_cntl[index].ch;
+		} else if (pdev->id == SMD_APPS_WCNSS) {
+			index = SMD_WCNSS_INDEX;
 			r = smd_named_open_on_edge("APPS_RIVA_CTRL",
-				SMD_APPS_WCNSS, &driver->ch_wcnss_cntl,
-					driver, diag_smd_wcnss_cntl_notify);
+					SMD_APPS_WCNSS,
+					&driver->smd_cntl[index].ch,
+					&driver->smd_cntl[index],
+					diag_smd_notify);
+			driver->smd_cntl[index].ch_save =
+					driver->smd_cntl[index].ch;
+		}
+
 		pr_debug("diag: open CNTL port, ID = %d,r = %d\n", pdev->id, r);
 	}
 	return 0;
@@ -312,53 +204,51 @@
 
 void diagfwd_cntl_init(void)
 {
+	int success;
+	int i;
+
 	reg_dirty = 0;
 	driver->polling_reg_flag = 0;
 	driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
-	if (driver->buf_in_cntl == NULL) {
-		driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_cntl == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_in_cntl);
-	}
-	if (driver->buf_in_lpass_cntl == NULL) {
-		driver->buf_in_lpass_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_lpass_cntl == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_in_lpass_cntl);
-	}
-	if (driver->buf_in_wcnss_cntl == NULL) {
-		driver->buf_in_wcnss_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
-		if (driver->buf_in_wcnss_cntl == NULL)
-			goto err;
-		kmemleak_not_leak(driver->buf_in_wcnss_cntl);
-	}
+
+	success = diag_smd_constructor(&driver->smd_cntl[SMD_MODEM_INDEX],
+				MODEM_PROC, SMD_CNTL_TYPE, DIAG_CON_MPSS);
+	if (!success)
+		goto err;
+
+	success = diag_smd_constructor(&driver->smd_cntl[SMD_LPASS_INDEX],
+				LPASS_PROC, SMD_CNTL_TYPE, DIAG_CON_LPASS);
+	if (!success)
+		goto err;
+
+	success = diag_smd_constructor(&driver->smd_cntl[SMD_WCNSS_INDEX],
+				WCNSS_PROC, SMD_CNTL_TYPE, DIAG_CON_WCNSS);
+	if (!success)
+		goto err;
+
 	platform_driver_register(&msm_smd_ch1_cntl_driver);
 	platform_driver_register(&diag_smd_lite_cntl_driver);
 
 	return;
 err:
-		pr_err("diag: Could not initialize diag buffers");
-		kfree(driver->buf_in_cntl);
-		kfree(driver->buf_in_lpass_cntl);
-		kfree(driver->buf_in_wcnss_cntl);
-		if (driver->diag_cntl_wq)
-			destroy_workqueue(driver->diag_cntl_wq);
+	pr_err("diag: Could not initialize diag buffers");
+
+	for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+		diag_smd_destructor(&driver->smd_cntl[i]);
+
+	if (driver->diag_cntl_wq)
+		destroy_workqueue(driver->diag_cntl_wq);
 }
 
 void diagfwd_cntl_exit(void)
 {
-	smd_close(driver->ch_cntl);
-	smd_close(driver->chlpass_cntl);
-	smd_close(driver->ch_wcnss_cntl);
-	driver->ch_cntl = 0;
-	driver->chlpass_cntl = 0;
-	driver->ch_wcnss_cntl = 0;
+	int i;
+
+	for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+		diag_smd_destructor(&driver->smd_cntl[i]);
+
 	destroy_workqueue(driver->diag_cntl_wq);
+
 	platform_driver_unregister(&msm_smd_ch1_cntl_driver);
 	platform_driver_unregister(&diag_smd_lite_cntl_driver);
-
-	kfree(driver->buf_in_cntl);
-	kfree(driver->buf_in_lpass_cntl);
-	kfree(driver->buf_in_wcnss_cntl);
 }
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 8a0ec3f..aeb4ba1 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -80,13 +80,8 @@
 void diagfwd_cntl_init(void);
 void diagfwd_cntl_exit(void);
 void diag_read_smd_cntl_work_fn(struct work_struct *);
-void diag_read_smd_lpass_cntl_work_fn(struct work_struct *);
-void diag_read_smd_wcnss_cntl_work_fn(struct work_struct *);
-void diag_smd_cntl_notify(void *ctxt, unsigned event);
-void diag_smd_lpass_cntl_notify(void *ctxt, unsigned event);
-void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event);
-void diag_clean_modem_reg_fn(struct work_struct *);
-void diag_clean_lpass_reg_fn(struct work_struct *);
-void diag_clean_wcnss_reg_fn(struct work_struct *);
+void diag_clean_reg_fn(struct work_struct *work);
+int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
+								int total_recd);
 
 #endif
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 4b03cfd..8a75cd9 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -92,6 +92,8 @@
 	unsigned int freq_lo_jiffies;
 	unsigned int freq_hi_jiffies;
 	unsigned int rate_mult;
+	unsigned int prev_load;
+	unsigned int max_load;
 	int cpu;
 	unsigned int sample_type:1;
 	/*
@@ -125,17 +127,27 @@
 static struct dbs_tuners {
 	unsigned int sampling_rate;
 	unsigned int up_threshold;
+	unsigned int up_threshold_multi_core;
 	unsigned int down_differential;
+	unsigned int down_differential_multi_core;
+	unsigned int optimal_freq;
+	unsigned int up_threshold_any_cpu_load;
+	unsigned int sync_freq;
 	unsigned int ignore_nice;
 	unsigned int sampling_down_factor;
 	int          powersave_bias;
 	unsigned int io_is_busy;
 } dbs_tuners_ins = {
+	.up_threshold_multi_core = DEF_FREQUENCY_UP_THRESHOLD,
 	.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
 	.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
 	.down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
+	.down_differential_multi_core = MICRO_FREQUENCY_DOWN_DIFFERENTIAL,
+	.up_threshold_any_cpu_load = DEF_FREQUENCY_UP_THRESHOLD,
 	.ignore_nice = 0,
 	.powersave_bias = 0,
+	.sync_freq = 0,
+	.optimal_freq = 0,
 };
 
 static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
@@ -293,9 +305,13 @@
 show_one(sampling_rate, sampling_rate);
 show_one(io_is_busy, io_is_busy);
 show_one(up_threshold, up_threshold);
+show_one(up_threshold_multi_core, up_threshold_multi_core);
 show_one(down_differential, down_differential);
 show_one(sampling_down_factor, sampling_down_factor);
 show_one(ignore_nice_load, ignore_nice);
+show_one(optimal_freq, optimal_freq);
+show_one(up_threshold_any_cpu_load, up_threshold_any_cpu_load);
+show_one(sync_freq, sync_freq);
 
 static ssize_t show_powersave_bias
 (struct kobject *kobj, struct attribute *attr, char *buf)
@@ -371,6 +387,19 @@
 	return count;
 }
 
+static ssize_t store_sync_freq(struct kobject *a, struct attribute *b,
+				   const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+
+	ret = sscanf(buf, "%u", &input);
+	if (ret != 1)
+		return -EINVAL;
+	dbs_tuners_ins.sync_freq = input;
+	return count;
+}
+
 static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b,
 				   const char *buf, size_t count)
 {
@@ -384,6 +413,19 @@
 	return count;
 }
 
+static ssize_t store_optimal_freq(struct kobject *a, struct attribute *b,
+				   const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+
+	ret = sscanf(buf, "%u", &input);
+	if (ret != 1)
+		return -EINVAL;
+	dbs_tuners_ins.optimal_freq = input;
+	return count;
+}
+
 static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
 				  const char *buf, size_t count)
 {
@@ -399,6 +441,36 @@
 	return count;
 }
 
+static ssize_t store_up_threshold_multi_core(struct kobject *a,
+			struct attribute *b, const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+	ret = sscanf(buf, "%u", &input);
+
+	if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD ||
+			input < MIN_FREQUENCY_UP_THRESHOLD) {
+		return -EINVAL;
+	}
+	dbs_tuners_ins.up_threshold_multi_core = input;
+	return count;
+}
+
+static ssize_t store_up_threshold_any_cpu_load(struct kobject *a,
+			struct attribute *b, const char *buf, size_t count)
+{
+	unsigned int input;
+	int ret;
+	ret = sscanf(buf, "%u", &input);
+
+	if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD ||
+			input < MIN_FREQUENCY_UP_THRESHOLD) {
+		return -EINVAL;
+	}
+	dbs_tuners_ins.up_threshold_any_cpu_load = input;
+	return count;
+}
+
 static ssize_t store_down_differential(struct kobject *a, struct attribute *b,
 		const char *buf, size_t count)
 {
@@ -581,6 +653,10 @@
 define_one_global_rw(sampling_down_factor);
 define_one_global_rw(ignore_nice_load);
 define_one_global_rw(powersave_bias);
+define_one_global_rw(up_threshold_multi_core);
+define_one_global_rw(optimal_freq);
+define_one_global_rw(up_threshold_any_cpu_load);
+define_one_global_rw(sync_freq);
 
 static struct attribute *dbs_attributes[] = {
 	&sampling_rate_min.attr,
@@ -591,6 +667,10 @@
 	&ignore_nice_load.attr,
 	&powersave_bias.attr,
 	&io_is_busy.attr,
+	&up_threshold_multi_core.attr,
+	&optimal_freq.attr,
+	&up_threshold_any_cpu_load.attr,
+	&sync_freq.attr,
 	NULL
 };
 
@@ -619,7 +699,7 @@
 	unsigned int max_load_freq;
 	/* Current load across this CPU */
 	unsigned int cur_load = 0;
-
+	unsigned int max_load_other_cpu = 0;
 	struct cpufreq_policy *policy;
 	unsigned int j;
 
@@ -696,7 +776,8 @@
 			continue;
 
 		cur_load = 100 * (wall_time - idle_time) / wall_time;
-
+		j_dbs_info->max_load  = max(cur_load, j_dbs_info->prev_load);
+		j_dbs_info->prev_load = cur_load;
 		freq_avg = __cpufreq_driver_getavg(policy, j);
 		if (freq_avg <= 0)
 			freq_avg = policy->cur;
@@ -705,11 +786,37 @@
 		if (load_freq > max_load_freq)
 			max_load_freq = load_freq;
 	}
+
+	for_each_online_cpu(j) {
+		struct cpu_dbs_info_s *j_dbs_info;
+		j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
+
+		if (j == policy->cpu)
+			continue;
+
+		if (max_load_other_cpu < j_dbs_info->max_load)
+			max_load_other_cpu = j_dbs_info->max_load;
+		/*
+		 * The other cpu could be running at higher frequency
+		 * but may not have completed it's sampling_down_factor.
+		 * For that case consider other cpu is loaded so that
+		 * frequency imbalance does not occur.
+		 */
+
+		if ((j_dbs_info->cur_policy != NULL)
+			&& (j_dbs_info->cur_policy->cur ==
+					j_dbs_info->cur_policy->max)) {
+
+			if (policy->cur >= dbs_tuners_ins.optimal_freq)
+				max_load_other_cpu =
+				dbs_tuners_ins.up_threshold_any_cpu_load;
+		}
+	}
+
 	/* calculate the scaled load across CPU */
 	load_at_max_freq = (cur_load * policy->cur)/policy->cpuinfo.max_freq;
 
 	cpufreq_notify_utilization(policy, load_at_max_freq);
-
 	/* Check for frequency increase */
 	if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
 		/* If switching to max speed, apply sampling_down_factor */
@@ -720,6 +827,25 @@
 		return;
 	}
 
+	if (num_online_cpus() > 1) {
+
+		if (max_load_other_cpu >
+				dbs_tuners_ins.up_threshold_any_cpu_load) {
+			if (policy->cur < dbs_tuners_ins.sync_freq)
+				dbs_freq_increase(policy,
+						dbs_tuners_ins.sync_freq);
+			return;
+		}
+
+		if (max_load_freq > dbs_tuners_ins.up_threshold_multi_core *
+								policy->cur) {
+			if (policy->cur < dbs_tuners_ins.optimal_freq)
+				dbs_freq_increase(policy,
+						dbs_tuners_ins.optimal_freq);
+			return;
+		}
+	}
+
 	/* Check for frequency decrease */
 	/* if we cannot reduce the frequency anymore, break out early */
 	if (policy->cur == policy->min)
@@ -744,6 +870,20 @@
 		if (freq_next < policy->min)
 			freq_next = policy->min;
 
+		if (num_online_cpus() > 1) {
+			if (max_load_other_cpu >
+			(dbs_tuners_ins.up_threshold_multi_core -
+			dbs_tuners_ins.down_differential) &&
+			freq_next < dbs_tuners_ins.sync_freq)
+				freq_next = dbs_tuners_ins.sync_freq;
+
+			if (max_load_freq >
+				 (dbs_tuners_ins.up_threshold_multi_core -
+				  dbs_tuners_ins.down_differential_multi_core) *
+				  policy->cur)
+				freq_next = dbs_tuners_ins.optimal_freq;
+
+		}
 		if (!dbs_tuners_ins.powersave_bias) {
 			__cpufreq_driver_target(policy, freq_next,
 					CPUFREQ_RELATION_L);
@@ -997,6 +1137,12 @@
 				max(min_sampling_rate,
 				    latency * LATENCY_MULTIPLIER);
 			dbs_tuners_ins.io_is_busy = should_io_be_busy();
+
+			if (dbs_tuners_ins.optimal_freq == 0)
+				dbs_tuners_ins.optimal_freq = policy->min;
+
+			if (dbs_tuners_ins.sync_freq == 0)
+				dbs_tuners_ins.sync_freq = policy->min;
 		}
 		if (!cpu)
 			rc = input_register_handler(&dbs_input_handler);
@@ -1014,7 +1160,6 @@
 		dbs_timer_exit(this_dbs_info);
 
 		mutex_lock(&dbs_mutex);
-		mutex_destroy(&this_dbs_info->timer_mutex);
 		dbs_enable--;
 		/* If device is being removed, policy is no longer
 		 * valid. */
@@ -1093,7 +1238,14 @@
 
 static void __exit cpufreq_gov_dbs_exit(void)
 {
+	unsigned int i;
+
 	cpufreq_unregister_governor(&cpufreq_gov_ondemand);
+	for_each_possible_cpu(i) {
+		struct cpu_dbs_info_s *this_dbs_info =
+			&per_cpu(od_cpu_dbs_info, i);
+		mutex_destroy(&this_dbs_info->timer_mutex);
+	}
 	destroy_workqueue(input_wq);
 }
 
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index 800c376..150c434 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -48,6 +48,8 @@
 };
 #endif
 
+static int tlmm_msm_summary_irq;
+
 struct tlmm_field_cfg {
 	enum msm_tlmm_register reg;
 	u8                     off;
@@ -381,12 +383,12 @@
 
 	if (on) {
 		if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
-			irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 1);
+			irq_set_irq_wake(tlmm_msm_summary_irq, 1);
 		set_bit(gpio, msm_gpio.wake_irqs);
 	} else {
 		clear_bit(gpio, msm_gpio.wake_irqs);
 		if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
-			irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 0);
+			irq_set_irq_wake(tlmm_msm_summary_irq, 0);
 	}
 
 	if (msm_gpio_irq_extn.irq_set_wake)
@@ -540,6 +542,11 @@
 #ifndef CONFIG_OF
 	int irq, i;
 #endif
+	tlmm_msm_summary_irq = platform_get_irq(pdev, 0);
+	if (tlmm_msm_summary_irq < 0) {
+		pr_err("%s: No interrupt defined for msmgpio\n", __func__);
+		return -ENXIO;
+	}
 	msm_gpio.gpio_chip.dev = &pdev->dev;
 	spin_lock_init(&tlmm_lock);
 	bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
@@ -558,10 +565,10 @@
 		set_irq_flags(irq, IRQF_VALID);
 	}
 #endif
-	ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
+	ret = request_irq(tlmm_msm_summary_irq, msm_summary_irq_handler,
 			IRQF_TRIGGER_HIGH, "msmgpio", NULL);
 	if (ret) {
-		pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
+		pr_err("Request_irq failed for tlmm_msm_summary_irq - %d\n",
 				ret);
 		return ret;
 	}
@@ -584,7 +591,7 @@
 	ret = gpiochip_remove(&msm_gpio.gpio_chip);
 	if (ret < 0)
 		return ret;
-	irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
+	irq_set_handler(tlmm_msm_summary_irq, NULL);
 
 	return 0;
 }
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index c9e8a94..51349f6 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o ion_cp_heap.o
+obj-$(CONFIG_CMA) += ion_cma_heap.o
 obj-$(CONFIG_ION_TEGRA) += tegra/
 obj-$(CONFIG_ION_MSM) += msm/
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
new file mode 100644
index 0000000..bef6b6f
--- /dev/null
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -0,0 +1,342 @@
+/*
+ * 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>
+#include <linux/msm_ion.h>
+#include <mach/iommu_domains.h>
+
+#include <asm/cacheflush.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;
+	bool is_cached;
+};
+
+static int cma_heap_has_outer_cache;
+/*
+ * 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;
+	}
+
+	if (!ION_IS_CACHED(flags))
+		info->cpu_addr = dma_alloc_writecombine(dev, len,
+					&(info->handle), 0);
+	else
+		info->cpu_addr = dma_alloc_nonconsistent(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;
+	}
+
+	info->is_cached = ION_IS_CACHED(flags);
+
+	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,
+		info->handle);
+
+	*addr = info->handle;
+	*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;
+
+	if (info->is_cached)
+		return dma_mmap_nonconsistent(dev, vma, info->cpu_addr,
+				info->handle, buffer->size);
+	else
+		return dma_mmap_writecombine(dev, vma, info->cpu_addr,
+				info->handle, buffer->size);
+}
+
+static void *ion_cma_map_kernel(struct ion_heap *heap,
+				struct ion_buffer *buffer)
+{
+	struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+	return info->cpu_addr;
+}
+
+static void ion_cma_unmap_kernel(struct ion_heap *heap,
+				 struct ion_buffer *buffer)
+{
+	return;
+}
+
+int ion_cma_map_iommu(struct ion_buffer *buffer,
+				struct ion_iommu_map *data,
+				unsigned int domain_num,
+				unsigned int partition_num,
+				unsigned long align,
+				unsigned long iova_length,
+				unsigned long flags)
+{
+	int ret = 0;
+	struct iommu_domain *domain;
+	unsigned long extra;
+	unsigned long extra_iova_addr;
+	struct ion_cma_buffer_info *info = buffer->priv_virt;
+	struct sg_table *table = info->table;
+	int prot = IOMMU_WRITE | IOMMU_READ;
+
+	data->mapped_size = iova_length;
+
+	if (!msm_use_iommu()) {
+		data->iova_addr = info->handle;
+		return 0;
+	}
+
+	extra = iova_length - buffer->size;
+
+	ret = msm_allocate_iova_address(domain_num, partition_num,
+						data->mapped_size, align,
+						&data->iova_addr);
+
+	if (ret)
+		goto out;
+
+	domain = msm_get_iommu_domain(domain_num);
+
+	if (!domain) {
+		ret = -EINVAL;
+		goto out1;
+	}
+
+	ret = iommu_map_range(domain, data->iova_addr, table->sgl,
+				buffer->size, prot);
+
+	if (ret) {
+		pr_err("%s: could not map %lx in domain %p\n",
+			__func__, data->iova_addr, domain);
+		goto out1;
+	}
+
+	extra_iova_addr = data->iova_addr + buffer->size;
+	if (extra) {
+		ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
+						prot);
+		if (ret)
+			goto out2;
+	}
+	return ret;
+
+out2:
+	iommu_unmap_range(domain, data->iova_addr, buffer->size);
+out1:
+	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+				data->mapped_size);
+out:
+	return ret;
+}
+
+
+void ion_cma_unmap_iommu(struct ion_iommu_map *data)
+{
+	unsigned int domain_num;
+	unsigned int partition_num;
+	struct iommu_domain *domain;
+
+	if (!msm_use_iommu())
+		return;
+
+	domain_num = iommu_map_domain(data);
+	partition_num = iommu_map_partition(data);
+
+	domain = msm_get_iommu_domain(domain_num);
+
+	if (!domain) {
+		WARN(1, "Could not get domain %d. Corruption?\n", domain_num);
+		return;
+	}
+
+	iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
+	msm_free_iova_address(data->iova_addr, domain_num, partition_num,
+				data->mapped_size);
+
+	return;
+}
+
+int ion_cma_cache_ops(struct ion_heap *heap,
+			struct ion_buffer *buffer, void *vaddr,
+			unsigned int offset, unsigned int length,
+			unsigned int cmd)
+{
+	void (*outer_cache_op)(phys_addr_t, phys_addr_t);
+
+	switch (cmd) {
+	case ION_IOC_CLEAN_CACHES:
+		dmac_clean_range(vaddr, vaddr + length);
+		outer_cache_op = outer_clean_range;
+		break;
+	case ION_IOC_INV_CACHES:
+		dmac_inv_range(vaddr, vaddr + length);
+		outer_cache_op = outer_inv_range;
+		break;
+	case ION_IOC_CLEAN_INV_CACHES:
+		dmac_flush_range(vaddr, vaddr + length);
+		outer_cache_op = outer_flush_range;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (cma_heap_has_outer_cache) {
+		struct ion_cma_buffer_info *info = buffer->priv_virt;
+
+		outer_cache_op(info->handle, info->handle + length);
+	}
+
+	return 0;
+}
+
+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,
+	.map_kernel = ion_cma_map_kernel,
+	.unmap_kernel = ion_cma_unmap_kernel,
+	.map_iommu = ion_cma_map_iommu,
+	.unmap_iommu = ion_cma_unmap_iommu,
+	.cache_op = ion_cma_cache_ops,
+};
+
+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;
+	cma_heap_has_outer_cache = data->has_outer_cache;
+	return heap;
+}
+
+void ion_cma_heap_destroy(struct ion_heap *heap)
+{
+	kfree(heap);
+}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index aa3469c..d96b755 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -2,7 +2,7 @@
  * drivers/gpu/ion/ion_cp_heap.c
  *
  * Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-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
@@ -15,7 +15,7 @@
  *
  */
 #include <linux/spinlock.h>
-
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/genalloc.h>
 #include <linux/io.h>
@@ -28,6 +28,7 @@
 #include <linux/seq_file.h>
 #include <linux/fmem.h>
 #include <linux/iommu.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/mach/map.h>
 
@@ -99,6 +100,11 @@
 	int iommu_2x_map_domain;
 	unsigned int has_outer_cache;
 	atomic_t protect_cnt;
+	void *cpu_addr;
+	size_t heap_size;
+	dma_addr_t handle;
+	int cma;
+	int disallow_non_secure_allocation;
 };
 
 enum {
@@ -126,6 +132,8 @@
 	void *data;
 };
 
+#define DMA_ALLOC_TRIES	5
+
 static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
 			unsigned int permission_type, int version,
 			void *data);
@@ -134,6 +142,71 @@
 				unsigned int permission_type, int version,
 				void *data);
 
+static int allocate_heap_memory(struct ion_heap *heap)
+{
+	struct device *dev = heap->priv;
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+	int ret;
+	int tries = 0;
+	DEFINE_DMA_ATTRS(attrs);
+	dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
+
+
+	if (cp_heap->cpu_addr)
+		return 0;
+
+	while (!cp_heap->cpu_addr && (++tries < DMA_ALLOC_TRIES)) {
+		cp_heap->cpu_addr = dma_alloc_attrs(dev,
+						cp_heap->heap_size,
+						&(cp_heap->handle),
+						0,
+						&attrs);
+		if (!cp_heap->cpu_addr)
+			msleep(20);
+	}
+
+	if (!cp_heap->cpu_addr)
+		goto out;
+
+	cp_heap->base = cp_heap->handle;
+
+	cp_heap->pool = gen_pool_create(12, -1);
+	if (!cp_heap->pool)
+		goto out_free;
+
+	ret = gen_pool_add(cp_heap->pool, cp_heap->base,
+				cp_heap->heap_size, -1);
+	if (ret < 0)
+		goto out_pool;
+
+	return 0;
+
+out_pool:
+	gen_pool_destroy(cp_heap->pool);
+out_free:
+	dma_free_coherent(dev, cp_heap->heap_size, cp_heap->cpu_addr,
+				cp_heap->handle);
+out:
+	return ION_CP_ALLOCATE_FAIL;
+}
+
+static void free_heap_memory(struct ion_heap *heap)
+{
+	struct device *dev = heap->priv;
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+
+	/* release memory */
+	dma_free_coherent(dev, cp_heap->heap_size, cp_heap->cpu_addr,
+				cp_heap->handle);
+	gen_pool_destroy(cp_heap->pool);
+	cp_heap->pool = NULL;
+	cp_heap->cpu_addr = 0;
+}
+
+
+
 /**
  * Get the total number of kernel mappings.
  * Must be called with heap->lock locked.
@@ -155,6 +228,12 @@
 		if (ret_value)
 			return 1;
 	}
+
+	if (cp_heap->cma) {
+		ret_value = allocate_heap_memory(heap);
+		if (ret_value)
+			return 1;
+	}
 	return 0;
 }
 
@@ -167,6 +246,9 @@
 		if (fmem_set_state(FMEM_T_STATE) != 0)
 			pr_err("%s: unable to transition heap to T-state\n",
 				__func__);
+
+	if (cp_heap->cma)
+		free_heap_memory(heap);
 }
 
 /* Must be protected by ion_cp_buffer lock */
@@ -399,6 +481,13 @@
 		return ION_CP_ALLOCATE_FAIL;
 	}
 
+	if (!secure_allocation && cp_heap->disallow_non_secure_allocation) {
+		mutex_unlock(&cp_heap->lock);
+		pr_debug("%s: non-secure allocation disallowed from this heap\n",
+			__func__);
+		return ION_CP_ALLOCATE_FAIL;
+	}
+
 	/*
 	 * The check above already checked for non-secure allocations when the
 	 * heap is protected. HEAP_PROTECTED implies that this must be a secure
@@ -688,7 +777,24 @@
 		if (cp_heap->reusable) {
 			ret_value = ion_map_fmem_buffer(buffer, cp_heap->base,
 				cp_heap->reserved_vrange, buffer->flags);
+		} else if (cp_heap->cma) {
+			int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
+			struct page **pages = vmalloc(
+						sizeof(struct page *) * npages);
+			int i;
+			pgprot_t pgprot;
 
+			if (ION_IS_CACHED(buffer->flags))
+				pgprot = PAGE_KERNEL;
+			else
+				pgprot = pgprot_writecombine(PAGE_KERNEL);
+
+			for (i = 0; i < npages; i++) {
+				pages[i] = phys_to_page(buf->buffer +
+						i * PAGE_SIZE);
+			}
+			ret_value = vmap(pages, npages, VM_IOREMAP, pgprot);
+			vfree(pages);
 		} else {
 			if (ION_IS_CACHED(buffer->flags))
 				ret_value = ioremap_cached(buf->buffer,
@@ -721,6 +827,8 @@
 
 	if (cp_heap->reusable)
 		unmap_kernel_range((unsigned long)buffer->vaddr, buffer->size);
+	else if (cp_heap->cma)
+		vunmap(buffer->vaddr);
 	else
 		__arm_iounmap(buffer->vaddr);
 
@@ -1148,14 +1256,6 @@
 
 	mutex_init(&cp_heap->lock);
 
-	cp_heap->pool = gen_pool_create(12, -1);
-	if (!cp_heap->pool)
-		goto free_heap;
-
-	cp_heap->base = heap_data->base;
-	ret = gen_pool_add(cp_heap->pool, cp_heap->base, heap_data->size, -1);
-	if (ret < 0)
-		goto destroy_pool;
 
 	cp_heap->allocated_bytes = 0;
 	cp_heap->umap_count = 0;
@@ -1165,9 +1265,11 @@
 	cp_heap->heap.ops = &cp_heap_ops;
 	cp_heap->heap.type = (enum ion_heap_type) ION_HEAP_TYPE_CP;
 	cp_heap->heap_protected = HEAP_NOT_PROTECTED;
-	cp_heap->secure_base = cp_heap->base;
+	cp_heap->secure_base = heap_data->base;
 	cp_heap->secure_size = heap_data->size;
 	cp_heap->has_outer_cache = heap_data->has_outer_cache;
+	cp_heap->heap_size = heap_data->size;
+
 	atomic_set(&cp_heap->protect_cnt, 0);
 	if (heap_data->extra_data) {
 		struct ion_cp_heap_pdata *extra_data =
@@ -1191,9 +1293,28 @@
 				extra_data->iommu_map_all;
 		cp_heap->iommu_2x_map_domain =
 				extra_data->iommu_2x_map_domain;
+		cp_heap->cma = extra_data->is_cma;
+		cp_heap->disallow_non_secure_allocation =
+			extra_data->no_nonsecure_alloc;
 
 	}
 
+	if (cp_heap->cma) {
+		cp_heap->pool = NULL;
+		cp_heap->cpu_addr = 0;
+		cp_heap->heap.priv = heap_data->priv;
+	} else {
+		cp_heap->pool = gen_pool_create(12, -1);
+		if (!cp_heap->pool)
+			goto free_heap;
+
+		cp_heap->base = heap_data->base;
+		ret = gen_pool_add(cp_heap->pool, cp_heap->base,
+					heap_data->size, -1);
+		if (ret < 0)
+			goto destroy_pool;
+
+	}
 	return &cp_heap->heap;
 
 destroy_pool:
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_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 345c07d..0b691f3 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -19,6 +19,7 @@
 #include <linux/vmalloc.h>
 #include <linux/iommu.h>
 #include <linux/pfn.h>
+#include <linux/dma-mapping.h>
 #include "ion_priv.h"
 
 #include <asm/mach/map.h>
@@ -80,8 +81,13 @@
 				goto err3;
 
 			sg_set_page(sg, data->pages[i], PAGE_SIZE, 0);
+			sg_dma_address(sg) = sg_phys(sg);
 		}
 
+		if (!ION_IS_CACHED(flags))
+			dma_sync_sg_for_device(NULL, table->sgl, table->nents,
+						DMA_BIDIRECTIONAL);
+
 		buffer->priv_virt = data;
 		return 0;
 
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/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index ad2ef83..8b63216 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -518,14 +518,26 @@
 	return ret;
 }
 
+void *ion_system_contig_heap_map_kernel(struct ion_heap *heap,
+	struct ion_buffer *buffer)
+{
+	return buffer->priv_virt;
+}
+
+void ion_system_contig_heap_unmap_kernel(struct ion_heap *heap,
+	struct ion_buffer *buffer)
+{
+	return;
+}
+
 static struct ion_heap_ops kmalloc_ops = {
 	.allocate = ion_system_contig_heap_allocate,
 	.free = ion_system_contig_heap_free,
 	.phys = ion_system_contig_heap_phys,
 	.map_dma = ion_system_contig_heap_map_dma,
 	.unmap_dma = ion_system_heap_unmap_dma,
-	.map_kernel = ion_system_heap_map_kernel,
-	.unmap_kernel = ion_system_heap_unmap_kernel,
+	.map_kernel = ion_system_contig_heap_map_kernel,
+	.unmap_kernel = ion_system_contig_heap_unmap_kernel,
 	.map_user = ion_system_contig_heap_map_user,
 	.cache_op = ion_system_contig_heap_cache_ops,
 	.print_debug = ion_system_contig_print_debug,
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 8699178..697587b 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) {
@@ -769,19 +777,6 @@
 	if (pdata_needs_to_be_freed)
 		free_pdata(pdata);
 
-	/* Check if each heap has been removed from the memblock */
-	for (i = 0; i < num_heaps; i++) {
-		struct ion_platform_heap *heap_data = &pdata->heaps[i];
-		if (!heap_data->base)
-			continue;
-		err = memblock_overlaps_memory(heap_data->base,
-						heap_data->size);
-		if (err) {
-			panic("ION heap %s not removed from memblock\n",
-							heap_data->name);
-		}
-	}
-
 	check_for_heap_overlap(pdata->heaps, num_heaps);
 	platform_set_drvdata(pdev, idev);
 	return 0;
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index fa66e96..24be1b0 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -29,6 +29,7 @@
 #include "kgsl_cffdump.h"
 #include "kgsl_sharedmem.h"
 #include "kgsl_iommu.h"
+#include "kgsl_trace.h"
 
 #include "adreno.h"
 #include "adreno_pm4types.h"
@@ -140,6 +141,7 @@
  */
 
 #define ANY_ID (~0)
+#define NO_VER (~0)
 
 static const struct {
 	enum adreno_gpurev gpurev;
@@ -149,45 +151,53 @@
 	struct adreno_gpudev *gpudev;
 	unsigned int istore_size;
 	unsigned int pix_shader_start;
-	unsigned int instruction_size; /* Size of an instruction in dwords */
-	unsigned int gmem_size; /* size of gmem for gpu*/
+	/* Size of an instruction in dwords */
+	unsigned int instruction_size;
+	/* size of gmem for gpu*/
+	unsigned int gmem_size;
+	/* version of pm4 microcode that supports sync_lock
+	   between CPU and GPU for SMMU-v1 programming */
+	unsigned int sync_lock_pm4_ver;
+	/* version of pfp microcode that supports sync_lock
+	   between CPU and GPU for SMMU-v1 programming */
+	unsigned int sync_lock_pfp_ver;
 } adreno_gpulist[] = {
 	{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
 		"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
-		512, 384, 3, SZ_256K },
+		512, 384, 3, SZ_256K, NO_VER, NO_VER },
 	{ ADRENO_REV_A203, 0, 1, 1, ANY_ID,
 		"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
-		512, 384, 3, SZ_256K },
+		512, 384, 3, SZ_256K, NO_VER, NO_VER },
 	{ ADRENO_REV_A205, 0, 1, 0, ANY_ID,
 		"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
-		512, 384, 3, SZ_256K },
+		512, 384, 3, SZ_256K, NO_VER, NO_VER },
 	{ ADRENO_REV_A220, 2, 1, ANY_ID, ANY_ID,
 		"leia_pm4_470.fw", "leia_pfp_470.fw", &adreno_a2xx_gpudev,
-		512, 384, 3, SZ_512K },
+		512, 384, 3, SZ_512K, NO_VER, NO_VER },
 	/*
 	 * patchlevel 5 (8960v2) needs special pm4 firmware to work around
 	 * a hardware problem.
 	 */
 	{ ADRENO_REV_A225, 2, 2, 0, 5,
 		"a225p5_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
-		1536, 768, 3, SZ_512K },
+		1536, 768, 3, SZ_512K, NO_VER, NO_VER },
 	{ ADRENO_REV_A225, 2, 2, 0, 6,
 		"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
-		1536, 768, 3, SZ_512K },
+		1536, 768, 3, SZ_512K, 0x225011, 0x225002 },
 	{ ADRENO_REV_A225, 2, 2, ANY_ID, ANY_ID,
 		"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
-		1536, 768, 3, SZ_512K },
+		1536, 768, 3, SZ_512K, 0x225011, 0x225002 },
 	/* A3XX doesn't use the pix_shader_start */
 	{ ADRENO_REV_A305, 3, 0, 5, ANY_ID,
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
-		512, 0, 2, SZ_256K },
+		512, 0, 2, SZ_256K, 0x3FF037, 0x3FF016 },
 	/* A3XX doesn't use the pix_shader_start */
 	{ ADRENO_REV_A320, 3, 2, ANY_ID, ANY_ID,
 		"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
-		512, 0, 2, SZ_512K },
+		512, 0, 2, SZ_512K, 0x3FF037, 0x3FF016 },
 	{ ADRENO_REV_A330, 3, 3, 0, 0,
 		"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
-		512, 0, 2, SZ_1M },
+		512, 0, 2, SZ_1M, NO_VER, NO_VER },
 };
 
 static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
@@ -281,7 +291,7 @@
 					uint32_t flags)
 {
 	unsigned int pt_val, reg_pt_val;
-	unsigned int link[200];
+	unsigned int link[250];
 	unsigned int *cmds = &link[0];
 	int sizedwords = 0;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -314,6 +324,11 @@
 					device->mmu.setstate_memory.gpuaddr +
 					KGSL_IOMMU_SETSTATE_NOP_OFFSET);
 
+	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
+	/* Acquire GPU-CPU sync Lock here */
+	cmds += kgsl_mmu_sync_lock(&device->mmu, cmds);
+
 	pt_val = kgsl_mmu_get_pt_base_addr(&device->mmu,
 					device->mmu.hwpagetable);
 	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
@@ -375,6 +390,9 @@
 		}
 	}
 
+	/* Release GPU-CPU sync Lock here */
+	cmds += kgsl_mmu_sync_unlock(&device->mmu, cmds);
+
 	if (cpu_is_msm8960())
 		cmds += adreno_add_change_mh_phys_limit_cmds(cmds,
 			kgsl_mmu_get_reg_gpuaddr(&device->mmu, 0,
@@ -387,19 +405,14 @@
 			device->mmu.setstate_memory.gpuaddr +
 			KGSL_IOMMU_SETSTATE_NOP_OFFSET);
 
+	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
 	sizedwords += (cmds - &link[0]);
 	if (sizedwords) {
 		/* invalidate all base pointers */
 		*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,
@@ -408,6 +421,11 @@
 		kgsl_mmu_disable_clk_on_ts(&device->mmu,
 		adreno_dev->ringbuffer.timestamp[KGSL_MEMSTORE_GLOBAL], true);
 	}
+
+	if (sizedwords > (ARRAY_SIZE(link))) {
+		KGSL_DRV_ERR(device, "Temp command buffer overflow\n");
+		BUG();
+	}
 }
 
 static void adreno_gpummu_setstate(struct kgsl_device *device,
@@ -580,7 +598,7 @@
 	/* 8x25 returns 0 for minor id, but it should be 1 */
 	if (cpu_is_qsd8x50())
 		patchid = 1;
-	else if (cpu_is_msm8625() && minorid == 0)
+	else if ((cpu_is_msm8625() || cpu_is_msm8625q()) && minorid == 0)
 		minorid = 1;
 
 	chipid |= (minorid << 8) | patchid;
@@ -643,6 +661,7 @@
 	adreno_dev->pix_shader_start = adreno_gpulist[i].pix_shader_start;
 	adreno_dev->instruction_size = adreno_gpulist[i].instruction_size;
 	adreno_dev->gmem_size = adreno_gpulist[i].gmem_size;
+	adreno_dev->gpulist_index = i;
 }
 
 static struct platform_device_id adreno_id_table[] = {
@@ -865,8 +884,8 @@
 	if (adreno_of_read_property(node, "qcom,algo-ss-util-pct",
 		&info->algo_param.ss_util_pct))
 		goto err;
-	if (adreno_of_read_property(node, "qcom,algo-ss-iobusy-conv",
-		&info->algo_param.ss_iobusy_conv))
+	if (adreno_of_read_property(node, "qcom,algo-ss-no-corr-below-freq",
+		&info->algo_param.ss_no_corr_below_freq))
 		goto err;
 
 	if (adreno_of_read_property(node, "qcom,energy-active-coeff-a",
@@ -1192,12 +1211,36 @@
 	/* Identify the specific GPU */
 	adreno_identify_gpu(adreno_dev);
 
+	if (adreno_ringbuffer_read_pm4_ucode(device)) {
+		KGSL_DRV_ERR(device, "Reading pm4 microcode failed %s\n",
+			adreno_dev->pm4_fwfile);
+		BUG_ON(1);
+	}
+
+	if (adreno_ringbuffer_read_pfp_ucode(device)) {
+		KGSL_DRV_ERR(device, "Reading pfp microcode failed %s\n",
+			adreno_dev->pfp_fwfile);
+		BUG_ON(1);
+	}
+
 	if (adreno_dev->gpurev == ADRENO_REV_UNKNOWN) {
 		KGSL_DRV_ERR(device, "Unknown chip ID %x\n",
 			adreno_dev->chip_id);
 		goto error_clk_off;
 	}
 
+
+	/*
+	 * Check if firmware supports the sync lock PM4 packets needed
+	 * for IOMMUv1
+	 */
+
+	if ((adreno_dev->pm4_fw_version >=
+		adreno_gpulist[adreno_dev->gpulist_index].sync_lock_pm4_ver) &&
+		(adreno_dev->pfp_fw_version >=
+		adreno_gpulist[adreno_dev->gpulist_index].sync_lock_pfp_ver))
+		device->mmu.flags |= KGSL_MMU_FLAGS_IOMMU_SYNC;
+
 	/* Set up the MMU */
 	if (adreno_is_a2xx(adreno_dev)) {
 		/*
@@ -2074,6 +2117,8 @@
 	if (!in_interrupt())
 		kgsl_pre_hwaccess(device);
 
+	trace_kgsl_regwrite(device, offsetwords, value);
+
 	kgsl_cffdump_regwrite(device->id, offsetwords << 2, value);
 	reg = (unsigned int *)(device->reg_virt + (offsetwords << 2));
 
@@ -2097,13 +2142,73 @@
 	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)
 {
 	int status;
 	unsigned int ref_ts, enableflag;
 	unsigned int context_id;
-	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
 	mutex_lock(&device->mutex);
 	context_id = _get_context_id(context);
@@ -2150,13 +2255,9 @@
 			cmds[0] = cp_type3_packet(CP_NOP, 1);
 			cmds[1] = 0;
 
-			if (adreno_dev->drawctxt_active)
+			if (context)
 				adreno_ringbuffer_issuecmds_intr(device,
 						context, &cmds[0], 2);
-			else
-				/* We would never call this function if there
-				 * was no active contexts running */
-				BUG();
 		}
 	}
 unlock:
@@ -2606,6 +2707,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.h b/drivers/gpu/msm/adreno.h
index 61378fe..836192c 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -86,9 +86,11 @@
 	const char *pfp_fwfile;
 	unsigned int *pfp_fw;
 	size_t pfp_fw_size;
+	unsigned int pfp_fw_version;
 	const char *pm4_fwfile;
 	unsigned int *pm4_fw;
 	size_t pm4_fw_size;
+	unsigned int pm4_fw_version;
 	struct adreno_ringbuffer ringbuffer;
 	unsigned int mharb;
 	struct adreno_gpudev *gpudev;
@@ -98,6 +100,7 @@
 	unsigned int instruction_size;
 	unsigned int ib_check_level;
 	unsigned int fast_hang_detect;
+	unsigned int gpulist_index;
 	struct ocmem_buf *ocmem_hdl;
 	unsigned int ocmem_base;
 };
@@ -168,6 +171,9 @@
 extern const unsigned int a3xx_registers[];
 extern const unsigned int a3xx_registers_count;
 
+extern const unsigned int a3xx_hlsq_registers[];
+extern const unsigned int a3xx_hlsq_registers_count;
+
 extern const unsigned int a330_registers[];
 extern const unsigned int a330_registers_count;
 
@@ -363,4 +369,26 @@
 	return cmds - start;
 }
 
+/*
+ * adreno_idle_cmds - Add pm4 packets for GPU idle
+ * @adreno_dev - Pointer to device structure
+ * @cmds - Pointer to memory where idle commands need to be added
+ */
+static inline int adreno_add_idle_cmds(struct adreno_device *adreno_dev,
+							unsigned int *cmds)
+{
+	unsigned int *start = cmds;
+
+	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+	*cmds++ = 0;
+
+	if ((adreno_dev->gpurev == ADRENO_REV_A305) ||
+		(adreno_dev->gpurev == ADRENO_REV_A320)) {
+		*cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
+		*cmds++ = 0;
+	}
+
+	return cmds - start;
+}
+
 #endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index feced43..2466a5c 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -40,8 +40,8 @@
 	0x0578, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e,
 	0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f,
 	0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7,
-	0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05,
-	0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65,
+	0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5,
+	0x0e41, 0x0e45, 0x0e64, 0x0e65,
 	0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7,
 	0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09,
 	0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069,
@@ -49,7 +49,7 @@
 	0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109,
 	0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115,
 	0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0,
-	0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e,
+	0x2240, 0x227e,
 	0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
 	0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
 	0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356,
@@ -58,7 +58,7 @@
 	0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef,
 	0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511,
 	0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed,
-	0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a,
+	0x25f0, 0x25f0,
 	0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
 	0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
 	0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
@@ -69,6 +69,18 @@
 
 const unsigned int a3xx_registers_count = ARRAY_SIZE(a3xx_registers) / 2;
 
+/* Removed the following HLSQ register ranges from being read during
+ * recovery since reading the registers may cause the device to hang:
+ */
+const unsigned int a3xx_hlsq_registers[] = {
+	0x0e00, 0x0e05, 0x0e0c, 0x0e0c, 0x0e22, 0x0e23,
+	0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a,
+	0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a,
+};
+
+const unsigned int a3xx_hlsq_registers_count =
+			ARRAY_SIZE(a3xx_hlsq_registers) / 2;
+
 /* The set of additional registers to be dumped for A330 */
 
 const unsigned int a330_registers[] = {
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index 1243dd0..de95951 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -341,6 +341,41 @@
 	return snapshot;
 }
 
+static void _snapshot_a3xx_regs(struct kgsl_snapshot_registers *regs,
+	struct kgsl_snapshot_registers_list *list)
+{
+	regs[list->count].regs = (unsigned int *) a3xx_registers;
+	regs[list->count].count = a3xx_registers_count;
+	list->count++;
+}
+
+static void _snapshot_hlsq_regs(struct kgsl_snapshot_registers *regs,
+	struct kgsl_snapshot_registers_list *list,
+	struct adreno_device *adreno_dev)
+{
+	/* HLSQ specific registers */
+	/*
+	 * Don't dump any a3xx HLSQ registers just yet.  Reading the HLSQ
+	 * registers can cause the device to hang if the HLSQ block is
+	 * busy.  Add specific checks for each a3xx core as the requirements
+	 * are discovered.  Disable by default for now.
+	 */
+	if (!adreno_is_a3xx(adreno_dev)) {
+		regs[list->count].regs = (unsigned int *) a3xx_hlsq_registers;
+		regs[list->count].count = a3xx_hlsq_registers_count;
+		list->count++;
+	}
+}
+
+static void _snapshot_a330_regs(struct kgsl_snapshot_registers *regs,
+	struct kgsl_snapshot_registers_list *list)
+{
+	/* For A330, append the additional list of new registers to grab */
+	regs[list->count].regs = (unsigned int *) a330_registers;
+	regs[list->count].count = a330_registers_count;
+	list->count++;
+}
+
 /* A3XX GPU snapshot function - this is where all of the A3XX specific
  * bits and pieces are grabbed into the snapshot memory
  */
@@ -350,21 +385,20 @@
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	struct kgsl_snapshot_registers_list list;
-	struct kgsl_snapshot_registers regs[2];
+	struct kgsl_snapshot_registers regs[5];
 	int size;
 
-	regs[0].regs = (unsigned int *) a3xx_registers;
-	regs[0].count = a3xx_registers_count;
-
 	list.registers = regs;
-	list.count = 1;
+	list.count = 0;
 
-	/* For A330, append the additional list of new registers to grab */
-	if (adreno_is_a330(adreno_dev)) {
-		regs[1].regs = (unsigned int *) a330_registers;
-		regs[1].count = a330_registers_count;
-		list.count++;
-	}
+	/* Disable Clock gating temporarily for the debug bus to work */
+	adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, 0x00);
+
+	/* Store relevant registers in list to snapshot */
+	_snapshot_a3xx_regs(regs, &list);
+	_snapshot_hlsq_regs(regs, &list, adreno_dev);
+	if (adreno_is_a330(adreno_dev))
+		_snapshot_a330_regs(regs, &list);
 
 	/* Master set of (non debug) registers */
 	snapshot = kgsl_snapshot_add_section(device,
@@ -385,9 +419,6 @@
 			remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS,
 			64, 44);
 
-	/* Disable Clock gating temporarily for the debug bus to work */
-	adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, 0x00);
-
 	/* VPC memory */
 	snapshot = kgsl_snapshot_add_section(device,
 			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index 016862b..6ec11ea 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -142,6 +142,12 @@
 /* copy sequencer instruction memory to system memory */
 #define CP_IM_STORE            0x2c
 
+/* test 2 memory locations to dword values specified */
+#define CP_TEST_TWO_MEMS	0x71
+
+/* PFP waits until the FIFO between the PFP and the ME is empty */
+#define CP_WAIT_FOR_ME		0x13
+
 /*
  * for a20x
  * program an offset that will added to the BIN_BASE value of
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/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 27343c5..97b35b0 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -209,10 +209,10 @@
 	return (*data != NULL) ? 0 : -ENOMEM;
 }
 
-static int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
+int adreno_ringbuffer_read_pm4_ucode(struct kgsl_device *device)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	int i, ret = 0;
+	int ret = 0;
 
 	if (adreno_dev->pm4_fw == NULL) {
 		int len;
@@ -234,24 +234,41 @@
 
 		adreno_dev->pm4_fw_size = len / sizeof(uint32_t);
 		adreno_dev->pm4_fw = ptr;
+		adreno_dev->pm4_fw_version = adreno_dev->pm4_fw[1];
+	}
+
+err:
+	return ret;
+}
+
+
+int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	int i;
+
+	if (adreno_dev->pm4_fw == NULL) {
+		int ret = adreno_ringbuffer_read_pm4_ucode(device);
+		if (ret)
+			return ret;
 	}
 
 	KGSL_DRV_INFO(device, "loading pm4 ucode version: %d\n",
-		adreno_dev->pm4_fw[0]);
+		adreno_dev->pm4_fw_version);
 
 	adreno_regwrite(device, REG_CP_DEBUG, CP_DEBUG_DEFAULT);
 	adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
 	for (i = 1; i < adreno_dev->pm4_fw_size; i++)
 		adreno_regwrite(device, REG_CP_ME_RAM_DATA,
-				     adreno_dev->pm4_fw[i]);
-err:
-	return ret;
+			adreno_dev->pm4_fw[i]);
+
+	return 0;
 }
 
-static int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
+int adreno_ringbuffer_read_pfp_ucode(struct kgsl_device *device)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-	int i, ret = 0;
+	int ret = 0;
 
 	if (adreno_dev->pfp_fw == NULL) {
 		int len;
@@ -272,18 +289,34 @@
 
 		adreno_dev->pfp_fw_size = len / sizeof(uint32_t);
 		adreno_dev->pfp_fw = ptr;
+		adreno_dev->pfp_fw_version = adreno_dev->pfp_fw[5];
+	}
+
+err:
+	return ret;
+}
+
+int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	int i;
+
+	if (adreno_dev->pfp_fw == NULL) {
+		int ret = adreno_ringbuffer_read_pfp_ucode(device);
+		if (ret)
+			return ret;
 	}
 
 	KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
-		adreno_dev->pfp_fw[0]);
+			adreno_dev->pfp_fw_version);
 
 	adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
 	for (i = 1; i < adreno_dev->pfp_fw_size; i++)
 		adreno_regwrite(device,
-			adreno_dev->gpudev->reg_cp_pfp_ucode_data,
-			adreno_dev->pfp_fw[i]);
-err:
-	return ret;
+		adreno_dev->gpudev->reg_cp_pfp_ucode_data,
+		adreno_dev->pfp_fw[i]);
+
+	return 0;
 }
 
 int adreno_ringbuffer_start(struct adreno_ringbuffer *rb, unsigned int init_ram)
@@ -390,7 +423,6 @@
 			     GSL_RB_MEMPTRS_SCRATCH_MASK);
 
 	/* load the CP ucode */
-
 	status = adreno_ringbuffer_load_pm4_ucode(device);
 	if (status != 0)
 		return status;
@@ -513,7 +545,7 @@
 	if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
 		context_id = context->id;
 
-	if ((context->flags & CTXT_FLAGS_USER_GENERATED_TS) &&
+	if ((context && context->flags & CTXT_FLAGS_USER_GENERATED_TS) &&
 			(!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))) {
 		if (timestamp_cmp(rb->timestamp[context_id],
 						timestamp) >= 0) {
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 4f58a15..50d9c25 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -130,6 +130,10 @@
 						struct adreno_context *context,
 						unsigned int numcmds);
 
+int adreno_ringbuffer_read_pfp_ucode(struct kgsl_device *device);
+
+int adreno_ringbuffer_read_pm4_ucode(struct kgsl_device *device);
+
 static inline int adreno_ringbuffer_count(struct adreno_ringbuffer *rb,
 	unsigned int rptr)
 {
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_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 1bccd4d..818bd63 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -18,6 +18,9 @@
 #include <linux/iommu.h>
 #include <linux/msm_kgsl.h>
 #include <mach/socinfo.h>
+#include <mach/msm_iomap.h>
+#include <mach/board.h>
+#include <stddef.h>
 
 #include "kgsl.h"
 #include "kgsl_device.h"
@@ -27,6 +30,8 @@
 #include "adreno_pm4types.h"
 #include "adreno.h"
 #include "kgsl_trace.h"
+#include "z180.h"
+
 
 static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
 	{ 0, 0, 0 },				/* GLOBAL_BASE */
@@ -46,6 +51,8 @@
 	{ 0x008, 0, 0 }				/* RESUME */
 };
 
+struct remote_iommu_petersons_spinlock kgsl_iommu_sync_lock_vars;
+
 static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
 			struct kgsl_iommu_unit **iommu_unit_out)
 {
@@ -93,8 +100,168 @@
 	return NULL;
 }
 
+/* These functions help find the nearest allocated memory entries on either side
+ * of a faulting address. If we know the nearby allocations memory we can
+ * get a better determination of what we think should have been located in the
+ * faulting region
+ */
+
+/*
+ * A local structure to make it easy to store the interesting bits for the
+ * memory entries on either side of the faulting address
+ */
+
+struct _mem_entry {
+	unsigned int gpuaddr;
+	unsigned int size;
+	unsigned int flags;
+	pid_t pid;
+};
+
+/*
+ * Find the closest alloated memory block with an smaller GPU address then the
+ * given address
+ */
+
+static void _prev_entry(struct kgsl_process_private *priv,
+	unsigned int faultaddr, struct _mem_entry *ret)
+{
+	struct rb_node *node;
+	struct kgsl_mem_entry *entry;
+
+	for (node = rb_first(&priv->mem_rb); node; ) {
+		entry = rb_entry(node, struct kgsl_mem_entry, node);
+
+		if (entry->memdesc.gpuaddr > faultaddr)
+			break;
+
+		/*
+		 * If this is closer to the faulting address, then copy
+		 * the entry
+		 */
+
+		if (entry->memdesc.gpuaddr > ret->gpuaddr) {
+			ret->gpuaddr = entry->memdesc.gpuaddr;
+			ret->size = entry->memdesc.size;
+			ret->flags = entry->flags;
+			ret->pid = priv->pid;
+		}
+
+		node = rb_next(&entry->node);
+	}
+}
+
+/*
+ * Find the closest alloated memory block with a greater starting GPU address
+ * then the given address
+ */
+
+static void _next_entry(struct kgsl_process_private *priv,
+	unsigned int faultaddr, struct _mem_entry *ret)
+{
+	struct rb_node *node;
+	struct kgsl_mem_entry *entry;
+
+	for (node = rb_last(&priv->mem_rb); node; ) {
+		entry = rb_entry(node, struct kgsl_mem_entry, node);
+
+		if (entry->memdesc.gpuaddr < faultaddr)
+			break;
+
+		/*
+		 * If this is closer to the faulting address, then copy
+		 * the entry
+		 */
+
+		if (entry->memdesc.gpuaddr < ret->gpuaddr) {
+			ret->gpuaddr = entry->memdesc.gpuaddr;
+			ret->size = entry->memdesc.size;
+			ret->flags = entry->flags;
+			ret->pid = priv->pid;
+		}
+
+		node = rb_prev(&entry->node);
+	}
+}
+
+static void _find_mem_entries(struct kgsl_mmu *mmu, unsigned int faultaddr,
+	unsigned int ptbase, struct _mem_entry *preventry,
+	struct _mem_entry *nextentry)
+{
+	struct kgsl_process_private *private;
+	int id = kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase);
+
+	memset(preventry, 0, sizeof(*preventry));
+	memset(nextentry, 0, sizeof(*nextentry));
+
+	/* Set the maximum possible size as an initial value */
+	nextentry->gpuaddr = 0xFFFFFFFF;
+
+	mutex_lock(&kgsl_driver.process_mutex);
+
+	list_for_each_entry(private, &kgsl_driver.process_list, list) {
+
+		if (private->pagetable->name != id)
+			continue;
+
+		spin_lock(&private->mem_lock);
+		_prev_entry(private, faultaddr, preventry);
+		_next_entry(private, faultaddr, nextentry);
+		spin_unlock(&private->mem_lock);
+	}
+
+	mutex_unlock(&kgsl_driver.process_mutex);
+}
+
+static void _print_entry(struct kgsl_device *device, struct _mem_entry *entry)
+{
+	char name[32];
+	memset(name, 0, sizeof(name));
+
+	kgsl_get_memory_usage(name, sizeof(name) - 1, entry->flags);
+
+	KGSL_LOG_DUMP(device,
+		"[%8.8X - %8.8X] (pid = %d) (%s)\n",
+		entry->gpuaddr,
+		entry->gpuaddr + entry->size,
+		entry->pid, name);
+}
+
+static void _check_if_freed(struct kgsl_iommu_device *iommu_dev,
+	unsigned long addr, unsigned int pid)
+{
+	void *base = kgsl_driver.memfree_hist.base_hist_rb;
+	struct kgsl_memfree_hist_elem *wptr;
+	struct kgsl_memfree_hist_elem *p;
+
+	mutex_lock(&kgsl_driver.memfree_hist_mutex);
+	wptr = kgsl_driver.memfree_hist.wptr;
+	p = wptr;
+	for (;;) {
+		if (p->size && p->pid == pid)
+			if (addr >= p->gpuaddr &&
+				addr < (p->gpuaddr + p->size)) {
+
+				KGSL_LOG_DUMP(iommu_dev->kgsldev,
+					"---- premature free ----\n");
+				KGSL_LOG_DUMP(iommu_dev->kgsldev,
+					"[%8.8X-%8.8X] was already freed by pid %d\n",
+					p->gpuaddr,
+					p->gpuaddr + p->size,
+					p->pid);
+			}
+		p++;
+		if ((void *)p >= base + kgsl_driver.memfree_hist.size)
+			p = (struct kgsl_memfree_hist_elem *) base;
+
+		if (p == kgsl_driver.memfree_hist.wptr)
+			break;
+	}
+	mutex_unlock(&kgsl_driver.memfree_hist_mutex);
+}
+
 static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
-	struct device *dev, unsigned long addr, int flags)
+	struct device *dev, unsigned long addr, int flags, void *token)
 {
 	int ret = 0;
 	struct kgsl_mmu *mmu;
@@ -102,6 +269,9 @@
 	struct kgsl_iommu_unit *iommu_unit;
 	struct kgsl_iommu_device *iommu_dev;
 	unsigned int ptbase, fsr;
+	unsigned int pid;
+
+	struct _mem_entry prev, next;
 
 	ret = get_iommu_unit(dev, &mmu, &iommu_unit);
 	if (ret)
@@ -120,12 +290,30 @@
 	fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
 		iommu_dev->ctx_id, FSR);
 
+	pid = kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase);
 	KGSL_MEM_CRIT(iommu_dev->kgsldev,
-		"GPU PAGE FAULT: addr = %lX pid = %d\n",
-		addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
+		"GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
 	KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
 		iommu_dev->ctx_id, fsr);
 
+	_check_if_freed(iommu_dev, addr, pid);
+
+	KGSL_LOG_DUMP(iommu_dev->kgsldev, "---- nearby memory ----\n");
+
+	_find_mem_entries(mmu, addr, ptbase, &prev, &next);
+
+	if (prev.gpuaddr)
+		_print_entry(iommu_dev->kgsldev, &prev);
+	else
+		KGSL_LOG_DUMP(iommu_dev->kgsldev, "*EMPTY*\n");
+
+	KGSL_LOG_DUMP(iommu_dev->kgsldev, " <- fault @ %8.8lX\n", addr);
+
+	if (next.gpuaddr != 0xFFFFFFFF)
+		_print_entry(iommu_dev->kgsldev, &next);
+	else
+		KGSL_LOG_DUMP(iommu_dev->kgsldev, "*EMPTY*\n");
+
 	mmu->fault = 1;
 	iommu_dev->fault = 1;
 
@@ -387,7 +575,7 @@
 		return NULL;
 	} else {
 		iommu_set_fault_handler(iommu_pt->domain,
-			kgsl_iommu_fault_handler);
+			kgsl_iommu_fault_handler, NULL);
 	}
 
 	return iommu_pt;
@@ -546,6 +734,195 @@
 }
 
 /*
+ * kgsl_iommu_start_sync_lock - Initialize some variables during MMU start up
+ * for GPU CPU synchronization
+ * @mmu - Pointer to mmu device
+ *
+ * Return - 0 on success else error code
+ */
+static int kgsl_iommu_start_sync_lock(struct kgsl_mmu *mmu)
+{
+	struct kgsl_iommu *iommu = mmu->priv;
+	uint32_t lock_gpu_addr = 0;
+
+	if (KGSL_DEVICE_3D0 != mmu->device->id ||
+		!msm_soc_version_supports_iommu_v1() ||
+		!kgsl_mmu_is_perprocess() ||
+		iommu->sync_lock_vars)
+		return 0;
+
+	if (!(mmu->flags & KGSL_MMU_FLAGS_IOMMU_SYNC)) {
+		KGSL_DRV_ERR(mmu->device,
+		"The GPU microcode does not support IOMMUv1 sync opcodes\n");
+		return -ENXIO;
+	}
+	/* Store Lock variables GPU address  */
+	lock_gpu_addr = (iommu->sync_lock_desc.gpuaddr +
+			iommu->sync_lock_offset);
+
+	kgsl_iommu_sync_lock_vars.flag[PROC_APPS] = (lock_gpu_addr +
+		(offsetof(struct remote_iommu_petersons_spinlock,
+			flag[PROC_APPS])));
+	kgsl_iommu_sync_lock_vars.flag[PROC_GPU] = (lock_gpu_addr +
+		(offsetof(struct remote_iommu_petersons_spinlock,
+			flag[PROC_GPU])));
+	kgsl_iommu_sync_lock_vars.turn = (lock_gpu_addr +
+		(offsetof(struct remote_iommu_petersons_spinlock, turn)));
+
+	iommu->sync_lock_vars = &kgsl_iommu_sync_lock_vars;
+
+	return 0;
+}
+
+/*
+ * kgsl_get_sync_lock - Init Sync Lock between GPU and CPU
+ * @mmu - Pointer to mmu device
+ *
+ * Return - 0 on success else error code
+ */
+static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu)
+{
+	struct kgsl_iommu *iommu = mmu->device->mmu.priv;
+	int status = 0;
+	uint32_t lock_phy_addr = 0;
+	uint32_t page_offset = 0;
+
+	if (KGSL_DEVICE_3D0 != mmu->device->id ||
+		!msm_soc_version_supports_iommu_v1() ||
+		!kgsl_mmu_is_perprocess())
+		return status;
+
+	/* Return if already initialized */
+	if (iommu->sync_lock_initialized)
+		return status;
+
+	/* Get the physical address of the Lock variables */
+	lock_phy_addr = (msm_iommu_lock_initialize()
+			- MSM_SHARED_RAM_BASE + msm_shared_ram_phys);
+
+	if (!lock_phy_addr) {
+		KGSL_DRV_ERR(mmu->device,
+				"GPU CPU sync lock is not supported by kernel\n");
+		return -ENXIO;
+	}
+
+	/* Align the physical address to PAGE boundary and store the offset */
+	page_offset = (lock_phy_addr & (PAGE_SIZE - 1));
+	lock_phy_addr = (lock_phy_addr & ~(PAGE_SIZE - 1));
+	iommu->sync_lock_desc.physaddr = (unsigned int)lock_phy_addr;
+	iommu->sync_lock_offset = page_offset;
+
+	iommu->sync_lock_desc.size =
+				PAGE_ALIGN(sizeof(kgsl_iommu_sync_lock_vars));
+	status =  memdesc_sg_phys(&iommu->sync_lock_desc,
+				 iommu->sync_lock_desc.physaddr,
+				 iommu->sync_lock_desc.size);
+
+	if (status)
+		return status;
+
+	/* Flag Sync Lock is Initialized  */
+	iommu->sync_lock_initialized = 1;
+
+	return status;
+}
+
+/*
+ * kgsl_iommu_sync_lock - Acquire Sync Lock between GPU and CPU
+ * @mmu - Pointer to mmu device
+ * @cmds - Pointer to array of commands
+ *
+ * Return - int - number of commands.
+ */
+inline unsigned int kgsl_iommu_sync_lock(struct kgsl_mmu *mmu,
+						unsigned int *cmds)
+{
+	struct kgsl_device *device = mmu->device;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct kgsl_iommu *iommu = mmu->device->mmu.priv;
+	struct remote_iommu_petersons_spinlock *lock_vars =
+					iommu->sync_lock_vars;
+	unsigned int *start = cmds;
+
+	if (!iommu->sync_lock_initialized)
+		return 0;
+
+	*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+	*cmds++ = lock_vars->flag[PROC_GPU];
+	*cmds++ = 1;
+
+	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
+	*cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
+	/* MEM SPACE = memory, FUNCTION = equals */
+	*cmds++ = 0x13;
+	*cmds++ = lock_vars->flag[PROC_GPU];
+	*cmds++ = 0x1;
+	*cmds++ = 0x1;
+	*cmds++ = 0x1;
+
+	*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+	*cmds++ = lock_vars->turn;
+	*cmds++ = 0;
+
+	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
+	*cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
+	/* MEM SPACE = memory, FUNCTION = equals */
+	*cmds++ = 0x13;
+	*cmds++ = lock_vars->flag[PROC_GPU];
+	*cmds++ = 0x1;
+	*cmds++ = 0x1;
+	*cmds++ = 0x1;
+
+	*cmds++ = cp_type3_packet(CP_TEST_TWO_MEMS, 3);
+	*cmds++ = lock_vars->flag[PROC_APPS];
+	*cmds++ = lock_vars->turn;
+	*cmds++ = 0;
+
+	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
+	return cmds - start;
+}
+
+/*
+ * kgsl_iommu_sync_lock - Release Sync Lock between GPU and CPU
+ * @mmu - Pointer to mmu device
+ * @cmds - Pointer to array of commands
+ *
+ * Return - int - number of commands.
+ */
+inline unsigned int kgsl_iommu_sync_unlock(struct kgsl_mmu *mmu,
+					unsigned int *cmds)
+{
+	struct kgsl_device *device = mmu->device;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct kgsl_iommu *iommu = mmu->device->mmu.priv;
+	struct remote_iommu_petersons_spinlock *lock_vars =
+						iommu->sync_lock_vars;
+	unsigned int *start = cmds;
+
+	if (!iommu->sync_lock_initialized)
+		return 0;
+
+	*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+	*cmds++ = lock_vars->flag[PROC_GPU];
+	*cmds++ = 0;
+
+	*cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
+	/* MEM SPACE = memory, FUNCTION = equals */
+	*cmds++ = 0x13;
+	*cmds++ = lock_vars->flag[PROC_GPU];
+	*cmds++ = 0x0;
+	*cmds++ = 0x1;
+	*cmds++ = 0x1;
+
+	cmds += adreno_add_idle_cmds(adreno_dev, cmds);
+
+	return cmds - start;
+}
+
+/*
  * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
  * @mmu - Pointer to mmu device
  *
@@ -727,23 +1104,27 @@
 		return 0;
 
 	for (i = 0; i < iommu->unit_count; i++) {
-		iommu->iommu_units[i].reg_map.priv |= KGSL_MEMDESC_GLOBAL;
-		status = kgsl_mmu_map(pt,
+		status = kgsl_mmu_map_global(pt,
 				&(iommu->iommu_units[i].reg_map),
 				GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
-		if (status) {
-			iommu->iommu_units[i].reg_map.priv &=
-				~KGSL_MEMDESC_GLOBAL;
+		if (status)
 			goto err;
-		}
 	}
+
+	/* Map Lock variables to GPU pagetable */
+	if (iommu->sync_lock_initialized) {
+		status = kgsl_mmu_map_global(pt, &iommu->sync_lock_desc,
+				GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+		if (status)
+			goto err;
+	}
+
 	return 0;
 err:
-	for (i--; i >= 0; i--) {
+	for (i--; i >= 0; i--)
 		kgsl_mmu_unmap(pt,
 				&(iommu->iommu_units[i].reg_map));
-		iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMDESC_GLOBAL;
-	}
+
 	return status;
 }
 
@@ -763,6 +1144,9 @@
 	int i;
 	for (i = 0; i < iommu->unit_count; i++)
 		kgsl_mmu_unmap(pt, &(iommu->iommu_units[i].reg_map));
+
+	if (iommu->sync_lock_desc.gpuaddr)
+		kgsl_mmu_unmap(pt, &iommu->sync_lock_desc);
 }
 
 
@@ -790,6 +1174,9 @@
 	status = kgsl_set_register_map(mmu);
 	if (status)
 		goto done;
+	status = kgsl_iommu_init_sync_lock(mmu);
+	if (status)
+		goto done;
 
 	iommu->iommu_reg_list = kgsl_iommuv1_reg;
 	iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
@@ -887,6 +1274,10 @@
 		if (status)
 			return -ENOMEM;
 	}
+	status = kgsl_iommu_start_sync_lock(mmu);
+	if (status)
+		return status;
+
 	/* We use the GPU MMU to control access to IOMMU registers on 8960 with
 	 * a225, hence we still keep the MMU active on 8960 */
 	if (cpu_is_msm8960()) {
@@ -897,8 +1288,6 @@
 
 		kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
 			mh->mpu_base + mh->mpu_range);
-	} else {
-		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
 	}
 
 	mmu->hwpagetable = mmu->defaultpagetable;
@@ -1070,7 +1459,12 @@
 		if (reg_map->hostptr)
 			iounmap(reg_map->hostptr);
 		kgsl_sg_free(reg_map->sg, reg_map->sglen);
+		reg_map->priv &= ~KGSL_MEMDESC_GLOBAL;
 	}
+	/* clear IOMMU GPU CPU sync structures */
+	kgsl_sg_free(iommu->sync_lock_desc.sg, iommu->sync_lock_desc.sglen);
+	memset(&iommu->sync_lock_desc, 0, sizeof(iommu->sync_lock_desc));
+	iommu->sync_lock_vars = NULL;
 
 	kfree(iommu);
 
@@ -1127,8 +1521,16 @@
 	pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
 			iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
 
-	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+	/* For v1 SMMU GPU needs to be idle for tlb invalidate as well */
+	if (msm_soc_version_supports_iommu_v1())
 		kgsl_idle(mmu->device);
+
+	/* Acquire GPU-CPU sync Lock here */
+	msm_iommu_lock();
+
+	if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+		if (!msm_soc_version_supports_iommu_v1())
+			kgsl_idle(mmu->device);
 		for (i = 0; i < iommu->unit_count; i++) {
 			/* get the lsb value which should not change when
 			 * changing ttbr0 */
@@ -1153,6 +1555,10 @@
 			mb();
 		}
 	}
+
+	/* Release GPU-CPU sync Lock here */
+	msm_iommu_unlock();
+
 	/* Disable smmu clock */
 	kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
 }
@@ -1205,6 +1611,8 @@
 	/* These callbacks will be set on some chipsets */
 	.mmu_setup_pt = NULL,
 	.mmu_cleanup_pt = NULL,
+	.mmu_sync_lock = kgsl_iommu_sync_lock,
+	.mmu_sync_unlock = kgsl_iommu_sync_unlock,
 };
 
 struct kgsl_mmu_pt_ops iommu_pt_ops = {
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index 661b4f0..f539b07 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -120,6 +120,13 @@
  * @ctx_offset: The context offset to be added to base address when
  * accessing IOMMU registers
  * @iommu_reg_list: List of IOMMU registers { offset, map, shift } array
+ * @sync_lock_vars: Pointer to the IOMMU spinlock for serializing access to the
+ * IOMMU registers
+ * @sync_lock_desc: GPU Memory descriptor for the memory containing the
+ * spinlocks
+ * @sync_lock_offset - The page offset within a page at which the sync
+ * variables are located
+ * @sync_lock_initialized: True if the sync_lock feature is enabled
  */
 struct kgsl_iommu {
 	struct kgsl_iommu_unit iommu_units[KGSL_IOMMU_MAX_UNITS];
@@ -129,6 +136,10 @@
 	struct kgsl_device *device;
 	unsigned int ctx_offset;
 	struct kgsl_iommu_register_list *iommu_reg_list;
+	struct remote_iommu_petersons_spinlock *sync_lock_vars;
+	struct kgsl_memdesc sync_lock_desc;
+	unsigned int sync_lock_offset;
+	bool sync_lock_initialized;
 };
 
 /*
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..9d96633 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
@@ -153,6 +152,10 @@
 			struct kgsl_pagetable *pt);
 	void (*mmu_cleanup_pt) (struct kgsl_mmu *mmu,
 			struct kgsl_pagetable *pt);
+	unsigned int (*mmu_sync_lock)
+			(struct kgsl_mmu *mmu, unsigned int *cmds);
+	unsigned int (*mmu_sync_unlock)
+			(struct kgsl_mmu *mmu, unsigned int *cmds);
 };
 
 struct kgsl_mmu_pt_ops {
@@ -167,6 +170,8 @@
 	void (*mmu_destroy_pagetable) (void *pt);
 };
 
+#define KGSL_MMU_FLAGS_IOMMU_SYNC BIT(31)
+
 struct kgsl_mmu {
 	unsigned int     refcnt;
 	uint32_t      flags;
@@ -350,33 +355,73 @@
 /*
  * 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;
 }
 
+static inline int kgsl_mmu_sync_lock(struct kgsl_mmu *mmu,
+				unsigned int *cmds)
+{
+	if ((mmu->flags & KGSL_MMU_FLAGS_IOMMU_SYNC) &&
+		mmu->mmu_ops && mmu->mmu_ops->mmu_sync_lock)
+		return mmu->mmu_ops->mmu_sync_lock(mmu, cmds);
+	else
+		return 0;
+}
+
+static inline int kgsl_mmu_sync_unlock(struct kgsl_mmu *mmu,
+				unsigned int *cmds)
+{
+	if ((mmu->flags & KGSL_MMU_FLAGS_IOMMU_SYNC) &&
+		mmu->mmu_ops && mmu->mmu_ops->mmu_sync_unlock)
+		return mmu->mmu_ops->mmu_sync_unlock(mmu, cmds);
+	else
+		return 0;
+}
+
 #endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 7a7a8dc..d33df60 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -86,63 +86,304 @@
 	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)
+{
+	int max_pwrlevel = max_t(int, pwr->thermal_pwrlevel, pwr->max_pwrlevel);
+	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;
+	int level;
 
-			/* 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);
+
+	level = pwr->active_pwrlevel;
+
+	/*
+	 * Set the active powerlevel first in case the clocks are off - if we
+	 * don't do this then the pwrlevel change won't take effect when the
+	 * clocks come back
+	 */
+
+	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);
+
+		/*
+		 * Don't shift by more than one level at a time to
+		 * avoid glitches.
+		 */
+
+		while (level != new_level) {
+			level += delta;
+
+			clk_set_rate(pwr->grp_clks[0],
+				pwr->pwrlevels[level].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 +391,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 +428,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 +629,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 +650,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
 };
 
@@ -422,6 +685,9 @@
 	clkstats->on_time_old = on_time;
 	clkstats->elapsed_old = clkstats->elapsed;
 	clkstats->elapsed = 0;
+
+	trace_kgsl_gpubusy(device, clkstats->on_time_old,
+		clkstats->elapsed_old);
 }
 
 /* Track the amount of time the gpu is on vs the total system time. *
@@ -623,6 +889,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 +1158,9 @@
 				kgsl_pwrstate_to_str(device->state));
 		break;
 	}
+
+	kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
+
 	return 0;
 }
 
@@ -994,6 +1270,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..bbef139 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -274,6 +274,32 @@
 	)
 );
 
+TRACE_EVENT(kgsl_gpubusy,
+	TP_PROTO(struct kgsl_device *device, unsigned int busy,
+		unsigned int elapsed),
+
+	TP_ARGS(device, busy, elapsed),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(unsigned int, busy)
+		__field(unsigned int, elapsed)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->busy = busy;
+		__entry->elapsed = elapsed;
+	),
+
+	TP_printk(
+		"d_name=%s busy=%d elapsed=%d",
+		__get_str(device_name),
+		__entry->busy,
+		__entry->elapsed
+	)
+);
+
 DECLARE_EVENT_CLASS(kgsl_pwrstate_template,
 	TP_PROTO(struct kgsl_device *device, unsigned int state),
 
@@ -317,6 +343,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 +353,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 +439,7 @@
 		__field(int, type)
 		__field(unsigned int, tgid)
 		__array(char, usage, 16)
+		__field(unsigned int, id)
 	),
 
 	TP_fast_assign(
@@ -357,13 +450,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 +474,7 @@
 		__field(int, fd)
 		__field(unsigned int, tgid)
 		__array(char, usage, 16)
+		__field(unsigned int, id)
 	),
 
 	TP_fast_assign(
@@ -389,12 +484,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 +507,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 +519,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 +527,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
@@ -535,6 +634,31 @@
 	)
 );
 
+TRACE_EVENT(kgsl_regwrite,
+
+	TP_PROTO(struct kgsl_device *device, unsigned int offset,
+		unsigned int value),
+
+	TP_ARGS(device, offset, value),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(unsigned int, offset)
+		__field(unsigned int, value)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->offset = offset;
+		__entry->value = value;
+	),
+
+	TP_printk(
+		"d_name=%s reg=%x value=%x",
+		__get_str(device_name), __entry->offset, __entry->value
+	)
+);
+
 #endif /* _KGSL_TRACE_H */
 
 /* This part must be outside protection */
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index 69a2f1c..606bc36 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -1324,6 +1324,10 @@
 				return -EINVAL;
 			}
 
+			psoc_get_data.reading_value = epm_psoc_scale_result(
+				psoc_get_data.reading_value,
+				psoc_get_data.chan_num);
+
 			if (copy_to_user((void __user *)arg, &psoc_get_data,
 				sizeof(struct epm_psoc_get_data)))
 				return -EFAULT;
@@ -1529,38 +1533,38 @@
 }
 
 static struct sensor_device_attribute epm_adc_psoc_in_attrs[] = {
-	SENSOR_ATTR(ads0_chan0,  S_IRUGO, epm_adc_psoc_show_in, NULL, 0),
-	SENSOR_ATTR(ads0_chan1,  S_IRUGO, epm_adc_psoc_show_in, NULL, 1),
-	SENSOR_ATTR(ads0_chan2,  S_IRUGO, epm_adc_psoc_show_in, NULL, 2),
-	SENSOR_ATTR(ads0_chan3,  S_IRUGO, epm_adc_psoc_show_in, NULL, 3),
-	SENSOR_ATTR(ads0_chan4,  S_IRUGO, epm_adc_psoc_show_in, NULL, 4),
-	SENSOR_ATTR(ads0_chan5,  S_IRUGO, epm_adc_psoc_show_in, NULL, 5),
-	SENSOR_ATTR(ads0_chan6,  S_IRUGO, epm_adc_psoc_show_in, NULL, 6),
-	SENSOR_ATTR(ads0_chan7,  S_IRUGO, epm_adc_psoc_show_in, NULL, 7),
-	SENSOR_ATTR(ads0_chan8,  S_IRUGO, epm_adc_psoc_show_in, NULL, 8),
-	SENSOR_ATTR(ads0_chan9,  S_IRUGO, epm_adc_psoc_show_in, NULL, 9),
-	SENSOR_ATTR(ads0_chan10, S_IRUGO, epm_adc_psoc_show_in, NULL, 10),
-	SENSOR_ATTR(ads0_chan11, S_IRUGO, epm_adc_psoc_show_in, NULL, 11),
-	SENSOR_ATTR(ads0_chan12, S_IRUGO, epm_adc_psoc_show_in, NULL, 12),
-	SENSOR_ATTR(ads0_chan13, S_IRUGO, epm_adc_psoc_show_in, NULL, 13),
-	SENSOR_ATTR(ads0_chan14, S_IRUGO, epm_adc_psoc_show_in, NULL, 14),
-	SENSOR_ATTR(ads0_chan15, S_IRUGO, epm_adc_psoc_show_in, NULL, 15),
-	SENSOR_ATTR(ads1_chan0,  S_IRUGO, epm_adc_psoc_show_in, NULL, 16),
-	SENSOR_ATTR(ads1_chan1,  S_IRUGO, epm_adc_psoc_show_in, NULL, 17),
-	SENSOR_ATTR(ads1_chan2,  S_IRUGO, epm_adc_psoc_show_in, NULL, 18),
-	SENSOR_ATTR(ads1_chan3,  S_IRUGO, epm_adc_psoc_show_in, NULL, 19),
-	SENSOR_ATTR(ads1_chan4,  S_IRUGO, epm_adc_psoc_show_in, NULL, 20),
-	SENSOR_ATTR(ads1_chan5,  S_IRUGO, epm_adc_psoc_show_in, NULL, 21),
-	SENSOR_ATTR(ads1_chan6,  S_IRUGO, epm_adc_psoc_show_in, NULL, 22),
-	SENSOR_ATTR(ads1_chan7,  S_IRUGO, epm_adc_psoc_show_in, NULL, 23),
-	SENSOR_ATTR(ads1_chan8,  S_IRUGO, epm_adc_psoc_show_in, NULL, 24),
-	SENSOR_ATTR(ads1_chan9,  S_IRUGO, epm_adc_psoc_show_in, NULL, 25),
-	SENSOR_ATTR(ads1_chan10, S_IRUGO, epm_adc_psoc_show_in, NULL, 26),
-	SENSOR_ATTR(ads1_chan11, S_IRUGO, epm_adc_psoc_show_in, NULL, 27),
-	SENSOR_ATTR(ads1_chan12, S_IRUGO, epm_adc_psoc_show_in, NULL, 28),
-	SENSOR_ATTR(ads1_chan13, S_IRUGO, epm_adc_psoc_show_in, NULL, 29),
-	SENSOR_ATTR(ads1_chan14, S_IRUGO, epm_adc_psoc_show_in, NULL, 30),
-	SENSOR_ATTR(ads1_chan15, S_IRUGO, epm_adc_psoc_show_in, NULL, 31),
+	SENSOR_ATTR(psoc0_chan0,  S_IRUGO, epm_adc_psoc_show_in, NULL, 0),
+	SENSOR_ATTR(psoc0_chan1,  S_IRUGO, epm_adc_psoc_show_in, NULL, 1),
+	SENSOR_ATTR(psoc0_chan2,  S_IRUGO, epm_adc_psoc_show_in, NULL, 2),
+	SENSOR_ATTR(psoc0_chan3,  S_IRUGO, epm_adc_psoc_show_in, NULL, 3),
+	SENSOR_ATTR(psoc0_chan4,  S_IRUGO, epm_adc_psoc_show_in, NULL, 4),
+	SENSOR_ATTR(psoc0_chan5,  S_IRUGO, epm_adc_psoc_show_in, NULL, 5),
+	SENSOR_ATTR(psoc0_chan6,  S_IRUGO, epm_adc_psoc_show_in, NULL, 6),
+	SENSOR_ATTR(psoc0_chan7,  S_IRUGO, epm_adc_psoc_show_in, NULL, 7),
+	SENSOR_ATTR(psoc0_chan8,  S_IRUGO, epm_adc_psoc_show_in, NULL, 8),
+	SENSOR_ATTR(psoc0_chan9,  S_IRUGO, epm_adc_psoc_show_in, NULL, 9),
+	SENSOR_ATTR(psoc0_chan10, S_IRUGO, epm_adc_psoc_show_in, NULL, 10),
+	SENSOR_ATTR(psoc0_chan11, S_IRUGO, epm_adc_psoc_show_in, NULL, 11),
+	SENSOR_ATTR(psoc0_chan12, S_IRUGO, epm_adc_psoc_show_in, NULL, 12),
+	SENSOR_ATTR(psoc0_chan13, S_IRUGO, epm_adc_psoc_show_in, NULL, 13),
+	SENSOR_ATTR(psoc0_chan14, S_IRUGO, epm_adc_psoc_show_in, NULL, 14),
+	SENSOR_ATTR(psoc0_chan15, S_IRUGO, epm_adc_psoc_show_in, NULL, 15),
+	SENSOR_ATTR(psoc0_chan16,  S_IRUGO, epm_adc_psoc_show_in, NULL, 16),
+	SENSOR_ATTR(psoc0_chan17,  S_IRUGO, epm_adc_psoc_show_in, NULL, 17),
+	SENSOR_ATTR(psoc0_chan18,  S_IRUGO, epm_adc_psoc_show_in, NULL, 18),
+	SENSOR_ATTR(psoc0_chan19,  S_IRUGO, epm_adc_psoc_show_in, NULL, 19),
+	SENSOR_ATTR(psoc0_chan20,  S_IRUGO, epm_adc_psoc_show_in, NULL, 20),
+	SENSOR_ATTR(psoc0_chan21,  S_IRUGO, epm_adc_psoc_show_in, NULL, 21),
+	SENSOR_ATTR(psoc0_chan22,  S_IRUGO, epm_adc_psoc_show_in, NULL, 22),
+	SENSOR_ATTR(psoc0_chan23,  S_IRUGO, epm_adc_psoc_show_in, NULL, 23),
+	SENSOR_ATTR(psoc0_chan24,  S_IRUGO, epm_adc_psoc_show_in, NULL, 24),
+	SENSOR_ATTR(psoc0_chan25,  S_IRUGO, epm_adc_psoc_show_in, NULL, 25),
+	SENSOR_ATTR(psoc0_chan26, S_IRUGO, epm_adc_psoc_show_in, NULL, 26),
+	SENSOR_ATTR(psoc0_chan27, S_IRUGO, epm_adc_psoc_show_in, NULL, 27),
+	SENSOR_ATTR(psoc0_chan28, S_IRUGO, epm_adc_psoc_show_in, NULL, 28),
+	SENSOR_ATTR(psoc0_chan29, S_IRUGO, epm_adc_psoc_show_in, NULL, 29),
+	SENSOR_ATTR(psoc0_chan30, S_IRUGO, epm_adc_psoc_show_in, NULL, 30),
+	SENSOR_ATTR(psoc0_chan31, S_IRUGO, epm_adc_psoc_show_in, NULL, 31),
 };
 
 static int __devinit epm_adc_psoc_init_hwmon(struct spi_device *spi,
@@ -1677,6 +1681,15 @@
 	epm_adc = epm_adc_drv;
 	epm_adc->misc.name = EPM_ADC_DRIVER_NAME;
 	epm_adc->misc.minor = MISC_DYNAMIC_MINOR;
+
+	if (node) {
+		epm_adc->misc.fops = &epm_adc_fops;
+		if (misc_register(&epm_adc->misc)) {
+			pr_err("Unable to register misc device!\n");
+			return -EFAULT;
+		}
+	}
+
 	epm_adc_drv->epm_spi_client = spi;
 	epm_adc_drv->epm_spi_client->bits_per_word =
 				EPM_ADC_ADS_SPI_BITS_PER_WORD;
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index e319813..440dc42 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_voltage_temp(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_temp_voltage(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_temp_voltage(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)
@@ -706,7 +822,7 @@
 	struct device_node *node = spmi->dev.of_node;
 	struct resource *res;
 	struct device_node *child;
-	struct qpnp_vadc_amux *adc_channel_list;
+	struct qpnp_adc_amux *adc_channel_list;
 	struct qpnp_adc_properties *adc_prop;
 	struct qpnp_adc_amux_properties *amux_prop;
 	int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
@@ -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_adc_amux)) * count_adc_channel_list),
 				GFP_KERNEL);
 	if (!adc_channel_list) {
 		dev_err(&spmi->dev, "Unable to allocate memory\n");
@@ -761,8 +877,7 @@
 			return -EINVAL;
 		}
 
-		rc = of_property_read_u32(child, "qcom,channel-num",
-								&channel_num);
+		rc = of_property_read_u32(child, "reg", &channel_num);
 		if (rc) {
 			pr_err("Invalid channel num\n");
 			return -EINVAL;
@@ -844,8 +959,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/input/touchscreen/cyttsp-i2c-qc.c b/drivers/input/touchscreen/cyttsp-i2c-qc.c
index f96348e..6eba5d1 100644
--- a/drivers/input/touchscreen/cyttsp-i2c-qc.c
+++ b/drivers/input/touchscreen/cyttsp-i2c-qc.c
@@ -2778,11 +2778,14 @@
 			return -EINVAL;
 		}
 
+		mutex_init(&ts->mutex);
 		i2c_set_clientdata(client, ts);
 
 		error = cyttsp_initialize(client, ts);
 		if (error) {
 			cyttsp_xdebug1("err cyttsp_initialize\n");
+			/* release mutex */
+			mutex_destroy(&ts->mutex);
 			/* deallocate memory */
 			kfree(ts);
 /*
@@ -2801,7 +2804,6 @@
 	}
 #endif /* CONFIG_HAS_EARLYSUSPEND */
 	device_init_wakeup(&client->dev, ts->platform_data->wakeup);
-	mutex_init(&ts->mutex);
 
 	cyttsp_info("Start Probe %s\n", \
 		(retval < CY_OK) ? "FAIL" : "PASS");
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index ec3429b..86703e0 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -16,7 +16,7 @@
 # MSM IOMMU support
 config MSM_IOMMU
 	bool "MSM IOMMU Support"
-	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092
+	depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8910
 	select IOMMU_API
 	help
 	  Support for the IOMMUs found on certain Qualcomm SOCs.
@@ -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/amd_iommu.c b/drivers/iommu/amd_iommu.c
index a5bee8e..32c00cd 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3193,26 +3193,6 @@
 	return 0;
 }
 
-static int amd_iommu_device_group(struct device *dev, unsigned int *groupid)
-{
-	struct iommu_dev_data *dev_data = dev->archdata.iommu;
-	struct pci_dev *pdev = to_pci_dev(dev);
-	u16 devid;
-
-	if (!dev_data)
-		return -ENODEV;
-
-	if (pdev->is_virtfn || !iommu_group_mf)
-		devid = dev_data->devid;
-	else
-		devid = calc_devid(pdev->bus->number,
-				   PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
-
-	*groupid = amd_iommu_alias_table[devid];
-
-	return 0;
-}
-
 static struct iommu_ops amd_iommu_ops = {
 	.domain_init = amd_iommu_domain_init,
 	.domain_destroy = amd_iommu_domain_destroy,
@@ -3222,7 +3202,6 @@
 	.unmap = amd_iommu_unmap,
 	.iova_to_phys = amd_iommu_iova_to_phys,
 	.domain_has_cap = amd_iommu_domain_has_cap,
-	.device_group = amd_iommu_device_group,
 	.pgsize_bitmap	= AMD_IOMMU_PGSIZES,
 };
 
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index f93d5ac..d4a0ff7 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -4087,54 +4087,6 @@
 	return 0;
 }
 
-/*
- * Group numbers are arbitrary.  Device with the same group number
- * indicate the iommu cannot differentiate between them.  To avoid
- * tracking used groups we just use the seg|bus|devfn of the lowest
- * level we're able to differentiate devices
- */
-static int intel_iommu_device_group(struct device *dev, unsigned int *groupid)
-{
-	struct pci_dev *pdev = to_pci_dev(dev);
-	struct pci_dev *bridge;
-	union {
-		struct {
-			u8 devfn;
-			u8 bus;
-			u16 segment;
-		} pci;
-		u32 group;
-	} id;
-
-	if (iommu_no_mapping(dev))
-		return -ENODEV;
-
-	id.pci.segment = pci_domain_nr(pdev->bus);
-	id.pci.bus = pdev->bus->number;
-	id.pci.devfn = pdev->devfn;
-
-	if (!device_to_iommu(id.pci.segment, id.pci.bus, id.pci.devfn))
-		return -ENODEV;
-
-	bridge = pci_find_upstream_pcie_bridge(pdev);
-	if (bridge) {
-		if (pci_is_pcie(bridge)) {
-			id.pci.bus = bridge->subordinate->number;
-			id.pci.devfn = 0;
-		} else {
-			id.pci.bus = bridge->bus->number;
-			id.pci.devfn = bridge->devfn;
-		}
-	}
-
-	if (!pdev->is_virtfn && iommu_group_mf)
-		id.pci.devfn = PCI_DEVFN(PCI_SLOT(id.pci.devfn), 0);
-
-	*groupid = id.group;
-
-	return 0;
-}
-
 static struct iommu_ops intel_iommu_ops = {
 	.domain_init	= intel_iommu_domain_init,
 	.domain_destroy = intel_iommu_domain_destroy,
@@ -4144,7 +4096,6 @@
 	.unmap		= intel_iommu_unmap,
 	.iova_to_phys	= intel_iommu_iova_to_phys,
 	.domain_has_cap = intel_iommu_domain_has_cap,
-	.device_group	= intel_iommu_device_group,
 	.pgsize_bitmap	= INTEL_IOMMU_PGSIZES,
 };
 
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index ef69d91..d07fb96 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -27,60 +27,535 @@
 #include <linux/errno.h>
 #include <linux/iommu.h>
 #include <linux/scatterlist.h>
+#include <linux/idr.h>
+#include <linux/notifier.h>
+#include <linux/err.h>
 
-static ssize_t show_iommu_group(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static struct kset *iommu_group_kset;
+static struct ida iommu_group_ida;
+static struct mutex iommu_group_mutex;
+
+struct iommu_group {
+	struct kobject kobj;
+	struct kobject *devices_kobj;
+	struct list_head devices;
+	struct mutex mutex;
+	struct blocking_notifier_head notifier;
+	void *iommu_data;
+	void (*iommu_data_release)(void *iommu_data);
+	char *name;
+	int id;
+};
+
+struct iommu_device {
+	struct list_head list;
+	struct device *dev;
+	char *name;
+};
+
+struct iommu_group_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct iommu_group *group, char *buf);
+	ssize_t (*store)(struct iommu_group *group,
+			 const char *buf, size_t count);
+};
+
+#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)		\
+struct iommu_group_attribute iommu_group_attr_##_name =		\
+	__ATTR(_name, _mode, _show, _store)
+
+#define to_iommu_group_attr(_attr)	\
+	container_of(_attr, struct iommu_group_attribute, attr)
+#define to_iommu_group(_kobj)		\
+	container_of(_kobj, struct iommu_group, kobj)
+
+static ssize_t iommu_group_attr_show(struct kobject *kobj,
+				     struct attribute *__attr, char *buf)
 {
-	unsigned int groupid;
+	struct iommu_group_attribute *attr = to_iommu_group_attr(__attr);
+	struct iommu_group *group = to_iommu_group(kobj);
+	ssize_t ret = -EIO;
 
-	if (iommu_device_group(dev, &groupid))
-		return 0;
-
-	return sprintf(buf, "%u", groupid);
+	if (attr->show)
+		ret = attr->show(group, buf);
+	return ret;
 }
-static DEVICE_ATTR(iommu_group, S_IRUGO, show_iommu_group, NULL);
+
+static ssize_t iommu_group_attr_store(struct kobject *kobj,
+				      struct attribute *__attr,
+				      const char *buf, size_t count)
+{
+	struct iommu_group_attribute *attr = to_iommu_group_attr(__attr);
+	struct iommu_group *group = to_iommu_group(kobj);
+	ssize_t ret = -EIO;
+
+	if (attr->store)
+		ret = attr->store(group, buf, count);
+	return ret;
+}
+
+static const struct sysfs_ops iommu_group_sysfs_ops = {
+	.show = iommu_group_attr_show,
+	.store = iommu_group_attr_store,
+};
+
+static int iommu_group_create_file(struct iommu_group *group,
+				   struct iommu_group_attribute *attr)
+{
+	return sysfs_create_file(&group->kobj, &attr->attr);
+}
+
+static void iommu_group_remove_file(struct iommu_group *group,
+				    struct iommu_group_attribute *attr)
+{
+	sysfs_remove_file(&group->kobj, &attr->attr);
+}
+
+static ssize_t iommu_group_show_name(struct iommu_group *group, char *buf)
+{
+	return sprintf(buf, "%s\n", group->name);
+}
+
+static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL);
+
+static void iommu_group_release(struct kobject *kobj)
+{
+	struct iommu_group *group = to_iommu_group(kobj);
+
+	if (group->iommu_data_release)
+		group->iommu_data_release(group->iommu_data);
+
+	mutex_lock(&iommu_group_mutex);
+	ida_remove(&iommu_group_ida, group->id);
+	mutex_unlock(&iommu_group_mutex);
+
+	kfree(group->name);
+	kfree(group);
+}
+
+static struct kobj_type iommu_group_ktype = {
+	.sysfs_ops = &iommu_group_sysfs_ops,
+	.release = iommu_group_release,
+};
+
+/**
+ * iommu_group_alloc - Allocate a new group
+ * @name: Optional name to associate with group, visible in sysfs
+ *
+ * This function is called by an iommu driver to allocate a new iommu
+ * group.  The iommu group represents the minimum granularity of the iommu.
+ * Upon successful return, the caller holds a reference to the supplied
+ * group in order to hold the group until devices are added.  Use
+ * iommu_group_put() to release this extra reference count, allowing the
+ * group to be automatically reclaimed once it has no devices or external
+ * references.
+ */
+struct iommu_group *iommu_group_alloc(void)
+{
+	struct iommu_group *group;
+	int ret;
+
+	group = kzalloc(sizeof(*group), GFP_KERNEL);
+	if (!group)
+		return ERR_PTR(-ENOMEM);
+
+	group->kobj.kset = iommu_group_kset;
+	mutex_init(&group->mutex);
+	INIT_LIST_HEAD(&group->devices);
+	BLOCKING_INIT_NOTIFIER_HEAD(&group->notifier);
+
+	mutex_lock(&iommu_group_mutex);
+
+again:
+	if (unlikely(0 == ida_pre_get(&iommu_group_ida, GFP_KERNEL))) {
+		kfree(group);
+		mutex_unlock(&iommu_group_mutex);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (-EAGAIN == ida_get_new(&iommu_group_ida, &group->id))
+		goto again;
+
+	mutex_unlock(&iommu_group_mutex);
+
+	ret = kobject_init_and_add(&group->kobj, &iommu_group_ktype,
+				   NULL, "%d", group->id);
+	if (ret) {
+		mutex_lock(&iommu_group_mutex);
+		ida_remove(&iommu_group_ida, group->id);
+		mutex_unlock(&iommu_group_mutex);
+		kfree(group);
+		return ERR_PTR(ret);
+	}
+
+	group->devices_kobj = kobject_create_and_add("devices", &group->kobj);
+	if (!group->devices_kobj) {
+		kobject_put(&group->kobj); /* triggers .release & free */
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/*
+	 * The devices_kobj holds a reference on the group kobject, so
+	 * as long as that exists so will the group.  We can therefore
+	 * use the devices_kobj for reference counting.
+	 */
+	kobject_put(&group->kobj);
+
+	return group;
+}
+EXPORT_SYMBOL_GPL(iommu_group_alloc);
+
+/**
+ * iommu_group_get_iommudata - retrieve iommu_data registered for a group
+ * @group: the group
+ *
+ * iommu drivers can store data in the group for use when doing iommu
+ * operations.  This function provides a way to retrieve it.  Caller
+ * should hold a group reference.
+ */
+void *iommu_group_get_iommudata(struct iommu_group *group)
+{
+	return group->iommu_data;
+}
+EXPORT_SYMBOL_GPL(iommu_group_get_iommudata);
+
+/**
+ * iommu_group_set_iommudata - set iommu_data for a group
+ * @group: the group
+ * @iommu_data: new data
+ * @release: release function for iommu_data
+ *
+ * iommu drivers can store data in the group for use when doing iommu
+ * operations.  This function provides a way to set the data after
+ * the group has been allocated.  Caller should hold a group reference.
+ */
+void iommu_group_set_iommudata(struct iommu_group *group, void *iommu_data,
+			       void (*release)(void *iommu_data))
+{
+	group->iommu_data = iommu_data;
+	group->iommu_data_release = release;
+}
+EXPORT_SYMBOL_GPL(iommu_group_set_iommudata);
+
+/**
+ * iommu_group_set_name - set name for a group
+ * @group: the group
+ * @name: name
+ *
+ * Allow iommu driver to set a name for a group.  When set it will
+ * appear in a name attribute file under the group in sysfs.
+ */
+int iommu_group_set_name(struct iommu_group *group, const char *name)
+{
+	int ret;
+
+	if (group->name) {
+		iommu_group_remove_file(group, &iommu_group_attr_name);
+		kfree(group->name);
+		group->name = NULL;
+		if (!name)
+			return 0;
+	}
+
+	group->name = kstrdup(name, GFP_KERNEL);
+	if (!group->name)
+		return -ENOMEM;
+
+	ret = iommu_group_create_file(group, &iommu_group_attr_name);
+	if (ret) {
+		kfree(group->name);
+		group->name = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(iommu_group_set_name);
+
+/**
+ * iommu_group_add_device - add a device to an iommu group
+ * @group: the group into which to add the device (reference should be held)
+ * @dev: the device
+ *
+ * This function is called by an iommu driver to add a device into a
+ * group.  Adding a device increments the group reference count.
+ */
+int iommu_group_add_device(struct iommu_group *group, struct device *dev)
+{
+	int ret, i = 0;
+	struct iommu_device *device;
+
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+
+	device->dev = dev;
+
+	ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group");
+	if (ret) {
+		kfree(device);
+		return ret;
+	}
+
+	device->name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj));
+rename:
+	if (!device->name) {
+		sysfs_remove_link(&dev->kobj, "iommu_group");
+		kfree(device);
+		return -ENOMEM;
+	}
+
+	ret = sysfs_create_link_nowarn(group->devices_kobj,
+				       &dev->kobj, device->name);
+	if (ret) {
+		kfree(device->name);
+		if (ret == -EEXIST && i >= 0) {
+			/*
+			 * Account for the slim chance of collision
+			 * and append an instance to the name.
+			 */
+			device->name = kasprintf(GFP_KERNEL, "%s.%d",
+						 kobject_name(&dev->kobj), i++);
+			goto rename;
+		}
+
+		sysfs_remove_link(&dev->kobj, "iommu_group");
+		kfree(device);
+		return ret;
+	}
+
+	kobject_get(group->devices_kobj);
+
+	dev->iommu_group = group;
+
+	mutex_lock(&group->mutex);
+	list_add_tail(&device->list, &group->devices);
+	mutex_unlock(&group->mutex);
+
+	/* Notify any listeners about change to group. */
+	blocking_notifier_call_chain(&group->notifier,
+				     IOMMU_GROUP_NOTIFY_ADD_DEVICE, dev);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(iommu_group_add_device);
+
+/**
+ * iommu_group_remove_device - remove a device from it's current group
+ * @dev: device to be removed
+ *
+ * This function is called by an iommu driver to remove the device from
+ * it's current group.  This decrements the iommu group reference count.
+ */
+void iommu_group_remove_device(struct device *dev)
+{
+	struct iommu_group *group = dev->iommu_group;
+	struct iommu_device *tmp_device, *device = NULL;
+
+	/* Pre-notify listeners that a device is being removed. */
+	blocking_notifier_call_chain(&group->notifier,
+				     IOMMU_GROUP_NOTIFY_DEL_DEVICE, dev);
+
+	mutex_lock(&group->mutex);
+	list_for_each_entry(tmp_device, &group->devices, list) {
+		if (tmp_device->dev == dev) {
+			device = tmp_device;
+			list_del(&device->list);
+			break;
+		}
+	}
+	mutex_unlock(&group->mutex);
+
+	if (!device)
+		return;
+
+	sysfs_remove_link(group->devices_kobj, device->name);
+	sysfs_remove_link(&dev->kobj, "iommu_group");
+
+	kfree(device->name);
+	kfree(device);
+	dev->iommu_group = NULL;
+	kobject_put(group->devices_kobj);
+}
+EXPORT_SYMBOL_GPL(iommu_group_remove_device);
+
+/**
+ * iommu_group_for_each_dev - iterate over each device in the group
+ * @group: the group
+ * @data: caller opaque data to be passed to callback function
+ * @fn: caller supplied callback function
+ *
+ * This function is called by group users to iterate over group devices.
+ * Callers should hold a reference count to the group during callback.
+ * The group->mutex is held across callbacks, which will block calls to
+ * iommu_group_add/remove_device.
+ */
+int iommu_group_for_each_dev(struct iommu_group *group, void *data,
+			     int (*fn)(struct device *, void *))
+{
+	struct iommu_device *device;
+	int ret = 0;
+
+	mutex_lock(&group->mutex);
+	list_for_each_entry(device, &group->devices, list) {
+		ret = fn(device->dev, data);
+		if (ret)
+			break;
+	}
+	mutex_unlock(&group->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_group_for_each_dev);
+
+/**
+ * iommu_group_get - Return the group for a device and increment reference
+ * @dev: get the group that this device belongs to
+ *
+ * This function is called by iommu drivers and users to get the group
+ * for the specified device.  If found, the group is returned and the group
+ * reference in incremented, else NULL.
+ */
+struct iommu_group *iommu_group_get(struct device *dev)
+{
+	struct iommu_group *group = dev->iommu_group;
+
+	if (group)
+		kobject_get(group->devices_kobj);
+
+	return group;
+}
+EXPORT_SYMBOL_GPL(iommu_group_get);
+
+/**
+ * iommu_group_put - Decrement group reference
+ * @group: the group to use
+ *
+ * This function is called by iommu drivers and users to release the
+ * iommu group.  Once the reference count is zero, the group is released.
+ */
+void iommu_group_put(struct iommu_group *group)
+{
+	if (group)
+		kobject_put(group->devices_kobj);
+}
+EXPORT_SYMBOL_GPL(iommu_group_put);
+
+/**
+ * iommu_group_register_notifier - Register a notifier for group changes
+ * @group: the group to watch
+ * @nb: notifier block to signal
+ *
+ * This function allows iommu group users to track changes in a group.
+ * See include/linux/iommu.h for actions sent via this notifier.  Caller
+ * should hold a reference to the group throughout notifier registration.
+ */
+int iommu_group_register_notifier(struct iommu_group *group,
+				  struct notifier_block *nb)
+{
+	return blocking_notifier_chain_register(&group->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(iommu_group_register_notifier);
+
+/**
+ * iommu_group_unregister_notifier - Unregister a notifier
+ * @group: the group to watch
+ * @nb: notifier block to signal
+ *
+ * Unregister a previously registered group notifier block.
+ */
+int iommu_group_unregister_notifier(struct iommu_group *group,
+				    struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&group->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(iommu_group_unregister_notifier);
+
+/**
+ * iommu_group_id - Return ID for a group
+ * @group: the group to ID
+ *
+ * Return the unique ID for the group matching the sysfs group number.
+ */
+int iommu_group_id(struct iommu_group *group)
+{
+	return group->id;
+}
+EXPORT_SYMBOL_GPL(iommu_group_id);
 
 static int add_iommu_group(struct device *dev, void *data)
 {
-	unsigned int groupid;
+	struct iommu_ops *ops = data;
 
-	if (iommu_device_group(dev, &groupid) == 0)
-		return device_create_file(dev, &dev_attr_iommu_group);
+	if (!ops->add_device)
+		return -ENODEV;
+
+	WARN_ON(dev->iommu_group);
+
+	ops->add_device(dev);
 
 	return 0;
 }
 
-static int remove_iommu_group(struct device *dev)
-{
-	unsigned int groupid;
-
-	if (iommu_device_group(dev, &groupid) == 0)
-		device_remove_file(dev, &dev_attr_iommu_group);
-
-	return 0;
-}
-
-static int iommu_device_notifier(struct notifier_block *nb,
-				 unsigned long action, void *data)
+static int iommu_bus_notifier(struct notifier_block *nb,
+			      unsigned long action, void *data)
 {
 	struct device *dev = data;
+	struct iommu_ops *ops = dev->bus->iommu_ops;
+	struct iommu_group *group;
+	unsigned long group_action = 0;
 
-	if (action == BUS_NOTIFY_ADD_DEVICE)
-		return add_iommu_group(dev, NULL);
-	else if (action == BUS_NOTIFY_DEL_DEVICE)
-		return remove_iommu_group(dev);
+	/*
+	 * ADD/DEL call into iommu driver ops if provided, which may
+	 * result in ADD/DEL notifiers to group->notifier
+	 */
+	if (action == BUS_NOTIFY_ADD_DEVICE) {
+		if (ops->add_device)
+			return ops->add_device(dev);
+	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
+		if (ops->remove_device && dev->iommu_group) {
+			ops->remove_device(dev);
+			return 0;
+		}
+	}
 
+	/*
+	 * Remaining BUS_NOTIFYs get filtered and republished to the
+	 * group, if anyone is listening
+	 */
+	group = iommu_group_get(dev);
+	if (!group)
+		return 0;
+
+	switch (action) {
+	case BUS_NOTIFY_BIND_DRIVER:
+		group_action = IOMMU_GROUP_NOTIFY_BIND_DRIVER;
+		break;
+	case BUS_NOTIFY_BOUND_DRIVER:
+		group_action = IOMMU_GROUP_NOTIFY_BOUND_DRIVER;
+		break;
+	case BUS_NOTIFY_UNBIND_DRIVER:
+		group_action = IOMMU_GROUP_NOTIFY_UNBIND_DRIVER;
+		break;
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		group_action = IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER;
+		break;
+	}
+
+	if (group_action)
+		blocking_notifier_call_chain(&group->notifier,
+					     group_action, dev);
+
+	iommu_group_put(group);
 	return 0;
 }
 
-static struct notifier_block iommu_device_nb = {
-	.notifier_call = iommu_device_notifier,
+static struct notifier_block iommu_bus_nb = {
+	.notifier_call = iommu_bus_notifier,
 };
 
 static void iommu_bus_init(struct bus_type *bus, struct iommu_ops *ops)
 {
-	bus_register_notifier(bus, &iommu_device_nb);
-	bus_for_each_dev(bus, NULL, NULL, add_iommu_group);
+	bus_register_notifier(bus, &iommu_bus_nb);
+	bus_for_each_dev(bus, NULL, ops, add_iommu_group);
 }
 
 /**
@@ -120,6 +595,7 @@
  * iommu_set_fault_handler() - set a fault handler for an iommu domain
  * @domain: iommu domain
  * @handler: fault handler
+ * @token: user data, will be passed back to the fault handler
  *
  * This function should be used by IOMMU users which want to be notified
  * whenever an IOMMU fault happens.
@@ -128,11 +604,13 @@
  * error code otherwise.
  */
 void iommu_set_fault_handler(struct iommu_domain *domain,
-					iommu_fault_handler_t handler)
+					iommu_fault_handler_t handler,
+					void *token)
 {
 	BUG_ON(!domain);
 
 	domain->handler = handler;
+	domain->handler_token = token;
 }
 EXPORT_SYMBOL_GPL(iommu_set_fault_handler);
 
@@ -190,6 +668,45 @@
 }
 EXPORT_SYMBOL_GPL(iommu_detach_device);
 
+/*
+ * IOMMU groups are really the natrual working unit of the IOMMU, but
+ * the IOMMU API works on domains and devices.  Bridge that gap by
+ * iterating over the devices in a group.  Ideally we'd have a single
+ * device which represents the requestor ID of the group, but we also
+ * allow IOMMU drivers to create policy defined minimum sets, where
+ * the physical hardware may be able to distiguish members, but we
+ * wish to group them at a higher level (ex. untrusted multi-function
+ * PCI devices).  Thus we attach each device.
+ */
+static int iommu_group_do_attach_device(struct device *dev, void *data)
+{
+	struct iommu_domain *domain = data;
+
+	return iommu_attach_device(domain, dev);
+}
+
+int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group)
+{
+	return iommu_group_for_each_dev(group, domain,
+					iommu_group_do_attach_device);
+}
+EXPORT_SYMBOL_GPL(iommu_attach_group);
+
+static int iommu_group_do_detach_device(struct device *dev, void *data)
+{
+	struct iommu_domain *domain = data;
+
+	iommu_detach_device(domain, dev);
+
+	return 0;
+}
+
+void iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group)
+{
+	iommu_group_for_each_dev(group, domain, iommu_group_do_detach_device);
+}
+EXPORT_SYMBOL_GPL(iommu_detach_group);
+
 phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
 			       unsigned long iova)
 {
@@ -367,11 +884,15 @@
 }
 EXPORT_SYMBOL_GPL(iommu_get_pt_base_addr);
 
-int iommu_device_group(struct device *dev, unsigned int *groupid)
+static int __init iommu_init(void)
 {
-	if (iommu_present(dev->bus) && dev->bus->iommu_ops->device_group)
-		return dev->bus->iommu_ops->device_group(dev, groupid);
+	iommu_group_kset = kset_create_and_add("iommu_groups",
+					       NULL, kernel_kobj);
+	ida_init(&iommu_group_ida);
+	mutex_init(&iommu_group_mutex);
 
-	return -ENODEV;
+	BUG_ON(!iommu_group_kset);
+
+	return 0;
 }
-EXPORT_SYMBOL_GPL(iommu_device_group);
+subsys_initcall(iommu_init);
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index 425eb8a..567b9ba 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -156,9 +156,7 @@
 	int i, smt_size;
 
 	SET_ACR(base, 0);
-	SET_NSACR(base, 0);
 	SET_CR2(base, 0);
-	SET_NSCR2(base, 0);
 	SET_GFAR(base, 0);
 	SET_GFSRRESTORE(base, 0);
 	SET_TLBIALLNSNH(base, 0);
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index f8c9809..1ce1cf8 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,24 +217,29 @@
 		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:
 	return ret;
 }
 
-static void __reset_context(void __iomem *base, int ctx)
+static void __reset_context(void __iomem *base, void __iomem *glb_base, int ctx)
 {
-	SET_BPRCOSH(base, ctx, 0);
-	SET_BPRCISH(base, ctx, 0);
-	SET_BPRCNSH(base, ctx, 0);
-	SET_BPSHCFG(base, ctx, 0);
-	SET_BPMTCFG(base, ctx, 0);
+	SET_BPRCOSH(glb_base, ctx, 0);
+	SET_BPRCISH(glb_base, ctx, 0);
+	SET_BPRCNSH(glb_base, ctx, 0);
+	SET_BPSHCFG(glb_base, ctx, 0);
+	SET_BPMTCFG(glb_base, ctx, 0);
 	SET_ACTLR(base, ctx, 0);
 	SET_SCTLR(base, ctx, 0);
 	SET_FSRRESTORE(base, ctx, 0);
@@ -183,13 +257,15 @@
 	mb();
 }
 
-static void __program_context(void __iomem *base, int ctx, int ncb,
-			      phys_addr_t pgtable, int redirect,
-			      int ttbr_split)
+static void __program_context(void __iomem *base, void __iomem *glb_base,
+			      int ctx, int ncb, phys_addr_t pgtable,
+			      int redirect, int ttbr_split)
 {
 	unsigned int prrr, nmrr;
 	int i, j, found;
-	__reset_context(base, ctx);
+	msm_iommu_remote_spin_lock();
+
+	__reset_context(base, glb_base, ctx);
 
 	/* Set up HTW mode */
 	/* TLB miss configuration: perform HTW on miss */
@@ -278,6 +354,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)
@@ -339,7 +417,6 @@
 static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
 {
 	struct msm_priv *priv;
-	struct msm_iommu_ctx_dev *ctx_dev;
 	struct msm_iommu_drvdata *iommu_drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata;
 	struct msm_iommu_ctx_drvdata *tmp_drvdata;
@@ -356,9 +433,8 @@
 
 	iommu_drvdata = dev_get_drvdata(dev->parent);
 	ctx_drvdata = dev_get_drvdata(dev);
-	ctx_dev = dev->platform_data;
 
-	if (!iommu_drvdata || !ctx_drvdata || !ctx_dev) {
+	if (!iommu_drvdata || !ctx_drvdata) {
 		ret = -EINVAL;
 		goto fail;
 	}
@@ -378,7 +454,8 @@
 	if (ret)
 		goto fail;
 
-	__program_context(iommu_drvdata->base, ctx_dev->num, iommu_drvdata->ncb,
+	__program_context(iommu_drvdata->base, iommu_drvdata->glb_base,
+			  ctx_drvdata->num, iommu_drvdata->ncb,
 			  __pa(priv->pgtable), priv->redirect,
 			  iommu_drvdata->ttbr_split);
 
@@ -417,10 +494,16 @@
 	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);
+	__reset_context(iommu_drvdata->base, iommu_drvdata->glb_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 +1166,8 @@
 	if (ret)
 		goto fail;
 
+	msm_iommu_remote_spin_lock();
+
 	SET_V2PPR(base, ctx, va & V2Pxx_VA);
 
 	mb();
@@ -1097,6 +1182,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 +1244,8 @@
 	if (ret)
 		goto fail;
 
+	msm_iommu_remote_spin_lock();
+
 	fsr = GET_FSR(base, num);
 
 	if (fsr) {
@@ -1188,6 +1277,8 @@
 	} else
 		ret = IRQ_NONE;
 
+	msm_iommu_remote_spin_unlock();
+
 	__disable_clocks(drvdata);
 fail:
 	mutex_unlock(&msm_iommu_lock);
@@ -1258,6 +1349,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/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index 5a0b593..cf30500 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.c
@@ -134,6 +134,8 @@
 	if (!drvdata->base)
 		return -ENOMEM;
 
+	drvdata->glb_base = drvdata->base;
+
 	drvdata->gdsc = devm_regulator_get(&pdev->dev, "vdd");
 	if (IS_ERR(drvdata->gdsc))
 		return -EINVAL;
diff --git a/drivers/iommu/msm_iommu_dev.c b/drivers/iommu/msm_iommu_dev.c
index d9eddcd..44fe454 100644
--- a/drivers/iommu/msm_iommu_dev.c
+++ b/drivers/iommu/msm_iommu_dev.c
@@ -23,6 +23,9 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
 
 #include <mach/iommu_hw-8xxx.h>
 #include <mach/iommu.h>
@@ -81,28 +84,28 @@
 }
 EXPORT_SYMBOL(msm_iommu_get_ctx);
 
-static void msm_iommu_reset(void __iomem *base, int ncb)
+static void msm_iommu_reset(void __iomem *base, void __iomem *glb_base, int ncb)
 {
 	int ctx;
 
-	SET_RPUE(base, 0);
-	SET_RPUEIE(base, 0);
-	SET_ESRRESTORE(base, 0);
-	SET_TBE(base, 0);
-	SET_CR(base, 0);
-	SET_SPDMBE(base, 0);
-	SET_TESTBUSCR(base, 0);
-	SET_TLBRSW(base, 0);
-	SET_GLOBAL_TLBIALL(base, 0);
-	SET_RPU_ACR(base, 0);
-	SET_TLBLKCRWE(base, 1);
+	SET_RPUE(glb_base, 0);
+	SET_RPUEIE(glb_base, 0);
+	SET_ESRRESTORE(glb_base, 0);
+	SET_TBE(glb_base, 0);
+	SET_CR(glb_base, 0);
+	SET_SPDMBE(glb_base, 0);
+	SET_TESTBUSCR(glb_base, 0);
+	SET_TLBRSW(glb_base, 0);
+	SET_GLOBAL_TLBIALL(glb_base, 0);
+	SET_RPU_ACR(glb_base, 0);
+	SET_TLBLKCRWE(glb_base, 1);
 
 	for (ctx = 0; ctx < ncb; ctx++) {
-		SET_BPRCOSH(base, ctx, 0);
-		SET_BPRCISH(base, ctx, 0);
-		SET_BPRCNSH(base, ctx, 0);
-		SET_BPSHCFG(base, ctx, 0);
-		SET_BPMTCFG(base, ctx, 0);
+		SET_BPRCOSH(glb_base, ctx, 0);
+		SET_BPRCISH(glb_base, ctx, 0);
+		SET_BPRCNSH(glb_base, ctx, 0);
+		SET_BPSHCFG(glb_base, ctx, 0);
+		SET_BPMTCFG(glb_base, ctx, 0);
 		SET_ACTLR(base, ctx, 0);
 		SET_SCTLR(base, ctx, 0);
 		SET_FSRRESTORE(base, ctx, 0);
@@ -124,135 +127,224 @@
 	mb();
 }
 
+static int msm_iommu_parse_dt(struct platform_device *pdev,
+				struct msm_iommu_drvdata *drvdata)
+{
+#ifdef CONFIG_OF_DEVICE
+	struct device_node *child;
+	struct resource *r;
+	u32 glb_offset = 0;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		pr_err("%s: Missing property reg\n", __func__);
+		return -EINVAL;
+	}
+	drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+	if (!drvdata->base) {
+		pr_err("%s: Unable to ioremap address %x size %x\n", __func__,
+			r->start, resource_size(r));
+		return -ENOMEM;
+	}
+	drvdata->glb_base = drvdata->base;
+
+	if (!of_property_read_u32(pdev->dev.of_node, "qcom,glb-offset",
+			&glb_offset)) {
+		drvdata->glb_base += glb_offset;
+	} else {
+		pr_err("%s: Missing property qcom,glb-offset\n", __func__);
+		return -EINVAL;
+	}
+
+	for_each_child_of_node(pdev->dev.of_node, child) {
+		drvdata->ncb++;
+		if (!of_platform_device_create(child, NULL, &pdev->dev))
+			pr_err("Failed to create %s device\n", child->name);
+	}
+
+	drvdata->name = dev_name(&pdev->dev);
+	drvdata->sec_id = -1;
+	drvdata->ttbr_split = 0;
+#endif
+	return 0;
+}
+
+static int __get_clocks(struct platform_device *pdev,
+				 struct msm_iommu_drvdata *drvdata)
+{
+	int ret = 0;
+
+	drvdata->pclk = clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(drvdata->pclk)) {
+		ret = PTR_ERR(drvdata->pclk);
+		drvdata->pclk = NULL;
+		pr_err("Unable to get %s clock for %s IOMMU device\n",
+			dev_name(&pdev->dev), drvdata->name);
+		goto fail;
+	}
+
+	drvdata->clk = clk_get(&pdev->dev, "core_clk");
+
+	if (!IS_ERR(drvdata->clk)) {
+		if (clk_get_rate(drvdata->clk) == 0) {
+			ret = clk_round_rate(drvdata->clk, 1000);
+			clk_set_rate(drvdata->clk, ret);
+		}
+	} else {
+		drvdata->clk = NULL;
+	}
+	return 0;
+fail:
+	return ret;
+}
+
+static void __put_clocks(struct msm_iommu_drvdata *drvdata)
+{
+	if (drvdata->clk)
+		clk_put(drvdata->clk);
+	clk_put(drvdata->pclk);
+}
+
+static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
+{
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->pclk);
+	if (ret)
+		goto fail;
+
+	if (drvdata->clk) {
+		ret = clk_prepare_enable(drvdata->clk);
+		if (ret)
+			clk_disable_unprepare(drvdata->pclk);
+	}
+fail:
+	return ret;
+}
+
+static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
+{
+	if (drvdata->clk)
+		clk_disable_unprepare(drvdata->clk);
+	clk_disable_unprepare(drvdata->pclk);
+}
+
+/*
+ * Do a basic check of the IOMMU by performing an ATS operation
+ * on context bank 0.
+ */
+static int iommu_sanity_check(struct msm_iommu_drvdata *drvdata)
+{
+	int par;
+	int ret = 0;
+
+	SET_M(drvdata->base, 0, 1);
+	SET_PAR(drvdata->base, 0, 0);
+	SET_V2PCFG(drvdata->base, 0, 1);
+	SET_V2PPR(drvdata->base, 0, 0);
+	mb();
+	par = GET_PAR(drvdata->base, 0);
+	SET_V2PCFG(drvdata->base, 0, 0);
+	SET_M(drvdata->base, 0, 0);
+	mb();
+
+	if (!par) {
+		pr_err("%s: Invalid PAR value detected\n", drvdata->name);
+		ret = -ENODEV;
+	}
+	return ret;
+}
+
 static int msm_iommu_probe(struct platform_device *pdev)
 {
-	struct resource *r, *r2;
-	struct clk *iommu_clk = NULL;
-	struct clk *iommu_pclk = NULL;
 	struct msm_iommu_drvdata *drvdata;
 	struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
-	void __iomem *regs_base;
-	resource_size_t	len;
-	int ret, par;
+	int ret;
 
-	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
 
 	if (!drvdata) {
 		ret = -ENOMEM;
 		goto fail;
 	}
 
-	if (!iommu_dev) {
-		ret = -ENODEV;
-		goto fail;
-	}
+	if (pdev->dev.of_node) {
+		ret = msm_iommu_parse_dt(pdev, drvdata);
+		if (ret)
+			goto fail;
+	} else if (pdev->dev.platform_data) {
+		struct resource *r, *r2;
+		resource_size_t	len;
 
-	iommu_pclk = clk_get_sys("msm_iommu", "iface_clk");
-	if (IS_ERR(iommu_pclk)) {
-		ret = -ENODEV;
-		goto fail;
-	}
+		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"physbase");
 
-	ret = clk_prepare_enable(iommu_pclk);
-	if (ret)
-		goto fail_enable;
-
-	iommu_clk = clk_get(&pdev->dev, "core_clk");
-
-	if (!IS_ERR(iommu_clk))	{
-		if (clk_get_rate(iommu_clk) == 0) {
-			ret = clk_round_rate(iommu_clk, 1);
-			clk_set_rate(iommu_clk, ret);
+		if (!r) {
+			ret = -ENODEV;
+			goto fail;
 		}
 
-		ret = clk_prepare_enable(iommu_clk);
-		if (ret) {
-			clk_put(iommu_clk);
-			goto fail_pclk;
-		}
-	} else
-		iommu_clk = NULL;
+		len = resource_size(r);
 
-	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase");
-
-	if (!r) {
-		ret = -ENODEV;
-		goto fail_clk;
-	}
-
-	len = resource_size(r);
-
-	r2 = request_mem_region(r->start, len, r->name);
-	if (!r2) {
-		pr_err("Could not request memory region: start=%p, len=%d\n",
+		r2 = request_mem_region(r->start, len, r->name);
+		if (!r2) {
+			pr_err("Could not request memory region: start=%p, len=%d\n",
 							(void *) r->start, len);
-		ret = -EBUSY;
-		goto fail_clk;
-	}
+			ret = -EBUSY;
+			goto fail;
+		}
 
-	regs_base = ioremap(r2->start, len);
+		drvdata->base = devm_ioremap(&pdev->dev, r2->start, len);
 
-	if (!regs_base) {
-		pr_err("Could not ioremap: start=%p, len=%d\n",
-			 (void *) r2->start, len);
-		ret = -EBUSY;
-		goto fail_mem;
-	}
-
-	msm_iommu_reset(regs_base, iommu_dev->ncb);
-
-	SET_M(regs_base, 0, 1);
-	SET_PAR(regs_base, 0, 0);
-	SET_V2PCFG(regs_base, 0, 1);
-	SET_V2PPR(regs_base, 0, 0);
-	mb();
-	par = GET_PAR(regs_base, 0);
-	SET_V2PCFG(regs_base, 0, 0);
-	SET_M(regs_base, 0, 0);
-	mb();
-
-	if (!par) {
-		pr_err("%s: Invalid PAR value detected\n", iommu_dev->name);
+		if (!drvdata->base) {
+			pr_err("Could not ioremap: start=%p, len=%d\n",
+				 (void *) r2->start, len);
+			ret = -EBUSY;
+			goto fail;
+		}
+		/*
+		 * Global register space offset for legacy IOMMUv1 hardware
+		 * is always 0xFF000
+		 */
+		drvdata->glb_base = drvdata->base + 0xFF000;
+		drvdata->name = iommu_dev->name;
+		drvdata->dev = &pdev->dev;
+		drvdata->ncb = iommu_dev->ncb;
+		drvdata->ttbr_split = iommu_dev->ttbr_split;
+	} else {
 		ret = -ENODEV;
-		goto fail_io;
+		goto fail;
 	}
 
-	drvdata->pclk = iommu_pclk;
-	drvdata->clk = iommu_clk;
-	drvdata->base = regs_base;
-	drvdata->ncb = iommu_dev->ncb;
-	drvdata->ttbr_split = iommu_dev->ttbr_split;
-	drvdata->name = iommu_dev->name;
 	drvdata->dev = &pdev->dev;
 
-	msm_iommu_add_drv(drvdata);
+	ret = __get_clocks(pdev, drvdata);
+
+	if (ret)
+		goto fail;
+
+	__enable_clocks(drvdata);
+
+	msm_iommu_reset(drvdata->base, drvdata->glb_base, drvdata->ncb);
+
+	ret = iommu_sanity_check(drvdata);
+	if (ret)
+		goto fail_clk;
 
 	pr_info("device %s mapped at %p, with %d ctx banks\n",
-		iommu_dev->name, regs_base, iommu_dev->ncb);
+		drvdata->name, drvdata->base, drvdata->ncb);
 
+	msm_iommu_add_drv(drvdata);
 	platform_set_drvdata(pdev, drvdata);
 
-	if (iommu_clk)
-		clk_disable_unprepare(iommu_clk);
-
-	clk_disable_unprepare(iommu_pclk);
+	__disable_clocks(drvdata);
 
 	return 0;
-fail_io:
-	iounmap(regs_base);
-fail_mem:
-	release_mem_region(r->start, len);
+
 fail_clk:
-	if (iommu_clk) {
-		clk_disable_unprepare(iommu_clk);
-		clk_put(iommu_clk);
-	}
-fail_pclk:
-	clk_disable_unprepare(iommu_pclk);
-fail_enable:
-	clk_put(iommu_pclk);
+	__disable_clocks(drvdata);
+	__put_clocks(drvdata);
 fail:
-	kfree(drvdata);
 	return ret;
 }
 
@@ -266,20 +358,116 @@
 		if (drv->clk)
 			clk_put(drv->clk);
 		clk_put(drv->pclk);
-		memset(drv, 0, sizeof(*drv));
-		kfree(drv);
 		platform_set_drvdata(pdev, NULL);
 	}
 	return 0;
 }
 
+static int msm_iommu_ctx_parse_dt(struct platform_device *pdev,
+				struct msm_iommu_ctx_drvdata *ctx_drvdata)
+{
+	struct resource *r, rp;
+	int irq, ret;
+	u32 nmid_array_size;
+	u32 nmid;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq > 0) {
+		ret = request_threaded_irq(irq, NULL,
+				msm_iommu_fault_handler,
+				IRQF_ONESHOT | IRQF_SHARED,
+				"msm_iommu_nonsecure_irq", pdev);
+		if (ret) {
+			pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
+			return ret;
+		}
+	}
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		pr_err("Could not find reg property for context bank\n");
+		return -EINVAL;
+	}
+
+	ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
+	if (ret) {
+		pr_err("of_address_to_resource failed\n");
+		return -EINVAL;
+	}
+
+	/* Calculate the context bank number using the base addresses. CB0
+	 * starts at the base address.
+	 */
+	ctx_drvdata->num = ((r->start - rp.start) >> CTX_SHIFT);
+
+	if (of_property_read_string(pdev->dev.of_node, "label",
+					&ctx_drvdata->name)) {
+		pr_err("Could not find label property\n");
+		return -EINVAL;
+	}
+
+	if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-mids",
+			     &nmid_array_size)) {
+		pr_err("Could not find iommu-ctx-mids property\n");
+		return -EINVAL;
+	}
+	if (nmid_array_size >= sizeof(ctx_drvdata->sids)) {
+		pr_err("Too many mids defined - array size: %u, mids size: %u\n",
+			nmid_array_size, sizeof(ctx_drvdata->sids));
+		return -EINVAL;
+	}
+	nmid = nmid_array_size / sizeof(*ctx_drvdata->sids);
+
+	if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-mids",
+				       ctx_drvdata->sids, nmid)) {
+		pr_err("Could not find iommu-ctx-mids property\n");
+		return -EINVAL;
+	}
+	ctx_drvdata->nsid = nmid;
+
+	return 0;
+}
+
+static void __program_m2v_tables(struct msm_iommu_drvdata *drvdata,
+				struct msm_iommu_ctx_drvdata *ctx_drvdata)
+{
+	int i;
+
+	/* Program the M2V tables for this context */
+	for (i = 0; i < ctx_drvdata->nsid; i++) {
+		int sid = ctx_drvdata->sids[i];
+		int num = ctx_drvdata->num;
+
+		SET_M2VCBR_N(drvdata->glb_base, sid, 0);
+		SET_CBACR_N(drvdata->glb_base, num, 0);
+
+		/* Route page faults to the non-secure interrupt */
+		SET_IRPTNDX(drvdata->glb_base, num, 1);
+
+		/* Set VMID = 0 */
+		SET_VMID(drvdata->glb_base, sid, 0);
+
+		/* Set the context number for that SID to this context */
+		SET_CBNDX(drvdata->glb_base, sid, num);
+
+		/* Set SID associated with this context bank to 0 */
+		SET_CBVMID(drvdata->glb_base, num, 0);
+
+		/* Set the ASID for TLB tagging for this context to 0 */
+		SET_CONTEXTIDR_ASID(drvdata->base, num, 0);
+
+		/* Set security bit override to be Non-secure */
+		SET_NSCFG(drvdata->glb_base, sid, 3);
+	}
+	mb();
+}
+
 static int msm_iommu_ctx_probe(struct platform_device *pdev)
 {
-	struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
 	struct msm_iommu_drvdata *drvdata;
 	struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
 	int i, ret, irq;
-	if (!c || !pdev->dev.parent) {
+	if (!pdev->dev.parent) {
 		ret = -EINVAL;
 		goto fail;
 	}
@@ -291,112 +479,100 @@
 		goto fail;
 	}
 
-	ctx_drvdata = kzalloc(sizeof(*ctx_drvdata), GFP_KERNEL);
+	ctx_drvdata = devm_kzalloc(&pdev->dev, sizeof(*ctx_drvdata),
+					GFP_KERNEL);
 	if (!ctx_drvdata) {
 		ret = -ENOMEM;
 		goto fail;
 	}
-	ctx_drvdata->num = c->num;
-	ctx_drvdata->pdev = pdev;
-	ctx_drvdata->name = c->name;
 
-	irq = platform_get_irq_byname(to_platform_device(pdev->dev.parent),
-				      "nonsecure_irq");
-	if (irq < 0) {
+	ctx_drvdata->pdev = pdev;
+	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
+	platform_set_drvdata(pdev, ctx_drvdata);
+
+	if (pdev->dev.of_node) {
+		ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
+		if (ret)
+			goto fail;
+	} else if (pdev->dev.platform_data) {
+		struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
+
+		ctx_drvdata->num = c->num;
+		ctx_drvdata->name = c->name;
+
+		for (i = 0;  i < MAX_NUM_MIDS; ++i) {
+			if (c->mids[i] == -1) {
+				ctx_drvdata->nsid = i;
+				break;
+			}
+			ctx_drvdata->sids[i] = c->mids[i];
+		}
+		irq = platform_get_irq_byname(
+					to_platform_device(pdev->dev.parent),
+					"nonsecure_irq");
+		if (irq < 0) {
+			ret = -ENODEV;
+			goto fail;
+		}
+
+		ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
+					IRQF_ONESHOT | IRQF_SHARED,
+					"msm_iommu_nonsecure_irq", ctx_drvdata);
+
+		if (ret) {
+			pr_err("request_threaded_irq %d failed: %d\n", irq,
+								       ret);
+			goto fail;
+		}
+	} else {
 		ret = -ENODEV;
 		goto fail;
 	}
 
-	ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
-				   IRQF_ONESHOT | IRQF_SHARED,
-				   "msm_iommu_nonsecure_irq", ctx_drvdata);
+	__enable_clocks(drvdata);
+	__program_m2v_tables(drvdata, ctx_drvdata);
+	__disable_clocks(drvdata);
 
-	if (ret) {
-		pr_err("request_threaded_irq %d failed: %d\n", irq, ret);
-		goto fail;
-	}
-
-	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
-	platform_set_drvdata(pdev, ctx_drvdata);
-
-	ret = clk_prepare_enable(drvdata->pclk);
-	if (ret)
-		goto fail;
-
-	if (drvdata->clk) {
-		ret = clk_prepare_enable(drvdata->clk);
-		if (ret) {
-			clk_disable_unprepare(drvdata->pclk);
-			goto fail;
-		}
-	}
-
-	/* Program the M2V tables for this context */
-	for (i = 0; i < MAX_NUM_MIDS; i++) {
-		int mid = c->mids[i];
-		if (mid == -1)
-			break;
-
-		SET_M2VCBR_N(drvdata->base, mid, 0);
-		SET_CBACR_N(drvdata->base, c->num, 0);
-
-		/* Route page faults to the non-secure interrupt */
-		SET_IRPTNDX(drvdata->base, c->num, 1);
-
-		/* Set VMID = 0 */
-		SET_VMID(drvdata->base, mid, 0);
-
-		/* Set the context number for that MID to this context */
-		SET_CBNDX(drvdata->base, mid, c->num);
-
-		/* Set MID associated with this context bank to 0 */
-		SET_CBVMID(drvdata->base, c->num, 0);
-
-		/* Set the ASID for TLB tagging for this context to 0 */
-		SET_CONTEXTIDR_ASID(drvdata->base, c->num, 0);
-
-		/* Set security bit override to be Non-secure */
-		SET_NSCFG(drvdata->base, mid, 3);
-	}
-	mb();
-
-	if (drvdata->clk)
-		clk_disable_unprepare(drvdata->clk);
-	clk_disable_unprepare(drvdata->pclk);
-
-	dev_info(&pdev->dev, "context %s using bank %d\n", c->name, c->num);
+	dev_info(&pdev->dev, "context %s using bank %d\n", ctx_drvdata->name,
+							   ctx_drvdata->num);
 	return 0;
 fail:
-	kfree(ctx_drvdata);
 	return ret;
 }
 
-static int msm_iommu_ctx_remove(struct platform_device *pdev)
+static int __devexit msm_iommu_ctx_remove(struct platform_device *pdev)
 {
-	struct msm_iommu_ctx_drvdata *drv = NULL;
-	drv = platform_get_drvdata(pdev);
-	if (drv) {
-		memset(drv, 0, sizeof(struct msm_iommu_ctx_drvdata));
-		kfree(drv);
-		platform_set_drvdata(pdev, NULL);
-	}
+	platform_set_drvdata(pdev, NULL);
 	return 0;
 }
 
+
+static struct of_device_id msm_iommu_match_table[] = {
+	{ .compatible = "qcom,msm-smmu-v1", },
+	{}
+};
+
 static struct platform_driver msm_iommu_driver = {
 	.driver = {
 		.name	= "msm_iommu",
+		.of_match_table = msm_iommu_match_table,
 	},
 	.probe		= msm_iommu_probe,
-	.remove		= msm_iommu_remove,
+	.remove		= __devexit_p(msm_iommu_remove),
+};
+
+static struct of_device_id msm_iommu_ctx_match_table[] = {
+	{ .name = "qcom,iommu-ctx", },
+	{}
 };
 
 static struct platform_driver msm_iommu_ctx_driver = {
 	.driver = {
 		.name	= "msm_iommu_ctx",
+		.of_match_table = msm_iommu_ctx_match_table,
 	},
 	.probe		= msm_iommu_ctx_probe,
-	.remove		= msm_iommu_ctx_remove,
+	.remove		= __devexit_p(msm_iommu_ctx_remove),
 };
 
 static int __init msm_iommu_driver_init(void)
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index a641ce9..f493129 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -70,6 +70,7 @@
 #define WLED_CTL_DLY_BIT_SHFT		0x05
 #define WLED_MAX_CURR			25
 #define WLED_MAX_CURR_MASK		0x1F
+#define WLED_BRIGHTNESS_MSB_MASK	0x0F
 #define WLED_OP_FDBCK_MASK		0x1C
 #define WLED_OP_FDBCK_BIT_SHFT		0x02
 
@@ -283,7 +284,8 @@
 			return rc;
 		}
 
-		val = (val & ~WLED_MAX_CURR_MASK) | (duty >> WLED_8_BIT_SHFT);
+		val = (val & ~WLED_BRIGHTNESS_MSB_MASK) |
+			(duty >> WLED_8_BIT_SHFT);
 		rc = pm8xxx_writeb(led->dev->parent,
 				WLED_BRIGHTNESS_CNTL_REG1(i), val);
 		if (rc) {
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/adapter/mpq_stream_buffer.c b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
index 4b0e7be..f779851 100644
--- a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
+++ b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
@@ -14,17 +14,47 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
+#include <linux/uaccess.h>
 #include "mpq_dvb_debug.h"
 #include "mpq_stream_buffer.h"
 
 
-void mpq_streambuffer_init(
+
+
+int mpq_streambuffer_init(
 		struct mpq_streambuffer *sbuff,
-		void *data_buff, size_t data_buff_len,
-		void *packet_buff, size_t packet_buff_size)
+		enum mpq_streambuffer_mode mode,
+		struct mpq_streambuffer_buffer_desc *data_buffers,
+		u32 data_buff_num,
+		void *packet_buff,
+		size_t packet_buff_size)
 {
-	dvb_ringbuffer_init(&sbuff->raw_data, data_buff, data_buff_len);
+	if ((NULL == sbuff) || (NULL == data_buffers) || (NULL == packet_buff))
+		return -EINVAL;
+
+	if (data_buff_num > 1) {
+		if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR)
+			return -EINVAL;
+		/* Linear buffer group */
+		dvb_ringbuffer_init(
+			&sbuff->raw_data,
+			data_buffers,
+			data_buff_num *
+			sizeof(struct mpq_streambuffer_buffer_desc));
+	} else if (data_buff_num == 1) {
+		if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_RING)
+			return -EINVAL;
+		/* Single ring-buffer */
+		dvb_ringbuffer_init(&sbuff->raw_data,
+			data_buffers[0].base, data_buffers[0].size);
+	}
+	sbuff->mode = mode;
+	sbuff->buffers = data_buffers;
+	sbuff->pending_buffers_count = 0;
+	sbuff->buffers_num = data_buff_num;
 	dvb_ringbuffer_init(&sbuff->packet_data, packet_buff, packet_buff_size);
+
+	return 0;
 }
 EXPORT_SYMBOL(mpq_streambuffer_init);
 
@@ -87,34 +117,55 @@
 	int ret;
 	struct mpq_streambuffer_packet_header packet;
 
-	if (dispose_data) {
-		/* read-out the packet header first */
-		ret = dvb_ringbuffer_pkt_read(
-				&sbuff->packet_data,
-				idx,
-				0,
-				(u8 *)&packet,
-				sizeof(struct mpq_streambuffer_packet_header));
+	if (NULL == sbuff)
+		return -EINVAL;
 
-		if (ret != sizeof(struct mpq_streambuffer_packet_header))
-			return -EINVAL;
+	/* read-out the packet header first */
+	ret = dvb_ringbuffer_pkt_read(&sbuff->packet_data, idx,
+			0,
+			(u8 *)&packet,
+			sizeof(struct mpq_streambuffer_packet_header));
 
+	if (ret != sizeof(struct mpq_streambuffer_packet_header))
+		return -EINVAL;
+
+	if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) ||
+		(dispose_data)) {
 		/* Advance the read pointer in the raw-data buffer first */
-		ret = mpq_streambuffer_data_read_dispose(
-							sbuff,
-							packet.raw_data_len);
+		ret = mpq_streambuffer_data_read_dispose(sbuff,
+				packet.raw_data_len);
 		if (ret != 0)
 			return ret;
 	}
 
+	/* Move read pointer to the next linear buffer for subsequent reads */
+	if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) &&
+		(packet.raw_data_len > 0)) {
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+
+		desc->write_ptr = 0;
+		desc->read_ptr = 0;
+
+		DVB_RINGBUFFER_SKIP(&sbuff->raw_data,
+				sizeof(struct mpq_streambuffer_buffer_desc));
+		sbuff->pending_buffers_count--;
+
+		wake_up_all(&sbuff->raw_data.queue);
+	}
+
 	/* Now clear the packet from the packet header */
 	dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx);
 
+	if (sbuff->cb)
+		sbuff->cb(sbuff, sbuff->cb_user_data);
+
 	return 0;
 }
 EXPORT_SYMBOL(mpq_streambuffer_pkt_dispose);
 
-
 int mpq_streambuffer_pkt_write(
 			struct mpq_streambuffer *sbuff,
 			struct mpq_streambuffer_packet_header *packet,
@@ -123,30 +174,48 @@
 	ssize_t idx;
 	size_t len;
 
-	len =
-		sizeof(struct mpq_streambuffer_packet_header) +
+	if ((NULL == sbuff) || (NULL == packet))
+		return -EINVAL;
+
+	MPQ_DVB_DBG_PRINT(
+		"%s: handle=%d, offset=%d, len=%d\n",
+		__func__,
+		packet->raw_data_handle,
+		packet->raw_data_offset,
+		packet->raw_data_len);
+
+	len = sizeof(struct mpq_streambuffer_packet_header) +
 		packet->user_data_len;
 
 	/* Make sure enough space available for packet header */
 	if (dvb_ringbuffer_free(&sbuff->packet_data) < len)
 		return -ENOSPC;
 
-	/* Starting writting packet header */
+	/* Starting writing packet header */
 	idx = dvb_ringbuffer_pkt_start(&sbuff->packet_data, len);
 
 	/* Write non-user private data header */
-	dvb_ringbuffer_write(
-				&sbuff->packet_data,
-				(u8 *)packet,
-				sizeof(struct mpq_streambuffer_packet_header));
+	dvb_ringbuffer_write(&sbuff->packet_data,
+		(u8 *)packet,
+		sizeof(struct mpq_streambuffer_packet_header));
 
 	/* Write user's own private data header */
 	dvb_ringbuffer_write(&sbuff->packet_data,
-						 user_data,
-						 packet->user_data_len);
+		user_data,
+		packet->user_data_len);
 
 	dvb_ringbuffer_pkt_close(&sbuff->packet_data, idx);
 
+	/* Move write pointer to next linear buffer for subsequent writes */
+	if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) &&
+		(packet->raw_data_len > 0)) {
+		if (sbuff->pending_buffers_count == sbuff->buffers_num)
+			return -ENOSPC;
+		DVB_RINGBUFFER_PUSH(&sbuff->raw_data,
+				sizeof(struct mpq_streambuffer_buffer_desc));
+		sbuff->pending_buffers_count++;
+	}
+
 	wake_up_all(&sbuff->packet_data.queue);
 
 	return 0;
@@ -160,11 +229,52 @@
 {
 	int res;
 
-	if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
-		return -ENOSPC;
+	if ((NULL == sbuff) || (NULL == buf))
+		return -EINVAL;
 
-	res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len);
-	wake_up_all(&sbuff->raw_data.queue);
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+		if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+			return -ENOSPC;
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (NULL == sbuff->raw_data.data)
+			return -EPERM;
+		res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len);
+		wake_up_all(&sbuff->raw_data.queue);
+	} else {
+		/* Linear buffer group */
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pwrite];
+
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (NULL == desc->base)
+			return -EPERM;
+
+		if ((sbuff->pending_buffers_count == sbuff->buffers_num) ||
+			((desc->size - desc->write_ptr) < len)) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: No space available! %d pending buffers out of %d total buffers. write_ptr=%d, size=%d\n",
+				__func__,
+				sbuff->pending_buffers_count,
+				sbuff->buffers_num,
+				desc->write_ptr,
+				desc->size);
+			return -ENOSPC;
+		}
+		memcpy(desc->base + desc->write_ptr, buf, len);
+		desc->write_ptr += len;
+		MPQ_DVB_DBG_PRINT(
+			"%s: copied %d data bytes. handle=%d, write_ptr=%d\n",
+			__func__, len, desc->handle, desc->write_ptr);
+		res = len;
+	}
 
 	return res;
 }
@@ -175,50 +285,244 @@
 				struct mpq_streambuffer *sbuff,
 				size_t len)
 {
+	if (NULL == sbuff)
+		return -EINVAL;
+
 	if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
 		return -ENOSPC;
 
-	sbuff->raw_data.pwrite =
-		(sbuff->raw_data.pwrite+len) % sbuff->raw_data.size;
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+		DVB_RINGBUFFER_PUSH(&sbuff->raw_data, len);
+		wake_up_all(&sbuff->raw_data.queue);
+	} else {
+		/* Linear buffer group */
+		struct mpq_streambuffer_buffer_desc *desc;
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pwrite];
 
-	wake_up_all(&sbuff->raw_data.queue);
+		if ((sbuff->pending_buffers_count == sbuff->buffers_num) ||
+			 ((desc->size - desc->write_ptr) < len)) {
+			MPQ_DVB_ERR_PRINT(
+				"%s: No space available!\n",
+				__func__);
+			return -ENOSPC;
+		}
+		desc->write_ptr += len;
+	}
 
 	return 0;
 }
 EXPORT_SYMBOL(mpq_streambuffer_data_write_deposit);
 
 
-size_t mpq_streambuffer_data_read(
+ssize_t mpq_streambuffer_data_read(
 				struct mpq_streambuffer *sbuff,
 				u8 *buf, size_t len)
 {
-	ssize_t actual_len;
+	ssize_t actual_len = 0;
 
-	actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
-	if (actual_len < len)
-		len = actual_len;
+	if ((NULL == sbuff) || (NULL == buf))
+		return -EINVAL;
 
-	if (len)
-		dvb_ringbuffer_read(&sbuff->raw_data, buf, len);
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (NULL == sbuff->raw_data.data)
+			return -EPERM;
 
-	wake_up_all(&sbuff->raw_data.queue);
+		actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
+		if (actual_len < len)
+			len = actual_len;
+		if (len)
+			dvb_ringbuffer_read(&sbuff->raw_data, buf, len);
+
+		wake_up_all(&sbuff->raw_data.queue);
+	} else {
+		/* Linear buffer group */
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (NULL == desc->base)
+			return -EPERM;
+
+		actual_len = (desc->write_ptr - desc->read_ptr);
+		if (actual_len < len)
+			len = actual_len;
+		memcpy(buf, desc->base + desc->read_ptr, len);
+		desc->read_ptr += len;
+	}
 
 	return len;
 }
 EXPORT_SYMBOL(mpq_streambuffer_data_read);
 
 
+ssize_t mpq_streambuffer_data_read_user(
+		struct mpq_streambuffer *sbuff,
+		u8 __user *buf, size_t len)
+{
+	ssize_t actual_len = 0;
+
+	if ((NULL == sbuff) || (NULL == buf))
+		return -EINVAL;
+
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (NULL == sbuff->raw_data.data)
+			return -EPERM;
+
+		actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
+		if (actual_len < len)
+			len = actual_len;
+		if (len)
+			dvb_ringbuffer_read_user(&sbuff->raw_data, buf, len);
+		wake_up_all(&sbuff->raw_data.queue);
+	} else {
+		/* Linear buffer group */
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+
+		/*
+		 * Secure buffers are not permitted to be mapped into kernel
+		 * memory, and so buffer base address may be NULL
+		 */
+		if (NULL == desc->base)
+			return -EPERM;
+
+		actual_len = (desc->write_ptr - desc->read_ptr);
+		if (actual_len < len)
+			len = actual_len;
+		if (copy_to_user(buf, desc->base + desc->read_ptr, len))
+			return -EFAULT;
+		desc->read_ptr += len;
+	}
+
+	return len;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_read_user);
+
+
 int mpq_streambuffer_data_read_dispose(
 			struct mpq_streambuffer *sbuff,
 			size_t len)
 {
-	if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len))
+	if (NULL == sbuff)
 		return -EINVAL;
 
-	DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len);
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+		if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len))
+			return -EINVAL;
 
-	wake_up_all(&sbuff->raw_data.queue);
+		DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len);
+		wake_up_all(&sbuff->raw_data.queue);
+	} else {
+		struct mpq_streambuffer_buffer_desc *desc;
+
+		desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+		if ((desc->read_ptr + len) > desc->size)
+			desc->read_ptr = desc->size;
+		else
+			desc->read_ptr += len;
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(mpq_streambuffer_data_read_dispose);
 
+
+int mpq_streambuffer_get_buffer_handle(
+	struct mpq_streambuffer *sbuff,
+	int read_buffer,
+	int *handle)
+{
+	struct mpq_streambuffer_buffer_desc *desc = NULL;
+
+	if ((NULL == sbuff) || (NULL == handle))
+		return -EINVAL;
+
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+		*handle = sbuff->buffers[0].handle;
+	} else {
+		if (read_buffer)
+			desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pread];
+		else
+			desc = (struct mpq_streambuffer_buffer_desc *)
+				&sbuff->raw_data.data[sbuff->raw_data.pwrite];
+		*handle = desc->handle;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_get_buffer_handle);
+
+
+int mpq_streambuffer_register_pkt_dispose(
+	struct mpq_streambuffer *sbuff,
+	mpq_streambuffer_pkt_dispose_cb cb_func,
+	void *user_data)
+{
+	if ((NULL == sbuff) || (NULL == cb_func))
+		return -EINVAL;
+
+	sbuff->cb = cb_func;
+	sbuff->cb_user_data = user_data;
+
+	return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_register_pkt_dispose);
+
+
+ssize_t mpq_streambuffer_data_free(
+	struct mpq_streambuffer *sbuff)
+{
+	struct mpq_streambuffer_buffer_desc *desc;
+
+	if (NULL == sbuff)
+		return -EINVAL;
+
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode)
+		return dvb_ringbuffer_free(&sbuff->raw_data);
+
+	if (sbuff->pending_buffers_count == sbuff->buffers_num)
+		return 0;
+
+	desc = (struct mpq_streambuffer_buffer_desc *)
+		&sbuff->raw_data.data[sbuff->raw_data.pwrite];
+
+	return desc->size - desc->write_ptr;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_free);
+
+
+ssize_t mpq_streambuffer_data_avail(
+	struct mpq_streambuffer *sbuff)
+{
+	struct mpq_streambuffer_buffer_desc *desc;
+
+	if (NULL == sbuff)
+		return -EINVAL;
+
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode)
+		return dvb_ringbuffer_avail(&sbuff->raw_data);
+
+	desc = (struct mpq_streambuffer_buffer_desc *)
+		&sbuff->raw_data.data[sbuff->raw_data.pread];
+
+	return desc->write_ptr - desc->read_ptr;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_avail);
+
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..2a60840 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
+#include <linux/file.h>
 #include "mpq_dvb_debug.h"
 #include "mpq_dmx_plugin_common.h"
 
@@ -473,16 +474,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 +505,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 +534,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++;
@@ -963,6 +984,19 @@
 		goto init_failed_free_payload_buffer;
 	}
 
+	feed_data->buffer_desc.read_ptr = 0;
+	feed_data->buffer_desc.write_ptr = 0;
+	feed_data->buffer_desc.base = payload_buffer;
+	feed_data->buffer_desc.size = actual_buffer_size;
+	feed_data->buffer_desc.handle =
+		ion_share_dma_buf(
+			mpq_demux->ion_client,
+			feed_data->payload_buff_handle);
+	if (feed_data->buffer_desc.handle < 0) {
+		ret = -EFAULT;
+		goto init_failed_unmap_payload_buffer;
+	}
+
 	/* Register the new stream-buffer interface to MPQ adapter */
 	switch (feed->pes_type) {
 	case DMX_TS_PES_VIDEO0:
@@ -991,7 +1025,7 @@
 			__func__,
 			feed->pes_type);
 		ret = -EINVAL;
-		goto init_failed_unmap_payload_buffer;
+		goto init_failed_unshare_payload_buffer;
 	}
 
 	/* make sure not occupied already */
@@ -1005,30 +1039,36 @@
 			__func__,
 			feed_data->stream_interface);
 		ret = -EBUSY;
-		goto init_failed_unmap_payload_buffer;
+		goto init_failed_unshare_payload_buffer;
 	}
 
 	feed_data->video_buffer =
 		&mpq_dmx_info.decoder_buffers[feed_data->stream_interface];
 
-	mpq_streambuffer_init(
-			feed_data->video_buffer,
-			payload_buffer,
-			actual_buffer_size,
-			packet_buffer,
-			VIDEO_META_DATA_BUFFER_SIZE);
+	ret = mpq_streambuffer_init(
+		feed_data->video_buffer,
+		MPQ_STREAMBUFFER_BUFFER_MODE_RING,
+		&feed_data->buffer_desc,
+		1,
+		packet_buffer,
+		VIDEO_META_DATA_BUFFER_SIZE);
+	if (ret < 0) {
+		MPQ_DVB_ERR_PRINT(
+			"%s: mpq_streambuffer_init failed, err = %d\n",
+			__func__, ret);
+		goto init_failed_unshare_payload_buffer;
+	}
 
-	ret =
-		mpq_adapter_register_stream_if(
-			feed_data->stream_interface,
-			feed_data->video_buffer);
+	ret = mpq_adapter_register_stream_if(
+		feed_data->stream_interface,
+		feed_data->video_buffer);
 
 	if (ret < 0) {
 		MPQ_DVB_ERR_PRINT(
 			"%s: mpq_adapter_register_stream_if failed, "
 			"err = %d\n",
 			__func__, ret);
-		goto init_failed_unmap_payload_buffer;
+		goto init_failed_unshare_payload_buffer;
 	}
 
 	feed->buffer_size = actual_buffer_size;
@@ -1047,7 +1087,13 @@
 			sizeof(struct mpq_framing_prefix_size_masks));
 	feed_data->first_pattern_offset = 0;
 	feed_data->first_prefix_size = 0;
-	feed_data->write_pts_dts = 0;
+	feed_data->saved_pts_dts_info.pts_exist = 0;
+	feed_data->saved_pts_dts_info.dts_exist = 0;
+	feed_data->new_pts_dts_info.pts_exist = 0;
+	feed_data->new_pts_dts_info.dts_exist = 0;
+	feed_data->saved_info_used = 1;
+	feed_data->new_info_exists = 0;
+	feed_data->first_pts_dts_copy = 1;
 
 	spin_lock(&mpq_demux->feed_lock);
 	feed->priv = (void *)feed_data;
@@ -1055,6 +1101,8 @@
 
 	return 0;
 
+init_failed_unshare_payload_buffer:
+	put_unused_fd(feed_data->buffer_desc.handle);
 init_failed_unmap_payload_buffer:
 	ion_unmap_kernel(mpq_demux->ion_client,
 					 feed_data->payload_buff_handle);
@@ -1099,6 +1147,8 @@
 
 	vfree(feed_data->video_buffer->packet_data.data);
 
+	put_unused_fd(feed_data->buffer_desc.handle);
+
 	ion_unmap_kernel(mpq_demux->ion_client,
 					 feed_data->payload_buff_handle);
 
@@ -1318,6 +1368,83 @@
 	return 0;
 }
 
+static inline void mpq_dmx_save_pts_dts(struct mpq_video_feed_info *feed_data)
+{
+	if (feed_data->new_info_exists) {
+		feed_data->saved_pts_dts_info.pts_exist =
+			feed_data->new_pts_dts_info.pts_exist;
+		feed_data->saved_pts_dts_info.pts =
+			feed_data->new_pts_dts_info.pts;
+		feed_data->saved_pts_dts_info.dts_exist =
+			feed_data->new_pts_dts_info.dts_exist;
+		feed_data->saved_pts_dts_info.dts =
+			feed_data->new_pts_dts_info.dts;
+
+		feed_data->new_info_exists = 0;
+		feed_data->saved_info_used = 0;
+	}
+}
+
+static inline void mpq_dmx_write_pts_dts(struct mpq_video_feed_info *feed_data,
+					struct dmx_pts_dts_info *info)
+{
+	if (!feed_data->saved_info_used) {
+		info->pts_exist = feed_data->saved_pts_dts_info.pts_exist;
+		info->pts = feed_data->saved_pts_dts_info.pts;
+		info->dts_exist = feed_data->saved_pts_dts_info.dts_exist;
+		info->dts = feed_data->saved_pts_dts_info.dts;
+
+		feed_data->saved_info_used = 1;
+	} else {
+		info->pts_exist = 0;
+		info->dts_exist = 0;
+	}
+}
+
+static inline void mpq_dmx_get_pts_dts(struct mpq_video_feed_info *feed_data,
+				struct pes_packet_header *pes_header)
+{
+	struct dmx_pts_dts_info *info = &(feed_data->new_pts_dts_info);
+
+	/* Get PTS/DTS information from PES header */
+
+	if ((pes_header->pts_dts_flag == 2) ||
+		(pes_header->pts_dts_flag == 3)) {
+		info->pts_exist = 1;
+
+		info->pts =
+			((u64)pes_header->pts_1 << 30) |
+			((u64)pes_header->pts_2 << 22) |
+			((u64)pes_header->pts_3 << 15) |
+			((u64)pes_header->pts_4 << 7) |
+			(u64)pes_header->pts_5;
+	} else {
+		info->pts_exist = 0;
+		info->pts = 0;
+	}
+
+	if (pes_header->pts_dts_flag == 3) {
+		info->dts_exist = 1;
+
+		info->dts =
+			((u64)pes_header->dts_1 << 30) |
+			((u64)pes_header->dts_2 << 22) |
+			((u64)pes_header->dts_3 << 15) |
+			((u64)pes_header->dts_4 << 7) |
+			(u64)pes_header->dts_5;
+	} else {
+		info->dts_exist = 0;
+		info->dts = 0;
+	}
+
+	feed_data->new_info_exists = 1;
+
+	if (feed_data->first_pts_dts_copy) {
+		mpq_dmx_save_pts_dts(feed_data);
+		feed_data->first_pts_dts_copy = 0;
+	}
+}
+
 static inline int mpq_dmx_parse_remaining_pes_header(
 				struct dvb_demux_feed *feed,
 				struct mpq_video_feed_info *feed_data,
@@ -1361,7 +1488,6 @@
 		/* else - we have the PTS */
 		*bytes_avail -= copy_len;
 		*ts_payload_offset += copy_len;
-		feed_data->write_pts_dts = 1;
 	}
 
 	/* Did we capture the DTS value (if exist)? */
@@ -1392,7 +1518,6 @@
 		/* else - we have the DTS */
 		*bytes_avail -= copy_len;
 		*ts_payload_offset += copy_len;
-		feed_data->write_pts_dts = 1;
 	}
 
 	/* Any more header bytes?! */
@@ -1401,6 +1526,9 @@
 		return -EINVAL;
 	}
 
+	/* get PTS/DTS information from PES header to be written later */
+	mpq_dmx_get_pts_dts(feed_data, pes_header);
+
 	/* Got PES header, process payload */
 	*bytes_avail -= feed_data->pes_header_left_bytes;
 	*ts_payload_offset += feed_data->pes_header_left_bytes;
@@ -1409,53 +1537,6 @@
 	return 0;
 }
 
-static inline void mpq_dmx_get_pts_dts(struct mpq_video_feed_info *feed_data,
-				struct pes_packet_header *pes_header,
-				struct mpq_adapter_video_meta_data *meta_data,
-				enum dmx_packet_type packet_type)
-{
-	struct dmx_pts_dts_info *info;
-
-	if (packet_type == DMX_PES_PACKET)
-		info = &(meta_data->info.pes.pts_dts_info);
-	else
-		info = &(meta_data->info.framing.pts_dts_info);
-
-	if (feed_data->write_pts_dts) {
-		if ((pes_header->pts_dts_flag == 2) ||
-			(pes_header->pts_dts_flag == 3)) {
-			info->pts_exist = 1;
-
-			info->pts =
-				((u64)pes_header->pts_1 << 30) |
-				((u64)pes_header->pts_2 << 22) |
-				((u64)pes_header->pts_3 << 15) |
-				((u64)pes_header->pts_4 << 7) |
-				(u64)pes_header->pts_5;
-		} else {
-			info->pts_exist = 0;
-			info->pts = 0;
-		}
-
-		if (pes_header->pts_dts_flag == 3) {
-			info->dts_exist = 1;
-
-			info->dts =
-				((u64)pes_header->dts_1 << 30) |
-				((u64)pes_header->dts_2 << 22) |
-				((u64)pes_header->dts_3 << 15) |
-				((u64)pes_header->dts_4 << 7) |
-				(u64)pes_header->dts_5;
-		} else {
-			info->dts_exist = 0;
-			info->dts = 0;
-		}
-	} else {
-		info->pts_exist = 0;
-		info->dts_exist = 0;
-	}
-}
-
 static int mpq_dmx_process_video_packet_framing(
 			struct dvb_demux_feed *feed,
 			const u8 *buf)
@@ -1530,7 +1611,6 @@
 			feed_data->pes_header_offset = 0;
 			feed_data->pes_header_left_bytes =
 				PES_MANDATORY_FIELDS_LEN;
-			feed_data->write_pts_dts = 0;
 		} else {
 			feed->pusi_seen = 1;
 		}
@@ -1672,6 +1752,8 @@
 		feed->peslen += bytes_avail;
 
 		meta_data.packet_type = DMX_FRAMING_INFO_PACKET;
+		packet.raw_data_handle = feed_data->buffer_desc.handle;
+		packet.raw_data_offset = 0;
 		packet.user_data_len =
 				sizeof(struct mpq_adapter_video_meta_data);
 
@@ -1681,10 +1763,10 @@
 					feed->indexing_params.standard,
 					feed_data->last_framing_match_type);
 				if (is_video_frame == 1) {
-					mpq_dmx_get_pts_dts(feed_data,
-						pes_header,
-						&meta_data,
-						DMX_FRAMING_INFO_PACKET);
+					mpq_dmx_write_pts_dts(feed_data,
+						&(meta_data.info.framing.
+							pts_dts_info));
+					mpq_dmx_save_pts_dts(feed_data);
 				} else {
 					meta_data.info.framing.
 						pts_dts_info.pts_exist = 0;
@@ -1697,8 +1779,6 @@
 				 */
 				meta_data.info.framing.pattern_type =
 					feed_data->last_framing_match_type;
-				packet.raw_data_addr =
-					feed_data->last_framing_match_address;
 
 				pattern_addr = feed_data->pes_payload_address +
 					framing_res.info[i].offset -
@@ -1722,10 +1802,8 @@
 					  feed_data->first_pattern_offset;
 				}
 
-				MPQ_DVB_DBG_PRINT("Writing Packet: "
-					"addr = 0x%X, len = %d, type = %d, "
-					"isPts = %d, isDts = %d\n",
-					packet.raw_data_addr,
+				MPQ_DVB_DBG_PRINT(
+					"Writing Packet: len = %d, type = %d, isPts = %d, isDts = %d\n",
 					packet.raw_data_len,
 					meta_data.info.framing.pattern_type,
 					meta_data.info.framing.
@@ -1734,16 +1812,11 @@
 						pts_dts_info.dts_exist);
 
 				if (mpq_streambuffer_pkt_write(stream_buffer,
-						&packet,
-						(u8 *)&meta_data) < 0) {
-							MPQ_DVB_ERR_PRINT(
-								"%s: "
-								"Couldn't write packet. "
-								"Should never happen\n",
+					&packet,
+					(u8 *)&meta_data) < 0) {
+						MPQ_DVB_ERR_PRINT(
+							"%s: Couldn't write packet. Should never happen\n",
 								__func__);
-				} else {
-					if (is_video_frame == 1)
-						feed_data->write_pts_dts = 0;
 				}
 			}
 
@@ -1835,18 +1908,17 @@
 			 */
 
 			if (0 == feed_data->pes_header_left_bytes) {
-				packet.raw_data_addr =
-					feed_data->pes_payload_address;
-
 				packet.raw_data_len = feed->peslen;
-
+				packet.raw_data_handle =
+					feed_data->buffer_desc.handle;
+				packet.raw_data_offset = 0;
 				packet.user_data_len =
 					sizeof(struct
 						mpq_adapter_video_meta_data);
 
-				mpq_dmx_get_pts_dts(feed_data, pes_header,
-							&meta_data,
-							DMX_PES_PACKET);
+				mpq_dmx_write_pts_dts(feed_data,
+					&(meta_data.info.pes.pts_dts_info));
+				mpq_dmx_save_pts_dts(feed_data);
 
 				meta_data.packet_type = DMX_PES_PACKET;
 
@@ -1859,8 +1931,6 @@
 						"Couldn't write packet. "
 						"Should never happen\n",
 						__func__);
-				else
-					feed_data->write_pts_dts = 0;
 			} else {
 				MPQ_DVB_ERR_PRINT(
 					"%s: received PUSI"
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..f7af1ef 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;
 };
@@ -268,6 +275,7 @@
  * @plugin_data: Underlying plugin's own private data.
  * @video_buffer: Holds the streamer buffer shared with
  * the decoder for feeds having the data going to the decoder.
+ * @buffer_desc: Holds decoder buffer(s) information used for stream buffer.
  * @pes_header: Used for feeds that output data to decoder,
  * holds PES header of current processed PES.
  * @pes_header_left_bytes: Used for feeds that output data to decoder,
@@ -301,14 +309,18 @@
  * to the stream buffer.
  * @first_prefix_size: used to save the prefix size used to find the first
  * pattern written to the stream buffer.
- * @write_pts_dts: Flag used to decide if to write PTS/DTS information
- * (if it is available in the PES header) in the meta-data passed
- * to the video decoder. PTS/DTS information is written in the first
- * packet after it is available.
+ * @saved_pts_dts_info: used to save PTS/DTS information until it is written.
+ * @new_pts_dts_info: used to store PTS/DTS information from current PES header.
+ * @saved_info_used: indicates if saved PTS/DTS information was used.
+ * @new_info_exists: indicates if new PTS/DTS information exists in
+ * new_pts_dts_info that should be saved to saved_pts_dts_info.
+ * @first_pts_dts_copy: a flag used to indicate if PTS/DTS information needs
+ * to be copied from the currently parsed PES header to the saved_pts_dts_info.
  */
 struct mpq_video_feed_info {
 	void *plugin_data;
 	struct mpq_streambuffer *video_buffer;
+	struct mpq_streambuffer_buffer_desc buffer_desc;
 	struct pes_packet_header pes_header;
 	u32 pes_header_left_bytes;
 	u32 pes_header_offset;
@@ -324,7 +336,11 @@
 	struct mpq_framing_prefix_size_masks prefix_size;
 	u32 first_pattern_offset;
 	u32 first_prefix_size;
-	int write_pts_dts;
+	struct dmx_pts_dts_info saved_pts_dts_info;
+	struct dmx_pts_dts_info new_pts_dts_info;
+	int saved_info_used;
+	int new_info_exists;
+	int first_pts_dts_copy;
 };
 
 /**
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/dvb/mpq/include/mpq_stream_buffer.h b/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
index 4ea4222..9476c73 100644
--- a/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
+++ b/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
@@ -19,7 +19,7 @@
 /**
  * DOC: MPQ Stream Buffer
  *
- * A stream buffer implmenetation used to transfer data between two units
+ * A stream buffer implementation is used to transfer data between two units
  * such as demux and decoders. The implementation relies on dvb_ringbuffer
  * implementation. Refer to dvb_ringbuffer.h for details.
  *
@@ -28,8 +28,19 @@
  * meta-data (information from PES header for example).
  *
  * The meta-data uses dvb_ringbuffer packet interface. Each meta-data
- * packet hold the address and size of raw-data described by the
- * meta-data packet, in addition to user's own parameters if any required.
+ * packet points to the data buffer, and includes the offset to the data in the
+ * buffer, the size of raw-data described by the meta-data packet, and also the
+ * size of user's own parameters if any required.
+ *
+ * Data can be managed in two ways: ring-buffer & linear buffers, as specified
+ * in initialization when calling the mpq_streambuffer_init function.
+ * For managing data as a ring buffer exactly 1 data buffer descriptor must be
+ * specified in initialization. For this mode, dvb_ringbuffer is used "as-is".
+ * For managing data in several linear buffers, an array of buffer descriptors
+ * must be passed.
+ * For both modes, data descriptor(s) must be remain valid throughout the life
+ * span of the mpq_streambuffer object.
+ * Apart from initialization API remains the same for both modes.
  *
  * Contrary to dvb_ringbuffer implementation, this API makes sure there's
  * enough data to read/write when making read/write operations.
@@ -44,18 +55,22 @@
  *
  * Typical call flow from producer:
  *
- * - Start writting the raw-data of new packet, the following call is
+ * - Start writing the raw-data of new packet, the following call is
  *   repeated until end of data of the specific packet
  *
- *     mpq_streambuffer_data_write(...)
+ *      mpq_streambuffer_data_write(...)
  *
  * - Now write a new packet describing the new available raw-data
- *     mpq_streambuffer_pkt_write(...)
+ *      mpq_streambuffer_pkt_write(...)
+ *
+ *   For linear buffer mode, writing a new packet with data size > 0, causes the
+ *   current buffer to be marked as pending for reading, and triggers moving to
+ *   the next available buffer, that shall now be the current write buffer.
  *
  * Typical call flow from consumer:
  *
  * - Poll for next available packet:
- *      mpq_streambuffer_pkt_next(&streambuff,-1)
+ *      mpq_streambuffer_pkt_next(&streambuff,-1,&len)
  *
  *   In different approach, consumer can wait on event for new data and then
  *   call mpq_streambuffer_pkt_next, waiting for data can be done as follows:
@@ -77,58 +92,126 @@
  *      data buffer, the amount of raw-data is provided part of the
  *      packet's information. User should then call mpq_streambuffer_pkt_dispose
  *      with dispose_data set to 0 as the raw-data was already disposed.
+ *      Note that secure buffer cannot be accessed directly and an error will
+ *      occur.
  *
  *   2. Access the data directly using the raw-data address. The address
  *      of the raw data is provided part of the packet's information. User
  *      then should call mpq_streambuffer_pkt_dispose with dispose_data set
  *      to 1 to dispose the packet along with it's raw-data.
+ *
+ * - Disposal of packets:
+ *      mpq_streambuffer_pkt_dispose(...)
+ *
+ *   For linear buffer mode, disposing of a packet with data size > 0, causes
+ *   the current buffer to be marked as free for writing, and triggers moving to
+ *   the next available buffer, that shall now be the current read buffer.
+
+ *
  */
 
+struct mpq_streambuffer;
+
+typedef void (*mpq_streambuffer_pkt_dispose_cb) (
+	struct mpq_streambuffer *sbuff,
+	void *user_data);
+
+enum mpq_streambuffer_mode {
+	MPQ_STREAMBUFFER_BUFFER_MODE_RING,
+	MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR
+};
+
 /**
  * struct mpq_streambuffer - mpq stream buffer representation
  *
- * @raw_data: The buffer used to hold the raw-data
+ * @raw_data: The buffer used to hold raw-data, or linear buffer descriptors
  * @packet_data: The buffer user to hold the meta-data
+ * @buffers: array of buffer descriptor(s) holding buffer initial & dynamic
+ *	     buffer information
+ * @mode: mpq_streambuffer buffer management work mode - Ring-buffer or Linear
+ *	  buffers
+ * @buffers_num: number of data buffers to manage
+ * @pending_buffers_count: for linear buffer management, counts the number of
+ * buffer that has been
  */
 struct mpq_streambuffer {
 	struct dvb_ringbuffer raw_data;
 	struct dvb_ringbuffer packet_data;
+	struct mpq_streambuffer_buffer_desc *buffers;
+	enum mpq_streambuffer_mode mode;
+	u32 buffers_num;
+	u32 pending_buffers_count;
+	mpq_streambuffer_pkt_dispose_cb cb;
+	void *cb_user_data;
+};
+
+/**
+ * mpq_streambuffer_linear_desc
+ * @handle:	ION handle's file descriptor of buffer
+ * @base:	kernel mapped address to start of buffer.
+ *		Can be NULL for secured buffers
+ * @size:	size of buffer
+ * @read_ptr:	initial read pointer value (should normally be 0)
+ * @write_ptr:	initial write pointer value (should normally be 0)
+ */
+struct mpq_streambuffer_buffer_desc {
+	int	handle;
+	void	*base;
+	u32	size;
+	u32	read_ptr;
+	u32	write_ptr;
 };
 
 /**
  * struct mpq_streambuffer_packet_header - packet header saved in packet buffer
  * @user_data_len: length of private user (meta) data
- * @raw_data_addr: raw-data address in the raw-buffer described by the packet
+ * @raw_data_handle: ION handle's file descriptor of raw-data buffer
+ * @raw_data_offset: offset of raw-data from start of buffer (0 for linear)
  * @raw_data_len: size of raw-data in the raw-data buffer (can be 0)
  *
  * The packet structure that is saved in each packet-buffer:
  * user_data_len
- * raw_data_addr
+ * raw_data_handle
+ * raw_data_offset
  * raw_data_len
  * private user-data bytes
  */
 struct mpq_streambuffer_packet_header {
 	u32 user_data_len;
-	u32	raw_data_addr;
-	u32	raw_data_len;
+	int raw_data_handle;
+	u32 raw_data_offset;
+	u32 raw_data_len;
 } __packed;
 
 /**
  * mpq_streambuffer_init - Initialize a new stream buffer
  *
  * @sbuff: The buffer to initialize
- * @data_buff: The buffer holding raw-data
- * @data_buff_len: Size of raw-data buffer
+ * @data_buffers: array of data buffer descriptor(s).
+ *		  Data descriptor(s) must be remain valid throughout the life
+ *		  span of the mpq_streambuffer object
+ * @data_buff_num: number of data buffer in array
  * @packet_buff: The buffer holding meta-data
  * @packet_buff_size: Size of meta-data buffer
+ *
+ * Return	Error status, -EINVAL if any of the arguments are invalid
+ *
+ * Note:
+ * for data_buff_num > 1, mpq_streambuffer object manages these buffers as a
+ * separated set of linear buffers. A linear buffer cannot wrap-around and one
+ * can only write as many data bytes as the buffer's size. Data will not be
+ * written to the next free buffer.
  */
-void mpq_streambuffer_init(
+int mpq_streambuffer_init(
 		struct mpq_streambuffer *sbuff,
-		void *data_buff, size_t data_buff_len,
-		void *packet_buff, size_t packet_buff_size);
+		enum mpq_streambuffer_mode mode,
+		struct mpq_streambuffer_buffer_desc *data_buffers,
+		u32 data_buff_num,
+		void *packet_buff,
+		size_t packet_buff_size);
 
 /**
- * mpq_streambuffer_packet_next - Returns index of next avaialble packet.
+ * mpq_streambuffer_packet_next - Returns index of next available packet.
  *
  * @sbuff: The stream buffer
  * @idx: Previous packet index or -1 to return index of the the first
@@ -234,19 +317,29 @@
  * @buf: The buffer to read the raw-data data to
  * @len: The length of the buffer that will hold the raw-data
  *
- * Return  The actual number of bytes read
+ * Return  The actual number of bytes read or error code
  *
- * This fucntion copies the data from the ring-buffer to the
+ * This function copies the data from the ring-buffer to the
  * provided buf parameter. The user can save the extra copy by accessing
  * the data pointer directly and reading from it, then update the
  * read pointer by the amount of data that was read using
  * mpq_streambuffer_data_read_dispose
  */
-size_t mpq_streambuffer_data_read(
+ssize_t mpq_streambuffer_data_read(
 		struct mpq_streambuffer *sbuff,
 		u8 *buf, size_t len);
 
 /**
+ * mpq_streambuffer_data_read_user
+ *
+ * Same as mpq_streambuffer_data_read except data can be copied to user-space
+ * buffer.
+ */
+ssize_t mpq_streambuffer_data_read_user(
+		struct mpq_streambuffer *sbuff,
+		u8 __user *buf, size_t len);
+
+/**
  * mpq_streambuffer_data_read_dispose - Advances the raw-buffer read pointer.
  * Assumes the raw-data was read by the user directly.
  *
@@ -256,12 +349,69 @@
  * Return  error status, -EINVAL if buffer there's no enough data to
  *			be disposed
  *
- * The user can instead dipose a packet along with the data in the
+ * The user can instead dispose a packet along with the data in the
  * raw-data buffer using mpq_streambuffer_pkt_dispose.
  */
 int mpq_streambuffer_data_read_dispose(
 		struct mpq_streambuffer *sbuff,
 		size_t len);
+/**
+ * mpq_streambuffer_get_buffer_handle - Returns the current linear buffer
+ * ION handle.
+ * @sbuff: The stream buffer
+ * @read_buffer: specifies if a read buffer handle is requested (when set),
+ *		 or a write buffer handle is requested.
+ *		 For linear buffer mode read & write buffers may be different
+ *		 buffers. For ring buffer mode, the same (single) buffer handle
+ *		 is returned.
+ * buffer handle
+ * @handle: returned handle
+ *
+ * Return error status
+ * -EINVAL is arguments are invalid.
+ * -EPERM if stream buffer specified was not initialized with linear support.
+ */
+int mpq_streambuffer_get_buffer_handle(
+	struct mpq_streambuffer *sbuff,
+	int read_buffer,
+	int *handle);
+
+/**
+ * mpq_streambuffer_data_free - Returns number of free bytes in data buffer.
+ * @sbuff: The stream buffer object
+ *
+ * Note: for linear buffer management this return number of free bytes in the
+ * current write buffer only.
+ */
+ssize_t mpq_streambuffer_data_free(
+	struct mpq_streambuffer *sbuff);
+
+/**
+ * mpq_streambuffer_data_avail - Returns number of bytes in data buffer that
+ * can be read.
+ * @sbuff: The stream buffer object
+ *
+ * Note: for linear buffer management this return number of data bytes in the
+ * current read buffer only.
+ */
+ssize_t mpq_streambuffer_data_avail(
+	struct mpq_streambuffer *sbuff);
+
+/**
+ * mpq_streambuffer_register_pkt_dispose - Registers a callback to notify on
+ * packet disposal events.
+ * can be read.
+ * @sbuff: The stream buffer object
+ * @cb_func: user callback function
+ * @user_data: user data to be passed to callback function.
+ *
+ * Returns error status
+ * -EINVAL if arguments are invalid
+ */
+int mpq_streambuffer_register_pkt_dispose(
+	struct mpq_streambuffer *sbuff,
+	mpq_streambuffer_pkt_dispose_cb cb_func,
+	void *user_data);
 
 
 
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index d2ed996..f33122f 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -35,6 +35,17 @@
 	   To compile this driver as a module, choose M here: the module will
 	   be called user-rc-input.
 
+config USER_SP_RC_INPUT
+	tristate "User Space Input device wrapper for Standby Processor Remote Control"
+	depends on RC_CORE
+
+	---help---
+	   Say Y if you want to report remote control input events
+	   from userspace.
+
+	   To compile this driver as a module, choose M here: the module will
+	   be called user-sp-input.
+
 source "drivers/media/rc/keymaps/Kconfig"
 
 config IR_NEC_DECODER
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index be02eec..fdc3e99 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -14,6 +14,7 @@
 obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
 obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 obj-$(CONFIG_USER_RC_INPUT) += user-rc-input.o
+obj-$(CONFIG_USER_SP_RC_INPUT) += user-sp-rc-input.o
 
 # stand-alone IR receivers/transmitters
 obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
diff --git a/drivers/media/rc/user-sp-rc-input.c b/drivers/media/rc/user-sp-rc-input.c
new file mode 100644
index 0000000..83da95d
--- /dev/null
+++ b/drivers/media/rc/user-sp-rc-input.c
@@ -0,0 +1,246 @@
+/* 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+
+#include <media/rc-core.h>
+#include <media/user-rc-input.h>
+
+#define MAX_SP_DEVICES		1
+#define USER_SP_INPUT_DEV_NAME	"user-sp-input"
+#define USER_SP_INPUT_DRV_NAME	"sp-user-input"
+
+struct user_sp_input_dev {
+	struct cdev sp_input_cdev;
+	struct class *sp_input_class;
+	struct device *sp_input_dev;
+	struct rc_dev *spdev;
+	dev_t sp_input_base_dev;
+	struct device *dev;
+	int in_use;
+};
+
+static int user_sp_input_open(struct inode *inode, struct file *file)
+{
+	struct cdev *input_cdev = inode->i_cdev;
+	struct user_sp_input_dev *input_dev =
+	container_of(input_cdev, struct user_sp_input_dev, sp_input_cdev);
+
+	if (input_dev->in_use) {
+		dev_err(input_dev->dev,
+		"Device is already open..only one instance is allowed\n");
+		return -EBUSY;
+	}
+	input_dev->in_use++;
+	file->private_data = input_dev;
+
+	return 0;
+}
+
+static int user_sp_input_release(struct inode *inode, struct file *file)
+{
+	struct user_sp_input_dev *input_dev = file->private_data;
+
+	input_dev->in_use--;
+
+	return 0;
+}
+
+static ssize_t user_sp_input_write(struct file *file,
+		const char __user *buffer, size_t count, loff_t *ppos)
+{
+	int ret = count;
+	struct user_sp_input_dev *input_dev = file->private_data;
+	unsigned char cmd = 0;
+	int scancode = 0;
+
+	if (copy_from_user(&cmd, buffer, 1)) {
+		dev_err(input_dev->dev, "Copy from user failed\n");
+		ret = -EFAULT;
+		goto out_free;
+	}
+
+	if (copy_from_user(&scancode, &buffer[1], 4)) {
+		dev_err(input_dev->dev, "Copy from user failed\n");
+		ret = -EFAULT;
+		goto out_free;
+	}
+
+	switch (cmd) {
+	case USER_CONTROL_PRESSED:
+		dev_dbg(input_dev->dev, "user controlled pressed 0x%x\n",
+			scancode);
+		rc_keydown(input_dev->spdev, scancode, 0);
+		break;
+	case USER_CONTROL_REPEATED:
+		dev_dbg(input_dev->dev, "user controlled repeated 0x%x\n",
+			scancode);
+		rc_repeat(input_dev->spdev);
+		break;
+	case USER_CONTROL_RELEASED:
+		dev_dbg(input_dev->dev, "user controlled released 0x%x\n",
+			scancode);
+		rc_keyup(input_dev->spdev);
+		break;
+	}
+
+out_free:
+	return ret;
+}
+
+const struct file_operations sp_fops = {
+	.owner  = THIS_MODULE,
+	.open   = user_sp_input_open,
+	.write  = user_sp_input_write,
+	.release = user_sp_input_release,
+};
+
+static int __devinit user_sp_input_probe(struct platform_device *pdev)
+{
+	struct user_sp_input_dev *user_sp_dev;
+	struct rc_dev *spdev;
+	int retval;
+
+	user_sp_dev = kzalloc(sizeof(struct user_sp_input_dev), GFP_KERNEL);
+	if (!user_sp_dev)
+		return -ENOMEM;
+
+	user_sp_dev->sp_input_class = class_create(THIS_MODULE,
+						"user-sp-input-loopback");
+
+	if (IS_ERR(user_sp_dev->sp_input_class)) {
+		retval = PTR_ERR(user_sp_dev->sp_input_class);
+		goto err;
+	}
+
+	retval = alloc_chrdev_region(&user_sp_dev->sp_input_base_dev, 0,
+				MAX_SP_DEVICES, USER_SP_INPUT_DEV_NAME);
+
+	if (retval) {
+		dev_err(&pdev->dev,
+			"alloc_chrdev_region failed\n");
+		goto alloc_chrdev_err;
+	}
+
+	dev_info(&pdev->dev, "User space report standby key event input" \
+				" driver registered, major %d\n",
+				MAJOR(user_sp_dev->sp_input_base_dev));
+
+	cdev_init(&user_sp_dev->sp_input_cdev, &sp_fops);
+	retval = cdev_add(&user_sp_dev->sp_input_cdev,
+			user_sp_dev->sp_input_base_dev, MAX_SP_DEVICES);
+	if (retval) {
+		dev_err(&pdev->dev, "cdev_add failed\n");
+		goto cdev_add_err;
+	}
+	user_sp_dev->sp_input_dev = device_create(user_sp_dev->sp_input_class,
+		NULL, MKDEV(MAJOR(user_sp_dev->sp_input_base_dev), 0), NULL,
+		"user-sp-input-dev%d", 0);
+
+	if (IS_ERR(user_sp_dev->sp_input_dev)) {
+		retval = PTR_ERR(user_sp_dev->sp_input_dev);
+		dev_err(&pdev->dev, "device_create failed\n");
+		goto device_create_err;
+	}
+
+	spdev = rc_allocate_device();
+	if (!spdev) {
+		dev_err(&pdev->dev, "failed to allocate rc device");
+		retval = -ENOMEM;
+		goto err_allocate_device;
+	}
+
+	spdev->driver_type = RC_DRIVER_SCANCODE;
+	spdev->allowed_protos = RC_TYPE_OTHER;
+	spdev->input_name = USER_SP_INPUT_DEV_NAME;
+	spdev->input_id.bustype = BUS_HOST;
+	spdev->driver_name = USER_SP_INPUT_DRV_NAME;
+	spdev->map_name = RC_MAP_RC6_PHILIPS;
+
+	retval = rc_register_device(spdev);
+	if (retval < 0) {
+		dev_err(&pdev->dev, "failed to register rc device\n");
+		goto rc_register_err;
+	}
+	user_sp_dev->spdev = spdev;
+	user_sp_dev->dev = &pdev->dev;
+	platform_set_drvdata(pdev, user_sp_dev);
+	user_sp_dev->in_use = 0;
+
+	return 0;
+
+rc_register_err:
+	rc_free_device(spdev);
+err_allocate_device:
+	device_destroy(user_sp_dev->sp_input_class,
+			MKDEV(MAJOR(user_sp_dev->sp_input_base_dev), 0));
+cdev_add_err:
+	unregister_chrdev_region(user_sp_dev->sp_input_base_dev,
+				MAX_SP_DEVICES);
+device_create_err:
+	cdev_del(&user_sp_dev->sp_input_cdev);
+alloc_chrdev_err:
+	class_destroy(user_sp_dev->sp_input_class);
+err:
+	kfree(user_sp_dev);
+	return retval;
+}
+
+static int __devexit user_sp_input_remove(struct platform_device *pdev)
+{
+	struct user_sp_input_dev *user_sp_dev = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	rc_free_device(user_sp_dev->spdev);
+	device_destroy(user_sp_dev->sp_input_class,
+			MKDEV(MAJOR(user_sp_dev->sp_input_base_dev), 0));
+	unregister_chrdev_region(user_sp_dev->sp_input_base_dev,
+				MAX_SP_DEVICES);
+	cdev_del(&user_sp_dev->sp_input_cdev);
+	class_destroy(user_sp_dev->sp_input_class);
+	kfree(user_sp_dev);
+
+	return 0;
+}
+
+static struct platform_driver user_sp_input_driver = {
+	.probe  = user_sp_input_probe,
+	.remove = __devexit_p(user_sp_input_remove),
+	.driver = {
+		.name   = USER_SP_INPUT_DRV_NAME,
+		.owner  = THIS_MODULE,
+	},
+};
+
+static int __init user_sp_input_init(void)
+{
+	return platform_driver_register(&user_sp_input_driver);
+}
+module_init(user_sp_input_init);
+
+static void __exit user_sp_input_exit(void)
+{
+	platform_driver_unregister(&user_sp_input_driver);
+}
+module_exit(user_sp_input_exit);
+
+MODULE_DESCRIPTION("User SP RC Input driver");
+MODULE_LICENSE("GPL v2");
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..af31748 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;
@@ -1446,9 +1445,10 @@
 					/*so that it isn't closed again*/
 					pmctl->mctl_release = NULL;
 				}
-				msm_cam_server_send_error_evt(pmctl,
-					V4L2_EVENT_PRIVATE_START +
-					MSM_CAM_APP_NOTIFY_ERROR_EVENT);
+				if (pmctl)
+					msm_cam_server_send_error_evt(pmctl,
+						V4L2_EVENT_PRIVATE_START +
+						MSM_CAM_APP_NOTIFY_ERROR_EVENT);
 			}
 		}
 		sub.type = V4L2_EVENT_ALL;
@@ -1754,7 +1754,7 @@
 	case NOTIFY_VFE_MSG_COMP_STATS:
 	case NOTIFY_VFE_BUF_EVT:
 		p_mctl = msm_cam_server_get_mctl(mctl_handle);
-		if (p_mctl->isp_notify && p_mctl->vfe_sdev)
+		if (p_mctl && p_mctl->isp_notify && p_mctl->vfe_sdev)
 			rc = p_mctl->isp_notify(p_mctl,
 				p_mctl->vfe_sdev, notification, arg);
 		break;
@@ -1773,18 +1773,20 @@
 		break;
 	case NOTIFY_AXI_RDI_SOF_COUNT:
 		p_mctl = msm_cam_server_get_mctl(mctl_handle);
-		if (p_mctl->axi_sdev)
+		if (p_mctl && p_mctl->axi_sdev)
 			rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
 				VIDIOC_MSM_AXI_RDI_COUNT_UPDATE, arg);
 		break;
 	case NOTIFY_PCLK_CHANGE:
 		p_mctl = v4l2_get_subdev_hostdata(sd);
-		if (p_mctl->axi_sdev)
-			rc = v4l2_subdev_call(p_mctl->axi_sdev, video,
-			s_crystal_freq, *(uint32_t *)arg, 0);
-		else
-			rc = v4l2_subdev_call(p_mctl->vfe_sdev, video,
-			s_crystal_freq, *(uint32_t *)arg, 0);
+		if (p_mctl) {
+			if (p_mctl->axi_sdev)
+				rc = v4l2_subdev_call(p_mctl->axi_sdev, video,
+				s_crystal_freq, *(uint32_t *)arg, 0);
+			else
+				rc = v4l2_subdev_call(p_mctl->vfe_sdev, video,
+				s_crystal_freq, *(uint32_t *)arg, 0);
+		}
 		break;
 	case NOTIFY_GESTURE_EVT:
 		rc = v4l2_subdev_call(g_server_dev.gesture_device,
@@ -1796,8 +1798,10 @@
 		break;
 	case NOTIFY_VFE_CAMIF_ERROR: {
 		p_mctl = msm_cam_server_get_mctl(mctl_handle);
-		msm_cam_server_send_error_evt(p_mctl, V4L2_EVENT_PRIVATE_START
-			+ MSM_CAM_APP_NOTIFY_ERROR_EVENT);
+		if (p_mctl)
+			msm_cam_server_send_error_evt(p_mctl,
+				V4L2_EVENT_PRIVATE_START +
+				MSM_CAM_APP_NOTIFY_ERROR_EVENT);
 		break;
 	}
 	default:
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..eae18c4 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,19 @@
 	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);
+	if (!(flags & SMEM_SECURE))
+		heap_mask |= ION_HEAP(ION_IOMMU_HEAP_ID);
+
 	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..48e6a93 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -27,6 +27,10 @@
 #define MIN_NUM_OUTPUT_BUFFERS 4
 #define MAX_NUM_OUTPUT_BUFFERS 6
 
+enum msm_vdec_ctrl_cluster {
+	MSM_VDEC_CTRL_CLUSTER_MAX = 1,
+};
+
 static const char *const mpeg_video_vidc_divx_format[] = {
 	"DIVX Format 3",
 	"DIVX Format 4",
@@ -68,7 +72,7 @@
 	"Extradata aspect ratio",
 };
 
-static const struct msm_vidc_ctrl msm_vdec_ctrls[] = {
+static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
 		.name = "NAL Format",
@@ -85,6 +89,7 @@
 		),
 		.qmenu = mpeg_video_stream_format,
 		.step = 0,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
@@ -99,6 +104,7 @@
 			),
 		.qmenu = mpeg_video_output_order,
 		.step = 0,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE,
@@ -110,6 +116,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
@@ -121,6 +128,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
@@ -132,6 +140,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
@@ -147,6 +156,7 @@
 			),
 		.qmenu = mpeg_video_vidc_divx_format,
 		.step = 0,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
@@ -158,6 +168,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
@@ -169,6 +180,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE,
@@ -188,6 +200,7 @@
 		.step = 0,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
@@ -430,7 +443,15 @@
 				core);
 		goto exit;
 	}
-
+	if (!inst->in_reconfig) {
+		rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to move inst: %p to relase res done\n",
+				inst);
+			goto exit;
+		}
+	}
 	switch (b->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		break;
@@ -462,7 +483,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 +652,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 +899,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 +990,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,
@@ -1062,10 +1073,11 @@
 	inst->prop.height = DEFAULT_HEIGHT;
 	inst->prop.width = DEFAULT_WIDTH;
 	inst->prop.fps = 30;
+	inst->prop.prev_time_stamp = 0;
 	return rc;
 }
 
-static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
 {
 	int rc = 0;
 	struct v4l2_control control;
@@ -1076,62 +1088,59 @@
 	enum hal_property property_id = 0;
 	u32 property_val = 0;
 	void *pdata;
-	struct msm_vidc_inst *inst = container_of(ctrl->handler,
-				struct msm_vidc_inst, ctrl_handler);
-	control.id = ctrl->id;
-	control.value = ctrl->val;
-	switch (control.id) {
+
+	switch (ctrl->id) {
 	case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
 		property_id =
 		HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
 		stream_format.nal_stream_format_supported =
-		(0x00000001 << control.value);
+		(0x00000001 << ctrl->val);
 		pdata = &stream_format;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
 		property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
-		property_val = control.value;
+		property_val = ctrl->val;
 		pdata = &property_val;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE:
 		property_id =
 			HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
-		enable_picture.picture_type = control.value;
+		enable_picture.picture_type = ctrl->val;
 		pdata = &enable_picture;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
 		property_id =
 			HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
-		hal_property.enable = control.value;
+		hal_property.enable = ctrl->val;
 		pdata = &hal_property;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
 		property_id =
 			HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
-		hal_property.enable = control.value;
+		hal_property.enable = ctrl->val;
 		pdata = &hal_property;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
 		property_id = HAL_PARAM_DIVX_FORMAT;
-		property_val = control.value;
+		property_val = ctrl->val;
 		pdata = &property_val;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
 		property_id =
 			HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
-		hal_property.enable = control.value;
+		hal_property.enable = ctrl->val;
 		pdata = &hal_property;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
 		property_id =
 			HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
-		hal_property.enable = control.value;
+		hal_property.enable = ctrl->val;
 		pdata = &hal_property;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE:
 		property_id =
 			HAL_PARAM_VDEC_SYNC_FRAME_DECODE;
-		hal_property.enable = control.value;
+		hal_property.enable = ctrl->val;
 		pdata = &hal_property;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
@@ -1142,7 +1151,7 @@
 	{
 		struct hal_extradata_enable extra;
 		property_id = HAL_PARAM_INDEX_EXTRADATA;
-		extra.index = msm_comm_get_hal_extradata_index(control.value);
+		extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
 		extra.enable = 1;
 		pdata = &extra;
 		break;
@@ -1150,13 +1159,8 @@
 	default:
 		break;
 	}
+
 	if (property_id) {
-		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
-		if (rc) {
-			dprintk(VIDC_ERR,
-			"Failed to move inst: %p to start done state\n", inst);
-			goto failed_open_done;
-		}
 		dprintk(VIDC_DBG,
 			"Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
 			property_id,
@@ -1165,10 +1169,37 @@
 			rc = vidc_hal_session_set_property((void *)
 				inst->session, property_id,
 					pdata);
+	}
+
+	return rc;
+}
+
+static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	int rc = 0, c = 0;
+	struct msm_vidc_inst *inst = container_of(ctrl->handler,
+				struct msm_vidc_inst, ctrl_handler);
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %p to start done state\n", inst);
+		goto failed_open_done;
+	}
+
+	for (c = 0; c < ctrl->ncontrols; ++c) {
+		if (ctrl->cluster[c]->is_new) {
+			rc = try_set_ctrl(inst, ctrl->cluster[c]);
+			if (rc) {
+				dprintk(VIDC_ERR, "Failed setting %x",
+						ctrl->cluster[c]->id);
+				break;
+			}
 		}
+	}
+
+failed_open_done:
 	if (rc)
 		dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
-failed_open_done:
 	return rc;
 }
 
@@ -1196,6 +1227,27 @@
 {
 	return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
 }
+
+static struct v4l2_ctrl **get_cluster(int type, int *size)
+{
+	int c = 0, sz = 0;
+	struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) *
+			NUM_CTRLS, GFP_KERNEL);
+
+	if (type <= 0 || !size || !cluster)
+		return NULL;
+
+	for (c = 0; c < NUM_CTRLS; c++) {
+		if (msm_vdec_ctrls[c].cluster == type) {
+			cluster[sz] = msm_vdec_ctrls[c].priv;
+			++sz;
+		}
+	}
+
+	*size = sz;
+	return cluster;
+}
+
 int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
 {
 	int idx = 0;
@@ -1211,12 +1263,13 @@
 	}
 
 	for (; idx < NUM_CTRLS; idx++) {
+		struct v4l2_ctrl *ctrl = NULL;
 		if (IS_PRIV_CTRL(msm_vdec_ctrls[idx].id)) {
 			/*add private control*/
 			ctrl_cfg.def = msm_vdec_ctrls[idx].default_value;
 			ctrl_cfg.flags = 0;
 			ctrl_cfg.id = msm_vdec_ctrls[idx].id;
-			/*ctrl_cfg.is_private =
+			/* ctrl_cfg.is_private =
 			 * msm_vdec_ctrls[idx].is_private;
 			 * ctrl_cfg.is_volatile =
 			 * msm_vdec_ctrls[idx].is_volatile;*/
@@ -1230,18 +1283,19 @@
 			ctrl_cfg.type = msm_vdec_ctrls[idx].type;
 			ctrl_cfg.qmenu = msm_vdec_ctrls[idx].qmenu;
 
-			v4l2_ctrl_new_custom(&inst->ctrl_handler,
+			ctrl = v4l2_ctrl_new_custom(&inst->ctrl_handler,
 					&ctrl_cfg, NULL);
 		} else {
 			if (msm_vdec_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
-				v4l2_ctrl_new_std_menu(&inst->ctrl_handler,
+				ctrl = v4l2_ctrl_new_std_menu(
+					&inst->ctrl_handler,
 					&msm_vdec_ctrl_ops,
 					msm_vdec_ctrls[idx].id,
 					msm_vdec_ctrls[idx].maximum,
 					msm_vdec_ctrls[idx].menu_skip_mask,
 					msm_vdec_ctrls[idx].default_value);
 			} else {
-				v4l2_ctrl_new_std(&inst->ctrl_handler,
+				ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler,
 					&msm_vdec_ctrl_ops,
 					msm_vdec_ctrls[idx].id,
 					msm_vdec_ctrls[idx].minimum,
@@ -1250,11 +1304,51 @@
 					msm_vdec_ctrls[idx].default_value);
 			}
 		}
+
+
+		msm_vdec_ctrls[idx].priv = ctrl;
 	}
 	ret_val = inst->ctrl_handler.error;
 	if (ret_val)
 		dprintk(VIDC_ERR,
 			"Error adding ctrls to ctrl handle, %d\n",
 			inst->ctrl_handler.error);
+
+	/* Construct clusters */
+	for (idx = 1; idx < MSM_VDEC_CTRL_CLUSTER_MAX; ++idx) {
+		struct msm_vidc_ctrl_cluster *temp = NULL;
+		struct v4l2_ctrl **cluster = NULL;
+		int cluster_size = 0;
+
+		cluster = get_cluster(idx, &cluster_size);
+		if (!cluster || !cluster_size) {
+			dprintk(VIDC_WARN, "Failed to setup cluster of type %d",
+					idx);
+			continue;
+		}
+
+		v4l2_ctrl_cluster(cluster_size, cluster);
+
+		temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+		if (!temp) {
+			ret_val = -ENOMEM;
+			break;
+		}
+
+		temp->cluster = cluster;
+		INIT_LIST_HEAD(&temp->list);
+		list_add_tail(&temp->list, &inst->ctrl_clusters);
+	}
 	return ret_val;
 }
+
+int msm_vdec_ctrl_deinit(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_ctrl_cluster *curr, *next;
+	list_for_each_entry_safe(curr, next, &inst->ctrl_clusters, list) {
+		kfree(curr->cluster);
+		kfree(curr);
+	}
+
+	return 0;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index 419c8c1..73a516e 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -18,6 +18,7 @@
 
 int msm_vdec_inst_init(struct msm_vidc_inst *inst);
 int msm_vdec_ctrl_init(struct msm_vidc_inst *inst);
+int msm_vdec_ctrl_deinit(struct msm_vidc_inst *inst);
 int msm_vdec_querycap(void *instance, struct v4l2_capability *cap);
 int msm_vdec_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
 int msm_vdec_s_fmt(void *instance, struct v4l2_format *f);
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index d01841d..a0aa150 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -88,7 +88,20 @@
 	"High Latency",
 };
 
-static const struct msm_vidc_ctrl msm_venc_ctrls[] = {
+enum msm_venc_ctrl_cluster {
+	MSM_VENC_CTRL_CLUSTER_QP = 1,
+	MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
+	MSM_VENC_CTRL_CLUSTER_H264_PROFILE_LEVEL,
+	MSM_VENC_CTRL_CLUSTER_MPEG_PROFILE_LEVEL,
+	MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
+	MSM_VENC_CTRL_CLUSTER_H264_ENTROPY,
+	MSM_VENC_CTRL_CLUSTER_SLICING,
+	MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
+	MSM_VENC_CTRL_CLUSTER_BITRATE,
+	MSM_VENC_CTRL_CLUSTER_MAX,
+};
+
+static struct msm_vidc_ctrl msm_venc_ctrls[] = {
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
 		.name = "Frame Rate",
@@ -99,12 +112,13 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD,
 		.name = "IDR Period",
 		.type = V4L2_CTRL_TYPE_INTEGER,
-		.minimum = 0,
+		.minimum = 1,
 		.maximum = 10*MAX_FRAME_RATE,
 		.default_value = DEFAULT_FRAME_RATE,
 		.step = 1,
@@ -112,6 +126,18 @@
 		.qmenu = NULL,
 	},
 	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+		.name = "Intra Period",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 10*MAX_FRAME_RATE,
+		.default_value = DEFAULT_FRAME_RATE,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
+	},
+	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES,
 		.name = "Intra Period for P frames",
 		.type = V4L2_CTRL_TYPE_INTEGER,
@@ -121,17 +147,19 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
 		.name = "Intra Period for B frames",
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.minimum = 0,
-		.maximum = 10*DEFAULT_FRAME_RATE,
+		.maximum = 2,
 		.default_value = 0,
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME,
@@ -143,10 +171,11 @@
 		.step = 0,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL,
-		.name = "Rate Control",
+		.name = "Video Framerate and Bitrate Control",
 		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF,
 		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR,
@@ -160,6 +189,22 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR)
 		),
 		.qmenu = mpeg_video_rate_control,
+		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+		.name = "Bitrate Control",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+		.maximum = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+		.default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+		.step = 0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
+		(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+		),
+		.qmenu = mpeg_video_rate_control,
+		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_BITRATE,
@@ -171,6 +216,7 @@
 		.step = BIT_RATE_STEP,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
@@ -184,6 +230,7 @@
 		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
 		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
 		),
+		.cluster = MSM_VENC_CTRL_CLUSTER_H264_ENTROPY,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
@@ -199,6 +246,7 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2)
 		),
 		.qmenu = h264_video_entropy_cabac_model,
+		.cluster = MSM_VENC_CTRL_CLUSTER_H264_ENTROPY,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
@@ -209,6 +257,7 @@
 		.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
 		.step = 1,
 		.menu_skip_mask = 0,
+		.cluster = MSM_VENC_CTRL_CLUSTER_MPEG_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
@@ -219,6 +268,7 @@
 		.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
 		.step = 1,
 		.menu_skip_mask = 0,
+		.cluster = MSM_VENC_CTRL_CLUSTER_MPEG_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
@@ -229,6 +279,7 @@
 		.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
 		.step = 1,
 		.menu_skip_mask = 0,
+		.cluster = MSM_VENC_CTRL_CLUSTER_H264_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
@@ -239,6 +290,7 @@
 		.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
 		.step = 0,
 		.menu_skip_mask = 0,
+		.cluster = MSM_VENC_CTRL_CLUSTER_H264_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
@@ -259,6 +311,7 @@
 		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
 		),
 		.qmenu = h263_profile,
+		.cluster = MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
@@ -277,6 +330,7 @@
 		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
 		),
 		.qmenu = h263_level,
+		.cluster = MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
@@ -293,6 +347,7 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)
 		),
 		.qmenu = mpeg_video_rotation,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
@@ -304,6 +359,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
@@ -315,6 +371,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
@@ -326,6 +383,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_QP,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
@@ -336,6 +394,7 @@
 		.default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
 		.step = 1,
 		.menu_skip_mask = 0,
+		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
@@ -347,6 +406,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
@@ -358,6 +418,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_SLICING,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE,
@@ -374,6 +435,7 @@
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE) |
 		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM)
 		),
+		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS,
@@ -385,6 +447,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF,
@@ -396,6 +459,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS,
@@ -407,6 +471,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
@@ -418,6 +483,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
@@ -429,6 +495,7 @@
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
+		.cluster = 0,
 	},
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
@@ -443,18 +510,24 @@
 		(1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
 		(1 << L_MODE)
 		),
+		.cluster = 0,
 	},
 	{
-		.id = V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR,
-		.name = "CodecConfig with sync frame",
-		.type = V4L2_CTRL_TYPE_BOOLEAN,
-		.minimum = 0,
-		.maximum = 1,
-		.default_value = 1,
+		.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+		.name = "Sequence Header Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+		.maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME,
+		.default_value =
+			V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME,
 		.step = 1,
-		.menu_skip_mask = 0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
+		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME)
+		),
 		.qmenu = NULL,
-	},
+		.cluster = 0,
+	}
 };
 
 #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -476,29 +549,6 @@
 	return sz;
 }
 
-static struct hal_quantization
-	venc_quantization = {I_FRAME_QP, P_FRAME_QP, B_FRAME_QP};
-static struct hal_intra_period
-	venc_intra_period = {2*DEFAULT_FRAME_RATE-1 , 0};
-static struct hal_profile_level
-	venc_h264_profile_level = {HAL_H264_PROFILE_BASELINE,
-		HAL_H264_LEVEL_1};
-static struct hal_profile_level
-	venc_mpeg4_profile_level = {HAL_MPEG4_PROFILE_SIMPLE,
-		HAL_MPEG4_LEVEL_0};
-static struct hal_profile_level
-	venc_h263_profile_level = {HAL_H263_PROFILE_BASELINE,
-				HAL_H263_LEVEL_10};
-static struct hal_h264_entropy_control
-	venc_h264_entropy_control = {HAL_H264_ENTROPY_CAVLC,
-		HAL_H264_CABAC_MODEL_0};
-static struct hal_multi_slice_control
-	venc_multi_slice_control = {HAL_MULTI_SLICE_OFF ,
-		0};
-static struct hal_intra_refresh
-	venc_intra_refresh = {HAL_INTRA_REFRESH_NONE ,
-		DEFAULT_IR_MBS, DEFAULT_IR_MBS, DEFAULT_IR_MBS};
-
 static const struct msm_vidc_format venc_formats[] = {
 	{
 		.name = "YCbCr Semiplanar 4:2:0",
@@ -639,10 +689,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 +765,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,
@@ -750,11 +794,162 @@
 	return &msm_venc_vb2q_ops;
 }
 
-static int msm_venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
+static struct v4l2_ctrl *get_ctrl_from_cluster(int id,
+		struct v4l2_ctrl **cluster, int ncontrols)
 {
+	int c;
 
+	for (c = 0; c < ncontrols; ++c)
+		if (cluster[c]->id == id)
+			return cluster[c];
+	return NULL;
+}
+
+/* Helper function to translate V4L2_* to HAL_* */
+static inline int venc_v4l2_to_hal(int id, int value)
+{
+	switch (id) {
+	/* MPEG4 */
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
+			return HAL_MPEG4_LEVEL_0;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
+			return HAL_MPEG4_LEVEL_0b;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
+			return HAL_MPEG4_LEVEL_1;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
+			return HAL_MPEG4_LEVEL_2;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
+			return HAL_MPEG4_LEVEL_3;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
+			return HAL_MPEG4_LEVEL_4;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
+			return HAL_MPEG4_LEVEL_5;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+			return HAL_MPEG4_PROFILE_SIMPLE;
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+			return HAL_MPEG4_PROFILE_ADVANCEDSIMPLE;
+		default:
+			goto unknown_value;
+		}
+	/* H264 */
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+			return HAL_H264_PROFILE_BASELINE;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+			return HAL_H264_PROFILE_MAIN;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+			return HAL_H264_PROFILE_EXTENDED;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+			return HAL_H264_PROFILE_HIGH;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+			return HAL_H264_PROFILE_HIGH10;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+			return HAL_H264_PROFILE_HIGH422;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+			return HAL_H264_PROFILE_HIGH444;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+			return HAL_H264_LEVEL_1;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+			return HAL_H264_LEVEL_1b;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+			return HAL_H264_LEVEL_11;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+			return HAL_H264_LEVEL_12;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+			return HAL_H264_LEVEL_13;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+			return HAL_H264_LEVEL_2;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+			return HAL_H264_LEVEL_21;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+			return HAL_H264_LEVEL_22;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+			return HAL_H264_LEVEL_3;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+			return HAL_H264_LEVEL_31;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+			return HAL_H264_LEVEL_32;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+			return HAL_H264_LEVEL_4;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+			return HAL_H264_LEVEL_41;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+			return HAL_H264_LEVEL_42;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+			return HAL_H264_LEVEL_3;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+			return HAL_H264_LEVEL_51;
+		default:
+			goto unknown_value;
+		}
+		/* H263 */
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
+			return HAL_H263_PROFILE_BASELINE;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING:
+			return HAL_H263_PROFILE_H320CODING;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE:
+			return HAL_H263_PROFILE_BACKWARDCOMPATIBLE;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2:
+			return HAL_H263_PROFILE_ISWV2;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3:
+			return HAL_H263_PROFILE_ISWV3;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION:
+			return HAL_H263_PROFILE_HIGHCOMPRESSION;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET:
+			return HAL_H263_PROFILE_INTERNET;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE:
+			return HAL_H263_PROFILE_INTERLACE;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY:
+			return HAL_H263_PROFILE_HIGHLATENCY;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0:
+			return HAL_H263_LEVEL_10;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0:
+			return HAL_H263_LEVEL_20;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0:
+			return HAL_H263_LEVEL_30;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0:
+			return HAL_H263_LEVEL_40;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5:
+			return HAL_H263_LEVEL_45;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0:
+			return HAL_H263_LEVEL_50;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0:
+			return HAL_H263_LEVEL_60;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0:
+			return HAL_H263_LEVEL_70;
+		default:
+			goto unknown_value;
+		}
+	}
+
+unknown_value:
+	dprintk(VIDC_WARN, "Unknown control (%x, %d)", id, value);
+	return -EINVAL;
+}
+
+static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
 	int rc = 0;
-	struct v4l2_control control;
 	struct hal_frame_rate frame_rate;
 	struct hal_request_iframe request_iframe;
 	struct hal_bitrate bitrate;
@@ -768,48 +963,78 @@
 	struct hal_multi_slice_control multi_slice_control;
 	struct hal_h264_db_control h264_db_control;
 	struct hal_enable enable;
-	u32 property_id = 0;
-	u32 property_val = 0;
+	u32 property_id = 0, property_val = 0;
 	void *pdata;
-	struct msm_vidc_inst *inst = container_of(ctrl->handler,
-					struct msm_vidc_inst, ctrl_handler);
-	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
-	if (rc) {
-		dprintk(VIDC_ERR,
-			"Failed to move inst: %p to start done state\n", inst);
-		goto failed_open_done;
-	}
-	control.id = ctrl->id;
-	control.value = ctrl->val;
+	struct v4l2_ctrl *temp_ctrl = NULL;
 
-	switch (control.id) {
+	/* Small helper macro for quickly getting a control and err checking */
+#define TRY_GET_CTRL(__ctrl_id) ({ \
+		struct v4l2_ctrl *__temp; \
+		__temp = get_ctrl_from_cluster( \
+			__ctrl_id, \
+			ctrl->cluster, ctrl->ncontrols); \
+		if (!__temp) { \
+			dprintk(VIDC_ERR, "Can't find %s (%x) in cluster", \
+				#__ctrl_id, __ctrl_id); \
+			rc = -ENOENT; \
+			break; \
+		} \
+		__temp; \
+	})
+
+	switch (ctrl->id) {
 	case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE:
-			property_id =
-				HAL_CONFIG_FRAME_RATE;
-			frame_rate.frame_rate = control.value;
-			frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
-			pdata = &frame_rate;
+		property_id =
+			HAL_CONFIG_FRAME_RATE;
+		frame_rate.frame_rate = ctrl->val;
+		frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
+		pdata = &frame_rate;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD:
 		property_id =
 			HAL_CONFIG_VENC_IDR_PERIOD;
-		idr_period.idr_period = control.value;
-			pdata = &idr_period;
+		idr_period.idr_period = ctrl->val;
+		pdata = &idr_period;
 		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: {
+		struct v4l2_ctrl *b;
+		b = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
+
+		if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_H264 &&
+			inst->fmts[CAPTURE_PORT]->fourcc !=
+				V4L2_PIX_FMT_H264_NO_SC) {
+			dprintk(VIDC_ERR, "Control 0x%x only valid for H264",
+					ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		/*
+		 * We can't set the I-period explicitly. So set it implicitly
+		 * by setting the number of P and B frames per I-period
+		 */
+		property_id = HAL_CONFIG_VENC_INTRA_PERIOD;
+		intra_period.pframes = (ctrl->val - 1) - b->val;
+		intra_period.bframes = b->val;
+		pdata = &intra_period;
+		break;
+	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
+
 		property_id =
 			HAL_CONFIG_VENC_INTRA_PERIOD;
-		intra_period.pframes = control.value;
-		venc_intra_period.pframes = control.value;
-		intra_period.bframes = venc_intra_period.bframes;
+		intra_period.pframes = ctrl->val;
+		intra_period.bframes = temp_ctrl->val;
 		pdata = &intra_period;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES);
+
 		property_id =
 			HAL_CONFIG_VENC_INTRA_PERIOD;
-		intra_period.bframes = control.value;
-		venc_intra_period.bframes = control.value;
-		intra_period.pframes = venc_intra_period.pframes;
+		intra_period.bframes = ctrl->val;
+		intra_period.pframes = temp_ctrl->val;
 		pdata = &intra_period;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME:
@@ -818,396 +1043,405 @@
 		request_iframe.enable = true;
 		pdata = &request_iframe;
 		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+	{
+		bool cfr = true, cbr = true;
+		int final_mode = 0;
+
+		temp_ctrl = TRY_GET_CTRL(
+			V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
+
+		switch (temp_ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF:
+			/* Let's assume CFR */
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
+			cfr = true;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR:
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR:
+			cfr = false;
+			break;
+		default:
+			dprintk(VIDC_WARN, "Unknown framerate mode");
+		}
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
+			cbr = false;
+			break;
+		case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
+			cbr = true;
+			break;
+		default:
+			dprintk(VIDC_WARN, "Unknown bitrate mode");
+		}
+
+		if (!cfr && !cbr)
+			final_mode =
+				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR;
+		else if (!cfr && cbr)
+			final_mode =
+				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR;
+		else if (cfr && !cbr)
+			final_mode =
+				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR;
+		else /* ... if (cfr && cbr) */
+			final_mode =
+				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR;
+
+		property_id = HAL_PARAM_VENC_RATE_CONTROL;
+		property_val = final_mode;
+		pdata = &property_val;
+		break;
+	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL:
-		property_id =
-			HAL_PARAM_VENC_RATE_CONTROL;
-		property_val = control.value;
+		property_id = HAL_PARAM_VENC_RATE_CONTROL;
+		property_val = ctrl->val;
 		pdata = &property_val;
 		break;
 	case V4L2_CID_MPEG_VIDEO_BITRATE:
 		property_id =
 			HAL_CONFIG_VENC_TARGET_BITRATE;
-		bitrate.bit_rate = control.value;
+		bitrate.bit_rate = ctrl->val;
 		pdata = &bitrate;
 		break;
 	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+		temp_ctrl = TRY_GET_CTRL(
+			V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL);
+
 		property_id =
 			HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
-		h264_entropy_control.entropy_mode = control.value;
-		venc_h264_entropy_control.entropy_mode = control.value;
-		h264_entropy_control.cabac_model =
-			venc_h264_entropy_control.cabac_model;
+		h264_entropy_control.entropy_mode = ctrl->val;
+		h264_entropy_control.cabac_model = temp_ctrl->val;
 		pdata = &h264_entropy_control;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE);
+
 		property_id =
 			HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
-		h264_entropy_control.cabac_model = control.value;
-		venc_h264_entropy_control.cabac_model = control.value;
-		h264_entropy_control.entropy_mode =
-			venc_h264_entropy_control.entropy_mode;
+		h264_entropy_control.cabac_model = ctrl->val;
+		h264_entropy_control.entropy_mode = temp_ctrl->val;
 		pdata = &h264_entropy_control;
 		break;
 	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL);
+
 		property_id =
 			HAL_PARAM_PROFILE_LEVEL_CURRENT;
-		switch (control.value) {
-		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
-			control.value = HAL_MPEG4_PROFILE_SIMPLE;
-			break;
-		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
-			control.value = HAL_MPEG4_PROFILE_ADVANCEDSIMPLE;
-			break;
-		default:
-			break;
-			}
-		profile_level.profile = control.value;
-		venc_mpeg4_profile_level.profile = control.value;
-		profile_level.level = venc_mpeg4_profile_level.level;
+		profile_level.profile =  venc_v4l2_to_hal(ctrl->id,
+						ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+				temp_ctrl->val);
 		pdata = &profile_level;
 		break;
 	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE);
+
 		property_id =
 			HAL_PARAM_PROFILE_LEVEL_CURRENT;
-		switch (control.value) {
-		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
-			control.value = HAL_MPEG4_LEVEL_0;
-			break;
-		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
-			control.value = HAL_MPEG4_LEVEL_0b;
-			break;
-		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
-			control.value = HAL_MPEG4_LEVEL_1;
-			break;
-		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
-			control.value = HAL_MPEG4_LEVEL_2;
-			break;
-		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
-			control.value = HAL_MPEG4_LEVEL_3;
-			break;
-		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
-			control.value = HAL_MPEG4_LEVEL_4;
-			break;
-		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
-			control.value = HAL_MPEG4_LEVEL_5;
-			break;
-		default:
-			break;
-		}
-		profile_level.level = control.value;
-		venc_mpeg4_profile_level.level = control.value;
-		profile_level.profile = venc_mpeg4_profile_level.profile;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+				temp_ctrl->val);
 		pdata = &profile_level;
 		break;
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+
 		property_id =
 			HAL_PARAM_PROFILE_LEVEL_CURRENT;
-
-		switch (control.value) {
-		case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
-			control.value = HAL_H264_PROFILE_BASELINE;
-			break;
-		case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
-			control.value = HAL_H264_PROFILE_MAIN;
-			break;
-		case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
-			control.value = HAL_H264_PROFILE_EXTENDED;
-			break;
-		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
-			control.value = HAL_H264_PROFILE_HIGH;
-			break;
-		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
-			control.value = HAL_H264_PROFILE_HIGH10;
-			break;
-		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
-			control.value = HAL_H264_PROFILE_HIGH422;
-			break;
-		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
-			control.value = HAL_H264_PROFILE_HIGH444;
-			break;
-		default:
-			break;
-			}
-		profile_level.profile = control.value;
-		venc_h264_profile_level.profile = control.value;
-		profile_level.level = venc_h264_profile_level.level;
+		profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+				temp_ctrl->val);
 		pdata = &profile_level;
 		dprintk(VIDC_DBG, "\nprofile: %d\n",
 			   profile_level.profile);
 		break;
 	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
+
 		property_id =
 			HAL_PARAM_PROFILE_LEVEL_CURRENT;
-
-		switch (control.value) {
-		case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
-			control.value = HAL_H264_LEVEL_1;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
-			control.value = HAL_H264_LEVEL_1b;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
-			control.value = HAL_H264_LEVEL_11;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
-			control.value = HAL_H264_LEVEL_12;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
-			control.value = HAL_H264_LEVEL_13;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
-			control.value = HAL_H264_LEVEL_2;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
-			control.value = HAL_H264_LEVEL_21;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
-			control.value = HAL_H264_LEVEL_22;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
-			control.value = HAL_H264_LEVEL_3;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
-			control.value = HAL_H264_LEVEL_31;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
-			control.value = HAL_H264_LEVEL_32;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
-			control.value = HAL_H264_LEVEL_4;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
-			control.value = HAL_H264_LEVEL_41;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
-			control.value = HAL_H264_LEVEL_42;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
-			control.value = HAL_H264_LEVEL_3;
-			break;
-		case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
-			control.value = HAL_H264_LEVEL_51;
-			break;
-		default:
-			break;
-		}
-		profile_level.level = control.value;
-		venc_h264_profile_level.level = control.value;
-		profile_level.profile = venc_h264_profile_level.profile;
-		pdata = &profile_level;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+				temp_ctrl->val);
 		pdata = &profile_level;
 		dprintk(VIDC_DBG, "\nLevel: %d\n",
 			   profile_level.level);
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL);
+
 		property_id =
 			HAL_PARAM_PROFILE_LEVEL_CURRENT;
-
-		switch (control.value) {
-		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
-			control.value = HAL_H263_PROFILE_BASELINE;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING:
-			control.value = HAL_H263_PROFILE_H320CODING;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE:
-			control.value = HAL_H263_PROFILE_BACKWARDCOMPATIBLE;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2:
-			control.value = HAL_H263_PROFILE_ISWV2;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3:
-			control.value = HAL_H263_PROFILE_ISWV3;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION:
-			control.value = HAL_H263_PROFILE_HIGHCOMPRESSION;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET:
-			control.value = HAL_H263_PROFILE_INTERNET;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE:
-			control.value = HAL_H263_PROFILE_INTERLACE;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY:
-			control.value = HAL_H263_PROFILE_HIGHLATENCY;
-			break;
-		default:
-			break;
-		}
-		profile_level.profile = control.value;
-		venc_h263_profile_level.profile = control.value;
-		profile_level.level = venc_h263_profile_level.level;
+		profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+				temp_ctrl->val);
 		pdata = &profile_level;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE);
+
 		property_id =
 			HAL_PARAM_PROFILE_LEVEL_CURRENT;
-
-		switch (control.value) {
-		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0:
-			control.value = HAL_H263_LEVEL_10;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0:
-			control.value = HAL_H263_LEVEL_20;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0:
-			control.value = HAL_H263_LEVEL_30;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0:
-			control.value = HAL_H263_LEVEL_40;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5:
-			control.value = HAL_H263_LEVEL_45;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0:
-			control.value = HAL_H263_LEVEL_50;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0:
-			control.value = HAL_H263_LEVEL_60;
-			break;
-		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0:
-			control.value = HAL_H263_LEVEL_70;
-			break;
-		default:
-			break;
-		}
-
-		profile_level.level = control.value;
-		venc_h263_profile_level.level = control.value;
-		profile_level.profile = venc_h263_profile_level.profile;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+				ctrl->val);
 		pdata = &profile_level;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
 		property_id =
 			HAL_CONFIG_VPE_OPERATIONS;
-		operations.rotate = control.value;
+		operations.rotate = ctrl->val;
 		pdata = &operations;
 		break;
-	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: {
+		struct v4l2_ctrl *qpp, *qpb;
+
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP);
+
 		property_id =
 			HAL_PARAM_VENC_SESSION_QP;
-		quantization.qpi = control.value;
-		venc_quantization.qpi = control.value;
-		quantization.qpp = venc_quantization.qpp;
-		quantization.qpb = venc_quantization.qpb;
+		quantization.qpi = ctrl->val;
+		quantization.qpp = qpp->val;
+		quantization.qpb = qpb->val;
+
 		pdata = &quantization;
 		break;
-	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: {
+		struct v4l2_ctrl *qpi, *qpb;
+
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP);
+
 		property_id =
 			HAL_PARAM_VENC_SESSION_QP;
-		quantization.qpp = control.value;
-		venc_quantization.qpp = control.value;
-		quantization.qpi = venc_quantization.qpi;
-		quantization.qpb = venc_quantization.qpb;
+		quantization.qpp = ctrl->val;
+		quantization.qpi = qpi->val;
+		quantization.qpb = qpb->val;
+
 		pdata = &quantization;
 		break;
-	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: {
+		struct v4l2_ctrl *qpi, *qpp;
+
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP);
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP);
+
 		property_id =
 			HAL_PARAM_VENC_SESSION_QP;
-		quantization.qpb = control.value;
-		venc_quantization.qpb = control.value;
-		quantization.qpi = venc_quantization.qpi;
-		quantization.qpp = venc_quantization.qpp;
+		quantization.qpb = ctrl->val;
+		quantization.qpi = qpi->val;
+		quantization.qpp = qpp->val;
+
 		pdata = &quantization;
 		break;
-	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+	}
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: {
+		int temp = 0;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+			temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB;
+			break;
+		case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+			temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES;
+			break;
+		case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+		default:
+			temp = 0;
+			break;
+		}
+
+		if (temp)
+			temp_ctrl = TRY_GET_CTRL(temp);
+
 		property_id =
 			HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
-		multi_slice_control.multi_slice = control.value;
-		venc_multi_slice_control.multi_slice = control.value;
-		multi_slice_control.slice_size =
-			venc_multi_slice_control.slice_size;
+		multi_slice_control.multi_slice = ctrl->val;
+		multi_slice_control.slice_size = temp ? temp_ctrl->val : 0;
+
 		pdata = &multi_slice_control;
 		break;
+	}
 	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
 	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
+
 		property_id =
 			HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
-		multi_slice_control.multi_slice =
-			venc_multi_slice_control.multi_slice;
-		multi_slice_control.slice_size = control.value;
-		venc_multi_slice_control.slice_size = control.value;
+		multi_slice_control.multi_slice = temp_ctrl->val;
+		multi_slice_control.slice_size = ctrl->val;
 		pdata = &multi_slice_control;
 		break;
-	case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: {
+		struct v4l2_ctrl *air_mbs, *air_ref, *cir_mbs;
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
 		property_id =
 			HAL_PARAM_VENC_INTRA_REFRESH;
-		intra_refresh.mode = control.value;
-		intra_refresh.air_mbs = venc_intra_refresh.air_mbs;
-		intra_refresh.air_ref = venc_intra_refresh.air_ref;
-		intra_refresh.cir_mbs = venc_intra_refresh.cir_mbs;
-		venc_intra_refresh.mode = intra_refresh.mode;
+
+		intra_refresh.mode = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.cir_mbs = cir_mbs->val;
+
 		pdata = &intra_refresh;
 		break;
-	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS:
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS: {
+		struct v4l2_ctrl *ir_mode, *air_ref, *cir_mbs;
+		ir_mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
 		property_id =
 			HAL_PARAM_VENC_INTRA_REFRESH;
-		intra_refresh.air_mbs = control.value;
-		intra_refresh.mode = venc_intra_refresh.mode;
-		intra_refresh.air_ref = venc_intra_refresh.air_ref;
-		intra_refresh.cir_mbs = venc_intra_refresh.cir_mbs;
-		venc_intra_refresh.air_mbs = control.value;
+		intra_refresh.air_mbs = ctrl->val;
+		intra_refresh.mode = ir_mode->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.cir_mbs = cir_mbs->val;
+
 		pdata = &intra_refresh;
 		break;
-	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF:
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF: {
+		struct v4l2_ctrl *ir_mode, *air_mbs, *cir_mbs;
+		ir_mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
 		property_id =
 			HAL_PARAM_VENC_INTRA_REFRESH;
-		intra_refresh.air_ref = control.value;
-		intra_refresh.air_mbs = venc_intra_refresh.air_mbs;
-		intra_refresh.mode = venc_intra_refresh.mode;
-		intra_refresh.cir_mbs = venc_intra_refresh.cir_mbs;
-		venc_intra_refresh.air_ref = control.value;
+		intra_refresh.air_ref = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.mode = ir_mode->val;
+		intra_refresh.cir_mbs = cir_mbs->val;
+
 		pdata = &intra_refresh;
 		break;
-	case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS:
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: {
+		struct v4l2_ctrl *ir_mode, *air_mbs, *air_ref;
+
+		ir_mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
 		property_id =
 			HAL_PARAM_VENC_INTRA_REFRESH;
-		intra_refresh.cir_mbs = control.value;
-		intra_refresh.air_mbs = venc_intra_refresh.air_mbs;
-		intra_refresh.air_ref = venc_intra_refresh.air_ref;
-		intra_refresh.mode = venc_intra_refresh.mode;
-		venc_intra_refresh.cir_mbs = control.value;
+
+		intra_refresh.cir_mbs = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.mode = ir_mode->val;
+
 		pdata = &intra_refresh;
 		break;
+	}
 	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
 		property_id =
 			HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
-		h264_db_control.mode = control.value;
+		h264_db_control.mode = ctrl->val;
 		pdata = &h264_db_control;
 		break;
 	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
 		property_id =
 			HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
-		h264_db_control.slice_alpha_offset = control.value;
+		h264_db_control.slice_alpha_offset = ctrl->val;
 		pdata = &h264_db_control;
 		break;
 	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
 		property_id =
 			HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
-		h264_db_control.slice_beta_offset = control.value;
+		h264_db_control.slice_beta_offset = ctrl->val;
 		pdata = &h264_db_control;
 		break;
-	case V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR:
+	case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
 		property_id =
 			HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
-		enable.enable = control.value;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE:
+			enable.enable = 0;
+			break;
+		case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME:
+			enable.enable = 1;
+			break;
+		case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME:
+		default:
+			rc = -ENOTSUPP;
+			break;
+		}
 		pdata = &enable;
 		break;
 	default:
+		rc = -ENOTSUPP;
 		break;
 	}
+#undef TRY_GET_CTRL
+
 	if (property_id) {
 		dprintk(VIDC_DBG, "Control: HAL property=%d,ctrl_value=%d\n",
 				property_id,
-				control.value);
+				ctrl->val);
 		rc = vidc_hal_session_set_property((void *)inst->session,
 				property_id, pdata);
 	}
-	if (rc)
-		dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
-failed_open_done:
+
 	return rc;
 }
+
+static int msm_venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+
+	int rc = 0, c = 0;
+	struct msm_vidc_inst *inst = container_of(ctrl->handler,
+					struct msm_vidc_inst, ctrl_handler);
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %p to start done state\n", inst);
+		goto failed_open_done;
+	}
+
+	for (c = 0; c < ctrl->ncontrols; ++c) {
+		if (ctrl->cluster[c]->is_new) {
+			rc = try_set_ctrl(inst, ctrl->cluster[c]);
+			if (rc) {
+				dprintk(VIDC_ERR, "Failed setting %x",
+						ctrl->cluster[c]->id);
+				break;
+			}
+		}
+	}
+failed_open_done:
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to set hal property\n");
+	return rc;
+}
+
 static int msm_venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
 	return 0;
@@ -1371,10 +1605,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;
@@ -1561,7 +1792,13 @@
 	int rc = 0;
 	int i;
 	struct vidc_buffer_addr_info buffer_info;
-
+	rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %p to release res done state\n",
+			inst);
+		goto exit;
+	}
 	switch (b->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		break;
@@ -1578,6 +1815,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)
@@ -1589,6 +1827,7 @@
 		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
 		break;
 	}
+exit:
 	return rc;
 }
 
@@ -1666,6 +1905,26 @@
 	return rc;
 }
 
+static struct v4l2_ctrl **get_cluster(int type, int *size)
+{
+	int c = 0, sz = 0;
+	struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) *
+			NUM_CTRLS, GFP_KERNEL);
+
+	if (type <= 0 || !size || !cluster)
+		return NULL;
+
+	for (c = 0; c < NUM_CTRLS; c++) {
+		if (msm_venc_ctrls[c].cluster == type) {
+			cluster[sz] = msm_venc_ctrls[c].priv;
+			++sz;
+		}
+	}
+
+	*size = sz;
+	return cluster;
+}
+
 int msm_venc_ctrl_init(struct msm_vidc_inst *inst)
 {
 
@@ -1680,6 +1939,7 @@
 	}
 
 	for (; idx < NUM_CTRLS; idx++) {
+		struct v4l2_ctrl *ctrl = NULL;
 		if (IS_PRIV_CTRL(msm_venc_ctrls[idx].id)) {
 			ctrl_cfg.def = msm_venc_ctrls[idx].default_value;
 			ctrl_cfg.flags = 0;
@@ -1693,18 +1953,20 @@
 			ctrl_cfg.step = msm_venc_ctrls[idx].step;
 			ctrl_cfg.type = msm_venc_ctrls[idx].type;
 			ctrl_cfg.qmenu = msm_venc_ctrls[idx].qmenu;
-			v4l2_ctrl_new_custom(&inst->ctrl_handler,
-				&ctrl_cfg, NULL);
+			ctrl = v4l2_ctrl_new_custom(
+					&inst->ctrl_handler,
+					&ctrl_cfg, NULL);
 		} else {
 			if (msm_venc_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
-				v4l2_ctrl_new_std_menu(&inst->ctrl_handler,
+				ctrl = v4l2_ctrl_new_std_menu(
+					&inst->ctrl_handler,
 					&msm_venc_ctrl_ops,
 					msm_venc_ctrls[idx].id,
 					msm_venc_ctrls[idx].maximum,
 					msm_venc_ctrls[idx].menu_skip_mask,
 					msm_venc_ctrls[idx].default_value);
 			} else {
-				v4l2_ctrl_new_std(&inst->ctrl_handler,
+				ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler,
 					&msm_venc_ctrl_ops,
 					msm_venc_ctrls[idx].id,
 					msm_venc_ctrls[idx].minimum,
@@ -1713,11 +1975,51 @@
 					msm_venc_ctrls[idx].default_value);
 			}
 		}
+
+		msm_venc_ctrls[idx].priv = ctrl;
 	}
 	ret_val = inst->ctrl_handler.error;
 	if (ret_val)
 		dprintk(VIDC_ERR,
 			"CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
 			inst->ctrl_handler.error);
+
+	/* Construct clusters */
+	for (idx = 1; idx < MSM_VENC_CTRL_CLUSTER_MAX; ++idx) {
+		struct msm_vidc_ctrl_cluster *temp = NULL;
+		struct v4l2_ctrl **cluster = NULL;
+		int cluster_size = 0;
+
+		cluster = get_cluster(idx, &cluster_size);
+		if (!cluster || !cluster_size) {
+			dprintk(VIDC_WARN, "Failed to setup cluster of type %d",
+					idx);
+			continue;
+		}
+
+		v4l2_ctrl_cluster(cluster_size, cluster);
+
+		temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+		if (!temp) {
+			ret_val = -ENOMEM;
+			break;
+		}
+
+		temp->cluster = cluster;
+		INIT_LIST_HEAD(&temp->list);
+		list_add_tail(&temp->list, &inst->ctrl_clusters);
+	}
+
 	return ret_val;
 }
+
+int msm_venc_ctrl_deinit(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_ctrl_cluster *curr, *next;
+	list_for_each_entry_safe(curr, next, &inst->ctrl_clusters, list) {
+		kfree(curr->cluster);
+		kfree(curr);
+	}
+
+	return 0;
+}
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
index ad63e7d..c098773 100644
--- a/drivers/media/video/msm_vidc/msm_venc.h
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -18,6 +18,7 @@
 
 int msm_venc_inst_init(struct msm_vidc_inst *inst);
 int msm_venc_ctrl_init(struct msm_vidc_inst *inst);
+int msm_venc_ctrl_deinit(struct msm_vidc_inst *inst);
 int msm_venc_querycap(void *instance, struct v4l2_capability *cap);
 int msm_venc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
 int msm_venc_s_fmt(void *instance, struct v4l2_format *f);
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 64897c7..13180c5 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -428,6 +428,7 @@
 	INIT_LIST_HEAD(&inst->pendingq);
 	INIT_LIST_HEAD(&inst->internalbufs);
 	INIT_LIST_HEAD(&inst->persistbufs);
+	INIT_LIST_HEAD(&inst->ctrl_clusters);
 	init_waitqueue_head(&inst->kernel_event_queue);
 	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
 	inst->core = core;
@@ -555,10 +556,18 @@
 			list_del(&inst->list);
 	}
 	mutex_unlock(&core->sync_lock);
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		msm_vdec_ctrl_deinit(inst);
+	else if (inst->session_type == MSM_VIDC_ENCODER)
+		msm_venc_ctrl_deinit(inst);
+
 	cleanup_instance(inst);
 	if (inst->state != MSM_VIDC_CORE_INVALID &&
 		core->state != VIDC_CORE_INVALID)
 		rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
+	else
+		rc = msm_comm_force_cleanup(inst);
 	if (rc)
 		dprintk(VIDC_ERR,
 			"Failed to move video instance to uninit state\n");
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index cda0ea8..b9ff82e 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -63,8 +63,9 @@
 	int ret;
 };
 
+#define TIME_DIFF_THRESHOLD 200
+
 static const u32 bus_table[] = {
-	0,
 	36000,
 	110400,
 	244800,
@@ -77,12 +78,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 +122,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 +356,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 +654,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,
@@ -671,7 +731,7 @@
 	mutex_unlock(&bufq->lock);
 	if (!found) {
 		dprintk(VIDC_ERR,
-			"Failed to find the buffer in queued list: %d, %d\n",
+			"Failed to find the buffer in queued list: 0x%x, %d\n",
 			dev_addr, q->type);
 		vb = NULL;
 	}
@@ -698,12 +758,58 @@
 	}
 }
 
+static void msm_comm_update_clocks(struct msm_vidc_inst *inst,
+	u64 cur_time_stamp)
+{
+	u32 new_time_diff = 0, cur_time_diff = 0;
+	u8 updated_fps = 0;
+	struct v4l2_ctrl *ctrl = NULL;
+	u32 output_order = 0;
+
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		goto exit;
+	ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
+		V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER);
+	if (!ctrl) {
+		dprintk(VIDC_WARN, "Unable to find output order control\n");
+		dprintk(VIDC_WARN,
+			"Performance might be impacted for higher fps clips\n");
+		goto exit;
+	}
+	output_order = v4l2_ctrl_g_ctrl(ctrl);
+	if (output_order == V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) {
+		new_time_diff =
+			(u32)(cur_time_stamp - inst->prop.prev_time_stamp);
+		inst->prop.prev_time_stamp = cur_time_stamp;
+		if (!new_time_diff)
+			goto exit;
+		if (inst->prop.fps)
+			cur_time_diff = USEC_PER_SEC / inst->prop.fps;
+		cur_time_diff = cur_time_diff > new_time_diff ?
+			cur_time_diff - new_time_diff :
+			new_time_diff - cur_time_diff;
+		if (cur_time_diff > TIME_DIFF_THRESHOLD) {
+			updated_fps = (u8) (USEC_PER_SEC / new_time_diff);
+			if (updated_fps && (updated_fps != inst->prop.fps)) {
+				inst->prop.fps = updated_fps;
+				dprintk(VIDC_DBG,
+						"Updating clocks: Decoding fps = %d\n",
+						inst->prop.fps);
+				msm_comm_scale_clocks_and_bus(inst);
+			}
+		}
+	}
+exit:
+	return;
+}
+
 static void handle_fbd(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_data_done *response = data;
 	struct msm_vidc_inst *inst;
 	struct vb2_buffer *vb;
 	struct vidc_hal_fbd *fill_buf_done;
+
 	if (!response) {
 		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
 		return;
@@ -719,9 +825,9 @@
 			int64_t time_usec = fill_buf_done->timestamp_hi;
 			time_usec = (time_usec << 32) |
 				fill_buf_done->timestamp_lo;
-
 			vb->v4l2_buf.timestamp =
 				ns_to_timeval(time_usec * NSEC_PER_USEC);
+				msm_comm_update_clocks(inst, time_usec);
 		}
 		vb->v4l2_buf.flags = 0;
 
@@ -876,13 +982,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 +1005,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 +1052,29 @@
 	}
 }
 
+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 +1082,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 +1115,7 @@
 fail_enable_clks:
 	subsystem_put(core->resources.fw.cookie);
 	core->resources.fw.cookie = NULL;
-fail_subsystem_get:
+fail_load_fw:
 	return rc;
 }
 
@@ -1045,6 +1174,11 @@
 		dprintk(VIDC_ERR, "Invalid params, core:%p\n",	core);
 		return -EINVAL;
 	}
+	if (core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Core is in bad state. Cannot unset ocmem\n");
+		return -EIO;
+	}
 	rhdr.resource_id = VIDC_RESOURCE_OCMEM;
 	rhdr.resource_handle = (u32) &core->resources.ocmem;
 	init_completion(
@@ -1189,16 +1323,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 +1358,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 +1375,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 +1390,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);
@@ -1257,6 +1399,11 @@
 	return rc;
 }
 
+int msm_comm_force_cleanup(struct msm_vidc_inst *inst)
+{
+	return msm_vidc_deinit_core(inst);
+}
+
 static enum hal_domain get_hal_domain(int session_type)
 {
 	enum hal_domain domain;
@@ -1367,11 +1514,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,
@@ -1605,7 +1759,6 @@
 				inst->state, state);
 	return rc;
 }
-
 int msm_comm_qbuf(struct vb2_buffer *vb)
 {
 	int rc = 0;
@@ -1790,6 +1943,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 +1955,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 +2003,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 +2015,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 +2101,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 +2174,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..d225a51 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);
@@ -41,6 +41,7 @@
 	enum instance_state state);
 int msm_comm_unset_ocmem(struct msm_vidc_core *core);
 int msm_comm_free_ocmem(struct msm_vidc_core *core);
+int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
 enum hal_extradata_id msm_comm_get_hal_extradata_index(
 	enum v4l2_mpeg_vidc_extradata index);
 #define IS_PRIV_CTRL(idx) (\
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index e9295a6..88aedf9 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;
@@ -165,6 +170,7 @@
 	u32 height;
 	u32 fps;
 	u32 bitrate;
+	u64 prev_time_stamp;
 };
 
 struct buf_queue {
@@ -253,6 +259,7 @@
 	void *mem_client;
 	struct v4l2_ctrl_handler ctrl_handler;
 	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+	struct list_head ctrl_clusters;
 	struct v4l2_fh event_handler;
 	struct msm_smem *extradata_handle;
 	wait_queue_head_t kernel_event_queue;
@@ -270,6 +277,11 @@
 
 extern struct msm_vidc_drv *vidc_driver;
 
+struct msm_vidc_ctrl_cluster {
+	struct v4l2_ctrl **cluster;
+	struct list_head list;
+};
+
 struct msm_vidc_ctrl {
 	u32 id;
 	char name[MAX_NAME_LENGTH];
@@ -280,6 +292,8 @@
 	u32 step;
 	u32 menu_skip_mask;
 	const char * const *qmenu;
+	u32 cluster;
+	struct v4l2_ctrl *priv;
 };
 
 void handle_cmd_response(enum command_response cmd, void *data);
diff --git a/drivers/media/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..333bad9 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -149,16 +149,18 @@
 static void hal_process_sys_error(struct hal_device *device)
 {
 	struct msm_vidc_cb_cmd_done cmd_done;
-	disable_irq_nosync(device->hal_data->irq);
 	memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
 	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,
@@ -174,12 +176,13 @@
 
 	switch (pkt->event_id) {
 	case HFI_EVENT_SYS_ERROR:
-		dprintk(VIDC_INFO, "HFI_EVENT_SYS_ERROR");
+		dprintk(VIDC_ERR, "HFI_EVENT_SYS_ERROR: %d\n",
+			pkt->event_data1);
 		hal_process_sys_error(device);
 		break;
 	case HFI_EVENT_SESSION_ERROR:
-		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR");
-		hal_process_session_error(device);
+		dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR");
+		hal_process_session_error(device, pkt);
 		break;
 	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
 		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED");
@@ -189,7 +192,7 @@
 		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED");
 		break;
 	default:
-		dprintk(VIDC_INFO, "hal_process_event_notify:unkown_event_id");
+		dprintk(VIDC_WARN, "hal_process_event_notify:unkown_event_id");
 		break;
 	}
 }
@@ -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..aadf5ed 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;
@@ -900,25 +903,13 @@
 	struct vcd_property_req_i_frame vcd_property_req_i_frame;
 	struct vcd_property_hdr vcd_property_hdr;
 
-	int rc = 0;
-	switch (type) {
-	case V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED:
-		/*So...nothing to do?*/
-		break;
-	case V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME:
-		vcd_property_hdr.prop_id = VCD_I_REQ_IFRAME;
-		vcd_property_hdr.sz = sizeof(struct vcd_property_req_i_frame);
-		vcd_property_req_i_frame.req_i_frame = 1;
+	vcd_property_hdr.prop_id = VCD_I_REQ_IFRAME;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_req_i_frame);
+	vcd_property_req_i_frame.req_i_frame = 1;
 
-		rc = vcd_set_property(client_ctx->vcd_handle,
-				&vcd_property_hdr, &vcd_property_req_i_frame);
-		break;
-	case V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED:
-	default:
-		rc = -ENOTSUPP;
-	}
+	return vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &vcd_property_req_i_frame);
 
-	return rc;
 }
 
 static long venc_set_bitrate(struct video_client_ctx *client_ctx,
@@ -1123,6 +1114,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)
 {
@@ -1337,10 +1336,10 @@
 	int level = 0;
 
 	switch (value) {
-	case V4L2_CID_MPEG_QCOM_PERF_LEVEL_PERFORMANCE:
+	case V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE:
 		level = VCD_PERF_LEVEL2;
 		break;
-	case V4L2_CID_MPEG_QCOM_PERF_LEVEL_TURBO:
+	case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO:
 		level = VCD_PERF_LEVEL_TURBO;
 		break;
 	default:
@@ -1400,6 +1399,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)
 {
@@ -2248,7 +2292,7 @@
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
 		rc = venc_set_codec_profile(client_ctx, ctrl->id, ctrl->value);
 		break;
-	case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME:
 		rc = venc_request_frame(client_ctx, ctrl->value);
 		break;
 	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
@@ -2279,12 +2323,15 @@
 		rc = venc_set_multislicing_mode(client_ctx, ctrl->id,
 				ctrl->value);
 		break;
-	case V4L2_CID_MPEG_QCOM_SET_PERF_LEVEL:
+	case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
 		rc = venc_set_max_perf_level(client_ctx, ctrl->value);
 		break;
 	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 +2406,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 +2553,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/enc-venus-subdev.c b/drivers/media/video/msm_wfd/enc-venus-subdev.c
index 150c667..0f3ed58 100644
--- a/drivers/media/video/msm_wfd/enc-venus-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-venus-subdev.c
@@ -136,7 +136,7 @@
 
 			msm_vidc_dqevent(inst->vidc_context, &event);
 			if (event.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) {
-				WFD_MSG_ERR("enc callback thread shutting " \
+				WFD_MSG_DBG("enc callback thread shutting " \
 						"down normally\n");
 				bail_out = true;
 			} else {
@@ -240,6 +240,18 @@
 	return 0;
 }
 
+static long set_default_properties(struct venc_inst *inst)
+{
+	struct v4l2_control ctrl = {0};
+
+	/* Set the IDR period as 1.  The venus core doesn't give
+	 * the sps/pps for I-frames, only IDR. */
+	ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD;
+	ctrl.value = 1;
+
+	return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
+}
+
 static long venc_open(struct v4l2_subdev *sd, void *arg)
 {
 	struct venc_inst *inst = NULL;
@@ -489,6 +501,9 @@
 
 	inst = (struct venc_inst *)sd->dev_priv;
 
+	if (set_default_properties(inst))
+		WFD_MSG_WARN("Couldn't set default properties\n");
+
 	rc = msm_vidc_streamon(inst->vidc_context, BUF_TYPE_OUTPUT);
 	if (rc) {
 		WFD_MSG_ERR("Failed to streamon vidc's output port");
@@ -1049,7 +1064,6 @@
 static long venc_set_property(struct v4l2_subdev *sd, void *arg)
 {
 	struct venc_inst *inst = NULL;
-	struct v4l2_control *ctrl = arg;
 
 	if (!sd) {
 		WFD_MSG_ERR("Subdevice required for %s\n", __func__);
@@ -1057,13 +1071,6 @@
 	}
 
 	inst = (struct venc_inst *)sd->dev_priv;
-	if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEADER_MODE) {
-		/* XXX: We don't support this yet, but to prevent unncessary
-		 * target specific code for the client, we'll not error out.
-		 * The client ideally shouldn't notice this */
-		return 0;
-	}
-
 	return msm_vidc_s_ctrl(inst->vidc_context, (struct v4l2_control *)arg);
 }
 
@@ -1141,6 +1148,15 @@
 	return 0;
 }
 
+static long venc_set_framerate_mode(struct v4l2_subdev *sd,
+				void *arg)
+{
+	/* TODO: Unsupported for now, but return false success
+	 * to preserve binary compatibility for userspace apps
+	 * across targets */
+	return 0;
+}
+
 long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	long rc = 0;
@@ -1210,6 +1226,9 @@
 	case ENC_MUNMAP:
 		rc = venc_munmap(sd, arg);
 		break;
+	case SET_FRAMERATE_MODE:
+		rc = venc_set_framerate_mode(sd, arg);
+		break;
 	default:
 		WFD_MSG_ERR("Unknown ioctl %d to enc-subdev\n", cmd);
 		rc = -ENOTSUPP;
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 5f67a96..74194ff 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,
@@ -508,7 +536,7 @@
 	struct mem_region mregion;
 
 	if (minfo == NULL) {
-		WFD_MSG_ERR("not freeing buffers since allocation failed");
+		WFD_MSG_DBG("not freeing buffers since allocation failed");
 		return;
 	}
 
@@ -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) {
@@ -1097,7 +1126,8 @@
 			goto set_parm_fail;
 
 		max_frame_interval = (int64_t)frameskip.maxframeinterval;
-		mode = VSG_MODE_VFR;
+		vsg_mode = VSG_MODE_VFR;
+		venc_mode = VENC_MODE_VFR;
 
 		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
 				ioctl, VSG_SET_MAX_FRAME_INTERVAL,
@@ -1105,19 +1135,24 @@
 
 		if (rc)
 			goto set_parm_fail;
-
-		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
-				ioctl, VSG_SET_MODE, &mode);
-
-		if (rc)
-			goto set_parm_fail;
 	} else {
-		mode = VSG_MODE_CFR;
-		rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
-				ioctl, VSG_SET_MODE, &mode);
+		vsg_mode = VSG_MODE_CFR;
+		venc_mode = VENC_MODE_CFR;
+	}
 
-		if (rc)
-			goto set_parm_fail;
+	rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
+			ioctl, VSG_SET_MODE, &vsg_mode);
+	if (rc) {
+		WFD_MSG_ERR("Setting FR mode for VSG failed\n");
+		goto set_parm_fail;
+	}
+
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+			ioctl, SET_FRAMERATE_MODE,
+			&venc_mode);
+	if (rc) {
+		WFD_MSG_ERR("Setting FR mode for VENC failed\n");
+		goto set_parm_fail;
 	}
 
 set_parm_fail:
diff --git a/drivers/media/video/msm_wfd/wfd-util.c b/drivers/media/video/msm_wfd/wfd-util.c
index 5c00e5c..28a6084 100644
--- a/drivers/media/video/msm_wfd/wfd-util.c
+++ b/drivers/media/video/msm_wfd/wfd-util.c
@@ -198,7 +198,7 @@
 
 int wfd_stats_deinit(struct wfd_stats *stats)
 {
-	WFD_MSG_ERR("Latencies: avg enc. latency %d",
+	WFD_MSG_DBG("Latencies: avg enc. latency %d",
 			stats->enc_avg_latency);
 	/* Delete all debugfs files in one shot :) */
 	if (stats->d_parent)
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 47b36ae..4012fec 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -252,6 +252,7 @@
 	static const char * const header_mode[] = {
 		"Separate Buffer",
 		"Joined With 1st Frame",
+		"Joined With I-Frames",
 		NULL,
 	};
 	static const char * const multi_slice[] = {
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/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 5161b7b..06891899 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -166,17 +166,22 @@
 void update_nr_value(struct vcap_dev *dev)
 {
 	struct nr_param *par;
+	uint32_t val = 0;
 	par = &dev->nr_param;
 	if (par->mode == NR_MANUAL) {
 		writel_relaxed(par->window << 24 | par->decay_ratio << 20,
 			VCAP_VP_NR_CONFIG);
-		writel_relaxed(par->luma.max_blend_ratio << 24 |
+		if (par->threshold)
+			val = VP_NR_DYNAMIC_THRESHOLD;
+		writel_relaxed(val |
+			par->luma.max_blend_ratio << 24 |
 			par->luma.scale_diff_ratio << 12 |
 			par->luma.diff_limit_ratio << 8  |
 			par->luma.scale_motion_ratio << 4 |
 			par->luma.blend_limit_ratio << 0,
 			VCAP_VP_NR_LUMA_CONFIG);
-		writel_relaxed(par->chroma.max_blend_ratio << 24 |
+		writel_relaxed(val |
+			par->chroma.max_blend_ratio << 24 |
 			par->chroma.scale_diff_ratio << 12 |
 			par->chroma.diff_limit_ratio << 8  |
 			par->chroma.scale_motion_ratio << 4 |
@@ -646,6 +651,9 @@
 	param->decay_ratio = BITS_VALUE(rc, 20, 3);
 
 	rc = readl_relaxed(VCAP_VP_NR_LUMA_CONFIG);
+	param->threshold = NR_THRESHOLD_STATIC;
+	if (BITS_VALUE(rc, 16, 1))
+		param->threshold = NR_THRESHOLD_DYNAMIC;
 	param->luma.max_blend_ratio = BITS_VALUE(rc, 24, 4);
 	param->luma.scale_diff_ratio = BITS_VALUE(rc, 12, 4);
 	param->luma.diff_limit_ratio = BITS_VALUE(rc, 8, 4);
@@ -662,6 +670,7 @@
 
 void s_default_nr_val(struct nr_param *param)
 {
+	param->threshold = NR_THRESHOLD_STATIC;
 	param->window = 10;
 	param->decay_ratio = 0;
 	param->luma.max_blend_ratio = 0;
diff --git a/drivers/media/video/vcap_vp.h b/drivers/media/video/vcap_vp.h
index 2ad5848..70b10c3 100644
--- a/drivers/media/video/vcap_vp.h
+++ b/drivers/media/video/vcap_vp.h
@@ -90,6 +90,7 @@
 
 #define VP_NR_MAX_WINDOW 120
 #define VP_NR_MAX_RATIO  16
+#define VP_NR_DYNAMIC_THRESHOLD 0x000F0000
 
 #define BITS_MASK(start, num_of_bits) \
 	(((1 << (num_of_bits)) - 1) << (start))
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index fa7c116..d43b399 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -37,6 +37,14 @@
 #define SITAR_I2C_MODE	0x01
 #define CODEC_DT_MAX_PROP_SIZE   40
 #define WCD9XXX_I2C_GSBI_SLAVE_ID "3-000d"
+#define WCD9XXX_I2C_TOP_SLAVE_ADDR	0x0d
+#define WCD9XXX_ANALOG_I2C_SLAVE_ADDR	0x77
+#define WCD9XXX_DIGITAL1_I2C_SLAVE_ADDR	0x66
+#define WCD9XXX_DIGITAL2_I2C_SLAVE_ADDR	0x55
+#define WCD9XXX_I2C_TOP_LEVEL	0
+#define WCD9XXX_I2C_ANALOG	1
+#define WCD9XXX_I2C_DIGITAL_1	2
+#define WCD9XXX_I2C_DIGITAL_2	3
 
 struct wcd9xxx_i2c {
 	struct i2c_client *client;
@@ -644,10 +652,11 @@
 	kfree(wcd9xxx->supplies);
 }
 
-int wcd9xxx_get_intf_type(void)
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
 {
 	return wcd9xxx_intf;
 }
+
 EXPORT_SYMBOL_GPL(wcd9xxx_get_intf_type);
 
 struct wcd9xxx_i2c *get_i2c_wcd9xxx_device_info(u16 reg)
@@ -768,100 +777,146 @@
 	return wcd9xxx_i2c_write_device(reg, src, bytes);
 }
 
+static int wcd9xxx_i2c_get_client_index(struct i2c_client *client,
+					int *wcd9xx_index)
+{
+	int ret = 0;
+	switch (client->addr) {
+	case WCD9XXX_I2C_TOP_SLAVE_ADDR:
+		*wcd9xx_index = WCD9XXX_I2C_TOP_LEVEL;
+	break;
+	case WCD9XXX_ANALOG_I2C_SLAVE_ADDR:
+		*wcd9xx_index = WCD9XXX_I2C_ANALOG;
+	break;
+	case WCD9XXX_DIGITAL1_I2C_SLAVE_ADDR:
+		*wcd9xx_index = WCD9XXX_I2C_DIGITAL_1;
+	break;
+	case WCD9XXX_DIGITAL2_I2C_SLAVE_ADDR:
+		*wcd9xx_index = WCD9XXX_I2C_DIGITAL_2;
+	break;
+	default:
+		ret = -EINVAL;
+	break;
+	}
+	return ret;
+}
+
 static int __devinit wcd9xxx_i2c_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
-	struct wcd9xxx *wcd9xxx;
-	struct wcd9xxx_pdata *pdata;
+	struct wcd9xxx *wcd9xxx = NULL;
+	struct wcd9xxx_pdata *pdata = NULL;
 	int val = 0;
 	int ret = 0;
 	int i2c_mode = 0;
-	static int device_id;
+	int wcd9xx_index = 0;
 	struct device *dev;
 
-	pr_info("%s\n", __func__);
+	pr_debug("%s: interface status %d\n", __func__, wcd9xxx_intf);
 	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
 		dev_dbg(&client->dev, "%s:Codec is detected in slimbus mode\n",
-			 __func__);
+			__func__);
 		return -ENODEV;
-	}
-	if (device_id > 0) {
-		wcd9xxx_modules[device_id++].client = client;
-		dev_dbg(&client->dev, "%s:probe for other slaves\n"
-			"devices of codec\n", __func__);
+	} else if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_I2C) {
+		ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
+		if (ret != 0)
+			dev_err(&client->dev, "%s: I2C set codec I2C\n"
+				"client failed\n", __func__);
+		else {
+			dev_err(&client->dev, "%s:probe for other slaves\n"
+				"devices of codec I2C slave Addr = %x\n",
+				__func__, client->addr);
+			wcd9xxx_modules[wcd9xx_index].client = client;
+		}
 		return ret;
-	}
-	dev = &client->dev;
-	if (client->dev.of_node) {
-		dev_dbg(&client->dev, "%s:Platform data from device tree\n",
-			__func__);
-		pdata = wcd9xxx_populate_dt_pdata(&client->dev);
-		client->dev.platform_data = pdata;
-	} else {
-		dev_dbg(&client->dev, "%s:Platform data from board file\n",
-			__func__);
-		pdata = client->dev.platform_data;
-	}
-	wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
-	if (wcd9xxx == NULL) {
-		pr_err("%s: error, allocation failed\n", __func__);
-		ret = -ENOMEM;
-		goto fail;
-	}
+	} else if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_PROBING) {
+		dev = &client->dev;
+		if (client->dev.of_node) {
+			dev_dbg(&client->dev, "%s:Platform data\n"
+				"from device tree\n", __func__);
+			pdata = wcd9xxx_populate_dt_pdata(&client->dev);
+			client->dev.platform_data = pdata;
+		} else {
+			dev_dbg(&client->dev, "%s:Platform data from\n"
+				"board file\n", __func__);
+			pdata = client->dev.platform_data;
+		}
+		wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
+		if (wcd9xxx == NULL) {
+			pr_err("%s: error, allocation failed\n", __func__);
+			ret = -ENOMEM;
+			goto fail;
+		}
 
-	if (!pdata) {
-		dev_dbg(&client->dev, "no platform data?\n");
-		ret = -EINVAL;
-		goto fail;
-	}
-	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
-		dev_dbg(&client->dev, "can't talk I2C?\n");
-		ret = -EIO;
-		goto fail;
-	}
-	dev_set_drvdata(&client->dev, wcd9xxx);
-	wcd9xxx->dev = &client->dev;
-	wcd9xxx->reset_gpio = pdata->reset_gpio;
-	ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
-	if (ret) {
-		pr_err("%s: Fail to enable Codec supplies\n", __func__);
-		goto err_codec;
-	}
+		if (!pdata) {
+			dev_dbg(&client->dev, "no platform data?\n");
+			ret = -EINVAL;
+			goto fail;
+		}
+		if (i2c_check_functionality(client->adapter,
+					    I2C_FUNC_I2C) == 0) {
+			dev_dbg(&client->dev, "can't talk I2C?\n");
+			ret = -EIO;
+			goto fail;
+		}
+		dev_set_drvdata(&client->dev, wcd9xxx);
+		wcd9xxx->dev = &client->dev;
+		wcd9xxx->reset_gpio = pdata->reset_gpio;
+		if (client->dev.of_node)
+			wcd9xxx->mclk_rate = pdata->mclk_rate;
+		ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
+		if (ret) {
+			pr_err("%s: Fail to enable Codec supplies\n",
+			       __func__);
+			goto err_codec;
+		}
 
-	usleep_range(5, 5);
-	ret = wcd9xxx_reset(wcd9xxx);
-	if (ret) {
-		pr_err("%s: Resetting Codec failed\n", __func__);
+		usleep_range(5, 5);
+		ret = wcd9xxx_reset(wcd9xxx);
+		if (ret) {
+			pr_err("%s: Resetting Codec failed\n", __func__);
 		goto err_supplies;
-	}
-	wcd9xxx_modules[device_id++].client = client;
+		}
 
-	wcd9xxx->read_dev = wcd9xxx_i2c_read;
-	wcd9xxx->write_dev = wcd9xxx_i2c_write;
-	if (!wcd9xxx->dev->of_node) {
-		wcd9xxx->irq = pdata->irq;
-		wcd9xxx->irq_base = pdata->irq_base;
-	}
+		ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
+		if (ret != 0) {
+			pr_err("%s:Set codec I2C client failed\n", __func__);
+			goto err_supplies;
+		}
 
-	ret = wcd9xxx_device_init(wcd9xxx);
-	if (ret) {
-		pr_err("%s: error, initializing device failed\n", __func__);
-		goto err_device_init;
-	}
+		wcd9xxx_modules[wcd9xx_index].client = client;
+		wcd9xxx->read_dev = wcd9xxx_i2c_read;
+		wcd9xxx->write_dev = wcd9xxx_i2c_write;
+		if (!wcd9xxx->dev->of_node) {
+			wcd9xxx->irq = pdata->irq;
+			wcd9xxx->irq_base = pdata->irq_base;
+		}
 
-	if ((wcd9xxx->idbyte[0] == 0x2) || (wcd9xxx->idbyte[0] == 0x1))
-		i2c_mode = TABLA_I2C_MODE;
-	else if (wcd9xxx->idbyte[0] == 0x0)
-		i2c_mode = SITAR_I2C_MODE;
+		ret = wcd9xxx_device_init(wcd9xxx);
+		if (ret) {
+			pr_err("%s: error, initializing device failed\n",
+			       __func__);
+			goto err_device_init;
+		}
 
-	ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+		if ((wcd9xxx->idbyte[0] == 0x2) || (wcd9xxx->idbyte[0] == 0x1))
+			i2c_mode = TABLA_I2C_MODE;
+		else if (wcd9xxx->idbyte[0] == 0x0)
+			i2c_mode = SITAR_I2C_MODE;
 
-	if ((ret < 0) || (val != i2c_mode))
-		pr_err("failed to read the wcd9xxx status ret = %d\n", ret);
+		ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+
+		if ((ret < 0) || (val != i2c_mode))
+			pr_err("failed to read the wcd9xxx status ret = %d\n",
+			       ret);
 
 	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
 
-	return ret;
+		return ret;
+	} else
+		pr_err("%s: I2C probe in wrong state\n", __func__);
+
+
 err_device_init:
 	wcd9xxx_free_reset(wcd9xxx);
 err_supplies:
@@ -1087,6 +1142,7 @@
 	int ret, i;
 	char **codec_supplies;
 	u32 num_of_supplies = 0;
+	u32 mclk_rate = 0;
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata) {
@@ -1130,6 +1186,19 @@
 		goto err;
 	}
 	dev_dbg(dev, "%s: reset gpio %d", __func__, pdata->reset_gpio);
+	ret = of_property_read_u32(dev->of_node,
+				   "qcom,cdc-mclk-clk-rate",
+				   &mclk_rate);
+	if (ret) {
+		dev_err(dev, "Looking up %s property in\n"
+			"node %s failed",
+			"qcom,cdc-mclk-clk-rate",
+			dev->of_node->full_name);
+		devm_kfree(dev, pdata);
+		ret = -EINVAL;
+		goto err;
+	}
+	pdata->mclk_rate = mclk_rate;
 	return pdata;
 err:
 	devm_kfree(dev, pdata);
@@ -1162,6 +1231,11 @@
 	struct wcd9xxx_pdata *pdata;
 	int ret = 0;
 
+	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_I2C) {
+		dev_dbg(&slim->dev, "%s:Codec is detected in I2C mode\n",
+			__func__);
+		return -ENODEV;
+	}
 	if (slim->dev.of_node) {
 		dev_info(&slim->dev, "Platform data from device tree\n");
 		pdata = wcd9xxx_populate_dt_pdata(&slim->dev);
@@ -1201,6 +1275,7 @@
 	slim_set_clientdata(slim, wcd9xxx);
 	wcd9xxx->reset_gpio = pdata->reset_gpio;
 	wcd9xxx->dev = &slim->dev;
+	wcd9xxx->mclk_rate = pdata->mclk_rate;
 
 	ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
 	if (ret)
@@ -1477,11 +1552,6 @@
 	.suspend = wcd9xxx_slim_suspend,
 };
 
-#define WCD9XXX_I2C_TOP_LEVEL	0
-#define WCD9XXX_I2C_ANALOG	1
-#define WCD9XXX_I2C_DIGITAL_1	2
-#define WCD9XXX_I2C_DIGITAL_2	3
-
 static struct i2c_device_id wcd9xxx_id_table[] = {
 	{"wcd9xxx-i2c", WCD9XXX_I2C_TOP_LEVEL},
 	{"wcd9xxx-i2c", WCD9XXX_I2C_ANALOG},
@@ -1528,6 +1598,8 @@
 {
 	int ret1, ret2, ret3, ret4, ret5, ret6, ret7;
 
+	wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_PROBING;
+
 	ret1 = slim_driver_register(&tabla_slim_driver);
 	if (ret1 != 0)
 		pr_err("Failed to register tabla SB driver: %d\n", ret1);
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index 6c3e787..604ffd7 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -42,7 +42,7 @@
 	struct hrtimer timer;
 	struct timed_output_dev dev;
 	struct work_struct work;
-	spinlock_t lock;
+	struct mutex lock;
 	unsigned int enable;
 	unsigned int period_ns;
 	bool is_len_gpio_valid;
@@ -216,9 +216,8 @@
 {
 	struct isa1200_chip *haptic = container_of(dev, struct isa1200_chip,
 					dev);
-	unsigned long flags;
 
-	spin_lock_irqsave(&haptic->lock, flags);
+	mutex_lock(&haptic->lock);
 	hrtimer_cancel(&haptic->timer);
 	if (value == 0)
 		haptic->enable = 0;
@@ -230,7 +229,7 @@
 			ktime_set(value / 1000, (value % 1000) * 1000000),
 			HRTIMER_MODE_REL);
 	}
-	spin_unlock_irqrestore(&haptic->lock, flags);
+	mutex_unlock(&haptic->lock);
 	schedule_work(&haptic->work);
 }
 
@@ -501,7 +500,7 @@
 		}
 	}
 
-	spin_lock_init(&haptic->lock);
+	mutex_init(&haptic->lock);
 	INIT_WORK(&haptic->work, isa1200_chip_work);
 	haptic->clk_on = false;
 
@@ -591,6 +590,7 @@
 hen_gpio_fail:
 	timed_output_dev_unregister(&haptic->dev);
 timed_reg_fail:
+	mutex_destroy(&haptic->lock);
 	if (pdata->power_on)
 		pdata->power_on(0);
 pwr_up_fail:
@@ -637,6 +637,9 @@
 				ISA1200_HCTRL1_RESET);
 
 
+	/* destroy mutex */
+	mutex_destroy(&haptic->lock);
+
 	/* power-off the chip */
 	if (haptic->pdata->regulator_info) {
 		isa1200_reg_power(haptic, false);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 3715417..c415952 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -235,6 +235,8 @@
 	uint32_t user_virt_sb_base;
 	size_t sb_length;
 	struct ion_handle *ihandle;		/* Retrieve phy addr */
+	bool  perf_enabled;
+	bool  fast_load_enabled;
 };
 
 struct qseecom_listener_handle {
@@ -266,8 +268,8 @@
 };
 
 /* Function proto types */
-static int qsee_vote_for_clock(int32_t);
-static void qsee_disable_clock_vote(int32_t);
+static int qsee_vote_for_clock(struct qseecom_dev_handle *, int32_t);
+static void qsee_disable_clock_vote(struct qseecom_dev_handle *, int32_t);
 
 static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
 		struct qseecom_register_listener_req *svc)
@@ -701,7 +703,7 @@
 		return -EFAULT;
 	}
 	/* Vote for the SFPB clock */
-	ret = qsee_vote_for_clock(CLK_SFPB);
+	ret = qsee_vote_for_clock(data, CLK_SFPB);
 	if (ret)
 		pr_warning("Unable to vote for SFPB clock");
 	req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
@@ -734,7 +736,7 @@
 					load_img_req.ifd_data_fd);
 		if (IS_ERR_OR_NULL(ihandle)) {
 			pr_err("Ion client could not retrieve the handle\n");
-			qsee_disable_clock_vote(CLK_SFPB);
+			qsee_disable_clock_vote(data, CLK_SFPB);
 			return -ENOMEM;
 		}
 
@@ -762,7 +764,7 @@
 			pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
-			qsee_disable_clock_vote(CLK_SFPB);
+			qsee_disable_clock_vote(data, CLK_SFPB);
 			return -EFAULT;
 		}
 
@@ -773,7 +775,7 @@
 					ret);
 				if (!IS_ERR_OR_NULL(ihandle))
 					ion_free(qseecom.ion_clnt, ihandle);
-				qsee_disable_clock_vote(CLK_SFPB);
+				qsee_disable_clock_vote(data, CLK_SFPB);
 				return ret;
 			}
 		}
@@ -783,7 +785,7 @@
 				resp.result);
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
-			qsee_disable_clock_vote(CLK_SFPB);
+			qsee_disable_clock_vote(data, CLK_SFPB);
 			return -EFAULT;
 		}
 
@@ -792,7 +794,7 @@
 		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 		if (!entry) {
 			pr_err("kmalloc failed\n");
-			qsee_disable_clock_vote(CLK_SFPB);
+			qsee_disable_clock_vote(data, CLK_SFPB);
 			return -ENOMEM;
 		}
 		entry->app_id = app_id;
@@ -815,10 +817,10 @@
 	if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
 		pr_err("copy_to_user failed\n");
 		kzfree(entry);
-		qsee_disable_clock_vote(CLK_SFPB);
+		qsee_disable_clock_vote(data, CLK_SFPB);
 		return -EFAULT;
 	}
-	qsee_disable_clock_vote(CLK_SFPB);
+	qsee_disable_clock_vote(data, CLK_SFPB);
 	return 0;
 }
 
@@ -1411,7 +1413,7 @@
 	/* Populate the remaining parameters */
 	load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
 	memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
-	ret = qsee_vote_for_clock(CLK_SFPB);
+	ret = qsee_vote_for_clock(data, CLK_SFPB);
 	if (ret) {
 		kzfree(img_data);
 		pr_warning("Unable to vote for SFPB clock");
@@ -1425,7 +1427,7 @@
 	kzfree(img_data);
 	if (ret) {
 		pr_err("scm_call to load failed : ret %d\n", ret);
-		qsee_disable_clock_vote(CLK_SFPB);
+		qsee_disable_clock_vote(data, CLK_SFPB);
 		return -EIO;
 	}
 
@@ -1448,7 +1450,7 @@
 		ret = -EINVAL;
 		break;
 	}
-	qsee_disable_clock_vote(CLK_SFPB);
+	qsee_disable_clock_vote(data, CLK_SFPB);
 
 	return ret;
 }
@@ -1713,6 +1715,10 @@
 		pr_err("Unable to find the handle, exiting\n");
 	else
 		ret = qseecom_unload_app(data);
+	if (data->client.fast_load_enabled == true)
+		qsee_disable_clock_vote(data, CLK_SFPB);
+	if (data->client.perf_enabled == true)
+		qsee_disable_clock_vote(data, CLK_DFAB);
 	if (ret == 0) {
 		kzfree(data);
 		kzfree(*handle);
@@ -1770,9 +1776,9 @@
 		return -EINVAL;
 	}
 	if (high)
-		return qsee_vote_for_clock(CLK_DFAB);
+		return qsee_vote_for_clock(handle->dev, CLK_DFAB);
 	else {
-		qsee_disable_clock_vote(CLK_DFAB);
+		qsee_disable_clock_vote(handle->dev, CLK_DFAB);
 		return 0;
 	}
 }
@@ -1802,7 +1808,8 @@
 	return 0;
 }
 
-static int qsee_vote_for_clock(int32_t clk_type)
+static int qsee_vote_for_clock(struct qseecom_dev_handle *data,
+						int32_t clk_type)
 {
 	int ret = 0;
 
@@ -1826,10 +1833,13 @@
 			if (ret)
 				pr_err("DFAB Bandwidth req failed (%d)\n",
 								ret);
-			else
+			else {
 				qsee_bw_count++;
+				data->client.perf_enabled = true;
+			}
 		} else {
 			qsee_bw_count++;
+			data->client.perf_enabled = true;
 		}
 		mutex_unlock(&qsee_bw_mutex);
 		break;
@@ -1850,10 +1860,13 @@
 			if (ret)
 				pr_err("SFPB Bandwidth req failed (%d)\n",
 								ret);
-			else
+			else {
 				qsee_sfpb_bw_count++;
+				data->client.fast_load_enabled = true;
+			}
 		} else {
 			qsee_sfpb_bw_count++;
+			data->client.fast_load_enabled = true;
 		}
 		mutex_unlock(&qsee_bw_mutex);
 		break;
@@ -1864,7 +1877,8 @@
 	return ret;
 }
 
-static void qsee_disable_clock_vote(int32_t clk_type)
+static void qsee_disable_clock_vote(struct qseecom_dev_handle *data,
+						int32_t clk_type)
 {
 	int32_t ret = 0;
 
@@ -1880,7 +1894,7 @@
 			return;
 		}
 
-		if ((qsee_bw_count > 0) && (qsee_bw_count-- == 1)) {
+		if (qsee_bw_count == 1) {
 			if (qsee_sfpb_bw_count > 0)
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 2);
@@ -1894,6 +1908,13 @@
 			if (ret)
 				pr_err("SFPB Bandwidth req fail (%d)\n",
 								ret);
+			else {
+				qsee_bw_count--;
+				data->client.perf_enabled = false;
+			}
+		} else {
+			qsee_bw_count--;
+			data->client.perf_enabled = false;
 		}
 		mutex_unlock(&qsee_bw_mutex);
 		break;
@@ -1904,7 +1925,7 @@
 			mutex_unlock(&qsee_bw_mutex);
 			return;
 		}
-		if ((qsee_sfpb_bw_count > 0) && (qsee_sfpb_bw_count-- == 1)) {
+		if (qsee_sfpb_bw_count == 1) {
 			if (qsee_bw_count > 0)
 				ret = msm_bus_scale_client_update_request(
 						qsee_perf_client, 1);
@@ -1918,6 +1939,13 @@
 			if (ret)
 				pr_err("SFPB Bandwidth req fail (%d)\n",
 								ret);
+			else {
+				qsee_sfpb_bw_count--;
+				data->client.fast_load_enabled = false;
+			}
+		} else {
+			qsee_sfpb_bw_count--;
+			data->client.fast_load_enabled = false;
 		}
 		mutex_unlock(&qsee_bw_mutex);
 		break;
@@ -2246,7 +2274,7 @@
 	}
 	case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
 		atomic_inc(&data->ioctl_count);
-		ret = qsee_vote_for_clock(CLK_DFAB);
+		ret = qsee_vote_for_clock(data, CLK_DFAB);
 		if (ret)
 			pr_err("Failed to vote for DFAB clock%d\n", ret);
 		atomic_dec(&data->ioctl_count);
@@ -2254,7 +2282,7 @@
 	}
 	case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
 		atomic_inc(&data->ioctl_count);
-		qsee_disable_clock_vote(CLK_DFAB);
+		qsee_disable_clock_vote(data, CLK_DFAB);
 		atomic_dec(&data->ioctl_count);
 		break;
 	}
@@ -2356,6 +2384,11 @@
 			return ret;
 		}
 	}
+	if (data->client.fast_load_enabled == true)
+		qsee_disable_clock_vote(data, CLK_SFPB);
+	if (data->client.perf_enabled == true)
+		qsee_disable_clock_vote(data, CLK_DFAB);
+
 	if (qseecom.qseos_version == QSEOS_VERSION_13) {
 		mutex_lock(&pil_access_lock);
 		if (pil_ref_cnt == 1)
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index bde25d9..31f18ed 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.c
@@ -16,6 +16,9 @@
 #include <linux/regulator/consumer.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/smsc3503.h>
@@ -28,12 +31,16 @@
 SMSC3503_I2C_ADDR, I2C_CLIENT_END };
 
 struct hsic_hub {
-	struct regulator *hsic_hub_reg;
 	struct device *dev;
+	struct smsc_hub_platform_data *pdata;
 	struct i2c_client *client;
 	struct msm_xo_voter *xo_handle;
+	struct clk		*ref_clk;
+	struct regulator	*hsic_hub_reg;
+	struct regulator	*int_pad_reg, *hub_vbus_reg;
 };
 static struct hsic_hub *smsc_hub;
+static struct platform_driver smsc_hub_driver;
 
 /* APIs for setting/clearing bits and for reading/writing values */
 static inline int hsic_hub_get_u8(struct i2c_client *client, u8 reg)
@@ -150,16 +157,208 @@
 	.id_table = hsic_hub_id,
 };
 
+static int msm_hsic_hub_init_clock(struct hsic_hub *hub, int init)
+{
+	int ret;
+
+	if (!init) {
+		if (!IS_ERR(hub->ref_clk))
+			clk_disable_unprepare(hub->ref_clk);
+		else
+			msm_xo_put(smsc_hub->xo_handle);
+
+		return 0;
+	}
+
+	hub->ref_clk = devm_clk_get(hub->dev, "ref_clk");
+	if (IS_ERR(hub->ref_clk)) {
+		dev_dbg(hub->dev, "failed to get ref_clk\n");
+
+		/* In the absence of dedicated ref_clk, xo clocks the HUB */
+		smsc_hub->xo_handle = msm_xo_get(MSM_XO_TCXO_D1, "hsic_hub");
+		if (IS_ERR(smsc_hub->xo_handle)) {
+			dev_err(hub->dev, "not able to get the handle\n"
+						 "for TCXO D1 buffer\n");
+			return PTR_ERR(smsc_hub->xo_handle);
+		}
+
+		ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
+		if (ret) {
+			dev_err(hub->dev, "failed to vote for TCXO\n"
+				"D1 buffer\n");
+			msm_xo_put(smsc_hub->xo_handle);
+			return ret;
+		}
+	} else {
+		ret = clk_prepare_enable(hub->ref_clk);
+		if (ret)
+			dev_err(hub->dev, "clk_enable failed for ref_clk\n");
+	}
+
+	return ret;
+}
+#define HSIC_HUB_INT_VOL_MIN	1800000 /* uV */
+#define HSIC_HUB_INT_VOL_MAX	2950000 /* uV */
+static int msm_hsic_hub_init_gpio(struct hsic_hub *hub, int init)
+{
+	int ret;
+	struct smsc_hub_platform_data *pdata = hub->pdata;
+
+	if (!init) {
+		if (!IS_ERR(smsc_hub->int_pad_reg)) {
+			regulator_disable(smsc_hub->int_pad_reg);
+			regulator_set_voltage(smsc_hub->int_pad_reg, 0,
+						HSIC_HUB_INT_VOL_MAX);
+		}
+		return 0;
+	}
+
+	ret = devm_gpio_request(hub->dev, pdata->hub_reset, "HSIC_HUB_RESET");
+	if (ret < 0) {
+		dev_err(hub->dev, "gpio request failed for GPIO%d\n",
+							pdata->hub_reset);
+		return ret;
+	}
+
+	if (pdata->refclk_gpio) {
+		ret = devm_gpio_request(hub->dev, pdata->refclk_gpio,
+							 "HSIC_HUB_CLK");
+		if (ret < 0)
+			dev_err(hub->dev, "gpio request failed (CLK GPIO)\n");
+	}
+
+	if (pdata->int_gpio) {
+		ret = devm_gpio_request(hub->dev, pdata->int_gpio,
+							 "HSIC_HUB_INT");
+		if (ret < 0) {
+			dev_err(hub->dev, "gpio request failed (INT GPIO)\n");
+			return ret;
+		}
+
+		/* Enable LDO if required for external pull-up */
+		smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub_int");
+		if (IS_ERR(smsc_hub->int_pad_reg)) {
+			dev_dbg(hub->dev, "unable to get ext hub_int reg\n");
+		} else {
+			ret = regulator_set_voltage(smsc_hub->int_pad_reg,
+						HSIC_HUB_INT_VOL_MIN,
+						HSIC_HUB_INT_VOL_MAX);
+			if (ret) {
+				dev_err(hub->dev, "unable to set the voltage\n"
+						" for hsic hub int reg\n");
+				return ret;
+			}
+			ret = regulator_enable(smsc_hub->int_pad_reg);
+			if (ret) {
+				dev_err(hub->dev, "unable to enable int reg\n");
+				regulator_set_voltage(smsc_hub->int_pad_reg, 0,
+							HSIC_HUB_INT_VOL_MAX);
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
 #define HSIC_HUB_VDD_VOL_MIN	1650000 /* uV */
 #define HSIC_HUB_VDD_VOL_MAX	1950000 /* uV */
 #define HSIC_HUB_VDD_LOAD	36000	/* uA */
+static int msm_hsic_hub_init_vdd(struct hsic_hub *hub, int init)
+{
+	int ret;
+
+	if (!init) {
+		if (!IS_ERR(smsc_hub->hsic_hub_reg)) {
+			regulator_disable(smsc_hub->hsic_hub_reg);
+			regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
+			regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
+							HSIC_HUB_VDD_VOL_MAX);
+		}
+		return 0;
+	}
+
+	smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "EXT_HUB_VDDIO");
+	if (IS_ERR(smsc_hub->hsic_hub_reg)) {
+		dev_dbg(hub->dev, "unable to get ext hub vddcx\n");
+	} else {
+		ret = regulator_set_voltage(smsc_hub->hsic_hub_reg,
+				HSIC_HUB_VDD_VOL_MIN,
+				HSIC_HUB_VDD_VOL_MAX);
+		if (ret) {
+			dev_err(hub->dev, "unable to set the voltage\n"
+						"for hsic hub reg\n");
+			return ret;
+		}
+
+		ret = regulator_set_optimum_mode(smsc_hub->hsic_hub_reg,
+					HSIC_HUB_VDD_LOAD);
+		if (ret < 0) {
+			dev_err(hub->dev, "Unable to set mode of VDDCX\n");
+			goto reg_optimum_mode_fail;
+		}
+
+		ret = regulator_enable(smsc_hub->hsic_hub_reg);
+		if (ret) {
+			dev_err(hub->dev, "unable to enable ext hub vddcx\n");
+			goto reg_enable_fail;
+		}
+	}
+
+	return 0;
+
+reg_enable_fail:
+	regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
+reg_optimum_mode_fail:
+	regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
+				HSIC_HUB_VDD_VOL_MAX);
+
+	return ret;
+}
+struct smsc_hub_platform_data *msm_hub_dt_to_pdata(
+				struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct smsc_hub_platform_data *pdata;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(&pdev->dev, "unable to allocate platform data\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pdata->hub_reset = of_get_named_gpio(node, "smsc,reset-gpio", 0);
+	if (pdata->hub_reset < 0)
+		return ERR_PTR(pdata->hub_reset);
+
+	pdata->refclk_gpio = of_get_named_gpio(node, "smsc,refclk-gpio", 0);
+	if (pdata->refclk_gpio < 0)
+		pdata->refclk_gpio = 0;
+
+	pdata->int_gpio = of_get_named_gpio(node, "smsc,int-gpio", 0);
+	if (pdata->int_gpio < 0)
+		pdata->int_gpio = 0;
+
+	return pdata;
+}
+
 static int __devinit smsc_hub_probe(struct platform_device *pdev)
 {
 	int ret = 0;
 	const struct smsc_hub_platform_data *pdata;
+	struct device_node *node = pdev->dev.of_node;
 	struct i2c_adapter *i2c_adap;
 	struct i2c_board_info i2c_info;
 
+	if (pdev->dev.of_node) {
+		dev_dbg(&pdev->dev, "device tree enabled\n");
+		pdev->dev.platform_data = msm_hub_dt_to_pdata(pdev);
+		if (IS_ERR(pdev->dev.platform_data))
+			return PTR_ERR(pdev->dev.platform_data);
+
+		dev_set_name(&pdev->dev, smsc_hub_driver.driver.name);
+	}
+
 	if (!pdev->dev.platform_data) {
 		dev_err(&pdev->dev, "No platform data\n");
 		return -ENODEV;
@@ -169,59 +368,34 @@
 	if (!pdata->hub_reset)
 		return -EINVAL;
 
-	smsc_hub = kzalloc(sizeof(*smsc_hub), GFP_KERNEL);
+	smsc_hub = devm_kzalloc(&pdev->dev, sizeof(*smsc_hub), GFP_KERNEL);
 	if (!smsc_hub)
 		return -ENOMEM;
 
-	smsc_hub->hsic_hub_reg = regulator_get(&pdev->dev, "EXT_HUB_VDDIO");
-	if (IS_ERR(smsc_hub->hsic_hub_reg)) {
-		dev_err(&pdev->dev, "unable to get ext hub vddcx\n");
-		ret = PTR_ERR(smsc_hub->hsic_hub_reg);
-		goto free_mem;
+	smsc_hub->dev = &pdev->dev;
+	smsc_hub->pdata = pdev->dev.platform_data;
+
+	smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev, "hub_vbus");
+	ret = PTR_ERR(smsc_hub->hub_vbus_reg);
+	if (ret == -EPROBE_DEFER) {
+		dev_dbg(&pdev->dev, "failed to get hub_vbus\n");
+		return ret;
 	}
 
-	ret = gpio_request(pdata->hub_reset, "HSIC_HUB_RESET_GPIO");
-	if (ret < 0) {
-		dev_err(&pdev->dev, "gpio request failed for GPIO%d\n",
-							pdata->hub_reset);
-		goto gpio_req_fail;
-	}
-
-	ret = regulator_set_voltage(smsc_hub->hsic_hub_reg,
-			HSIC_HUB_VDD_VOL_MIN,
-			HSIC_HUB_VDD_VOL_MAX);
+	ret = msm_hsic_hub_init_vdd(smsc_hub, 1);
 	if (ret) {
-		dev_err(&pdev->dev, "unable to set the voltage"
-				"for hsic hub reg\n");
-		goto reg_set_voltage_fail;
+		dev_err(&pdev->dev, "failed to init hub VDD\n");
+		return ret;
 	}
-
-	ret = regulator_set_optimum_mode(smsc_hub->hsic_hub_reg,
-				HSIC_HUB_VDD_LOAD);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Unable to set optimum mode of regulator:"
-							"VDDCX\n");
-		goto reg_optimum_mode_fail;
-	}
-
-	ret = regulator_enable(smsc_hub->hsic_hub_reg);
+	ret = msm_hsic_hub_init_clock(smsc_hub, 1);
 	if (ret) {
-		dev_err(&pdev->dev, "unable to enable ext hub vddcx\n");
-		goto reg_enable_fail;
+		dev_err(&pdev->dev, "failed to init hub clock\n");
+		goto uninit_vdd;
 	}
-
-	smsc_hub->xo_handle = msm_xo_get(MSM_XO_TCXO_D1, "hsic_hub");
-	if (IS_ERR(smsc_hub->xo_handle)) {
-		dev_err(&pdev->dev, "not able to get the handle"
-					 "for TCXO D1 buffer\n");
-			goto disable_regulator;
-	}
-
-	ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
+	ret = msm_hsic_hub_init_gpio(smsc_hub, 1);
 	if (ret) {
-		dev_err(&pdev->dev, "failed to vote for TCXO"
-			"D1 buffer\n");
-		goto xo_vote_fail;
+		dev_err(&pdev->dev, "failed to init hub gpios\n");
+		goto uninit_clock;
 	}
 
 	gpio_direction_output(pdata->hub_reset, 0);
@@ -231,6 +405,20 @@
 	udelay(5);
 	gpio_direction_output(pdata->hub_reset, 1);
 
+	ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
+		goto uninit_gpio;
+	}
+
+	if (!IS_ERR(smsc_hub->hub_vbus_reg)) {
+		ret = regulator_enable(smsc_hub->hub_vbus_reg);
+		if (ret) {
+			dev_err(&pdev->dev, "unable to enable hub_vbus\n");
+			goto uninit_gpio;
+		}
+	}
+
 	ret = i2c_add_driver(&hsic_hub_driver);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to add I2C hsic_hub_driver\n");
@@ -261,21 +449,12 @@
 
 	return 0;
 
-xo_vote_fail:
-	msm_xo_put(smsc_hub->xo_handle);
-disable_regulator:
-	regulator_disable(smsc_hub->hsic_hub_reg);
-reg_enable_fail:
-	regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
-reg_optimum_mode_fail:
-	regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
-				HSIC_HUB_VDD_VOL_MIN);
-reg_set_voltage_fail:
-	gpio_free(pdata->hub_reset);
-gpio_req_fail:
-	regulator_put(smsc_hub->hsic_hub_reg);
-free_mem:
-	kfree(smsc_hub);
+uninit_gpio:
+	msm_hsic_hub_init_gpio(smsc_hub, 0);
+uninit_clock:
+	msm_hsic_hub_init_clock(smsc_hub, 0);
+uninit_vdd:
+	msm_hsic_hub_init_vdd(smsc_hub, 0);
 
 	return ret;
 }
@@ -291,15 +470,11 @@
 		i2c_del_driver(&hsic_hub_driver);
 	}
 	pm_runtime_disable(&pdev->dev);
-	msm_xo_put(smsc_hub->xo_handle);
 
-	regulator_disable(smsc_hub->hsic_hub_reg);
-	regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
-	regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
-				HSIC_HUB_VDD_VOL_MIN);
-	gpio_free(pdata->hub_reset);
-	regulator_put(smsc_hub->hsic_hub_reg);
-	kfree(smsc_hub);
+	regulator_disable(smsc_hub->hub_vbus_reg);
+	msm_hsic_hub_init_gpio(smsc_hub, 0);
+	msm_hsic_hub_init_clock(smsc_hub, 0);
+	msm_hsic_hub_init_vdd(smsc_hub, 0);
 
 	return 0;
 }
@@ -314,24 +489,32 @@
 
 static int smsc_hub_lpm_enter(struct device *dev)
 {
-	int ret;
+	int ret = 0;
 
-	ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_OFF);
-	if (ret) {
-		pr_err("%s: failed to devote for TCXO"
-			"D1 buffer%d\n", __func__, ret);
+	if (!IS_ERR(smsc_hub->ref_clk)) {
+		clk_disable_unprepare(smsc_hub->ref_clk);
+	} else {
+		ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_OFF);
+		if (ret) {
+			pr_err("%s: failed to devote for TCXO\n"
+				"D1 buffer%d\n", __func__, ret);
+		}
 	}
 	return ret;
 }
 
 static int smsc_hub_lpm_exit(struct device *dev)
 {
-	int ret;
+	int ret = 0;
 
-	ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
-	if (ret) {
-		pr_err("%s: failed to vote for TCXO"
-			"D1 buffer%d\n", __func__, ret);
+	if (!IS_ERR(smsc_hub->ref_clk)) {
+		clk_prepare_enable(smsc_hub->ref_clk);
+	} else {
+		ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
+		if (ret) {
+			pr_err("%s: failed to vote for TCXO\n"
+				"D1 buffer%d\n", __func__, ret);
+		}
 	}
 	return ret;
 }
@@ -345,6 +528,13 @@
 };
 #endif
 
+static const struct of_device_id hsic_hub_dt_match[] = {
+	{ .compatible = "qcom,hsic-smsc-hub",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, hsic_hub_dt_match);
+
 static struct platform_driver smsc_hub_driver = {
 	.driver = {
 		.name = "msm_smsc_hub",
@@ -352,13 +542,15 @@
 #ifdef CONFIG_PM
 		.pm = &smsc_hub_dev_pm_ops,
 #endif
+		.of_match_table = hsic_hub_dt_match,
 	},
+	.probe = smsc_hub_probe,
 	.remove = smsc_hub_remove,
 };
 
 static int __init smsc_hub_init(void)
 {
-	return platform_driver_probe(&smsc_hub_driver, smsc_hub_probe);
+	return platform_driver_register(&smsc_hub_driver);
 }
 
 static void __exit smsc_hub_exit(void)
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..0b5449e 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -136,6 +136,10 @@
 module_param(perdev_minors, int, 0444);
 MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
 
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+				      struct mmc_blk_data *md);
+static int get_card_status(struct mmc_card *card, u32 *status, int retries);
+
 static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
 {
 	mqrq->packed_cmd = MMC_PACKED_NONE;
@@ -298,13 +302,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 +341,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;
@@ -443,6 +467,38 @@
 	return ERR_PTR(err);
 }
 
+static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
+				       u32 retries_max)
+{
+	int err;
+	u32 retry_count = 0;
+
+	if (!status || !retries_max)
+		return -EINVAL;
+
+	do {
+		err = get_card_status(card, status, 5);
+		if (err)
+			break;
+
+		if (!R1_STATUS(*status) &&
+				(R1_CURRENT_STATE(*status) != R1_STATE_PRG))
+			break; /* RPMB programming operation complete */
+
+		/*
+		 * Rechedule to give the MMC device a chance to continue
+		 * processing the previous command without being polled too
+		 * frequently.
+		 */
+		usleep_range(1000, 5000);
+	} while (++retry_count < retries_max);
+
+	if (retry_count == retries_max)
+		err = -EPERM;
+
+	return err;
+}
+
 static int mmc_blk_ioctl_cmd(struct block_device *bdev,
 	struct mmc_ioc_cmd __user *ic_ptr)
 {
@@ -454,6 +510,8 @@
 	struct mmc_request mrq = {NULL};
 	struct scatterlist sg;
 	int err;
+	int is_rpmb = false;
+	u32 status = 0;
 
 	/*
 	 * The caller must have CAP_SYS_RAWIO, and must be calling this on the
@@ -473,6 +531,9 @@
 		goto cmd_done;
 	}
 
+	if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
+		is_rpmb = true;
+
 	card = md->queue.card;
 	if (IS_ERR(card)) {
 		err = PTR_ERR(card);
@@ -523,12 +584,23 @@
 
 	mmc_claim_host(card->host);
 
+	err = mmc_blk_part_switch(card, md);
+	if (err)
+		goto cmd_rel_host;
+
 	if (idata->ic.is_acmd) {
 		err = mmc_app_cmd(card->host, card);
 		if (err)
 			goto cmd_rel_host;
 	}
 
+	if (is_rpmb) {
+		err = mmc_set_blockcount(card, data.blocks,
+			idata->ic.write_flag & (1 << 31));
+		if (err)
+			goto cmd_rel_host;
+	}
+
 	mmc_wait_for_req(card->host, &mrq);
 
 	if (cmd.error) {
@@ -564,6 +636,18 @@
 		}
 	}
 
+	if (is_rpmb) {
+		/*
+		 * Ensure RPMB command has completed by polling CMD13
+		 * "Send Status".
+		 */
+		err = ioctl_rpmb_card_status_poll(card, &status, 5);
+		if (err)
+			dev_err(mmc_dev(card->host),
+					"%s: Card Status=0x%08X, error %d\n",
+					__func__, status, err);
+	}
+
 cmd_rel_host:
 	mmc_release_host(card->host);
 
@@ -1002,9 +1086,6 @@
 			goto out;
 	}
 
-	if (mmc_can_sanitize(card))
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_SANITIZE_START, 1, 0);
 out_retry:
 	if (err && !mmc_blk_reset(md, card->host, type))
 		goto retry;
@@ -1409,6 +1490,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
@@ -2095,6 +2180,8 @@
 	md->disk->driverfs_dev = parent;
 	set_disk_ro(md->disk, md->read_only || default_ro);
 	md->disk->flags = GENHD_FL_EXT_DEVT;
+	if (area_type & MMC_BLK_DATA_AREA_RPMB)
+		md->disk->flags |= GENHD_FL_NO_PART_SCAN;
 
 	/*
 	 * As discussed on lkml, GENHD_FL_REMOVABLE should:
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..89f834a 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);
 }
 
@@ -2194,6 +2214,20 @@
 }
 EXPORT_SYMBOL(mmc_set_blocklen);
 
+int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
+			bool is_rel_write)
+{
+	struct mmc_command cmd = {0};
+
+	cmd.opcode = MMC_SET_BLOCK_COUNT;
+	cmd.arg = blockcount & 0x0000FFFF;
+	if (is_rel_write)
+		cmd.arg |= 1 << 31;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+	return mmc_wait_for_cmd(card->host, &cmd, 5);
+}
+EXPORT_SYMBOL(mmc_set_blockcount);
+
 static void mmc_hw_reset_for_init(struct mmc_host *host)
 {
 	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
@@ -2286,6 +2320,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..751ba75 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -4,6 +4,7 @@
  *  Copyright (C) 2003 Russell King, All Rights Reserved.
  *  Copyright (C) 2007-2008 Pierre Ossman
  *  Copyright (C) 2010 Linus Walleij
+ *  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 as
@@ -163,6 +164,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));
 	}
@@ -359,6 +363,169 @@
 }
 
 EXPORT_SYMBOL(mmc_alloc_host);
+
+static ssize_t show_enable(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+	if (!host)
+		return -EINVAL;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", mmc_can_scale_clk(host));
+}
+
+static ssize_t store_enable(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	unsigned long value, freq;
+	int retval = -EINVAL;
+
+	if (!host)
+		goto out;
+
+	mmc_claim_host(host);
+	if (!host->card || kstrtoul(buf, 0, &value))
+		goto err;
+
+	if (value && !mmc_can_scale_clk(host)) {
+		if (mmc_card_ddr_mode(host->card) ||
+				mmc_card_hs200(host->card) ||
+				mmc_card_uhs(host->card)) {
+			host->caps2 |= MMC_CAP2_CLK_SCALE;
+			mmc_init_clk_scaling(host);
+		}
+
+		if (!mmc_can_scale_clk(host)) {
+			host->caps2 &= ~MMC_CAP2_CLK_SCALE;
+			goto err;
+		}
+	} else if (!value && mmc_can_scale_clk(host)) {
+		host->caps2 &= ~MMC_CAP2_CLK_SCALE;
+		mmc_disable_clk_scaling(host);
+
+		/* Set to max. frequency, since we are disabling */
+		if (host->bus_ops && host->bus_ops->change_bus_speed) {
+			freq = mmc_get_max_frequency(host);
+			if (host->bus_ops->change_bus_speed(host, &freq))
+				goto err;
+		}
+		host->clk_scaling.initialized = false;
+	}
+	retval = count;
+err:
+	mmc_release_host(host);
+out:
+	return retval;
+}
+
+static ssize_t show_up_threshold(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+	if (!host)
+		return -EINVAL;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", host->clk_scaling.up_threshold);
+}
+
+#define MAX_PERCENTAGE	100
+static ssize_t store_up_threshold(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	unsigned long value;
+
+	if (!host || kstrtoul(buf, 0, &value) || (value > MAX_PERCENTAGE))
+		return -EINVAL;
+
+	host->clk_scaling.up_threshold = value;
+
+	pr_debug("%s: clkscale_up_thresh set to %lu\n",
+			mmc_hostname(host), value);
+	return count;
+}
+
+static ssize_t show_down_threshold(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+	if (!host)
+		return -EINVAL;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			host->clk_scaling.down_threshold);
+}
+
+static ssize_t store_down_threshold(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	unsigned long value;
+
+	if (!host || kstrtoul(buf, 0, &value) || (value > MAX_PERCENTAGE))
+		return -EINVAL;
+
+	host->clk_scaling.down_threshold = value;
+
+	pr_debug("%s: clkscale_down_thresh set to %lu\n",
+			mmc_hostname(host), value);
+	return count;
+}
+
+static ssize_t show_polling(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+	if (!host)
+		return -EINVAL;
+
+	return snprintf(buf, PAGE_SIZE, "%lu milliseconds\n",
+			host->clk_scaling.polling_delay_ms);
+}
+
+static ssize_t store_polling(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	unsigned long value;
+
+	if (!host || kstrtoul(buf, 0, &value))
+		return -EINVAL;
+
+	host->clk_scaling.polling_delay_ms = value;
+
+	pr_debug("%s: clkscale_polling_delay_ms set to %lu\n",
+			mmc_hostname(host), value);
+	return count;
+}
+
+DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
+		show_enable, store_enable);
+DEVICE_ATTR(polling_interval, S_IRUGO | S_IWUSR,
+		show_polling, store_polling);
+DEVICE_ATTR(up_threshold, S_IRUGO | S_IWUSR,
+		show_up_threshold, store_up_threshold);
+DEVICE_ATTR(down_threshold, S_IRUGO | S_IWUSR,
+		show_down_threshold, store_down_threshold);
+
+static struct attribute *clk_scaling_attrs[] = {
+	&dev_attr_enable.attr,
+	&dev_attr_up_threshold.attr,
+	&dev_attr_down_threshold.attr,
+	&dev_attr_polling_interval.attr,
+	NULL,
+};
+
+static struct attribute_group clk_scaling_attr_grp = {
+	.name = "clk_scaling",
+	.attrs = clk_scaling_attrs,
+};
+
 #ifdef CONFIG_MMC_PERF_PROFILING
 static ssize_t
 show_perf(struct device *dev, struct device_attribute *attr, char *buf)
@@ -446,6 +613,15 @@
 #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->class_dev.kobj, &clk_scaling_attr_grp);
+	if (err)
+		pr_err("%s: failed to create clk scale sysfs group with err %d\n",
+				__func__, err);
+
 	err = sysfs_create_group(&host->parent->kobj, &dev_attr_grp);
 	if (err)
 		pr_err("%s: failed to create sysfs group with err %d\n",
@@ -479,7 +655,7 @@
 	mmc_remove_host_debugfs(host);
 #endif
 	sysfs_remove_group(&host->parent->kobj, &dev_attr_grp);
-
+	sysfs_remove_group(&host->class_dev.kobj, &clk_scaling_attr_grp);
 
 	device_del(&host->class_dev);
 
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a98ed3d..c1a6b28 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -501,6 +501,17 @@
 
 		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
 		card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
+
+		/*
+		 * RPMB regions are defined in multiples of 128K.
+		 */
+		card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
+		if (ext_csd[EXT_CSD_RPMB_MULT]) {
+			mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
+				EXT_CSD_PART_CONFIG_ACC_RPMB,
+				"rpmb", 0, false,
+				MMC_BLK_DATA_AREA_RPMB);
+		}
 	}
 
 	card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
@@ -632,6 +643,8 @@
 MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
 		card->ext_csd.enhanced_area_offset);
 MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
+MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
+MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
 
 static struct attribute *mmc_std_attrs[] = {
 	&dev_attr_cid.attr,
@@ -647,6 +660,8 @@
 	&dev_attr_serial.attr,
 	&dev_attr_enhanced_area_offset.attr,
 	&dev_attr_enhanced_area_size.attr,
+	&dev_attr_raw_rpmb_size_mult.attr,
+	&dev_attr_rel_sectors.attr,
 	NULL,
 };
 
@@ -1460,6 +1475,7 @@
 
 	mmc_claim_host(host);
 	host->card = NULL;
+	mmc_exit_clk_scaling(host);
 	mmc_release_host(host);
 }
 
@@ -1510,6 +1526,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 +1562,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 +1576,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 +1721,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..f3598cf 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;
@@ -1633,6 +1640,11 @@
 
 	spin_lock(&host->lock);
 
+	if (!atomic_read(&host->clks_on)) {
+		spin_unlock(&host->lock);
+		return IRQ_NONE;
+	}
+
 	status = readl_relaxed(base + MMCISTATUS);
 
 	if (((readl_relaxed(host->base + MMCIMASK0) & status) &
@@ -1768,6 +1780,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 +1878,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 +1913,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 +2163,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 +3375,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 +4227,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__);
@@ -5061,6 +5109,31 @@
 	}
 }
 
+/*
+ * This function prints the testbus debug output for all the
+ * available SDCC controller test bus.
+ *
+ * Note: This function should only be called if the SDCC is clocked.
+ */
+static void msmsdcc_print_testbus_info(struct msmsdcc_host *host)
+{
+	int testbus_num;
+
+	if (!is_testbus_debug(host))
+		return;
+
+	pr_err("== SDCC Test Bus Debug ==");
+	for (testbus_num = 0; testbus_num < MAX_TESTBUS; testbus_num++) {
+		writel_relaxed(((testbus_num & MCI_TESTBUS_SEL_MASK)
+			       | MCI_TESTBUS_ENA),
+			       host->base + MCI_TESTBUS_CONFIG);
+		pr_err("TestBus(%d) = 0x%.8x\n", testbus_num,
+			(u32)readl_relaxed(host->base + MCI_SDCC_DEBUG_REG));
+	}
+	/* Disable the test bus output */
+	writel_relaxed(~MCI_TESTBUS_ENA, host->base + MCI_TESTBUS_CONFIG);
+}
+
 static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
 {
 	/* Dump current state of SDCC clocks, power and irq */
@@ -5080,6 +5153,7 @@
 		pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
 			mmc_hostname(host->mmc),
 			readl_relaxed(host->base + MCI_TEST_INPUT));
+		msmsdcc_print_testbus_info(host);
 	}
 
 	if (host->curr.data) {
@@ -6493,19 +6567,19 @@
 
 #if CONFIG_DEBUG_FS
 static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
-		const char *func)
+				   const char *func, int err)
 {
 	ktime_t diff;
 
-	if (host->print_pm_stats) {
+	if (host->print_pm_stats && !err) {
 		diff = ktime_sub(ktime_get(), start);
-		pr_info("%s: %s: Completed in %llu usec\n", func,
-		mmc_hostname(host->mmc), (u64)ktime_to_us(diff));
+		pr_info("%s: %s: Completed in %llu usec\n",
+			mmc_hostname(host->mmc), func, (u64)ktime_to_us(diff));
 	}
 }
 #else
 static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
-		const char *func) {}
+				   const char *func, int err) {}
 #endif
 
 static int
@@ -6572,7 +6646,7 @@
 out:
 	/* set bus bandwidth to 0 immediately */
 	msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
-	msmsdcc_print_pm_stats(host, start, __func__);
+	msmsdcc_print_pm_stats(host, start, __func__, rc);
 	return rc;
 }
 
@@ -6621,7 +6695,7 @@
 	host->pending_resume = false;
 	pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
 out:
-	msmsdcc_print_pm_stats(host, start, __func__);
+	msmsdcc_print_pm_stats(host, start, __func__, 0);
 	return 0;
 }
 
@@ -6658,7 +6732,7 @@
 	if (!pm_runtime_suspended(dev))
 		rc = msmsdcc_runtime_suspend(dev);
  out:
-	msmsdcc_print_pm_stats(host, start, __func__);
+	msmsdcc_print_pm_stats(host, start, __func__, rc);
 	return rc;
 }
 
@@ -6714,7 +6788,7 @@
 		enable_irq(host->plat->status_irq);
 	}
 out:
-	msmsdcc_print_pm_stats(host, start, __func__);
+	msmsdcc_print_pm_stats(host, start, __func__, rc);
 	return rc;
 }
 
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index bb1b211..7469c8e 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -193,6 +193,13 @@
 
 #define MCI_TEST_INPUT		0x0D4
 
+#define MCI_TESTBUS_CONFIG	0x0CC
+#define MCI_TESTBUS_SEL_MASK	(0x7)
+#define MAX_TESTBUS		8
+#define MCI_TESTBUS_ENA		(1 << 3)
+
+#define MCI_SDCC_DEBUG_REG	0x124
+
 #define MCI_IRQENABLE	\
 	(MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|	\
 	MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|	\
@@ -401,6 +408,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;
@@ -448,6 +456,7 @@
 #define MSMSDCC_AUTO_CMD21	(1 << 10)
 #define MSMSDCC_SW_RST_CFG_BROKEN	(1 << 11)
 #define MSMSDCC_DATA_PEND_FOR_CMD53	(1 << 12)
+#define MSMSDCC_TESTBUS_DEBUG		(1 << 13)
 
 #define set_hw_caps(h, val)		((h)->hw_caps |= val)
 #define is_sps_mode(h)			((h)->hw_caps & MSMSDCC_SPS_BAM_SUP)
@@ -464,6 +473,7 @@
 #define is_sw_reset_save_config_broken(h) \
 				((h)->hw_caps & MSMSDCC_SW_RST_CFG_BROKEN)
 #define is_data_pend_for_cmd53(h) ((h)->hw_caps & MSMSDCC_DATA_PEND_FOR_CMD53)
+#define is_testbus_debug(h) ((h)->hw_caps & MSMSDCC_TESTBUS_DEBUG)
 
 /* Set controller capabilities based on version */
 static inline void set_default_hw_caps(struct msmsdcc_host *host)
@@ -497,7 +507,8 @@
 	if (step >= 0x2b) /* SDCC v4 2.1.0 and greater */
 		host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_SW_RST_CFG |
 				 MSMSDCC_AUTO_CMD21 |
-				 MSMSDCC_DATA_PEND_FOR_CMD53;
+				 MSMSDCC_DATA_PEND_FOR_CMD53 |
+				 MSMSDCC_TESTBUS_DEBUG;
 
 	if (step == 0x2b)
 		host->hw_caps |= MSMSDCC_SW_RST_CFG_BROKEN;
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..9394986 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:
@@ -89,5 +85,11 @@
 	  for the IPA core.
 	  Kernel and user-space processes can call the IPA driver
 	  to configure IPA core.
+config MSM_AVTIMER
+	tristate "Avtimer Driver"
+	depends on ARCH_MSM8960
+	help
+		This driver gets the Q6 out of power collapsed state and
+		exposes ioctl control to read avtimer tick.
 
 endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 0a755d3..919c07f 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -8,3 +8,4 @@
 obj-$(CONFIG_QPNP_PWM) += qpnp-pwm.o
 obj-$(CONFIG_QPNP_POWER_ON) += qpnp-power-on.o
 obj-$(CONFIG_QPNP_CLKDIV) += qpnp-clkdiv.o
+obj-$(CONFIG_MSM_AVTIMER) += avtimer.o
diff --git a/drivers/platform/msm/avtimer.c b/drivers/platform/msm/avtimer.c
new file mode 100644
index 0000000..f513ceb
--- /dev/null
+++ b/drivers/platform/msm/avtimer.c
@@ -0,0 +1,369 @@
+
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/avtimer.h>
+#include <mach/qdsp6v2/apr.h>
+
+#define DEVICE_NAME "avtimer"
+
+
+#define ADSP_CMD_SET_POWER_COLLAPSE_STATE 0x0001115C
+
+static int major;	/* Major number assigned to our device driver */
+struct avtimer_t {
+	struct cdev myc;
+	struct class *avtimer_class;
+	struct mutex avtimer_lock;
+	int avtimer_open_cnt;
+	struct dev_avtimer_data *avtimer_pdata;
+};
+static struct avtimer_t avtimer;
+
+static struct apr_svc *core_handle;
+
+struct adsp_power_collapse {
+	struct apr_hdr hdr;
+	uint32_t power_collapse;
+};
+
+static int32_t avcs_core_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *payload;
+
+	pr_debug("core msg: payload len = %u, apr resp opcode = 0x%X\n",
+		data->payload_size, data->opcode);
+
+	switch (data->opcode) {
+
+	case APR_BASIC_RSP_RESULT:{
+
+		if (data->payload_size == 0) {
+			pr_err("%s: APR_BASIC_RSP_RESULT No Payload ",
+					__func__);
+			return 0;
+		}
+
+		payload = data->payload;
+
+		switch (payload[0]) {
+
+		case ADSP_CMD_SET_POWER_COLLAPSE_STATE:
+			pr_debug("CMD_SET_POWER_COLLAPSE_STATE status[0x%x]\n",
+					payload[1]);
+			break;
+		default:
+			pr_err("Invalid cmd rsp[0x%x][0x%x]\n",
+					payload[0], payload[1]);
+			break;
+		}
+		break;
+	}
+	case RESET_EVENTS:{
+		pr_debug("Reset event received in Core service");
+		apr_reset(core_handle);
+		core_handle = NULL;
+		break;
+	}
+
+	default:
+		pr_err("Message id from adsp core svc: %d\n", data->opcode);
+		break;
+	}
+
+	return 0;
+}
+
+int avcs_core_open(void)
+{
+	if (core_handle == NULL)
+		core_handle = apr_register("ADSP", "CORE",
+					avcs_core_callback, 0xFFFFFFFF, NULL);
+
+	pr_debug("Open_q %p\n", core_handle);
+	if (core_handle == NULL) {
+		pr_err("%s: Unable to register CORE\n", __func__);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+int avcs_core_disable_power_collapse(int disable)
+{
+	struct adsp_power_collapse pc;
+	int rc = 0;
+
+	if (core_handle) {
+		pc.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		pc.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(uint32_t));
+		pc.hdr.src_port = 0;
+		pc.hdr.dest_port = 0;
+		pc.hdr.token = 0;
+		pc.hdr.opcode = ADSP_CMD_SET_POWER_COLLAPSE_STATE;
+		/*
+		* When power_collapse set to 1 -- If the aDSP is in the power
+		* collapsed state when this command is received, it is awakened
+		* from this state. The aDSP does not power collapse again until
+		* the client revokes this	command
+		* When power_collapse set to 0 -- This indicates to the aDSP
+		* that the remote client does not need it to be out of power
+		* collapse any longer. This may not always put the aDSP into
+		* power collapse; the aDSP must honor an internal client's
+		* power requirements as well.
+		*/
+		pc.power_collapse = disable;
+		rc = apr_send_pkt(core_handle, (uint32_t *)&pc);
+		if (rc < 0) {
+			pr_debug("disable power collapse = %d failed\n",
+				disable);
+			return rc;
+		}
+		pr_debug("disable power collapse = %d\n", disable);
+	}
+	return 0;
+}
+
+static int avtimer_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct avtimer_t *pavtimer = &avtimer;
+
+	pr_debug("avtimer_open\n");
+	mutex_lock(&pavtimer->avtimer_lock);
+
+	if (pavtimer->avtimer_open_cnt != 0) {
+		pavtimer->avtimer_open_cnt++;
+		pr_debug("%s: opened avtimer open count=%d\n",
+			__func__, pavtimer->avtimer_open_cnt);
+		mutex_unlock(&pavtimer->avtimer_lock);
+		return 0;
+	}
+	try_module_get(THIS_MODULE);
+
+	rc = avcs_core_open();
+	if (core_handle)
+		rc = avcs_core_disable_power_collapse(1);
+
+	pavtimer->avtimer_open_cnt++;
+	pr_debug("%s: opened avtimer open count=%d\n",
+		__func__, pavtimer->avtimer_open_cnt);
+	mutex_unlock(&pavtimer->avtimer_lock);
+	pr_debug("avtimer_open leave rc=%d\n", rc);
+
+	return rc;
+}
+
+static int avtimer_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct avtimer_t *pavtimer = &avtimer;
+
+	mutex_lock(&pavtimer->avtimer_lock);
+	pavtimer->avtimer_open_cnt--;
+
+	if (core_handle && pavtimer->avtimer_open_cnt == 0)
+		rc = avcs_core_disable_power_collapse(0);
+
+	pr_debug("device_release(%p,%p) open count=%d\n",
+		inode, file, pavtimer->avtimer_open_cnt);
+
+	module_put(THIS_MODULE);
+
+	mutex_unlock(&pavtimer->avtimer_lock);
+
+	return rc;
+}
+
+/*
+ * ioctl call provides GET_AVTIMER
+ */
+static long avtimer_ioctl(struct file *file, unsigned int ioctl_num,
+				unsigned long ioctl_param)
+{
+	struct avtimer_t *pavtimer = &avtimer;
+	pr_debug("avtimer_ioctl: ioctlnum=%d,param=%lx\n",
+				ioctl_num, ioctl_param);
+
+	switch (ioctl_num) {
+	case IOCTL_GET_AVTIMER_TICK:
+	{
+		void __iomem *p_avtimer_msw = NULL, *p_avtimer_lsw = NULL;
+		uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0;
+		uint32_t avtimer_msw_2nd = 0;
+		uint64_t avtimer_tick;
+
+		if (pavtimer->avtimer_pdata) {
+			p_avtimer_lsw = ioremap(
+			pavtimer->avtimer_pdata->avtimer_lsw_phy_addr, 4);
+			p_avtimer_msw = ioremap(
+			pavtimer->avtimer_pdata->avtimer_msw_phy_addr, 4);
+		}
+		if (!p_avtimer_lsw || !p_avtimer_msw) {
+			pr_err("ioremap failed\n");
+			return -EIO;
+		}
+		do {
+			avtimer_msw_1st = ioread32(p_avtimer_msw);
+			avtimer_lsw = ioread32(p_avtimer_lsw);
+			avtimer_msw_2nd = ioread32(p_avtimer_msw);
+		} while (avtimer_msw_1st != avtimer_msw_2nd);
+
+		avtimer_tick =
+		((uint64_t) avtimer_msw_1st << 32) | avtimer_lsw;
+
+		pr_debug("AV Timer tick: msw: %d, lsw: %d\n", avtimer_msw_1st,
+				avtimer_lsw);
+		if (copy_to_user((void *) ioctl_param, &avtimer_tick,
+				sizeof(avtimer_tick))) {
+					pr_err("copy_to_user failed\n");
+					iounmap(p_avtimer_lsw);
+					iounmap(p_avtimer_msw);
+					return -EFAULT;
+			}
+		iounmap(p_avtimer_lsw);
+		iounmap(p_avtimer_msw);
+		}
+		break;
+
+	default:
+		pr_err("invalid cmd\n");
+		break;
+	}
+
+	return 0;
+}
+
+static const struct file_operations avtimer_fops = {
+	.unlocked_ioctl = avtimer_ioctl,
+	.open = avtimer_open,
+	.release = avtimer_release
+};
+
+static int dev_avtimer_probe(struct platform_device *pdev)
+{
+	int result;
+	dev_t dev = MKDEV(major, 0);
+	struct device *device_handle;
+	struct avtimer_t *pavtimer = &avtimer;
+
+	/* get the device number */
+	if (major)
+		result = register_chrdev_region(dev, 1, DEVICE_NAME);
+	else {
+		result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
+		major = MAJOR(dev);
+	}
+
+	if (result < 0) {
+		pr_err("Registering avtimer device failed\n");
+		return result;
+	}
+
+	pavtimer->avtimer_class = class_create(THIS_MODULE, "avtimer");
+	if (IS_ERR(pavtimer->avtimer_class)) {
+		result = PTR_ERR(pavtimer->avtimer_class);
+		pr_err("Error creating avtimer class: %d\n", result);
+		goto unregister_chrdev_region;
+	}
+	pavtimer->avtimer_pdata = pdev->dev.platform_data;
+
+	cdev_init(&pavtimer->myc, &avtimer_fops);
+	result = cdev_add(&pavtimer->myc, dev, 1);
+
+	if (result < 0) {
+		pr_err("Registering file operations failed\n");
+		goto class_destroy;
+	}
+
+	device_handle = device_create(pavtimer->avtimer_class,
+			NULL, pavtimer->myc.dev, NULL, "avtimer");
+	if (IS_ERR(device_handle)) {
+		result = PTR_ERR(device_handle);
+		pr_err("device_create failed: %d\n", result);
+		goto class_destroy;
+	}
+
+	mutex_init(&pavtimer->avtimer_lock);
+	core_handle = NULL;
+	pavtimer->avtimer_open_cnt = 0;
+
+	pr_debug("Device create done for avtimer major=%d\n", major);
+
+	return 0;
+
+class_destroy:
+	class_destroy(pavtimer->avtimer_class);
+unregister_chrdev_region:
+	unregister_chrdev_region(MKDEV(major, 0), 1);
+	return result;
+
+}
+
+static int __devexit dev_avtimer_remove(struct platform_device *pdev)
+{
+	struct avtimer_t *pavtimer = &avtimer;
+
+	pr_debug("dev_avtimer_remove\n");
+
+	device_destroy(pavtimer->avtimer_class, pavtimer->myc.dev);
+	cdev_del(&pavtimer->myc);
+	class_destroy(pavtimer->avtimer_class);
+	unregister_chrdev_region(MKDEV(major, 0), 1);
+
+	return 0;
+}
+
+static struct platform_driver dev_avtimer_driver = {
+	.probe = dev_avtimer_probe,
+	.remove = __exit_p(dev_avtimer_remove),
+	.driver = {.name = "dev_avtimer"}
+};
+
+static int  __init avtimer_init(void)
+{
+	s32 rc;
+	rc = platform_driver_register(&dev_avtimer_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("platform_driver_register failed.\n");
+		goto error_platform_driver;
+	}
+	pr_debug("dev_avtimer_init : done\n");
+
+	return 0;
+error_platform_driver:
+
+	pr_err("encounterd error\n");
+	return -ENODEV;
+}
+
+static void __exit avtimer_exit(void)
+{
+	pr_debug("avtimer_exit\n");
+	platform_driver_unregister(&dev_avtimer_driver);
+}
+
+module_init(avtimer_init);
+module_exit(avtimer_exit);
+
+MODULE_DESCRIPTION("avtimer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 8f68ef5..7973cfe 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -637,7 +637,7 @@
 
 		switch (tx_pkt->cnt) {
 		case 1:
-			ipa_write_done(&tx_pkt->work);
+			ipa_wq_write_done(&tx_pkt->work);
 			break;
 		case 0xFFFF:
 			/* reached end of set */
@@ -651,7 +651,7 @@
 			   list_first_entry(&sys->head_desc_list,
 					    struct ipa_tx_pkt_wrapper, link);
 			spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-			ipa_write_done(&tx_pkt->work);
+			ipa_wq_write_done(&tx_pkt->work);
 			break;
 		default:
 			/* keep looping till reach the end of the set */
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index cf51ab6..a6221b8 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -24,7 +24,7 @@
 
 static int polling_min_sleep[IPA_DIR_MAX] = { 950, 950 };
 static int polling_max_sleep[IPA_DIR_MAX] = { 1050, 1050 };
-static int polling_inactivity[IPA_DIR_MAX] = { 20, 20 };
+static int polling_inactivity[IPA_DIR_MAX] = { 4, 4 };
 
 struct ipa_pkt_info {
 	void *buffer;
@@ -167,6 +167,34 @@
 	return -ENOMEM;
 }
 
+static int ipa_reclaim_tx(struct ipa_bridge_pipe_context *sys_tx, bool all)
+{
+	struct sps_iovec iov;
+	struct ipa_pkt_info *tx_pkt;
+	int cnt = 0;
+	int ret;
+
+	do {
+		iov.addr = 0;
+		ret = sps_get_iovec(sys_tx->pipe, &iov);
+		if (ret || iov.addr == 0) {
+			break;
+		} else {
+			tx_pkt = list_first_entry(&sys_tx->head_desc_list,
+						  struct ipa_pkt_info,
+						  list_node);
+			list_move_tail(&tx_pkt->list_node,
+					&sys_tx->free_desc_list);
+			sys_tx->len--;
+			sys_tx->free_len++;
+			tx_pkt->len = ~0;
+			cnt++;
+		}
+	} while (all);
+
+	return cnt;
+}
+
 static void ipa_do_bridge_work(enum ipa_bridge_dir dir)
 {
 	struct ipa_bridge_pipe_context *sys_rx = &bridge[2 * dir];
@@ -180,22 +208,9 @@
 
 	while (1) {
 		++inactive_cycles;
-		iov.addr = 0;
-		ret = sps_get_iovec(sys_tx->pipe, &iov);
-		if (ret || iov.addr == 0) {
-			/* no-op */
-		} else {
-			inactive_cycles = 0;
 
-			tx_pkt = list_first_entry(&sys_tx->head_desc_list,
-						  struct ipa_pkt_info,
-						  list_node);
-			list_move_tail(&tx_pkt->list_node,
-					&sys_tx->free_desc_list);
-			sys_tx->len--;
-			sys_tx->free_len++;
-			tx_pkt->len = ~0;
-		}
+		if (ipa_reclaim_tx(sys_tx, false))
+			inactive_cycles = 0;
 
 		iov.addr = 0;
 		ret = sps_get_iovec(sys_rx->pipe, &iov);
@@ -216,7 +231,7 @@
 				tmp_pkt = kmalloc(sizeof(struct ipa_pkt_info),
 						GFP_KERNEL);
 				if (!tmp_pkt) {
-					pr_err_ratelimited("%s: unable to alloc tx_pkt_info\n",
+					pr_debug_ratelimited("%s: unable to alloc tx_pkt_info\n",
 					       __func__);
 					usleep_range(polling_min_sleep[dir],
 							polling_max_sleep[dir]);
@@ -226,7 +241,7 @@
 				tmp_pkt->buffer = kmalloc(IPA_RX_SKB_SIZE,
 						GFP_KERNEL | GFP_DMA);
 				if (!tmp_pkt->buffer) {
-					pr_err_ratelimited("%s: unable to alloc tx_pkt_buffer\n",
+					pr_debug_ratelimited("%s: unable to alloc tx_pkt_buffer\n",
 					       __func__);
 					kfree(tmp_pkt);
 					usleep_range(polling_min_sleep[dir],
@@ -240,7 +255,7 @@
 						DMA_BIDIRECTIONAL);
 				if (tmp_pkt->dma_address == 0 ||
 						tmp_pkt->dma_address == ~0) {
-					pr_err_ratelimited("%s: dma_map_single failure %p for %p\n",
+					pr_debug_ratelimited("%s: dma_map_single failure %p for %p\n",
 					       __func__,
 					       (void *)tmp_pkt->dma_address,
 					       tmp_pkt->buffer);
@@ -271,7 +286,7 @@
 					SPS_IOVEC_FLAG_EOT);
 			if (ret) {
 				list_del(&tx_pkt->list_node);
-				pr_err_ratelimited("%s: sps_transfer_one failed %d\n",
+				pr_debug_ratelimited("%s: sps_transfer_one failed %d\n",
 						__func__, ret);
 				usleep_range(polling_min_sleep[dir],
 						polling_max_sleep[dir]);
@@ -289,9 +304,10 @@
 					       SPS_IOVEC_FLAG_INT |
 					       SPS_IOVEC_FLAG_EOT);
 			if (ret) {
-				pr_err_ratelimited("%s: fail to add to TX dir=%d\n",
+				pr_debug_ratelimited("%s: fail to add to TX dir=%d\n",
 						__func__, dir);
 				list_del(&rx_pkt->list_node);
+				ipa_reclaim_tx(sys_tx, true);
 				usleep_range(polling_min_sleep[dir],
 						polling_max_sleep[dir]);
 				goto retry_add_tx;
@@ -306,7 +322,7 @@
 	}
 }
 
-static void ipa_rx_notify(struct sps_event_notify *notify)
+static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
 {
 	switch (notify->event_id) {
 	case SPS_EVENT_EOT:
@@ -457,7 +473,7 @@
 		sys->register_event.options = SPS_O_EOT;
 		sys->register_event.mode = SPS_TRIGGER_CALLBACK;
 		sys->register_event.xfer_done = NULL;
-		sys->register_event.callback = ipa_rx_notify;
+		sys->register_event.callback = ipa_sps_irq_rx_notify;
 		sys->register_event.user = NULL;
 		ret = sps_register_event(sys->pipe, &sys->register_event);
 		if (ret < 0) {
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index 823b17d..dc9da7d 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -157,7 +157,7 @@
 
 	ep->valid = 1;
 	ep->client = in->client;
-	ep->notify = in->notify;
+	ep->client_notify = in->notify;
 	ep->priv = in->priv;
 
 	if (ipa_cfg_ep(ipa_ep_idx, &in->ipa_ep_cfg)) {
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index c677a6e..4de19d2 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -18,12 +18,21 @@
 
 #define list_next_entry(pos, member) \
 	list_entry(pos->member.next, typeof(*pos), member)
+#define IPA_LAST_DESC_COOKIE 0xFFFF
 /**
- * ipa_write_done - this function will be (enevtually) called when a Tx
+ * ipa_write_done() - this function will be (eventually) called when a Tx
  * operation is complete
- * @work:	work_struct used by the work queue
+ * * @work:	work_struct used by the work queue
+ *
+ * Will be called in deferred context.
+ * - invoke the callback supplied by the client who sent this command
+ * - iterate over all packets and validate that
+ *   the order for sent packet is the same as expected
+ * - delete all the tx packet descriptors from the system
+ *   pipe context (not needed anymore)
+ * - return the tx buffer back to one_kb_no_straddle_pool
  */
-void ipa_write_done(struct work_struct *work)
+void ipa_wq_write_done(struct work_struct *work)
 {
 	struct ipa_tx_pkt_wrapper *tx_pkt;
 	struct ipa_tx_pkt_wrapper *next_pkt;
@@ -40,7 +49,7 @@
 	if (unlikely(cnt == 0))
 		WARN_ON(1);
 
-	if (cnt > 1 && cnt != 0xFFFF)
+	if (cnt > 1 && cnt != IPA_LAST_DESC_COOKIE)
 		mult = tx_pkt->mult;
 
 	for (i = 0; i < cnt; i++) {
@@ -77,6 +86,14 @@
  * @sys:	system pipe context
  * @desc:	descriptor to send
  *
+ * - Allocate tx_packet wrapper
+ * - Allocate a bounce buffer due to HW constrains
+ *   (This buffer will be used for the DMA command)
+ * - Copy the data (desc->pyld) to the bounce buffer
+ * - transfer data to the IPA
+ * - after the transfer was done the SPS will
+ *   notify the sending user via ipa_sps_irq_comp_tx()
+ *
  * Return codes: 0: success, -EFAULT: failure
  */
 int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc)
@@ -117,7 +134,7 @@
 	}
 
 	INIT_LIST_HEAD(&tx_pkt->link);
-	INIT_WORK(&tx_pkt->work, ipa_write_done);
+	INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
 	tx_pkt->type = desc->type;
 	tx_pkt->cnt = 1;    /* only 1 desc in this "set" */
 
@@ -175,7 +192,20 @@
  * ipa_send() - Send multiple descriptors in one HW transaction
  * @sys: system pipe context
  * @num_desc: number of packets
- * @desc: packets to send
+ * @desc: packets to send (may be immediate command or data)
+ *
+ * This function is used for system-to-bam connection.
+ * - SPS driver expect struct sps_transfer which will contain all the data
+ *   for a transaction
+ * - The sps_transfer struct will be pointing to bounce buffers for
+ *   its DMA command (immediate command and data)
+ * - ipa_tx_pkt_wrapper will be used for each ipa
+ *   descriptor (allocated from wrappers cache)
+ * - The wrapper struct will be configured for each ipa-desc payload and will
+ *   contain information which will be later used by the user callbacks
+ * - each transfer will be made by calling to sps_transfer()
+ * - Each packet (command or data) that will be sent will also be saved in
+ *   ipa_sys_context for later check that all data was sent
  *
  * Return codes: 0: success, -EFAULT: failure
  */
@@ -187,12 +217,20 @@
 	struct sps_iovec *iovec;
 	unsigned long irq_flags;
 	dma_addr_t dma_addr;
-	int i;
+	int i = 0;
 	int j;
 	int result;
-	int fail_dma_wrap;
+	int fail_dma_wrap = 0;
 	uint size = num_desc * sizeof(struct sps_iovec);
 
+	transfer.iovec = dma_alloc_coherent(NULL, size, &dma_addr, 0);
+	transfer.iovec_phys = dma_addr;
+	transfer.iovec_count = num_desc;
+	if (!transfer.iovec) {
+		IPAERR("fail to alloc DMA mem for sps xfr buff\n");
+		goto failure;
+	}
+
 	for (i = 0; i < num_desc; i++) {
 		fail_dma_wrap = 0;
 		tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache,
@@ -207,14 +245,6 @@
 		 */
 		if (i == 0) {
 			transfer.user = tx_pkt;
-			transfer.iovec =
-				dma_alloc_coherent(NULL, size, &dma_addr, 0);
-			transfer.iovec_phys = dma_addr;
-			transfer.iovec_count = num_desc;
-			if (!transfer.iovec) {
-				IPAERR("fail alloc DMA mem for sps xfr buff\n");
-				goto failure;
-			}
 
 			tx_pkt->mult.phys_base = dma_addr;
 			tx_pkt->mult.base = transfer.iovec;
@@ -226,7 +256,7 @@
 		iovec->flags = 0;
 
 		INIT_LIST_HEAD(&tx_pkt->link);
-		INIT_WORK(&tx_pkt->work, ipa_write_done);
+		INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
 		tx_pkt->type = desc[i].type;
 
 		tx_pkt->mem.base = desc[i].pyld;
@@ -263,6 +293,10 @@
 		tx_pkt->user1 = desc[i].user1;
 		tx_pkt->user2 = desc[i].user2;
 
+		/*
+		 * Point the iovec to the bounce buffer and
+		 * add this packet to system pipe context.
+		 */
 		iovec->addr = tx_pkt->mem.phys_base;
 		spin_lock_irqsave(&sys->spinlock, irq_flags);
 		list_add_tail(&tx_pkt->link, &sys->head_desc_list);
@@ -284,7 +318,7 @@
 			iovec->flags |= (SPS_IOVEC_FLAG_EOT |
 					SPS_IOVEC_FLAG_INT);
 			/* "mark" the last desc */
-			tx_pkt->cnt = 0xFFFF;
+			tx_pkt->cnt = IPA_LAST_DESC_COOKIE;
 		}
 	}
 
@@ -320,7 +354,7 @@
 }
 
 /**
- * ipa_cmd_ack - callback function which will be called by SPS driver after an
+ * ipa_sps_irq_cmd_ack - callback function which will be called by SPS driver after an
  * immediate command is complete.
  * @user1:	pointer to the descriptor of the transfer
  * @user2:
@@ -328,7 +362,7 @@
  * Complete the immediate commands completion object, this will release the
  * thread which waits on this completion object (ipa_send_cmd())
  */
-static void ipa_cmd_ack(void *user1, void *user2)
+static void ipa_sps_irq_cmd_ack(void *user1, void *user2)
 {
 	struct ipa_desc *desc = (struct ipa_desc *)user1;
 
@@ -340,11 +374,13 @@
 
 /**
  * ipa_send_cmd - send immediate commands
- * @num_desc:	number of descriptors within the descr struct
+ * @num_desc:	number of descriptors within the desc struct
  * @descr:	descriptor structure
  *
  * Function will block till command gets ACK from IPA HW, caller needs
  * to free any resources it allocated after function returns
+ * The callback in ipa_desc should not be set by the caller
+ * for this function.
  */
 int ipa_send_cmd(u16 num_desc, struct ipa_desc *descr)
 {
@@ -353,11 +389,10 @@
 	if (num_desc == 1) {
 		init_completion(&descr->xfer_done);
 
-		/* client should not set these */
 		if (descr->callback || descr->user1)
 			WARN_ON(1);
 
-		descr->callback = ipa_cmd_ack;
+		descr->callback = ipa_sps_irq_cmd_ack;
 		descr->user1 = descr;
 		if (ipa_send_one(&ipa_ctx->sys[IPA_A5_CMD], descr)) {
 			IPAERR("fail to send immediate command\n");
@@ -368,11 +403,10 @@
 		desc = &descr[num_desc - 1];
 		init_completion(&desc->xfer_done);
 
-		/* client should not set these */
 		if (desc->callback || desc->user1)
 			WARN_ON(1);
 
-		desc->callback = ipa_cmd_ack;
+		desc->callback = ipa_sps_irq_cmd_ack;
 		desc->user1 = desc;
 		if (ipa_send(&ipa_ctx->sys[IPA_A5_CMD], num_desc, descr)) {
 			IPAERR("fail to send multiple immediate command set\n");
@@ -385,11 +419,15 @@
 }
 
 /**
- * ipa_tx_notify() - Callback function which will be called by the SPS driver
- * after a Tx operation is complete. Called in an interrupt context.
+ * ipa_sps_irq_tx_notify() - Callback function which will be called by
+ * the SPS driver after a Tx operation is complete.
+ * Called in an interrupt context.
  * @notify:	SPS driver supplied notification struct
+ *
+ * This function defer the work for this event to the tx workqueue.
+ * This event will be later handled by ipa_write_done.
  */
-static void ipa_tx_notify(struct sps_event_notify *notify)
+static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
 {
 	struct ipa_tx_pkt_wrapper *tx_pkt;
 
@@ -473,19 +511,19 @@
 		mux_hdr = (struct ipa_a5_mux_hdr *)rx_skb->data;
 
 		IPADBG("RX pkt len=%d IID=0x%x src=%d, flags=0x%x, meta=0x%x\n",
-		       rx_skb->len, ntohs(mux_hdr->interface_id),
-		       mux_hdr->src_pipe_index,
-		       mux_hdr->flags, ntohl(mux_hdr->metadata));
+			rx_skb->len, ntohs(mux_hdr->interface_id),
+			mux_hdr->src_pipe_index,
+			mux_hdr->flags, ntohl(mux_hdr->metadata));
 
 		IPA_DUMP_BUFF(rx_skb->data, 0, rx_skb->len);
 
 		if (mux_hdr->src_pipe_index >= IPA_NUM_PIPES ||
-		    !ipa_ctx->ep[mux_hdr->src_pipe_index].valid ||
-		    !ipa_ctx->ep[mux_hdr->src_pipe_index].notify) {
-			IPAERR("drop pipe=%d ep_valid=%d notify=%p\n",
-			       mux_hdr->src_pipe_index,
-			       ipa_ctx->ep[mux_hdr->src_pipe_index].valid,
-			       ipa_ctx->ep[mux_hdr->src_pipe_index].notify);
+			!ipa_ctx->ep[mux_hdr->src_pipe_index].valid ||
+			!ipa_ctx->ep[mux_hdr->src_pipe_index].client_notify) {
+			IPAERR("drop pipe=%d ep_valid=%d client_notify=%p\n",
+			  mux_hdr->src_pipe_index,
+			  ipa_ctx->ep[mux_hdr->src_pipe_index].valid,
+			  ipa_ctx->ep[mux_hdr->src_pipe_index].client_notify);
 			dev_kfree_skb_any(rx_skb);
 			ipa_replenish_rx_cache();
 			continue;
@@ -505,7 +543,8 @@
 
 		IPADBG("pulling %d bytes from skb\n", pull_len);
 		skb_pull(rx_skb, pull_len);
-		ep->notify(ep->priv, IPA_RECEIVE, (unsigned long)(rx_skb));
+		ep->client_notify(ep->priv, IPA_RECEIVE,
+				(unsigned long)(rx_skb));
 		ipa_replenish_rx_cache();
 	} while (1);
 }
@@ -587,7 +626,7 @@
  * This comes to prevent the CPU from handling too many interrupts when the
  * throughput is high.
  */
-static void ipa_rx_notify(struct sps_event_notify *notify)
+static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
 {
 	struct ipa_rx_pkt_wrapper *rx_pkt;
 
@@ -609,9 +648,17 @@
 /**
  * ipa_setup_sys_pipe() - Setup an IPA end-point in system-BAM mode and perform
  * IPA EP configuration
- * @sys_in:	[in] input needed to setup BAM pipe and config EP
+ * @sys_in:	[in] input needed to setup BAM pipe and configure EP
  * @clnt_hdl:	[out] client handle
  *
+ *  - configure the end-point registers with the supplied
+ *    parameters from the user.
+ *  - call SPS APIs to create a system-to-bam connection with IPA.
+ *  - allocate descriptor FIFO
+ *  - register callback function(ipa_sps_irq_rx_notify or
+ *    ipa_sps_irq_tx_notify - depends on client type) in case the driver is
+ *    not configured to pulling mode
+ *
  * Returns:	0 on success, negative on failure
  */
 int ipa_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl)
@@ -729,34 +776,21 @@
 	}
 
 	if (!ipa_ctx->polling_mode) {
-		if (IPA_CLIENT_IS_CONS(sys_in->client)) {
-			ipa_ctx->sys[sys_idx].event.options = SPS_O_EOT;
-			ipa_ctx->sys[sys_idx].event.mode = SPS_TRIGGER_CALLBACK;
-			ipa_ctx->sys[sys_idx].event.xfer_done = NULL;
-			ipa_ctx->sys[sys_idx].event.callback = ipa_rx_notify;
-			ipa_ctx->sys[sys_idx].event.user =
-				&ipa_ctx->sys[sys_idx];
-			result =
-			   sps_register_event(ipa_ctx->ep[ipa_ep_idx].ep_hdl,
-					      &ipa_ctx->sys[sys_idx].event);
-			if (result < 0) {
-				IPAERR("rx register event error %d\n", result);
-				goto fail_register_event;
-			}
-		} else {
-			ipa_ctx->sys[sys_idx].event.options = SPS_O_EOT;
-			ipa_ctx->sys[sys_idx].event.mode = SPS_TRIGGER_CALLBACK;
-			ipa_ctx->sys[sys_idx].event.xfer_done = NULL;
-			ipa_ctx->sys[sys_idx].event.callback = ipa_tx_notify;
-			ipa_ctx->sys[sys_idx].event.user =
-				&ipa_ctx->sys[sys_idx];
-			result =
-			   sps_register_event(ipa_ctx->ep[ipa_ep_idx].ep_hdl,
-					      &ipa_ctx->sys[sys_idx].event);
-			if (result < 0) {
-				IPAERR("tx register event error %d\n", result);
-				goto fail_register_event;
-			}
+
+		ipa_ctx->sys[sys_idx].event.options = SPS_O_EOT;
+		ipa_ctx->sys[sys_idx].event.mode = SPS_TRIGGER_CALLBACK;
+		ipa_ctx->sys[sys_idx].event.xfer_done = NULL;
+		ipa_ctx->sys[sys_idx].event.user =
+			&ipa_ctx->sys[sys_idx];
+		ipa_ctx->sys[sys_idx].event.callback =
+				IPA_CLIENT_IS_CONS(sys_in->client) ?
+					ipa_sps_irq_rx_notify :
+					ipa_sps_irq_tx_notify;
+		result = sps_register_event(ipa_ctx->ep[ipa_ep_idx].ep_hdl,
+					  &ipa_ctx->sys[sys_idx].event);
+		if (result < 0) {
+			IPAERR("register event error %d\n", result);
+			goto fail_register_event;
 		}
 	}
 
@@ -801,21 +835,25 @@
 EXPORT_SYMBOL(ipa_teardown_sys_pipe);
 
 /**
- * ipa_tx_comp() - Callback function which will call the user supplied callback
- * function to release the skb, or release it on its own if no callback function
- * was supplied.
+ * ipa_tx_comp_usr_notify_release() - Callback function which will call the
+ * user supplied callback function to release the skb, or release it on
+ * its own if no callback function was supplied.
  * @user1
  * @user2
+ *
+ * This notified callback (client_notify) is for
+ * the destination client.
+ * This function is supplied in ipa_connect.
  */
-static void ipa_tx_comp(void *user1, void *user2)
+static void ipa_tx_comp_usr_notify_release(void *user1, void *user2)
 {
 	struct sk_buff *skb = (struct sk_buff *)user1;
 	u32 ep_idx = (u32)user2;
 
 	IPADBG("skb=%p ep=%d\n", skb, ep_idx);
 
-	if (ipa_ctx->ep[ep_idx].notify)
-		ipa_ctx->ep[ep_idx].notify(ipa_ctx->ep[ep_idx].priv,
+	if (ipa_ctx->ep[ep_idx].client_notify)
+		ipa_ctx->ep[ep_idx].client_notify(ipa_ctx->ep[ep_idx].priv,
 				IPA_WRITE_DONE, (unsigned long)skb);
 	else
 		dev_kfree_skb_any(skb);
@@ -832,10 +870,20 @@
  * dst is a "valid" CONS type, then SW data-path is used. If dst is the
  * WLAN_AMPDU PROD type, then HW data-path for WLAN AMPDU is used. Anything else
  * is an error. For errors, client needs to free the skb as needed. For success,
- * IPA driver will later invoke client calback if one was supplied. That
+ * IPA driver will later invoke client callback if one was supplied. That
  * callback should free the skb. If no callback supplied, IPA driver will free
  * the skb internally
  *
+ * The function will use two descriptors for this send command
+ * (for A5_WLAN_AMPDU_PROD only one desciprtor will be sent),
+ * the first descriptor will be used to inform the IPA hardware that
+ * apps need to push data into the IPA (IP_PACKET_INIT immediate command).
+ * Once this send was done from SPS point-of-view the IPA driver will
+ * get notified by the supplied callback - ipa_sps_irq_tx_comp()
+ *
+ * ipa_sps_irq_tx_comp will call to the user supplied
+ * callback (supplied in ipa_connect())
+ *
  * Returns:	0 on success, negative on failure
  */
 int ipa_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
@@ -864,6 +912,7 @@
 			IPAERR("failed to alloc immediate command object\n");
 			goto fail_mem_alloc;
 		}
+		memset(cmd, 0x00, sizeof(*cmd));
 
 		cmd->destination_pipe_index = ipa_ep_idx;
 		if (meta && meta->mbim_stream_id_valid)
@@ -875,7 +924,7 @@
 		desc[1].pyld = skb->data;
 		desc[1].len = skb->len;
 		desc[1].type = IPA_DATA_DESC_SKB;
-		desc[1].callback = ipa_tx_comp;
+		desc[1].callback = ipa_tx_comp_usr_notify_release;
 		desc[1].user1 = skb;
 		desc[1].user2 = (void *)ipa_ep_idx;
 
@@ -887,7 +936,7 @@
 		desc[0].pyld = skb->data;
 		desc[0].len = skb->len;
 		desc[0].type = IPA_DATA_DESC_SKB;
-		desc[0].callback = ipa_tx_comp;
+		desc[0].callback = ipa_tx_comp_usr_notify_release;
 		desc[0].user1 = skb;
 		desc[0].user2 = (void *)ipa_ep_idx;
 
@@ -919,7 +968,7 @@
  * ipa_handle_rx_core() is run in polling mode. After all packets has been
  * received, the driver switches back to interrupt mode.
  */
-void ipa_handle_rx(struct work_struct *work)
+void ipa_wq_handle_rx(struct work_struct *work)
 {
 	ipa_handle_rx_core();
 	ipa_rx_switch_to_intr_mode();
@@ -962,7 +1011,7 @@
 		}
 
 		INIT_LIST_HEAD(&rx_pkt->link);
-		INIT_WORK(&rx_pkt->work, ipa_handle_rx);
+		INIT_WORK(&rx_pkt->work, ipa_wq_handle_rx);
 
 		rx_pkt->skb = __dev_alloc_skb(IPA_RX_SKB_SIZE, GFP_KERNEL);
 		if (rx_pkt->skb == NULL) {
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index 63ef5fb..3be2369 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -296,8 +296,9 @@
  * @dst_pipe_index: destination pipe index
  * @rt_tbl_idx: routing table index
  * @connect: SPS connect
- * @priv: user provided information
- * @notify: user provided CB for EP events notification
+ * @priv: user provided information which will forwarded once the user is
+ *        notified for new data avail
+ * @client_notify: user provided CB for EP events notification
  * @desc_fifo_in_pipe_mem: flag indicating if descriptors FIFO uses pipe memory
  * @data_fifo_in_pipe_mem: flag indicating if data FIFO uses pipe memory
  * @desc_fifo_pipe_mem_ofst: descriptors FIFO pipe memory offset
@@ -314,7 +315,7 @@
 	u32 rt_tbl_idx;
 	struct sps_connect connect;
 	void *priv;
-	void (*notify)(void *priv, enum ipa_dp_evt_type evt,
+	void (*client_notify)(void *priv, enum ipa_dp_evt_type evt,
 		       unsigned long data);
 	bool desc_fifo_in_pipe_mem;
 	bool data_fifo_in_pipe_mem;
@@ -357,7 +358,8 @@
 
 /**
  * struct ipa_tx_pkt_wrapper - IPA Tx packet wrapper
- * @type: info for the skb or immediate command param
+ * @type: specify if this packet is a data packet (skb) or
+ * an immediate command
  * @mem: memory buffer used by this Tx packet
  * @work: work struct for current Tx packet
  * @link: linked to the wrappers on that pipe
@@ -371,6 +373,8 @@
  * >1 and <0xFFFF for first of a "multiple" tranfer,
  * 0xFFFF for last desc, 0 for rest of "multiple' transfer
  * @bounce: va of bounce buffer
+ *
+ * This struct can wrap both data packet and immediate command packet.
  */
 struct ipa_tx_pkt_wrapper {
 	enum ipa_desc_type type;
@@ -693,8 +697,8 @@
 void ipa_replenish_rx_cache(void);
 void ipa_cleanup_rx(void);
 int ipa_cfg_filter(u32 disable);
-void ipa_write_done(struct work_struct *work);
-void ipa_handle_rx(struct work_struct *work);
+void ipa_wq_write_done(struct work_struct *work);
+void ipa_wq_handle_rx(struct work_struct *work);
 void ipa_handle_rx_core(void);
 int ipa_pipe_mem_init(u32 start_ofst, u32 size);
 int ipa_pipe_mem_alloc(u32 *ofst, u32 size);
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index f671ece..af421ac 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++) {
@@ -1165,6 +1167,7 @@
 	struct sps_iovec *desc;
 	struct sps_iovec iovec;
 	u32 next_write;
+	static int show_recom;
 
 	/* Is this a BAM-to-BAM or satellite connection? */
 	if ((pipe->state & (BAM_STATE_BAM2BAM | BAM_STATE_REMOTE))) {
@@ -1197,12 +1200,24 @@
 		if (!pipe->sys.ack_xfers && pipe->polled) {
 			pipe_handler_eot(dev, pipe);
 			if (next_write == pipe->sys.acked_offset) {
+				if (!show_recom) {
+					show_recom = true;
+					SPS_ERR("sps:Client of BAM 0x%x pipe %d is recommended to have flow control",
+						BAM_ID(dev), pipe_index);
+				}
+
 				SPS_DBG2("sps:Descriptor FIFO is full for BAM "
 					"0x%x pipe %d after pipe_handler_eot",
 					BAM_ID(dev), pipe_index);
 				return SPS_ERROR;
 			}
 		} else {
+			if (!show_recom) {
+				show_recom = true;
+				SPS_ERR("sps:Client of BAM 0x%x pipe %d is recommended to have flow control.",
+					BAM_ID(dev), pipe_index);
+			}
+
 			SPS_DBG2("sps:Descriptor FIFO is full for "
 				"BAM 0x%x pipe %d", BAM_ID(dev), pipe_index);
 			return SPS_ERROR;
@@ -1773,7 +1788,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/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 8f97531..6b067e7 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -398,8 +398,8 @@
 			pr_err("%s: src pipe connection failure\n", __func__);
 			return ret;
 		}
+		connection->src_enabled = 1;
 	}
-	connection->src_enabled = 1;
 
 	if (dst_pipe_idx) {
 		/* open Peripheral -> USB pipe */
@@ -409,8 +409,8 @@
 			pr_err("%s: dst pipe connection failure\n", __func__);
 			return ret;
 		}
+		connection->dst_enabled = 1;
 	}
-	connection->dst_enabled = 1;
 
 	return 0;
 }
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 703aca9..a8d52b5 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,
@@ -127,7 +130,7 @@
 	int			default_rbatt_mohm;
 	int			amux_2_trim_delta;
 	uint16_t		prev_last_good_ocv_raw;
-	unsigned int		rconn_mohm;
+	int			rconn_mohm;
 	struct mutex		last_ocv_uv_mutex;
 	int			last_ocv_uv;
 	int			pon_ocv_uv;
@@ -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;
@@ -1301,14 +1396,16 @@
 				int fcc_uah, int cc_uah, int uuc_uah)
 {
 	int chg_soc;
+	int vbat_batt_terminal_uv = vbat_uv
+					+ (ibat_ua * chip->rconn_mohm) / 1000;
 
 	if (chip->soc_at_cv == -EINVAL) {
 		/* In constant current charging return the calc soc */
-		if (vbat_uv <= chip->max_voltage_uv)
+		if (vbat_batt_terminal_uv <= chip->max_voltage_uv)
 			pr_debug("CC CHG SOC %d\n", soc);
 
 		/* Note the CC to CV point */
-		if (vbat_uv >= chip->max_voltage_uv) {
+		if (vbat_batt_terminal_uv >= chip->max_voltage_uv) {
 			chip->soc_at_cv = soc;
 			chip->prev_chg_soc = soc;
 			chip->ibat_at_cv_ua = ibat_ua;
@@ -1324,17 +1421,18 @@
 	 */
 
 	/*
-	 * if voltage lessened (possibly because of a system load)
-	 * keep reporting the prev chg soc
+	 * if voltage lessened by more than 10mV (possibly because of
+	 * a sudden increase in system load) keep reporting the prev chg soc
 	 */
-	if (vbat_uv <= chip->max_voltage_uv) {
-		pr_debug("vbat %d < max = %d CC CHG SOC %d\n",
-			vbat_uv, chip->max_voltage_uv, chip->prev_chg_soc);
+	if (vbat_batt_terminal_uv <= chip->max_voltage_uv - 10000) {
+		pr_debug("vbat_terminals %d < max = %d CC CHG SOC %d\n",
+			vbat_batt_terminal_uv,
+			chip->max_voltage_uv, chip->prev_chg_soc);
 		return chip->prev_chg_soc;
 	}
 
 	chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua,
-					100, -100000,
+					100, -1 * chip->chg_term_ua,
 					ibat_ua);
 
 	/* always report a higher soc */
@@ -1370,6 +1468,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 +1476,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;
 	}
 }
 
@@ -1700,7 +1800,7 @@
 
 	pr_debug("RUC = %duAh\n", remaining_usable_charge_uah);
 	if (fcc_uah - unusable_charge_uah <= 0) {
-		pr_warn("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
+		pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
 						fcc_uah, unusable_charge_uah);
 		soc = 0;
 	} else {
@@ -1743,13 +1843,13 @@
 		soc = 100;
 
 	if (soc < 0) {
-		pr_err("bad rem_usb_chg = %d rem_chg %d,"
+		pr_debug("bad rem_usb_chg = %d rem_chg %d,"
 				"cc_uah %d, unusb_chg %d\n",
 				remaining_usable_charge_uah,
 				remaining_charge_uah,
 				cc_uah, unusable_charge_uah);
 
-		pr_err("for bad rem_usb_chg last_ocv_uv = %d"
+		pr_debug("for bad rem_usb_chg last_ocv_uv = %d"
 				"chargecycles = %d, batt_temp = %d"
 				"fcc = %d soc =%d\n",
 				chip->last_ocv_uv, chargecycles, batt_temp,
@@ -1811,7 +1911,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 +1940,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 +2785,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 +3008,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..87e41e6 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -87,6 +87,7 @@
 #define EOC_CHECK_PERIOD_MS	10000
 /* check for USB unplug every 200 msecs */
 #define UNPLUG_CHECK_WAIT_PERIOD_MS 200
+#define UNPLUG_CHECK_RAMP_MS 25
 #define USB_TRIM_ENTRIES 16
 
 enum chg_fsm_state {
@@ -260,11 +261,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;
@@ -281,6 +280,7 @@
 	struct delayed_work		eoc_work;
 	struct delayed_work		unplug_check_work;
 	struct delayed_work		vin_collapse_check_work;
+	struct delayed_work		btc_override_work;
 	struct wake_lock		eoc_wake_lock;
 	enum pm8921_chg_cold_thr	cold_thr;
 	enum pm8921_chg_hot_thr		hot_thr;
@@ -292,6 +292,11 @@
 	int				recent_reported_soc;
 	int				battery_less_hardware;
 	int				ibatmax_max_adj_ma;
+	int				btc_override;
+	int				btc_override_cold_decidegc;
+	int				btc_override_hot_decidegc;
+	int				btc_delay_ms;
+	bool				btc_panic_if_cant_stop_chg;
 };
 
 /* user space parameter to limit usb current */
@@ -307,7 +312,16 @@
 
 static struct pm8921_chg_chip *the_chip;
 
-static struct pm8xxx_adc_arb_btm_param btm_config;
+static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
+{
+	int rc;
+
+	rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
+	if (rc)
+		pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
+
+	return rc;
+}
 
 static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
 							u8 mask, u8 val)
@@ -322,9 +336,9 @@
 	}
 	reg &= ~mask;
 	reg |= val & mask;
-	rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
+	rc = pm_chg_write(chip, addr, reg);
 	if (rc) {
-		pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
+		pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
 		return rc;
 	}
 	return 0;
@@ -361,14 +375,14 @@
 	int err, ret = 0;
 
 	temp = CAPTURE_FSM_STATE_CMD;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return err;
 	}
 
 	temp = READ_BANK_7;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return err;
@@ -383,7 +397,7 @@
 	ret = temp & 0xF;
 
 	temp = READ_BANK_4;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return err;
@@ -406,7 +420,7 @@
 	int err;
 
 	temp = READ_BANK_6;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return err;
@@ -488,7 +502,7 @@
 	}
 
 	pr_debug("voltage=%d setting %02x\n", voltage, temp);
-	return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
+	return pm_chg_write(chip, CHG_VDD_MAX, temp);
 }
 
 static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
@@ -757,7 +771,7 @@
 	0x13,
 	0x14,
 	0x13,
-	0x16,
+	0x3,
 	0x1A,
 	0x1D,
 	0x1D,
@@ -786,15 +800,18 @@
 	{1600, 0xF},
 };
 
-#define REG_SBI_CONFIG		0x04F
-#define PAGE3_ENABLE_MASK	0x6
-#define USB_OVP_TRIM_MASK	0x3F
-#define USB_OVP_TRIM_MIN	0x00
+#define REG_SBI_CONFIG			0x04F
+#define PAGE3_ENABLE_MASK		0x6
+#define USB_OVP_TRIM_MASK		0x3F
+#define USB_OVP_TRIM_PM8917_MASK	0x7F
+#define USB_OVP_TRIM_MIN		0x00
 #define REG_USB_OVP_TRIM_ORIG_LSB	0x10A
 #define REG_USB_OVP_TRIM_ORIG_MSB	0x09C
+#define REG_USB_OVP_TRIM_PM8917		0x2B5
+#define REG_USB_OVP_TRIM_PM8917_BIT	BIT(0)
 static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
 {
-	u8 temp, sbi_config, msb, lsb;
+	u8 temp, sbi_config, msb, lsb, mask;
 	s8 trim;
 	int rc = 0;
 	static u8 usb_trim_reg_orig = 0xFF;
@@ -821,6 +838,19 @@
 		msb = msb >> 5;
 		lsb = lsb >> 5;
 		usb_trim_reg_orig = msb << 3 | lsb;
+
+		if (pm8xxx_get_version(chip->dev->parent)
+				== PM8XXX_VERSION_8917) {
+			rc = pm8xxx_readb(chip->dev->parent,
+					REG_USB_OVP_TRIM_PM8917, &msb);
+			if (rc) {
+				pr_err("error = %d reading config reg\n", rc);
+				return rc;
+			}
+
+			msb = msb & REG_USB_OVP_TRIM_PM8917_BIT;
+			usb_trim_reg_orig |= msb << 6;
+		}
 	}
 
 	/* use the original trim value */
@@ -840,19 +870,24 @@
 	}
 
 	temp = sbi_config | PAGE3_ENABLE_MASK;
-	rc = pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, temp);
+	rc = pm_chg_write(chip, REG_SBI_CONFIG, temp);
 	if (rc) {
 		pr_err("error = %d writing sbi config reg\n", rc);
 		return rc;
 	}
 
-	rc = pm_chg_masked_write(chip, USB_OVP_TRIM, USB_OVP_TRIM_MASK, trim);
+	mask = USB_OVP_TRIM_MASK;
+
+	if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
+		mask = USB_OVP_TRIM_PM8917_MASK;
+
+	rc = pm_chg_masked_write(chip, USB_OVP_TRIM, mask, trim);
 	if (rc) {
 		pr_err("error = %d writing USB_OVP_TRIM\n", rc);
 		return rc;
 	}
 
-	rc = pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+	rc = pm_chg_write(chip, REG_SBI_CONFIG, sbi_config);
 	if (rc) {
 		pr_err("error = %d writing sbi config reg\n", rc);
 		return rc;
@@ -1315,20 +1350,6 @@
 			return 0;
 		}
 
-		if (charging_disabled)
-			return 0;
-
-		/* check external charger first before the dc path */
-		if (is_ext_charging(the_chip)) {
-			val->intval = 1;
-			return 0;
-		}
-
-		if (pm_is_chg_charge_dis(the_chip)) {
-			val->intval = 0;
-			return 0;
-		}
-
 		if (the_chip->dc_present) {
 			val->intval = 1;
 			return 0;
@@ -1354,7 +1375,7 @@
 		return 0;
 
 	/* enable usbin valid comparator and remove force usb ovp fet off */
-	rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0xB2);
+	rc = pm_chg_write(chip, USB_OVP_TEST, 0xB2);
 	if (rc < 0) {
 		pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
 		return rc;
@@ -1373,7 +1394,7 @@
 		return 0;
 
 	/* disable usbin valid comparator and force usb ovp fet off */
-	rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0xB3);
+	rc = pm_chg_write(chip, USB_OVP_TEST, 0xB3);
 	if (rc < 0) {
 		pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
 		return rc;
@@ -1431,15 +1452,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 +1485,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 +1771,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 +1824,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 +1923,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) {
@@ -1975,7 +1977,7 @@
 	if (disable) {
 		pr_warn("Disabling input current limit!\n");
 
-		return pm8xxx_writeb(the_chip->dev->parent,
+		return pm_chg_write(the_chip,
 			 CHG_BUCK_CTRL_TEST3, 0xF2);
 	}
 	return 0;
@@ -2243,8 +2245,7 @@
 	}
 	if (usb_present) {
 		schedule_delayed_work(&chip->unplug_check_work,
-			round_jiffies_relative(msecs_to_jiffies
-				(UNPLUG_CHECK_WAIT_PERIOD_MS)));
+			msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
 		pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
 	} else {
 		/* USB unplugged reset target current */
@@ -2312,7 +2313,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__);
@@ -2320,20 +2324,24 @@
 	}
 
 	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);
+			msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
 
 	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);
+	if (chip->btc_override)
+		schedule_delayed_work(&chip->btc_override_work,
+				round_jiffies_relative(msecs_to_jiffies
+					(chip->btc_delay_ms)));
 	/* Update battery charging LEDs and user space battery info */
 	power_supply_changed(&chip->batt_psy);
 }
@@ -2343,7 +2351,7 @@
 	u8 temp;
 	int rc;
 
-	rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, 0x30);
+	rc = pm_chg_write(chip, ovptestreg, 0x30);
 	if (rc) {
 		pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
 		return;
@@ -2355,7 +2363,7 @@
 	}
 	/* set ovp fet disable bit and the write bit */
 	temp |= 0x81;
-	rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, temp);
+	rc = pm_chg_write(chip, ovptestreg, temp);
 	if (rc) {
 		pr_err("Failed to write 0x%x OVP_TEST rc=%d\n", temp, rc);
 		return;
@@ -2422,7 +2430,7 @@
 	u8 temp;
 	int rc;
 
-	rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, 0x30);
+	rc = pm_chg_write(chip, ovptestreg, 0x30);
 	if (rc) {
 		pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
 		return;
@@ -2435,7 +2443,7 @@
 	/* unset ovp fet disable bit and set the write bit */
 	temp &= 0xFE;
 	temp |= 0x80;
-	rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, temp);
+	rc = pm_chg_write(chip, ovptestreg, temp);
 	if (rc) {
 		pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
 								temp, rc);
@@ -2568,15 +2576,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,
+				      msecs_to_jiffies
+						(UNPLUG_CHECK_WAIT_PERIOD_MS));
 	} else {
 		handle_usb_insertion_removal(chip);
 	}
@@ -2730,7 +2748,7 @@
 	u8 temp;
 	int rc;
 
-	rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x40);
+	rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
 	if (rc) {
 		pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
 		return;
@@ -2746,7 +2764,7 @@
 	temp |= (u8)pon_time_ns;
 	/* write enable bank 4 */
 	temp |= 0x80;
-	rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
+	rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
 	if (rc) {
 		pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
 		return;
@@ -2775,6 +2793,7 @@
 	u8 reg_loop, active_path;
 	int rc, ibat, active_chg_plugged_in, usb_ma;
 	int chg_gone = 0;
+	bool ramp = false;
 
 	reg_loop = 0;
 
@@ -2801,12 +2820,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)
@@ -2878,15 +2891,20 @@
 			__pm8921_charger_vbus_draw(usb_ma);
 			pr_debug("usb_now=%d, usb_target = %d\n",
 					usb_ma, usb_target_ma);
+			ramp = true;
 		} else {
 			usb_target_ma = usb_ma;
 		}
 	}
 check_again_later:
+	pr_debug("ramp: %d\n", ramp);
 	/* schedule to check again later */
-	schedule_delayed_work(&chip->unplug_check_work,
-		      round_jiffies_relative(msecs_to_jiffies
-				(UNPLUG_CHECK_WAIT_PERIOD_MS)));
+	if (ramp)
+		schedule_delayed_work(&chip->unplug_check_work,
+			msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
+	else
+		schedule_delayed_work(&chip->unplug_check_work,
+			msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
 }
 
 static irqreturn_t loop_change_irq_handler(int irq, void *data)
@@ -2936,6 +2954,13 @@
 				      round_jiffies_relative(msecs_to_jiffies
 						     (EOC_CHECK_PERIOD_MS)));
 	}
+	if (high_transition
+		&& chip->btc_override
+		&& !delayed_work_pending(&chip->btc_override_work)) {
+		schedule_delayed_work(&chip->btc_override_work,
+					round_jiffies_relative(msecs_to_jiffies
+						(chip->btc_delay_ms)));
+	}
 	power_supply_changed(&chip->batt_psy);
 	bms_notify_check(chip);
 	return IRQ_HANDLED;
@@ -3079,20 +3104,32 @@
 	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,
+				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 +3280,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,
@@ -3343,6 +3453,155 @@
 	return CHG_FINISHED;
 }
 
+#define COMP_OVERRIDE_HOT_BANK	6
+#define COMP_OVERRIDE_COLD_BANK	7
+#define COMP_OVERRIDE_BIT  BIT(1)
+static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
+{
+	u8 val;
+	int rc = 0;
+
+	val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
+
+	if (flag)
+		val |= 0x01;
+
+	rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
+	if (rc < 0)
+		pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
+
+	pr_debug("btc cold = %d val = 0x%x\n", flag, val);
+	return rc;
+}
+
+static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
+{
+	u8 val;
+	int rc = 0;
+
+	val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
+
+	if (flag)
+		val |= 0x01;
+
+	rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
+	if (rc < 0)
+		pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
+
+	pr_debug("btc hot = %d val = 0x%x\n", flag, val);
+	return rc;
+}
+
+static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
+{
+	int rc = 0;
+	u8 reg;
+	u8 val;
+
+	val = COMP_OVERRIDE_HOT_BANK << 2;
+	rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
+	if (rc < 0) {
+		pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
+		goto cold_init;
+	}
+	rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
+	if (rc < 0) {
+		pr_err("Could not read bank %d of override rc = %d\n",
+				COMP_OVERRIDE_HOT_BANK, rc);
+		goto cold_init;
+	}
+	if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
+		/* for now override it as not hot */
+		rc = pm_chg_override_hot(chip, 0);
+		if (rc < 0)
+			pr_err("Could not override hot rc = %d\n", rc);
+	}
+
+cold_init:
+	val = COMP_OVERRIDE_COLD_BANK << 2;
+	rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
+	if (rc < 0) {
+		pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
+		return;
+	}
+	rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
+	if (rc < 0) {
+		pr_err("Could not read bank %d of override rc = %d\n",
+				COMP_OVERRIDE_COLD_BANK, rc);
+		return;
+	}
+	if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
+		/* for now override it as not cold */
+		rc = pm_chg_override_cold(chip, 0);
+		if (rc < 0)
+			pr_err("Could not override cold rc = %d\n", rc);
+	}
+}
+
+static void btc_override_worker(struct work_struct *work)
+{
+	int decidegc;
+	int temp;
+	int rc = 0;
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct pm8921_chg_chip *chip = container_of(dwork,
+				struct pm8921_chg_chip, btc_override_work);
+
+	if (!chip->btc_override) {
+		pr_err("called when not enabled\n");
+		return;
+	}
+
+	decidegc = get_prop_batt_temp(chip);
+
+	pr_debug("temp=%d\n", decidegc);
+
+	temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
+	if (temp) {
+		if (decidegc < chip->btc_override_hot_decidegc)
+			/* stop forcing batt hot */
+			rc = pm_chg_override_hot(chip, 0);
+			if (rc)
+				pr_err("Couldnt write 0 to hot comp\n");
+	} else {
+		if (decidegc >= chip->btc_override_hot_decidegc)
+			/* start forcing batt hot */
+			rc = pm_chg_override_hot(chip, 1);
+			if (rc && chip->btc_panic_if_cant_stop_chg)
+				panic("Couldnt override comps to stop chg\n");
+	}
+
+	temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
+	if (temp) {
+		if (decidegc > chip->btc_override_cold_decidegc)
+			/* stop forcing batt cold */
+			rc = pm_chg_override_cold(chip, 0);
+			if (rc)
+				pr_err("Couldnt write 0 to cold comp\n");
+	} else {
+		if (decidegc <= chip->btc_override_cold_decidegc)
+			/* start forcing batt cold */
+			rc = pm_chg_override_cold(chip, 1);
+			if (rc && chip->btc_panic_if_cant_stop_chg)
+				panic("Couldnt override comps to stop chg\n");
+	}
+
+	if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
+		&& get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
+		schedule_delayed_work(&chip->btc_override_work,
+					round_jiffies_relative(msecs_to_jiffies
+						(chip->btc_delay_ms)));
+		return;
+	}
+
+	rc = pm_chg_override_hot(chip, 0);
+	if (rc)
+		pr_err("Couldnt write 0 to hot comp\n");
+	rc = pm_chg_override_cold(chip, 0);
+	if (rc)
+		pr_err("Couldnt write 0 to cold comp\n");
+}
+
 /**
  * eoc_worker - internal function to check if battery EOC
  *		has happened
@@ -3418,6 +3677,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 +3692,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 -
  *
@@ -3656,8 +3822,7 @@
 	notify_usb_of_the_plugin_event(chip->usb_present);
 	if (chip->usb_present || chip->dc_present) {
 		schedule_delayed_work(&chip->unplug_check_work,
-			round_jiffies_relative(msecs_to_jiffies
-				(UNPLUG_CHECK_WAIT_PERIOD_MS)));
+			msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
 		pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
 	}
 
@@ -3808,28 +3973,28 @@
 	u8 temp;
 
 	temp  = 0xD1;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return;
 	}
 
 	temp  = 0xD3;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return;
 	}
 
 	temp  = 0xD1;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return;
 	}
 
 	temp  = 0xD5;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return;
@@ -3838,14 +4003,14 @@
 	udelay(183);
 
 	temp  = 0xD1;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return;
 	}
 
 	temp  = 0xD0;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return;
@@ -3853,14 +4018,14 @@
 	udelay(32);
 
 	temp  = 0xD1;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return;
 	}
 
 	temp  = 0xD3;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return;
@@ -3873,14 +4038,14 @@
 	u8 temp;
 
 	temp  = 0xD1;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return;
 	}
 
 	temp  = 0xD0;
-	err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
+	err = pm_chg_write(chip, CHG_TEST, temp);
 	if (err) {
 		pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
 		return;
@@ -4000,6 +4165,10 @@
 						1000 * MIN_CHARGE_CURRENT_MA);
 		/* add 20 minutes of buffer time */
 		safety_time += 20;
+
+		/* make sure we do not exceed the maximum programmable time */
+		if (safety_time > PM8921_CHG_TCHG_MAX)
+			safety_time = PM8921_CHG_TCHG_MAX;
 	}
 
 	rc = pm_chg_tchg_max_set(chip, safety_time);
@@ -4043,10 +4212,10 @@
 	}
 	/* switch to a 3.2Mhz for the buck */
 	if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
-		rc = pm8xxx_writeb(chip->dev->parent,
+		rc = pm_chg_write(chip,
 			CHG_BUCK_CLOCK_CTRL_8038, 0x15);
 	else
-		rc = pm8xxx_writeb(chip->dev->parent,
+		rc = pm_chg_write(chip,
 			CHG_BUCK_CLOCK_CTRL, 0x15);
 
 	if (rc) {
@@ -4119,10 +4288,10 @@
 		}
 		/* Check if die 3.0.1 is present */
 		if (subrev == 0x1)
-			pm8xxx_writeb(chip->dev->parent,
+			pm_chg_write(chip,
 				CHG_BUCK_CTRL_TEST3, 0xA4);
 		else
-			pm8xxx_writeb(chip->dev->parent,
+			pm_chg_write(chip,
 				CHG_BUCK_CTRL_TEST3, 0xAC);
 	}
 
@@ -4139,10 +4308,10 @@
 		}
 	}
 
-	pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
+	pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
 
 	/* Disable EOC FSM processing */
-	pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
+	pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
 
 	rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
 						VREF_BATT_THERM_FORCE_ON);
@@ -4223,9 +4392,9 @@
 	u8 temp;
 
 	temp = (u8) val;
-	ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
+	ret = pm_chg_write(the_chip, addr, temp);
 	if (ret) {
-		pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
+		pr_err("pm_chg_write to %x value =%d errored = %d\n",
 			addr, temp, ret);
 		return -EAGAIN;
 	}
@@ -4435,19 +4604,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 +4618,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 +4675,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;
@@ -4545,6 +4696,16 @@
 	chip->led_src_config = pdata->led_src_config;
 	chip->has_dc_supply = pdata->has_dc_supply;
 	chip->battery_less_hardware = pdata->battery_less_hardware;
+	chip->btc_override = pdata->btc_override;
+	if (chip->btc_override) {
+		chip->btc_delay_ms = pdata->btc_delay_ms;
+		chip->btc_override_cold_decidegc
+			= pdata->btc_override_cold_degc * 10;
+		chip->btc_override_hot_decidegc
+			= pdata->btc_override_hot_degc * 10;
+		chip->btc_panic_if_cant_stop_chg
+			= pdata->btc_panic_if_cant_stop_chg;
+	}
 
 	if (chip->battery_less_hardware)
 		charging_disabled = 1;
@@ -4558,6 +4719,9 @@
 		goto free_chip;
 	}
 
+	if (chip->btc_override)
+		pm8921_chg_btc_override_init(chip);
+
 	chip->usb_psy.name = "usb",
 	chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
 	chip->usb_psy.supplied_to = pm_power_supplied_to,
@@ -4612,6 +4776,7 @@
 	INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
 
 	INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
+	INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
 
 	rc = request_irqs(chip, pdev);
 	if (rc) {
@@ -4621,20 +4786,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) {
@@ -4661,6 +4814,7 @@
 free_irq:
 	free_irqs(chip);
 unregister_batt:
+	wake_lock_destroy(&chip->eoc_wake_lock);
 	power_supply_unregister(&chip->batt_psy);
 unregister_dc:
 	power_supply_unregister(&chip->dc_psy);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 1955ff4..81ffa3a 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -33,7 +33,7 @@
 #define BMS1_MODE_CTL			0X40
 /* Coulomb counter clear registers */
 #define BMS1_CC_DATA_CTL		0x42
-#define BMS1_CC_CLEAR_CTRL		0x43
+#define BMS1_CC_CLEAR_CTL		0x43
 /* OCV limit registers */
 #define BMS1_OCV_USE_LOW_LIMIT_THR0	0x48
 #define BMS1_OCV_USE_LOW_LIMIT_THR1	0x49
@@ -73,6 +73,8 @@
 #define IAVG_STORAGE_REG		0xB1
 #define SOC_STORAGE_REG			0xB2
 #define BMS1_BMS_DATA_REG_3		0xB3
+/* IADC Channel Select */
+#define IADC1_BMS_ADC_CH_SEL_CTL	0x48
 
 /* Configuration for saving of shutdown soc/iavg */
 #define IGNORE_SOC_TEMP_DECIDEG		50
@@ -105,6 +107,7 @@
 	struct power_supply		*batt_psy;
 	struct spmi_device		*spmi;
 	u16				base;
+	u16				iadc_base;
 
 	u8				revision1;
 	u8				revision2;
@@ -134,6 +137,8 @@
 	struct mutex			last_ocv_uv_mutex;
 	struct mutex			soc_invalidation_mutex;
 
+	bool				use_external_rsense;
+
 	unsigned int			start_percent;
 	unsigned int			end_percent;
 	bool				ignore_shutdown_soc;
@@ -176,7 +181,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 +202,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 +345,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));
@@ -510,12 +489,49 @@
 	pr_debug("last_good_ocv_uv = %d\n", raw->last_good_ocv_uv);
 }
 
+#define CLEAR_CC			BIT(7)
+#define CLEAR_SW_CC			BIT(6)
+/**
+ * reset both cc and sw-cc.
+ * note: this should only be ever called from one thread
+ * or there may be a race condition where CC is never enabled
+ * again
+ */
+static void reset_cc(struct qpnp_bms_chip *chip)
+{
+	int rc;
+
+	pr_debug("resetting cc manually\n");
+	rc = qpnp_masked_write(chip, BMS1_CC_CLEAR_CTL,
+				CLEAR_CC | CLEAR_SW_CC,
+				CLEAR_CC | CLEAR_SW_CC);
+	if (rc)
+		pr_err("cc reset failed: %d\n", rc);
+
+	/* wait for 100us for cc to reset */
+	udelay(100);
+
+	rc = qpnp_masked_write(chip, BMS1_CC_CLEAR_CTL,
+				CLEAR_CC | CLEAR_SW_CC, 0);
+	if (rc)
+		pr_err("cc reenable failed: %d\n", rc);
+}
+
 static int read_soc_params_raw(struct qpnp_bms_chip *chip,
 				struct raw_soc_params *raw)
 {
 	int rc;
 
 	mutex_lock(&chip->bms_output_lock);
+
+	if (chip->prev_last_good_ocv_raw == 0) {
+		/* software workaround for BMS 1.0
+		 * The coulomb counter does not reset upon PON, so reset it
+		 * manually upon probe. */
+		if (chip->revision1 == 0 && chip->revision2 == 0)
+			reset_cc(chip);
+	}
+
 	lock_output_data(chip);
 
 	rc = qpnp_read_wrapper(chip, (u8 *)&raw->last_good_ocv_raw,
@@ -1056,11 +1072,8 @@
 	return 0;
 }
 
-static int get_simultaneous_batt_v_and_i(
-						struct qpnp_bms_chip *chip,
-						int *ibat_ua, int *vbat_uv)
+static bool is_batfet_open(struct qpnp_bms_chip *chip)
 {
-	int rc;
 	union power_supply_propval ret = {0,};
 
 	if (chip->batt_psy == NULL)
@@ -1069,12 +1082,20 @@
 		/* if battery has been registered, use the status property */
 		chip->batt_psy->get_property(chip->batt_psy,
 					POWER_SUPPLY_PROP_STATUS, &ret);
-	} else {
-		/* default to using separate vbat/ibat if unregistered */
-		ret.intval = POWER_SUPPLY_STATUS_FULL;
+		return ret.intval == POWER_SUPPLY_STATUS_FULL;
 	}
 
-	if (ret.intval == POWER_SUPPLY_STATUS_FULL) {
+	/* Default to true if the battery power supply is not registered. */
+	pr_debug("battery power supply is not registered\n");
+	return true;
+}
+
+static int get_simultaneous_batt_v_and_i(struct qpnp_bms_chip *chip,
+					int *ibat_ua, int *vbat_uv)
+{
+	int rc;
+
+	if (is_batfet_open(chip)) {
 		pr_debug("batfet is open using separate vbat and ibat meas\n");
 		rc = get_battery_voltage(vbat_uv);
 		if (rc < 0) {
@@ -1186,7 +1207,7 @@
 				(s64)params->fcc_uah - params->uuc_uah);
 	soc_est = bound_soc(soc_est);
 
-	if (ibat_ua < 0) {
+	if (ibat_ua < 0 && !is_batfet_open(chip)) {
 		soc = charging_adjustments(chip, params, soc, vbat_uv, ibat_ua,
 				batt_temp);
 		goto out;
@@ -1280,6 +1301,34 @@
 	return soc;
 }
 
+static int clamp_soc_based_on_voltage(struct qpnp_bms_chip *chip, int soc)
+{
+	int rc, vbat_uv;
+	struct qpnp_vadc_result result;
+
+	rc = qpnp_vadc_read(VBAT_SNS, &result);
+	if (rc) {
+		pr_err("error reading vbat_sns adc channel = %d, rc = %d\n",
+						VBAT_SNS, rc);
+		return rc;
+	}
+
+	vbat_uv = (int)result.physical;
+	if (soc == 0 && vbat_uv > chip->v_cutoff_uv) {
+		pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n",
+						vbat_uv, chip->v_cutoff_uv);
+		return 1;
+	} else if (soc > 0 && vbat_uv < chip->v_cutoff_uv) {
+		pr_debug("forcing soc to 0, vbat (%d) < cutoff (%d)\n",
+						vbat_uv, chip->v_cutoff_uv);
+		return 0;
+	} else {
+		pr_debug("not clamping, using soc = %d, vbat = %d and cutoff = %d\n",
+				soc, vbat_uv, chip->v_cutoff_uv);
+		return soc;
+	}
+}
+
 static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
 					struct raw_soc_params *raw,
 					int batt_temp)
@@ -1296,7 +1345,7 @@
 
 	pr_debug("RUC = %duAh\n", remaining_usable_charge_uah);
 	if (params.fcc_uah - params.uuc_uah <= 0) {
-		pr_warn("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
+		pr_debug("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
 						params.fcc_uah,
 						params.uuc_uah);
 		soc = 0;
@@ -1330,12 +1379,12 @@
 		soc = 100;
 
 	if (soc < 0) {
-		pr_err("bad rem_usb_chg = %d rem_chg %d, cc_uah %d, unusb_chg %d\n",
+		pr_debug("bad rem_usb_chg = %d rem_chg %d, cc_uah %d, unusb_chg %d\n",
 				remaining_usable_charge_uah,
 				params.ocv_charge_uah,
 				params.cc_uah, params.uuc_uah);
 
-		pr_err("for bad rem_usb_chg last_ocv_uv = %d batt_temp = %d fcc = %d soc =%d\n",
+		pr_debug("for bad rem_usb_chg last_ocv_uv = %d batt_temp = %d fcc = %d soc =%d\n",
 				chip->last_ocv_uv, batt_temp,
 				params.fcc_uah, soc);
 		soc = 0;
@@ -1374,6 +1423,11 @@
 	pr_debug("SOC before adjustment = %d\n", soc);
 	new_calculated_soc = adjust_soc(chip, &params, soc, batt_temp);
 
+	/* clamp soc due to BMS HW inaccuracies in pm8941v2.0 */
+	if (chip->revision1 == 0 && chip->revision2 == 0)
+		new_calculated_soc = clamp_soc_based_on_voltage(chip,
+						new_calculated_soc);
+
 	if (new_calculated_soc != chip->calculated_soc
 			&& chip->bms_psy.name != NULL) {
 		power_supply_changed(&chip->bms_psy);
@@ -1381,12 +1435,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 +1449,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 +1489,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 +1597,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 +1613,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);
@@ -1584,7 +1669,8 @@
 	}
 
 	/* last_soc < soc  ... scale and catch up */
-	if (chip->last_soc != -EINVAL && chip->last_soc < soc && soc != 100)
+	if (chip->last_soc != -EINVAL && chip->last_soc < soc
+			&& soc != 100 && chip->catch_up_time_us != 0)
 		soc = scale_soc_while_chg(chip, delta_time_us,
 						soc, chip->last_soc);
 
@@ -1598,27 +1684,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 +1953,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 +1969,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,17 +1982,109 @@
 	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;
 }
 
-static int __devinit
-qpnp_bms_probe(struct spmi_device *spmi)
+#define REG_OFFSET_PERP_TYPE			0x04
+#define REG_OFFSET_PERP_SUBTYPE			0x05
+#define BMS_BMS_TYPE				0xD
+#define BMS_BMS_SUBTYPE				0x1
+#define BMS_IADC_TYPE				0x8
+#define BMS_IADC_SUBTYPE			0x3
+
+static int register_spmi(struct qpnp_bms_chip *chip, struct spmi_device *spmi)
+{
+	struct spmi_resource *spmi_resource;
+	struct resource *resource;
+	int rc;
+	u8 type, subtype;
+
+	chip->dev = &(spmi->dev);
+	chip->spmi = spmi;
+
+	spmi_for_each_container_dev(spmi_resource, spmi) {
+		if (!spmi_resource) {
+			pr_err("qpnp_bms: spmi resource absent\n");
+			return -ENXIO;
+		}
+
+		resource = spmi_get_resource(spmi, spmi_resource,
+						IORESOURCE_MEM, 0);
+		if (!(resource && resource->start)) {
+			pr_err("node %s IO resource absent!\n",
+				spmi->dev.of_node->full_name);
+			return -ENXIO;
+		}
+
+		rc = qpnp_read_wrapper(chip, &type,
+				resource->start + REG_OFFSET_PERP_TYPE, 1);
+		if (rc) {
+			pr_err("Peripheral type read failed rc=%d\n", rc);
+			return rc;
+		}
+		rc = qpnp_read_wrapper(chip, &subtype,
+				resource->start + REG_OFFSET_PERP_SUBTYPE, 1);
+		if (rc) {
+			pr_err("Peripheral subtype read failed rc=%d\n", rc);
+			return rc;
+		}
+
+		if (type == BMS_BMS_TYPE && subtype == BMS_BMS_SUBTYPE) {
+			chip->base = resource->start;
+		} else if (type == BMS_IADC_TYPE
+					&& subtype == BMS_IADC_SUBTYPE) {
+			chip->iadc_base = resource->start;
+		} else {
+			pr_err("Invalid peripheral start=0x%x type=0x%x, subtype=0x%x\n",
+					resource->start, type, subtype);
+		}
+	}
+
+	if (chip->base == 0) {
+		dev_err(&spmi->dev, "BMS peripheral was not registered\n");
+		return -EINVAL;
+	}
+	if (chip->iadc_base == 0) {
+		dev_err(&spmi->dev, "BMS_IADC peripheral was not registered\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#define ADC_CH_SEL_MASK			0x7
+static int read_iadc_channel_select(struct qpnp_bms_chip *chip)
+{
+	u8 iadc_channel_select;
+	int rc;
+
+	rc = qpnp_read_wrapper(chip, &iadc_channel_select,
+			chip->iadc_base + IADC1_BMS_ADC_CH_SEL_CTL, 1);
+	if (rc) {
+		pr_err("Error reading bms_iadc channel register %d\n", rc);
+		return rc;
+	}
+
+	iadc_channel_select &= ADC_CH_SEL_MASK;
+	if (iadc_channel_select == INTERNAL_RSENSE) {
+		pr_debug("Internal rsense used\n");
+		chip->use_external_rsense = false;
+	} else if (iadc_channel_select == EXTERNAL_RSENSE) {
+		pr_debug("External rsense used\n");
+		chip->use_external_rsense = true;
+	} else {
+		pr_err("IADC1_BMS_IADC configured incorrectly. Selected channel = %d\n",
+							iadc_channel_select);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
 {
 	struct qpnp_bms_chip *chip;
-	struct resource *bms_resource;
 	int rc, vbatt;
 
 	chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -1922,19 +2094,23 @@
 		return -ENOMEM;
 	}
 
-	chip->dev = &(spmi->dev);
-	chip->spmi = spmi;
-
-	mutex_init(&chip->bms_output_lock);
-	mutex_init(&chip->last_ocv_uv_mutex);
-	mutex_init(&chip->soc_invalidation_mutex);
-
-	bms_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
-	if (!bms_resource) {
-		dev_err(&spmi->dev, "Unable to get BMS base address\n");
-		return -ENXIO;
+	rc = qpnp_vadc_is_ready();
+	if (rc) {
+		pr_info("vadc not ready: %d, deferring probe\n", rc);
+		goto error_read;
 	}
-	chip->base = bms_resource->start;
+
+	rc = qpnp_iadc_is_ready();
+	if (rc) {
+		pr_info("iadc not ready: %d, deferring probe\n", rc);
+		goto error_read;
+	}
+
+	rc = register_spmi(chip, spmi);
+	if (rc) {
+		pr_err("error registering spmi resource %d\n", rc);
+		goto error_resource;
+	}
 
 	rc = qpnp_read_wrapper(chip, &chip->revision1,
 			chip->base + BMS1_REVISION1, 1);
@@ -1949,10 +2125,11 @@
 		pr_err("Error reading version register %d\n", rc);
 		goto error_read;
 	}
+	pr_debug("BMS version: %hhu.%hhu\n", chip->revision2, chip->revision1);
 
-	rc = set_battery_data(chip);
+	rc = read_iadc_channel_select(chip);
 	if (rc) {
-		pr_err("Bad battery data %d\n", rc);
+		pr_err("Unable to get iadc selected channel = %d\n", rc);
 		goto error_read;
 	}
 
@@ -1962,8 +2139,18 @@
 		goto error_read;
 	}
 
+	rc = set_battery_data(chip);
+	if (rc) {
+		pr_err("Bad battery data %d\n", rc);
+		goto error_read;
+	}
+
 	bms_initialize_constants(chip);
 
+	mutex_init(&chip->bms_output_lock);
+	mutex_init(&chip->last_ocv_uv_mutex);
+	mutex_init(&chip->soc_invalidation_mutex);
+
 	INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
 			calculate_soc_work);
 
@@ -1996,7 +2183,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");
@@ -2005,6 +2192,7 @@
 unregister_dc:
 	power_supply_unregister(&chip->bms_psy);
 	dev_set_drvdata(&spmi->dev, NULL);
+error_resource:
 error_read:
 	kfree(chip);
 	return rc;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index b5559db..a0d84df 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -71,6 +71,7 @@
 #define CHGR_CHG_WDOG_EN			0x65
 #define CHGR_USB_IUSB_MAX			0x44
 #define CHGR_USB_USB_SUSP			0x47
+#define CHGR_USB_USB_OTG_CTL			0x48
 #define CHGR_USB_ENUM_T_STOP			0x4E
 #define CHGR_CHG_TEMP_THRESH			0x66
 #define CHGR_BAT_IF_PRES_STATUS			0x08
@@ -271,6 +272,27 @@
 	return 0;
 }
 
+#define USB_OTG_EN_BIT	BIT(0)
+static int
+qpnp_chg_is_otg_en_set(struct qpnp_chg_chip *chip)
+{
+	u8 usb_otg_en;
+	int rc;
+
+	rc = qpnp_chg_read(chip, &usb_otg_en,
+				 chip->usb_chgpth_base + CHGR_USB_USB_OTG_CTL,
+				 1);
+
+	if (rc) {
+		pr_err("spmi read failed: addr=%03X, rc=%d\n",
+				chip->usb_chgpth_base + CHGR_STATUS, rc);
+		return rc;
+	}
+	pr_debug("usb otg en 0x%x\n", usb_otg_en);
+
+	return (usb_otg_en & USB_OTG_EN_BIT) ? 1 : 0;
+}
+
 #define USB_VALID_BIT	BIT(7)
 static int
 qpnp_chg_is_usb_chg_plugged_in(struct qpnp_chg_chip *chip)
@@ -380,10 +402,16 @@
 qpnp_chg_usb_usbin_valid_irq_handler(int irq, void *_chip)
 {
 	struct qpnp_chg_chip *chip = _chip;
-	int usb_present;
+	int usb_present, host_mode;
 
 	usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
-	pr_debug("usbin-valid triggered: %d\n", usb_present);
+	host_mode = qpnp_chg_is_otg_en_set(chip);
+	pr_debug("usbin-valid triggered: %d host_mode: %d\n",
+		usb_present, host_mode);
+
+	/* In host mode notifications cmoe from USB supply */
+	if (host_mode)
+		return IRQ_HANDLED;
 
 	if (chip->usb_present ^ usb_present) {
 		chip->usb_present = usb_present;
@@ -436,6 +464,80 @@
 	return 0;
 }
 
+static int
+qpnp_chg_charge_en(struct qpnp_chg_chip *chip, int enable)
+{
+	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
+			CHGR_CHG_EN,
+			enable ? CHGR_CHG_EN : 0, 1);
+}
+
+static int
+qpnp_chg_force_run_on_batt(struct qpnp_chg_chip *chip, int disable)
+{
+	/* This bit forces the charger to run off of the battery rather
+	 * than a connected charger */
+	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
+			CHGR_ON_BAT_FORCE_BIT,
+			disable ? CHGR_ON_BAT_FORCE_BIT : 0, 1);
+}
+
+static
+int switch_usb_to_charge_mode(struct qpnp_chg_chip *chip)
+{
+	int rc;
+
+	pr_debug("switch to charge mode\n");
+	if (!qpnp_chg_is_otg_en_set(chip))
+		return 0;
+
+	/* enable usb ovp fet */
+	rc = qpnp_chg_masked_write(chip,
+			chip->usb_chgpth_base + CHGR_USB_USB_OTG_CTL,
+			USB_OTG_EN_BIT,
+			0, 1);
+	if (rc) {
+		pr_err("Failed to turn on usb ovp rc = %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
+	if (rc) {
+		pr_err("Failed re-enable charging rc = %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static
+int switch_usb_to_host_mode(struct qpnp_chg_chip *chip)
+{
+	int rc;
+
+	pr_debug("switch to host mode\n");
+	if (qpnp_chg_is_otg_en_set(chip))
+		return 0;
+
+	rc = qpnp_chg_force_run_on_batt(chip, 1);
+	if (rc) {
+		pr_err("Failed to disable charging rc = %d\n", rc);
+		return rc;
+	}
+
+	/* force usb ovp fet off */
+	rc = qpnp_chg_masked_write(chip,
+			chip->usb_chgpth_base + CHGR_USB_USB_OTG_CTL,
+			USB_OTG_EN_BIT,
+			USB_OTG_EN_BIT, 1);
+	if (rc) {
+		pr_err("Failed to turn off usb ovp rc = %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 static enum power_supply_property pm_power_props_mains[] = {
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_ONLINE,
@@ -682,6 +784,21 @@
 		chip->bms_psy = power_supply_get_by_name("bms");
 
 	chip->usb_psy->get_property(chip->usb_psy,
+			  POWER_SUPPLY_PROP_SCOPE, &ret);
+	if (ret.intval) {
+		if ((ret.intval == POWER_SUPPLY_SCOPE_SYSTEM)
+				&& !qpnp_chg_is_otg_en_set(chip)) {
+			switch_usb_to_host_mode(chip);
+			return;
+		}
+		if ((ret.intval == POWER_SUPPLY_SCOPE_DEVICE)
+				&& qpnp_chg_is_otg_en_set(chip)) {
+			switch_usb_to_charge_mode(chip);
+			return;
+		}
+	}
+
+	chip->usb_psy->get_property(chip->usb_psy,
 			  POWER_SUPPLY_PROP_ONLINE, &ret);
 
 	if (ret.intval && qpnp_chg_is_usb_chg_plugged_in(chip)) {
@@ -702,24 +819,6 @@
 }
 
 static int
-qpnp_chg_force_run_on_batt(struct qpnp_chg_chip *chip, int disable)
-{
-	/* This bit forces the charger to run off of the battery rather
-	 * than a connected charger */
-	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
-			CHGR_ON_BAT_FORCE_BIT,
-			disable ? CHGR_ON_BAT_FORCE_BIT : 0, 1);
-}
-
-static int
-qpnp_chg_charge_en(struct qpnp_chg_chip *chip, int enable)
-{
-	return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
-			CHGR_CHG_EN,
-			enable ? CHGR_CHG_EN : 0, 1);
-}
-
-static int
 qpnp_batt_power_get_property(struct power_supply *psy,
 				       enum power_supply_property psp,
 				       union power_supply_propval *val)
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/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index e756a0d..289293a 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -78,7 +78,7 @@
  * the recovery of the remote processor.
  */
 static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev,
-		unsigned long iova, int flags)
+		unsigned long iova, int flags, void *token)
 {
 	dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags);
 
@@ -117,7 +117,7 @@
 		return -ENOMEM;
 	}
 
-	iommu_set_fault_handler(domain, rproc_iommu_fault);
+	iommu_set_fault_handler(domain, rproc_iommu_fault, rproc);
 
 	ret = iommu_attach_device(domain, dev);
 	if (ret) {
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 02e1952..78e8a6f 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -172,13 +172,16 @@
 				u8 *tid, struct completion *done)
 {
 	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+	mutex_lock(&ctrl->m_ctrl);
 	if (ctrl->last_tid <= 255) {
 		ctrl->txnt = krealloc(ctrl->txnt,
 				(ctrl->last_tid + 1) *
 				sizeof(struct slim_msg_txn *),
 				GFP_KERNEL);
-		if (!ctrl->txnt)
+		if (!ctrl->txnt) {
+			mutex_unlock(&ctrl->m_ctrl);
 			return -ENOMEM;
+		}
 		dev->msg_cnt = ctrl->last_tid;
 		ctrl->last_tid++;
 	} else {
@@ -190,6 +193,7 @@
 		}
 		if (i >= 256) {
 			dev_err(&ctrl->dev, "out of TID");
+			mutex_unlock(&ctrl->m_ctrl);
 			return -ENOMEM;
 		}
 	}
@@ -197,6 +201,7 @@
 	txn->tid = dev->msg_cnt;
 	txn->comp = done;
 	*tid = dev->msg_cnt;
+	mutex_unlock(&ctrl->m_ctrl);
 	return 0;
 }
 static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
@@ -369,6 +374,9 @@
 			pr_err("connect/disc :0x%x, tid:%d timed out", txn->mc,
 					txn->tid);
 			ret = -ETIMEDOUT;
+			mutex_lock(&ctrl->m_ctrl);
+			ctrl->txnt[txn->tid] = NULL;
+			mutex_unlock(&ctrl->m_ctrl);
 		} else {
 			ret = txn->ec;
 		}
@@ -394,6 +402,9 @@
 			pr_err("master req:0x%x, tid:%d timed out", txn->mc,
 					txn->tid);
 			ret = -ETIMEDOUT;
+			mutex_lock(&ctrl->m_ctrl);
+			ctrl->txnt[txn->tid] = NULL;
+			mutex_unlock(&ctrl->m_ctrl);
 		} else {
 			ret = txn->ec;
 		}
@@ -526,10 +537,8 @@
 	txn.dt = SLIM_MSG_DEST_LOGICALADDR;
 	txn.la = SLIM_LA_MGR;
 	txn.ec = 0;
-	mutex_lock(&ctrl->m_ctrl);
 	ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
 	if (ret) {
-		mutex_unlock(&ctrl->m_ctrl);
 		return ret;
 	}
 	memcpy(&wbuf[1], ea, elen);
@@ -543,7 +552,6 @@
 		ret = -ENXIO;
 	else if (!ret)
 		*laddr = txn.la;
-	mutex_unlock(&ctrl->m_ctrl);
 	return ret;
 }
 
@@ -606,20 +614,33 @@
 	}
 	if (mc == SLIM_USR_MC_ADDR_REPLY &&
 		mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
-		struct slim_msg_txn *txn = dev->ctrl.txnt[buf[3]];
+		struct slim_msg_txn *txn;
 		u8 failed_ea[6] = {0, 0, 0, 0, 0, 0};
-		if (!txn)
+		mutex_lock(&dev->ctrl.m_ctrl);
+		txn = dev->ctrl.txnt[buf[3]];
+		if (!txn) {
+			pr_err("LADDR response after timeout, tid:0x%x",
+				buf[3]);
+			mutex_unlock(&dev->ctrl.m_ctrl);
 			return;
+		}
 		if (memcmp(&buf[4], failed_ea, 6))
 			txn->la = buf[10];
 		dev->ctrl.txnt[buf[3]] = NULL;
+		mutex_unlock(&dev->ctrl.m_ctrl);
 		complete(txn->comp);
 	}
 	if (mc == SLIM_USR_MC_GENERIC_ACK &&
 		mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
-		struct slim_msg_txn *txn = dev->ctrl.txnt[buf[3]];
-		if (!txn)
+		struct slim_msg_txn *txn;
+		mutex_lock(&dev->ctrl.m_ctrl);
+		txn = dev->ctrl.txnt[buf[3]];
+		if (!txn) {
+			pr_err("ACK received after timeout, tid:0x%x",
+				buf[3]);
+			mutex_unlock(&dev->ctrl.m_ctrl);
 			return;
+		}
 		dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
 				(int)buf[3], buf[4]);
 		if (!(buf[4] & MSM_SAT_SUCCSS)) {
@@ -628,6 +649,7 @@
 			txn->ec = -EIO;
 		}
 		dev->ctrl.txnt[buf[3]] = NULL;
+		mutex_unlock(&dev->ctrl.m_ctrl);
 		complete(txn->comp);
 	}
 }
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index d5d6e0c..c320e46 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1216,7 +1216,7 @@
 	if (flow != SLIM_SRC)
 		return -EINVAL;
 
-	mutex_lock(&ctrl->m_ctrl);
+	mutex_lock(&ctrl->sched.m_reconf);
 
 	if (slc->state == SLIM_CH_FREE) {
 		ret = -ENOTCONN;
@@ -1238,7 +1238,7 @@
 		slc->srch = srch;
 
 connect_src_err:
-	mutex_unlock(&ctrl->m_ctrl);
+	mutex_unlock(&ctrl->sched.m_reconf);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(slim_connect_src);
@@ -1265,7 +1265,7 @@
 	if (!sinkh || !nsink)
 		return -EINVAL;
 
-	mutex_lock(&ctrl->m_ctrl);
+	mutex_lock(&ctrl->sched.m_reconf);
 
 	/*
 	 * Once channel is removed, its ports can be considered disconnected
@@ -1303,7 +1303,7 @@
 	slc->nsink += nsink;
 
 connect_sink_err:
-	mutex_unlock(&ctrl->m_ctrl);
+	mutex_unlock(&ctrl->sched.m_reconf);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(slim_connect_sink);
@@ -1320,11 +1320,11 @@
 	struct slim_controller *ctrl = sb->ctrl;
 	int i;
 
-	mutex_lock(&ctrl->m_ctrl);
+	mutex_lock(&ctrl->sched.m_reconf);
 
 	for (i = 0; i < nph; i++)
 		disconnect_port_ch(ctrl, ph[i]);
-	mutex_unlock(&ctrl->m_ctrl);
+	mutex_unlock(&ctrl->sched.m_reconf);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(slim_disconnect_ports);
@@ -1660,13 +1660,13 @@
 
 	if (!ctrl)
 		return -EINVAL;
-	mutex_lock(&ctrl->m_ctrl);
+	mutex_lock(&ctrl->sched.m_reconf);
 	for (i = 0; i < ctrl->nchans; i++) {
 		if (ctrl->chans[i].state == SLIM_CH_FREE)
 			break;
 	}
 	if (i >= ctrl->nchans) {
-		mutex_unlock(&ctrl->m_ctrl);
+		mutex_unlock(&ctrl->sched.m_reconf);
 		return -EXFULL;
 	}
 	*chanh = i;
@@ -1674,7 +1674,7 @@
 	ctrl->chans[i].state = SLIM_CH_ALLOCATED;
 	ctrl->chans[i].chan = (u8)(ctrl->reserved + i);
 
-	mutex_unlock(&ctrl->m_ctrl);
+	mutex_unlock(&ctrl->sched.m_reconf);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(slim_alloc_ch);
@@ -1698,7 +1698,7 @@
 	int ret = 0;
 	if (!ctrl || !chanh)
 		return -EINVAL;
-	mutex_lock(&ctrl->m_ctrl);
+	mutex_lock(&ctrl->sched.m_reconf);
 	/* start with modulo number */
 	i = ch % ctrl->nchans;
 
@@ -1729,7 +1729,7 @@
 		i = (i + 1) % ctrl->nchans;
 	}
 query_out:
-	mutex_unlock(&ctrl->m_ctrl);
+	mutex_unlock(&ctrl->sched.m_reconf);
 	dev_dbg(&ctrl->dev, "query ch:%d,hdl:%d,ref:%d,ret:%d",
 				ch, i, ctrl->chans[i].ref, ret);
 	return ret;
@@ -1751,26 +1751,26 @@
 	if (!ctrl)
 		return -EINVAL;
 
-	mutex_lock(&ctrl->m_ctrl);
+	mutex_lock(&ctrl->sched.m_reconf);
 	if (slc->state == SLIM_CH_FREE) {
-		mutex_unlock(&ctrl->m_ctrl);
+		mutex_unlock(&ctrl->sched.m_reconf);
 		return -ENOTCONN;
 	}
 	if (slc->ref > 1) {
 		slc->ref--;
-		mutex_unlock(&ctrl->m_ctrl);
+		mutex_unlock(&ctrl->sched.m_reconf);
 		dev_dbg(&ctrl->dev, "remove chan:%d,hdl:%d,ref:%d",
 					slc->chan, chanh, slc->ref);
 		return 0;
 	}
 	if (slc->state >= SLIM_CH_PENDING_ACTIVE) {
 		dev_err(&ctrl->dev, "Channel:%d should be removed first", chan);
-		mutex_unlock(&ctrl->m_ctrl);
+		mutex_unlock(&ctrl->sched.m_reconf);
 		return -EISCONN;
 	}
 	slc->ref--;
 	slc->state = SLIM_CH_FREE;
-	mutex_unlock(&ctrl->m_ctrl);
+	mutex_unlock(&ctrl->sched.m_reconf);
 	dev_dbg(&ctrl->dev, "remove chan:%d,hdl:%d,ref:%d",
 				slc->chan, chanh, slc->ref);
 	return 0;
@@ -1812,7 +1812,7 @@
 
 	if (!ctrl || !chanh || !prop || !nchan)
 		return -EINVAL;
-	mutex_lock(&ctrl->m_ctrl);
+	mutex_lock(&ctrl->sched.m_reconf);
 	for (i = 0; i < nchan; i++) {
 		u8 chan = SLIM_HDL_TO_CHIDX(chanh[i]);
 		struct slim_ich *slc = &ctrl->chans[chan];
@@ -1856,7 +1856,7 @@
 	}
 err_define_ch:
 	dev_dbg(&ctrl->dev, "define_ch: ch:%d, ret:%d", *chanh, ret);
-	mutex_unlock(&ctrl->m_ctrl);
+	mutex_unlock(&ctrl->sched.m_reconf);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(slim_define_ch);
@@ -2607,7 +2607,6 @@
 	struct slim_pending_ch *pch;
 
 	mutex_lock(&ctrl->sched.m_reconf);
-	mutex_lock(&ctrl->m_ctrl);
 	/*
 	 * If there are no pending changes from this client, avoid sending
 	 * the reconfiguration sequence
@@ -2631,7 +2630,6 @@
 			}
 		}
 		if (list_empty(&sb->mark_removal)) {
-			mutex_unlock(&ctrl->m_ctrl);
 			mutex_unlock(&ctrl->sched.m_reconf);
 			pr_info("SLIM_CL: skip reconfig sequence");
 			return 0;
@@ -2820,7 +2818,6 @@
 		ctrl->sched.msgsl = ctrl->sched.pending_msgsl;
 		sb->cur_msgsl = sb->pending_msgsl;
 		slim_chan_changes(sb, false);
-		mutex_unlock(&ctrl->m_ctrl);
 		mutex_unlock(&ctrl->sched.m_reconf);
 		return 0;
 	}
@@ -2828,7 +2825,6 @@
 revert_reconfig:
 	/* Revert channel changes */
 	slim_chan_changes(sb, true);
-	mutex_unlock(&ctrl->m_ctrl);
 	mutex_unlock(&ctrl->sched.m_reconf);
 	return ret;
 }
@@ -2876,7 +2872,6 @@
 		return -EINVAL;
 
 	mutex_lock(&sb->sldev_reconf);
-	mutex_lock(&ctrl->m_ctrl);
 	do {
 		struct slim_pending_ch *pch;
 		u8 add_mark_removal  = true;
@@ -2935,7 +2930,6 @@
 		if (nchan < SLIM_GRP_TO_NCHAN(chanh))
 			chan = SLIM_HDL_TO_CHIDX(slc->nextgrp);
 	} while (nchan < SLIM_GRP_TO_NCHAN(chanh));
-	mutex_unlock(&ctrl->m_ctrl);
 	if (!ret && commit == true)
 		ret = slim_reconfigure_now(sb);
 	mutex_unlock(&sb->sldev_reconf);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 0497a32..6135e71 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -127,13 +127,72 @@
 	}
 }
 
+/**
+ * msm_spi_clk_max_rate: finds the nearest lower rate for a clk
+ * @clk the clock for which to find nearest lower rate
+ * @rate clock frequency in Hz
+ * @return nearest lower rate or negative error value
+ *
+ * Public clock API extends clk_round_rate which is a ceiling function. This
+ * function is a floor function implemented as a binary search using the
+ * ceiling function.
+ */
+static long msm_spi_clk_max_rate(struct clk *clk, unsigned long rate)
+{
+	long lowest_available, nearest_low, step_size, cur;
+	long step_direction = -1;
+	long guess = rate;
+	int  max_steps = 10;
+
+	cur =  clk_round_rate(clk, rate);
+	if (cur == rate)
+		return rate;
+
+	/* if we got here then: cur > rate */
+	lowest_available =  clk_round_rate(clk, 0);
+	if (lowest_available > rate)
+		return -EINVAL;
+
+	step_size = (rate - lowest_available) >> 1;
+	nearest_low = lowest_available;
+
+	while (max_steps-- && step_size) {
+		guess += step_size * step_direction;
+
+		cur =  clk_round_rate(clk, guess);
+
+		if ((cur < rate) && (cur > nearest_low))
+			nearest_low = cur;
+
+		/*
+		 * if we stepped too far, then start stepping in the other
+		 * direction with half the step size
+		 */
+		if (((cur > rate) && (step_direction > 0))
+		 || ((cur < rate) && (step_direction < 0))) {
+			step_direction = -step_direction;
+			step_size >>= 1;
+		 }
+	}
+	return nearest_low;
+}
+
 static void msm_spi_clock_set(struct msm_spi *dd, int speed)
 {
+	long rate;
 	int rc;
 
-	rc = clk_set_rate(dd->clk, speed);
+	rate = msm_spi_clk_max_rate(dd->clk, speed);
+	if (rate < 0) {
+		dev_err(dd->dev,
+		"%s: no match found for requested clock frequency:%d",
+			__func__, speed);
+		return;
+	}
+
+	rc = clk_set_rate(dd->clk, rate);
 	if (!rc)
-		dd->clock_speed = speed;
+		dd->clock_speed = rate;
 }
 
 static int msm_spi_calculate_size(int *fifo_size,
@@ -288,6 +347,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 +392,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 +1476,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 +1569,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 +1588,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 +1614,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 +2739,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 +2823,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/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index c67b75b..7b8788d 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -62,65 +62,6 @@
 			printk(x);			\
 	} while (0)
 
-static int nr_free_zone_mtype_pages(struct zone *zone, int mtype)
-{
-	int order;
-	int sum = 0;
-
-	for (order = 0; order < MAX_ORDER; ++order) {
-		unsigned long freecount = 0;
-		struct free_area *area;
-		struct list_head *curr;
-
-		area = &(zone->free_area[order]);
-
-		list_for_each(curr, &area->free_list[mtype])
-			freecount++;
-
-		sum += freecount << order;
-	}
-	return sum;
-}
-
-static int nr_free_zone_pages(struct zone *zone, gfp_t gfp_mask)
-{
-	int sum = 0;
-	int mtype = allocflags_to_migratetype(gfp_mask);
-	int i = 0;
-	int *mtype_fallbacks = get_migratetype_fallbacks(mtype);
-
-	sum = nr_free_zone_mtype_pages(zone, mtype);
-
-	/*
-	 * Also count the fallback pages
-	 */
-	for (i = 0;; i++) {
-		int fallbacktype = mtype_fallbacks[i];
-		sum += nr_free_zone_mtype_pages(zone, fallbacktype);
-
-		if (fallbacktype == MIGRATE_RESERVE)
-			break;
-	}
-
-	return sum;
-}
-
-static int nr_free_pages(gfp_t gfp_mask)
-{
-	struct zoneref *z;
-	struct zone *zone;
-	int sum = 0;
-
-	struct zonelist *zonelist = node_zonelist(numa_node_id(), gfp_mask);
-
-	for_each_zone_zonelist(zone, z, zonelist, gfp_zone(gfp_mask)) {
-		sum += nr_free_zone_pages(zone, gfp_mask);
-	}
-
-	return sum;
-}
-
-
 static int test_task_flag(struct task_struct *p, int flag)
 {
 	struct task_struct *t = p;
@@ -152,15 +93,6 @@
 	int other_file = global_page_state(NR_FILE_PAGES) -
 						global_page_state(NR_SHMEM);
 
-	if (sc->nr_to_scan > 0 && other_free > other_file) {
-		/*
-		 * If the number of free pages is going to affect the decision
-		 * of which process is selected then ensure only free pages
-		 * which can satisfy the request are considered.
-		 */
-		other_free = nr_free_pages(sc->gfp_mask);
-	}
-
 	if (lowmem_adj_size < array_size)
 		array_size = lowmem_adj_size;
 	if (lowmem_minfree_size < array_size)
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index e70924c..347d9f2 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -107,3 +107,13 @@
 	  available. If allowed via compile time configuration; enabling the
 	  thermal zone device via the mode file results in shifting PMIC over
 	  temperature shutdown control from hardware to software.
+
+config THERMAL_QPNP_ADC_TM
+	tristate "Qualcomm 8974 Thermal Monitor ADC Driver"
+	depends on THERMAL && SPMI
+	help
+	  This enables the thermal Sysfs driver for the ADC thermal monitoring
+	  device. It shows up in Sysfs as a thermal zone with multiple trip points.
+	  Disabling the thermal zone device via the mode file results in disabling
+	  the sensor. Also able to set threshold temperature for both hot and cold
+	  and update when a threshold is reached.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 3b2b3a8..01dce2d 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -11,3 +11,4 @@
 obj-$(CONFIG_SPEAR_THERMAL)		+= spear_thermal.o
 obj-$(CONFIG_THERMAL_TSENS8974)	+= msm8974-tsens.o
 obj-$(CONFIG_THERMAL_QPNP)	+= qpnp-temp-alarm.o
+obj-$(CONFIG_THERMAL_QPNP_ADC_TM)	+= qpnp-adc-tm.o
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
new file mode 100644
index 0000000..bcc85f3
--- /dev/null
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -0,0 +1,1531 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/spmi.h>
+#include <linux/of_irq.h>
+#include <linux/wakelock.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/thermal.h>
+#include <linux/platform_device.h>
+
+/* QPNP VADC TM register definition */
+#define QPNP_STATUS1					0x8
+#define QPNP_STATUS1_OP_MODE				4
+#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS		BIT(2)
+#define QPNP_STATUS1_REQ_STS				BIT(1)
+#define QPNP_STATUS1_EOC				BIT(0)
+#define QPNP_STATUS2					0x9
+#define QPNP_STATUS2_CONV_SEQ_STATE			6
+#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG		BIT(1)
+#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS		BIT(0)
+#define QPNP_CONV_TIMEOUT_ERR				2
+
+#define QPNP_MODE_CTL					0x40
+#define QPNP_OP_MODE_SHIFT				3
+#define QPNP_VREF_XO_THM_FORCE				BIT(2)
+#define QPNP_AMUX_TRIM_EN				BIT(1)
+#define QPNP_ADC_TRIM_EN				BIT(0)
+#define QPNP_EN_CTL1					0x46
+#define QPNP_ADC_TM_EN					BIT(7)
+#define QPNP_ADC_CH_SEL_CTL				0x48
+#define QPNP_ADC_DIG_PARAM				0x50
+#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT		3
+#define QPNP_HW_SETTLE_DELAY				0x51
+#define QPNP_CONV_REQ					0x52
+#define QPNP_CONV_REQ_SET				BIT(7)
+#define QPNP_CONV_SEQ_CTL				0x54
+#define QPNP_CONV_SEQ_HOLDOFF_SHIFT			4
+#define QPNP_CONV_SEQ_TRIG_CTL				0x55
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL			0x57
+#define QPNP_ADC_TM_MEAS_INTERVAL_TIME_SHIFT		0x3
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2			0x58
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT		0x4
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK		0xf0
+#define QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK		0xf
+
+#define QPNP_ADC_MEAS_INTERVAL_OP_CTL			0x59
+#define QPNP_ADC_MEAS_INTERVAL_OP			BIT(7)
+
+#define QPNP_FAST_AVG_CTL				0x5a
+#define QPNP_FAST_AVG_EN				0x5b
+
+#define QPNP_M0_LOW_THR_LSB				0x5c
+#define QPNP_M0_LOW_THR_MSB				0x5d
+#define QPNP_M0_HIGH_THR_LSB				0x5e
+#define QPNP_M0_HIGH_THR_MSB				0x5f
+#define QPNP_M1_LOW_THR_LSB				0x69
+#define QPNP_M1_LOW_THR_MSB				0x6a
+#define QPNP_M1_HIGH_THR_LSB				0x6b
+#define QPNP_M1_HIGH_THR_MSB				0x6c
+#define QPNP_M2_LOW_THR_LSB				0x71
+#define QPNP_M2_LOW_THR_MSB				0x72
+#define QPNP_M2_HIGH_THR_LSB				0x7b
+#define QPNP_M2_HIGH_THR_MSB				0x7c
+#define QPNP_M3_LOW_THR_LSB				0x79
+#define QPNP_M3_LOW_THR_MSB				0x7a
+#define QPNP_M3_HIGH_THR_LSB				0x7b
+#define QPNP_M3_HIGH_THR_MSB				0x7c
+#define QPNP_M4_LOW_THR_LSB				0x81
+#define QPNP_M4_LOW_THR_MSB				0x82
+#define QPNP_M4_HIGH_THR_LSB				0x83
+#define QPNP_M4_HIGH_THR_MSB				0x84
+
+#define QPNP_ADC_TM_MULTI_MEAS_EN			0x41
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M0			BIT(0)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M1			BIT(1)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M2			BIT(2)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M3			BIT(3)
+#define QPNP_ADC_TM_MULTI_MEAS_EN_M4			BIT(4)
+#define QPNP_ADC_TM_LOW_THR_INT_EN			0x42
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M0			BIT(0)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M1			BIT(1)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M2			BIT(2)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M3			BIT(3)
+#define QPNP_ADC_TM_LOW_THR_INT_EN_M4			BIT(4)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN			0x43
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M0			BIT(0)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M1			BIT(1)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M2			BIT(2)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M3			BIT(3)
+#define QPNP_ADC_TM_HIGH_THR_INT_EN_M4			BIT(4)
+
+#define QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL			0x57
+#define QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL			0x6d
+#define QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL			0x75
+#define QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL			0x7d
+#define QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL			0x85
+#define QPNP_ADC_TM_STATUS1				0x8
+#define QPNP_ADC_TM_STATUS_LOW				0xa
+#define QPNP_ADC_TM_STATUS_HIGH				0xb
+
+#define QPNP_ADC_TM_M0_LOW_THR				0x5d5c
+#define QPNP_ADC_TM_M0_HIGH_THR				0x5f5e
+#define QPNP_ADC_TM_MEAS_INTERVAL			0x0
+
+#define QPNP_ADC_TM_THR_LSB_MASK(val)			(val & 0xff)
+#define QPNP_ADC_TM_THR_MSB_MASK(val)			((val & 0xff00) >> 8)
+
+struct qpnp_adc_tm_sensor {
+	struct thermal_zone_device	*tz_dev;
+	enum thermal_device_mode	mode;
+	uint32_t			sensor_num;
+	enum qpnp_adc_meas_timer_select	timer_select;
+	uint32_t			meas_interval;
+	uint32_t			low_thr;
+	uint32_t			high_thr;
+	uint32_t			btm_channel_num;
+	struct work_struct		work;
+};
+
+struct qpnp_adc_tm_drv {
+	struct qpnp_adc_drv		*adc;
+	struct qpnp_adc_tm_usbid_param	*usb_id_param;
+	struct work_struct		usbid_work;
+	struct qpnp_adc_tm_btm_param	*battery_param;
+	struct work_struct		batt_work;
+	bool				adc_tm_initialized;
+	struct qpnp_adc_tm_sensor	sensor[0];
+};
+
+struct qpnp_adc_tm_drv	*qpnp_adc_tm;
+
+struct qpnp_adc_tm_trip_reg_type {
+	uint16_t low_thr_lsb_addr;
+	uint16_t low_thr_msb_addr;
+	uint16_t high_thr_lsb_addr;
+	uint16_t high_thr_msb_addr;
+	u8 multi_meas_en;
+	u8 low_thr_int_chan_en;
+	u8 high_thr_int_chan_en;
+};
+
+static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
+	[QPNP_ADC_TM_M0_ADC_CH_SEL_CTL] = {QPNP_M0_LOW_THR_LSB,
+		QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
+		QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0},
+	[QPNP_ADC_TM_M1_ADC_CH_SEL_CTL] = {QPNP_M1_LOW_THR_LSB,
+		QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
+		QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1},
+	[QPNP_ADC_TM_M2_ADC_CH_SEL_CTL] = {QPNP_M2_LOW_THR_LSB,
+		QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
+		QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2},
+	[QPNP_ADC_TM_M3_ADC_CH_SEL_CTL] = {QPNP_M3_LOW_THR_LSB,
+		QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
+		QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3},
+	[QPNP_ADC_TM_M4_ADC_CH_SEL_CTL] = {QPNP_M4_LOW_THR_LSB,
+		QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
+		QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
+		QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4},
+};
+
+static int32_t qpnp_adc_tm_read_reg(int16_t reg, u8 *data)
+{
+	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	int rc = 0;
+
+	rc = spmi_ext_register_readl(adc_tm->adc->spmi->ctrl,
+		adc_tm->adc->slave, (adc_tm->adc->offset + reg), data, 1);
+	if (rc < 0)
+		pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_write_reg(int16_t reg, u8 data)
+{
+	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	int rc = 0;
+	u8 *buf;
+
+	buf = &data;
+
+	rc = spmi_ext_register_writel(adc_tm->adc->spmi->ctrl,
+		adc_tm->adc->slave, (adc_tm->adc->offset + reg), buf, 1);
+	if (rc < 0)
+		pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_enable(bool state)
+{
+	int rc = 0;
+	u8 data = 0, enable_check = 0;
+
+	if (state) {
+		data = QPNP_ADC_TM_EN;
+		rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1,
+					data);
+		if (rc < 0)
+			pr_err("adc-tm enable failed\n");
+	} else {
+		rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
+					&enable_check);
+		if (rc < 0) {
+			pr_err("multi measurement read failed\n");
+			return rc;
+		}
+
+		if (!enable_check) {
+			data = 0;
+			rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
+			if (rc < 0)
+				pr_err("adc-tm disable failed\n");
+		}
+	}
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_enable_req_sts_check(void)
+{
+	u8 status1;
+	int rc;
+
+	/* The VADC_TM bank needs to be disabled for new conversion request */
+	rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
+	if (rc) {
+		pr_err("adc-tm read status1 failed\n");
+		return rc;
+	}
+
+	/* Disable the bank if a conversion is occuring */
+	if (status1 & QPNP_STATUS1_REQ_STS) {
+		rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, 0);
+		if (rc < 0)
+			pr_err("adc-tm disable failed\n");
+	}
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_mode_select(u8 mode_ctl)
+{
+	int rc;
+
+	/* VADC_BTM current sets mode to recurring measurements */
+	rc = qpnp_adc_tm_write_reg(QPNP_MODE_CTL, mode_ctl);
+	if (rc < 0)
+		pr_err("adc-tm write mode selection err\n");
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_timer_interval_select(
+		struct qpnp_vadc_chan_properties *chan_prop)
+{
+	int rc;
+	u8 meas_interval_timer2 = 0;
+
+	/* Configure USB_ID to timer1, batt_therm to timer2 */
+	switch (chan_prop->timer_select) {
+	case ADC_MEAS_TIMER_SELECT1:
+		rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL,
+				chan_prop->meas_interval1);
+		if (rc < 0) {
+			pr_err("timer1 configure failed\n");
+			return rc;
+		}
+	break;
+	case ADC_MEAS_TIMER_SELECT2:
+		rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+				&meas_interval_timer2);
+		if (rc < 0) {
+			pr_err("timer2 configure read failed\n");
+			return rc;
+		}
+		meas_interval_timer2 |=
+			(chan_prop->meas_interval2 <<
+			QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
+		rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+			meas_interval_timer2);
+		if (rc < 0) {
+			pr_err("timer2 configure failed\n");
+			return rc;
+		}
+	break;
+	case ADC_MEAS_TIMER_SELECT3:
+		/* Thermal channels uses timer3, default to 1 second */
+		rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+				&meas_interval_timer2);
+		if (rc < 0) {
+			pr_err("timer3 read failed\n");
+			return rc;
+		}
+		chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
+		meas_interval_timer2 |= chan_prop->meas_interval2;
+		rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+			meas_interval_timer2);
+		if (rc < 0) {
+			pr_err("timer3 configure failed\n");
+			return rc;
+		}
+	break;
+	default:
+		pr_err("Invalid timer selection\n");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_meas_int_update(uint16_t reg_addr_src,
+		u8 reg_addr_dst, bool state)
+{
+	u8 bit_mask_check = 0;
+	int rc = 0;
+
+	rc = qpnp_adc_tm_read_reg(reg_addr_src, &bit_mask_check);
+	if (rc < 0) {
+		pr_err("read failed for addr:%x\n", reg_addr_src);
+		return rc;
+	}
+
+	if (state)
+		bit_mask_check |= reg_addr_dst;
+	else
+		bit_mask_check &= ~reg_addr_dst;
+
+	rc = qpnp_adc_tm_write_reg(reg_addr_src, bit_mask_check);
+	if (rc < 0)
+		pr_err("write failed for addr:%x\n", reg_addr_src);
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_usbid_btm_thr_en(uint32_t btm_chan,
+			struct qpnp_vadc_chan_properties *chan_prop)
+{
+	int rc = 0;
+
+	rc = qpnp_adc_tm_write_reg(
+			adc_tm_data[btm_chan].low_thr_lsb_addr,
+			QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
+	if (rc < 0) {
+		pr_err("low threshold lsb setting failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_write_reg(
+		adc_tm_data[btm_chan].low_thr_msb_addr,
+		QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
+	if (rc < 0) {
+		pr_err("low threshold msb setting failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_write_reg(
+		adc_tm_data[btm_chan].high_thr_lsb_addr,
+		QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
+	if (rc < 0) {
+		pr_err("high threshold lsb setting failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_write_reg(
+		adc_tm_data[btm_chan].high_thr_msb_addr,
+		QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
+	if (rc < 0)
+		pr_err("high threshold msb setting failed\n");
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_channel_configure(uint32_t btm_chan,
+			struct qpnp_vadc_chan_properties *chan_prop,
+			uint32_t amux_channel)
+{
+	int rc = 0;
+
+	switch (btm_chan) {
+	case QPNP_ADC_TM_M0_ADC_CH_SEL_CTL:
+	case QPNP_ADC_TM_M1_ADC_CH_SEL_CTL:
+		/* Update low and high notification thresholds */
+		rc = qpnp_adc_tm_usbid_btm_thr_en(btm_chan,
+				chan_prop);
+		if (rc < 0) {
+			pr_err("setting chan:%d threshold failed\n", btm_chan);
+			return rc;
+		}
+
+		if ((chan_prop->state_request ==
+					ADC_TM_LOW_THR_ENABLE) ||
+			(chan_prop->state_request ==
+					ADC_TM_HIGH_LOW_THR_ENABLE)) {
+			/* Enable low threshold's interrupt */
+			rc = qpnp_adc_tm_meas_int_update(
+				QPNP_ADC_TM_LOW_THR_INT_EN,
+				adc_tm_data[btm_chan].low_thr_int_chan_en,
+				true);
+			if (rc < 0) {
+				pr_err("low thr enable err:%d\n", btm_chan);
+				return rc;
+			}
+		}
+
+		if ((chan_prop->state_request ==
+					ADC_TM_HIGH_THR_ENABLE) ||
+			(chan_prop->state_request ==
+					ADC_TM_HIGH_LOW_THR_ENABLE)) {
+			/* Enable high threshold's interrupt */
+			rc = qpnp_adc_tm_meas_int_update(
+				QPNP_ADC_TM_HIGH_THR_INT_EN,
+				adc_tm_data[btm_chan].high_thr_int_chan_en,
+				true);
+			if (rc < 0) {
+				pr_err("high thr enable err:%d\n", btm_chan);
+				return rc;
+			}
+		}
+	/* intention fall through to configure common chan meas */
+	case QPNP_ADC_TM_M2_ADC_CH_SEL_CTL:
+	case QPNP_ADC_TM_M3_ADC_CH_SEL_CTL:
+	case QPNP_ADC_TM_M4_ADC_CH_SEL_CTL:
+		/* Configure AMUX control register for channel selection */
+		rc = qpnp_adc_tm_write_reg(btm_chan, amux_channel);
+		if (rc < 0) {
+			pr_err("btm_chan:%d selection failed\n", btm_chan);
+			return rc;
+		}
+
+		/* Enable corresponding BTM channel measurement */
+		rc = qpnp_adc_tm_meas_int_update(
+			QPNP_ADC_TM_MULTI_MEAS_EN,
+			adc_tm_data[btm_chan].multi_meas_en, true);
+		if (rc < 0) {
+			pr_err("multi measurement en failed\n");
+			return rc;
+		}
+	break;
+	default:
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int32_t qpnp_adc_tm_configure(
+			struct qpnp_adc_amux_properties *chan_prop)
+{
+	u8 decimation = 0;
+	int rc = 0;
+	uint32_t btm_chan = 0;
+
+	/* Check if a conversion is in progress */
+	rc = qpnp_adc_tm_enable_req_sts_check();
+	if (rc < 0) {
+		pr_err("adc-tm req_sts check failed\n");
+		return rc;
+	}
+
+	/* Set measurement in recurring mode */
+	rc = qpnp_adc_tm_mode_select(chan_prop->mode_sel);
+	if (rc < 0) {
+		pr_err("adc-tm mode select failed\n");
+		return rc;
+	}
+
+	/* Configure AMUX channel */
+	rc = qpnp_adc_tm_write_reg(QPNP_ADC_CH_SEL_CTL,
+				chan_prop->amux_channel);
+	if (rc < 0) {
+		pr_err("adc-tm channel selection err\n");
+		return rc;
+	}
+
+	/* Digital paramater setup */
+	decimation |= chan_prop->decimation <<
+				QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
+	rc = qpnp_adc_tm_write_reg(QPNP_ADC_DIG_PARAM, decimation);
+	if (rc < 0) {
+		pr_err("adc-tm digital parameter setup err\n");
+		return rc;
+	}
+
+	/* Hardware setting time */
+	rc = qpnp_adc_tm_write_reg(QPNP_HW_SETTLE_DELAY,
+					chan_prop->hw_settle_time);
+	if (rc < 0) {
+		pr_err("adc-tm hw settling time setup err\n");
+		return rc;
+	}
+
+	/* Fast averaging setup */
+	rc = qpnp_adc_tm_write_reg(QPNP_FAST_AVG_CTL,
+					chan_prop->fast_avg_setup);
+	if (rc < 0) {
+		pr_err("adc-tm fast-avg setup err\n");
+		return rc;
+	}
+
+	/* Measurement interval setup */
+	rc = qpnp_adc_tm_timer_interval_select(chan_prop->chan_prop);
+	if (rc < 0) {
+		pr_err("adc-tm timer select failed\n");
+		return rc;
+	}
+
+	/* Channel configuration setup */
+	btm_chan = chan_prop->chan_prop->tm_channel_select;
+	rc = qpnp_adc_tm_channel_configure(btm_chan, chan_prop->chan_prop,
+					chan_prop->amux_channel);
+	if (rc < 0) {
+		pr_err("adc-tm channel configure failed\n");
+		return rc;
+	}
+
+	/* Enable bank */
+	rc = qpnp_adc_tm_enable(true);
+	if (rc)
+		return rc;
+
+	/* Recurring interval measurement enable */
+	rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
+			QPNP_ADC_MEAS_INTERVAL_OP, true);
+	if (rc < 0) {
+		pr_err("adc-tm meas interval op configure failed\n");
+		return rc;
+	}
+
+	/* Request conversion */
+	rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
+	if (rc < 0) {
+		pr_err("adc-tm request conversion failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int qpnp_adc_tm_get_mode(struct thermal_zone_device *thermal,
+			      enum thermal_device_mode *mode)
+{
+	struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+
+	if (!adc_tm || !mode)
+		return -EINVAL;
+
+	*mode = adc_tm->mode;
+
+	return 0;
+}
+
+static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
+			      enum thermal_device_mode mode)
+{
+	struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+	struct qpnp_adc_tm_drv *adc_drv = qpnp_adc_tm;
+	int rc = 0, channel;
+
+	if (!adc_tm)
+		return -EINVAL;
+
+	if (mode == THERMAL_DEVICE_ENABLED) {
+		adc_drv->adc->amux_prop->amux_channel = adc_tm->sensor_num;
+		channel = adc_tm->sensor_num;
+		adc_drv->adc->amux_prop->decimation =
+			adc_drv->adc->adc_channels[channel].adc_decimation;
+		adc_drv->adc->amux_prop->hw_settle_time =
+			adc_drv->adc->adc_channels[channel].hw_settle_time;
+		adc_drv->adc->amux_prop->fast_avg_setup =
+			adc_drv->adc->adc_channels[channel].fast_avg_setup;
+		adc_drv->adc->amux_prop->mode_sel =
+			ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+		adc_drv->adc->amux_prop->chan_prop->timer_select =
+					ADC_MEAS_TIMER_SELECT1;
+		adc_drv->adc->amux_prop->chan_prop->meas_interval1 =
+						ADC_MEAS1_INTERVAL_1S;
+		adc_drv->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
+		adc_drv->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
+		adc_drv->adc->amux_prop->chan_prop->tm_channel_select =
+			adc_tm->btm_channel_num;
+
+		rc = qpnp_adc_tm_configure(adc_drv->adc->amux_prop);
+		if (rc) {
+			pr_err("adc-tm tm configure failed with %d\n", rc);
+			return -EINVAL;
+		}
+	} else if (mode == THERMAL_DEVICE_DISABLED) {
+		rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+			adc_tm_data[adc_tm->btm_channel_num].multi_meas_en,
+			false);
+		if (rc < 0) {
+			pr_err("multi measurement update failed\n");
+			return rc;
+		}
+
+		rc = qpnp_adc_tm_enable(false);
+		if (rc < 0) {
+			pr_err("adc-tm disable failed\n");
+			return rc;
+		}
+	}
+
+	adc_tm->mode = mode;
+
+	return 0;
+}
+
+static int qpnp_adc_tm_get_trip_type(struct thermal_zone_device *thermal,
+				   int trip, enum thermal_trip_type *type)
+{
+	struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+
+	if (!adc_tm || !type || type < 0)
+		return -EINVAL;
+
+	switch (trip) {
+	case ADC_TM_TRIP_HIGH_WARM:
+		*type = THERMAL_TRIP_CONFIGURABLE_HI;
+	break;
+	case ADC_TM_TRIP_LOW_COOL:
+		*type = THERMAL_TRIP_CONFIGURABLE_LOW;
+	break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
+				   int trip, unsigned long *temp)
+{
+	struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
+	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	int64_t result = 0;
+	u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
+	unsigned int reg, rc = 0, btm_channel_num;
+	uint16_t reg_low_thr_lsb, reg_low_thr_msb;
+	uint16_t reg_high_thr_lsb, reg_high_thr_msb;
+
+	if (!adc_tm)
+		return -EINVAL;
+
+	btm_channel_num = adc_tm_sensor->btm_channel_num;
+	reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
+	reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
+	reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
+	reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+
+	switch (trip) {
+	case ADC_TM_TRIP_HIGH_WARM:
+		rc = qpnp_adc_tm_read_reg(reg_low_thr_lsb, &trip_warm_thr0);
+		if (rc) {
+			pr_err("adc-tm low_thr_lsb err\n");
+			return rc;
+		}
+
+		rc = qpnp_adc_tm_read_reg(reg_low_thr_msb, &trip_warm_thr1);
+		if (rc) {
+			pr_err("adc-tm low_thr_msb err\n");
+			return rc;
+		}
+	reg = (trip_warm_thr1 << 8) | trip_warm_thr0;
+	break;
+	case ADC_TM_TRIP_LOW_COOL:
+		rc = qpnp_adc_tm_read_reg(reg_high_thr_lsb, &trip_cool_thr0);
+		if (rc) {
+			pr_err("adc-tm_tm high_thr_lsb err\n");
+			return rc;
+		}
+
+		rc = qpnp_adc_tm_read_reg(reg_high_thr_msb, &trip_cool_thr1);
+		if (rc) {
+			pr_err("adc-tm_tm high_thr_lsb err\n");
+			return rc;
+		}
+	reg = (trip_cool_thr1 << 8) | trip_cool_thr0;
+	break;
+	default:
+		return -EINVAL;
+	}
+
+	rc = qpnp_adc_tm_scale_voltage_therm_pu2(reg, &result);
+	if (rc < 0) {
+		pr_err("Failed to lookup the therm thresholds\n");
+		return rc;
+	}
+
+	*temp = result;
+
+	return 0;
+}
+
+static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
+				   int trip, long temp)
+{
+	struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
+	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	struct qpnp_adc_tm_config tm_config;
+	u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
+	uint16_t reg_low_thr_lsb, reg_low_thr_msb;
+	uint16_t reg_high_thr_lsb, reg_high_thr_msb;
+	int rc = 0, btm_channel_num;
+
+	if (!adc_tm)
+		return -EINVAL;
+
+	tm_config.channel = adc_tm_sensor->sensor_num;
+	switch (trip) {
+	case ADC_TM_TRIP_HIGH_WARM:
+		tm_config.high_thr_temp = temp;
+		break;
+	case ADC_TM_TRIP_LOW_COOL:
+		tm_config.low_thr_temp = temp;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rc = qpnp_adc_tm_scale_therm_voltage_pu2(&tm_config);
+	if (rc < 0) {
+		pr_err("Failed to lookup the adc-tm thresholds\n");
+		return rc;
+	}
+
+	trip_warm_thr0 = ((tm_config.low_thr_voltage << 24) >> 24);
+	trip_warm_thr1 = ((tm_config.low_thr_voltage << 16) >> 24);
+	trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
+	trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
+
+	btm_channel_num = adc_tm_sensor->btm_channel_num;
+	reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
+	reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
+	reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
+	reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
+
+	switch (trip) {
+	case ADC_TM_TRIP_HIGH_WARM:
+		rc = qpnp_adc_tm_write_reg(reg_low_thr_lsb, trip_cool_thr0);
+		if (rc) {
+			pr_err("adc-tm_tm read threshold err\n");
+			return rc;
+		}
+
+		rc = qpnp_adc_tm_write_reg(reg_low_thr_msb, trip_cool_thr1);
+		if (rc) {
+			pr_err("adc-tm_tm read threshold err\n");
+			return rc;
+		}
+	adc_tm_sensor->low_thr = tm_config.high_thr_voltage;
+	break;
+	case ADC_TM_TRIP_LOW_COOL:
+		rc = qpnp_adc_tm_write_reg(reg_high_thr_lsb, trip_warm_thr0);
+		if (rc) {
+			pr_err("adc-tm_tm read threshold err\n");
+			return rc;
+		}
+
+		rc = qpnp_adc_tm_write_reg(reg_high_thr_msb, trip_warm_thr1);
+		if (rc) {
+			pr_err("adc-tm_tm read threshold err\n");
+			return rc;
+		}
+	adc_tm_sensor->high_thr = tm_config.low_thr_voltage;
+	break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void notify_uspace_qpnp_adc_tm_fn(struct work_struct *work)
+{
+	struct qpnp_adc_tm_sensor *adc_tm = container_of(work,
+		struct qpnp_adc_tm_sensor, work);
+
+	sysfs_notify(&adc_tm->tz_dev->device.kobj,
+					NULL, "btm");
+}
+
+static void notify_usb_fn(struct work_struct *work)
+{
+	struct qpnp_adc_tm_drv *adc_tm = container_of(work,
+		struct qpnp_adc_tm_drv, usbid_work);
+	int rc;
+	u8 status_low, status_high;
+
+	if (adc_tm->usb_id_param->threshold_notification != NULL) {
+		rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW,
+							&status_low);
+		if (rc) {
+			pr_err("adc-tm read low status failed\n");
+			return;
+		}
+
+		rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH,
+							&status_high);
+		if (rc) {
+			pr_err("adc-tm read high status failed\n");
+			return;
+		}
+
+		if (status_low & 1)
+			adc_tm->usb_id_param->threshold_notification(
+			ADC_TM_LOW_STATE, adc_tm->usb_id_param->usbid_ctx);
+		else if (status_high & 1)
+			adc_tm->usb_id_param->threshold_notification(
+			ADC_TM_HIGH_STATE, adc_tm->usb_id_param->usbid_ctx);
+	}
+
+	return;
+}
+
+static void notify_batt_fn(struct work_struct *work)
+{
+	struct qpnp_adc_tm_drv *adc_tm = container_of(work,
+		struct qpnp_adc_tm_drv, batt_work);
+	int rc;
+	u8 status_low, status_high;
+
+	if (adc_tm->battery_param->threshold_notification != NULL) {
+		rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW,
+							&status_low);
+		if (rc) {
+			pr_err("adc-tm read low status failed\n");
+			return;
+		}
+
+		rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH,
+							&status_high);
+		if (rc) {
+			pr_err("adc-tm read high status failed\n");
+			return;
+		}
+
+		if (status_low & QPNP_ADC_TM_LOW_THR_INT_EN_M1)
+			adc_tm->battery_param->threshold_notification(
+							ADC_TM_LOW_STATE);
+		else if (status_high & QPNP_ADC_TM_HIGH_THR_INT_EN_M1)
+			adc_tm->battery_param->threshold_notification(
+							ADC_TM_HIGH_STATE);
+	}
+
+	return;
+}
+
+static int qpnp_adc_tm_activate_trip_type_fn(uint32_t btm_channel_num,
+	enum thermal_trip_activation_mode mode, u8 *data, uint32_t reg)
+{
+	u8 thr_int = 0;
+	int rc = 0;
+
+	rc = qpnp_adc_tm_read_reg(reg, &thr_int);
+	if (rc) {
+		pr_err("multi meas read failed\n");
+		return rc;
+	}
+
+	thr_int = adc_tm_data[btm_channel_num].low_thr_int_chan_en;
+
+	if (mode == THERMAL_TRIP_ACTIVATION_ENABLED)
+		thr_int |= *data;
+	else
+		thr_int &= ~*data;
+
+	rc = qpnp_adc_tm_write_reg(reg, thr_int);
+	if (rc)
+		pr_err("multi meas write failed\n");
+
+	return rc;
+}
+
+static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
+			int trip, enum thermal_trip_activation_mode mode)
+{
+	struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
+	int rc = 0;
+	u8 thr_int_en = 0;
+
+	if (!adc_tm)
+		return -EINVAL;
+
+	switch (trip) {
+	case ADC_TM_TRIP_HIGH_WARM:
+		thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
+							low_thr_int_chan_en;
+		rc = qpnp_adc_tm_activate_trip_type_fn(adc_tm->btm_channel_num,
+				mode, &thr_int_en, QPNP_ADC_TM_LOW_THR_INT_EN);
+		if (rc)
+			pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+	break;
+	case ADC_TM_TRIP_LOW_COOL:
+		thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
+							high_thr_int_chan_en;
+		rc = qpnp_adc_tm_activate_trip_type_fn(adc_tm->btm_channel_num,
+				mode, &thr_int_en, QPNP_ADC_TM_HIGH_THR_INT_EN);
+		if (rc)
+			pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
+	break;
+	default:
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int qpnp_adc_tm_read_status(void)
+{
+	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
+	u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
+	u8 thr_int_disable = 0;
+	int rc = 0, sensor_notify_num = 0;
+
+	rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW, &status_low);
+	if (rc) {
+		pr_err("adc-tm-tm read status low failed with %d\n", rc);
+		goto fail;
+	}
+
+	rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH, &status_high);
+	if (rc) {
+		pr_err("adc-tm-tm read status high failed with %d\n", rc);
+		goto fail;
+	}
+
+	/* Check which interrupt threshold is lower and measure against the
+	 * enabled channel */
+	rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
+							&qpnp_adc_tm_meas_en);
+	if (rc) {
+		pr_err("adc-tm-tm read status high failed with %d\n", rc);
+		goto fail;
+	}
+
+	adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
+	adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
+
+	if (adc_tm_high_enable) {
+		sensor_notify_num = (adc_tm_high_enable >> 3);
+		switch (adc_tm_high_enable) {
+		case 1:
+		case 2:
+		{
+			if (adc_tm_high_enable == 1)
+				thr_int_disable =
+					QPNP_ADC_TM_HIGH_THR_INT_EN_M0;
+			else if (adc_tm_high_enable == 2)
+				thr_int_disable =
+					QPNP_ADC_TM_HIGH_THR_INT_EN_M1;
+
+			rc = qpnp_adc_tm_meas_int_update(
+				QPNP_ADC_TM_HIGH_THR_INT_EN,
+				thr_int_disable, false);
+			if (rc < 0) {
+				pr_err("high threshold int read failed\n");
+				goto fail;
+			}
+
+			if (adc_tm_high_enable == 1)
+				schedule_work(&adc_tm->usbid_work);
+			else if (adc_tm_high_enable == 2)
+				schedule_work(&adc_tm->batt_work);
+		}
+		break;
+		case 4:
+		case 8:
+		case 16:
+		{
+			/* High voltage threshold is triggered by low temp */
+			rc = qpnp_adc_tm_activate_trip_type(
+				adc_tm->sensor[sensor_notify_num].tz_dev,
+				ADC_TM_TRIP_LOW_COOL,
+				THERMAL_TRIP_ACTIVATION_DISABLED);
+			if (rc < 0) {
+				pr_err("notify error:%d\n", sensor_notify_num);
+				goto fail;
+			}
+			schedule_work(&adc_tm->sensor[sensor_notify_num].work);
+		}
+		break;
+		default:
+			rc = -EINVAL;
+		}
+	}
+
+	if (adc_tm_low_enable) {
+		sensor_notify_num = (adc_tm_low_enable >> 3);
+		switch (adc_tm_low_enable) {
+		case 1:
+		case 2:
+		{
+			if (adc_tm_low_enable == 1)
+				thr_int_disable = QPNP_ADC_TM_LOW_THR_INT_EN_M0;
+			else if (adc_tm_low_enable == 2)
+				thr_int_disable = QPNP_ADC_TM_LOW_THR_INT_EN_M1;
+
+			rc = qpnp_adc_tm_meas_int_update(
+				QPNP_ADC_TM_LOW_THR_INT_EN,
+				thr_int_disable, false);
+			if (rc < 0) {
+				pr_err("low threshold int disable failed\n");
+				goto fail;
+			}
+
+			if (adc_tm_low_enable == 1)
+				schedule_work(&adc_tm->usbid_work);
+			else if (adc_tm_low_enable == 2)
+				schedule_work(&adc_tm->batt_work);
+		}
+		break;
+		case 4:
+		case 8:
+		case 16:
+		{
+			/* Low voltage threshold is triggered by high temp */
+			rc = qpnp_adc_tm_activate_trip_type(
+				adc_tm->sensor[sensor_notify_num].tz_dev,
+				ADC_TM_TRIP_HIGH_WARM,
+				THERMAL_TRIP_ACTIVATION_DISABLED);
+			if (rc < 0) {
+				pr_err("notify error:%d\n", sensor_notify_num);
+				goto fail;
+			}
+			schedule_work(&adc_tm->sensor[sensor_notify_num].work);
+		}
+		break;
+		default:
+			rc = -EINVAL;
+		}
+	}
+
+fail:
+	return rc;
+}
+
+static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
+{
+	int rc;
+
+	rc = qpnp_adc_tm_read_status();
+
+	return;
+}
+DECLARE_WORK(trigger_completion_adc_tm_high_thr_work,
+					qpnp_adc_tm_high_thr_work);
+
+static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
+{
+	schedule_work(&trigger_completion_adc_tm_high_thr_work);
+
+	return IRQ_HANDLED;
+}
+
+static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
+{
+	int rc;
+
+	rc = qpnp_adc_tm_read_status();
+
+	return;
+}
+DECLARE_WORK(trigger_completion_adc_tm_low_thr_work, qpnp_adc_tm_low_thr_work);
+
+static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
+{
+	schedule_work(&trigger_completion_adc_tm_low_thr_work);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t qpnp_adc_tm_isr(int irq, void *dev_id)
+{
+	struct qpnp_adc_tm_drv *adc_tm = dev_id;
+
+	complete(&adc_tm->adc->adc_rslt_completion);
+
+	return IRQ_HANDLED;
+}
+
+static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
+			     unsigned long *temp)
+{
+	struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
+	struct qpnp_vadc_result result;
+	int rc = 0;
+
+	rc = qpnp_vadc_read(adc_tm_sensor->sensor_num, &result);
+	if (rc)
+		return rc;
+
+	*temp = result.physical;
+
+	return rc;
+}
+
+static struct thermal_zone_device_ops qpnp_adc_tm_thermal_ops = {
+	.get_temp = qpnp_adc_read_temp,
+	.get_mode = qpnp_adc_tm_get_mode,
+	.set_mode = qpnp_adc_tm_set_mode,
+	.get_trip_type = qpnp_adc_tm_get_trip_type,
+	.activate_trip_type = qpnp_adc_tm_activate_trip_type,
+	.get_trip_temp = qpnp_adc_tm_get_trip_temp,
+	.set_trip_temp = qpnp_adc_tm_set_trip_temp,
+};
+
+int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_usbid_param *param)
+{
+	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	uint32_t channel;
+	int rc = 0;
+
+	if (!adc_tm || !adc_tm->adc_tm_initialized)
+		return -ENODEV;
+
+	if (param->threshold_notification == NULL) {
+		pr_err("No USB_ID high/low voltage notificaton??\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&adc_tm->adc->adc_lock);
+
+	adc_tm->adc->amux_prop->amux_channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
+	channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
+	adc_tm->adc->amux_prop->decimation =
+			adc_tm->adc->adc_channels[channel].adc_decimation;
+	adc_tm->adc->amux_prop->hw_settle_time =
+			adc_tm->adc->adc_channels[channel].hw_settle_time;
+	adc_tm->adc->amux_prop->fast_avg_setup =
+			adc_tm->adc->adc_channels[channel].fast_avg_setup;
+	adc_tm->adc->amux_prop->mode_sel =
+		ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+	adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
+						ADC_MEAS1_INTERVAL_1S;
+	qpnp_adc_usb_scaler(param, &adc_tm->adc->amux_prop->chan_prop->low_thr,
+			&adc_tm->adc->amux_prop->chan_prop->high_thr);
+	adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
+					QPNP_ADC_TM_M0_ADC_CH_SEL_CTL;
+	adc_tm->adc->amux_prop->chan_prop->timer_select =
+					ADC_MEAS_TIMER_SELECT1;
+	adc_tm->adc->amux_prop->chan_prop->state_request =
+					param->state_request;
+	rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
+	if (rc) {
+		pr_err("adc-tm configure failed with %d\n", rc);
+		goto fail_unlock;
+	}
+
+	adc_tm->usb_id_param = param;
+
+fail_unlock:
+	mutex_unlock(&adc_tm->adc->adc_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
+
+static int32_t qpnp_adc_tm_chan_usbid_chan_btm_end(
+				uint32_t btm_chan_num)
+{
+	int32_t rc = 0;
+
+	rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_LOW_THR_INT_EN,
+		adc_tm_data[btm_chan_num].low_thr_int_chan_en,
+		false);
+	if (rc < 0) {
+		pr_err("low threshold int write failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
+		adc_tm_data[btm_chan_num].high_thr_int_chan_en,
+		false);
+	if (rc < 0) {
+		pr_err("high threshold int enable failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_MULTI_MEAS_EN,
+		adc_tm_data[btm_chan_num].multi_meas_en,
+		false);
+	if (rc < 0) {
+		pr_err("multi measurement en failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_enable(false);
+	if (rc < 0)
+		pr_err("TM disable failed\n");
+
+	return rc;
+}
+
+int32_t qpnp_adc_tm_usbid_end(void)
+{
+	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	int rc = 0;
+
+	if (!adc_tm || !adc_tm->adc_tm_initialized)
+		return -ENODEV;
+
+	mutex_lock(&adc_tm->adc->adc_lock);
+
+	rc = qpnp_adc_tm_chan_usbid_chan_btm_end(
+				QPNP_ADC_TM_M0_ADC_CH_SEL_CTL);
+	if (rc < 0)
+		pr_err("disabling thresholds for usb channel failed\n");
+
+	mutex_unlock(&adc_tm->adc->adc_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
+
+int32_t qpnp_adc_tm_btm_configure(struct qpnp_adc_tm_btm_param *param)
+{
+	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	uint32_t channel;
+	int rc = 0;
+
+	if (!adc_tm || !adc_tm->adc_tm_initialized)
+		return -ENODEV;
+
+	if (param->threshold_notification == NULL) {
+		pr_err("No battery high/low temp notificaton??\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&adc_tm->adc->adc_lock);
+
+	adc_tm->adc->amux_prop->amux_channel = LR_MUX1_BATT_THERM;
+	channel = LR_MUX1_BATT_THERM;
+	adc_tm->adc->amux_prop->decimation =
+			adc_tm->adc->adc_channels[channel].adc_decimation;
+	adc_tm->adc->amux_prop->hw_settle_time =
+			adc_tm->adc->adc_channels[channel].hw_settle_time;
+	adc_tm->adc->amux_prop->fast_avg_setup =
+			adc_tm->adc->adc_channels[channel].fast_avg_setup;
+	adc_tm->adc->amux_prop->mode_sel =
+		ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+	adc_tm->adc->amux_prop->chan_prop->meas_interval2 =
+						ADC_MEAS2_INTERVAL_1S;
+	qpnp_adc_btm_scaler(param, &adc_tm->adc->amux_prop->chan_prop->low_thr,
+			&adc_tm->adc->amux_prop->chan_prop->high_thr);
+	adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
+					QPNP_ADC_TM_M1_ADC_CH_SEL_CTL;
+	adc_tm->adc->amux_prop->chan_prop->timer_select =
+					ADC_MEAS_TIMER_SELECT2;
+	adc_tm->adc->amux_prop->chan_prop->state_request =
+					param->state_request;
+	rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
+	if (rc) {
+		pr_err("adc-tm configure failed with %d\n", rc);
+		goto fail_unlock;
+	}
+
+	adc_tm->battery_param = param;
+
+fail_unlock:
+	mutex_unlock(&adc_tm->adc->adc_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_adc_tm_btm_configure);
+
+int32_t qpnp_adc_tm_btm_end(void)
+{
+	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+	int rc = 0;
+
+	if (!adc_tm || !adc_tm->adc_tm_initialized)
+		return -ENODEV;
+
+	mutex_lock(&adc_tm->adc->adc_lock);
+
+	rc = qpnp_adc_tm_chan_usbid_chan_btm_end(
+				QPNP_ADC_TM_M1_ADC_CH_SEL_CTL);
+	if (rc < 0)
+		pr_err("disabling thresholds for batt channel failed\n");
+
+	mutex_unlock(&adc_tm->adc->adc_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_adc_tm_btm_end);
+
+int32_t qpnp_adc_tm_is_ready(void)
+{
+	struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
+
+	if (!adc_tm || !adc_tm->adc_tm_initialized)
+		return -EPROBE_DEFER;
+	else
+		return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_tm_is_ready);
+
+static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
+{
+	struct device_node *node = spmi->dev.of_node, *child;
+	struct qpnp_adc_tm_drv *adc_tm;
+	struct qpnp_adc_drv *adc_qpnp;
+	int32_t count_adc_channel_list = 0, rc, i = 0, j = 0;
+	u8 thr_init = 0;
+
+	if (!node)
+		return -EINVAL;
+
+	if (qpnp_adc_tm) {
+		pr_err("adc-tm already in use\n");
+		return -EBUSY;
+	}
+
+	for_each_child_of_node(node, child)
+		count_adc_channel_list++;
+
+	if (!count_adc_channel_list) {
+		pr_err("No channel listing\n");
+		return -EINVAL;
+	}
+
+	adc_tm = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_drv) +
+			(count_adc_channel_list *
+			sizeof(struct qpnp_adc_tm_sensor)),
+				GFP_KERNEL);
+	if (!adc_tm) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
+			GFP_KERNEL);
+	if (!adc_qpnp) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	adc_tm->adc = adc_qpnp;
+
+	rc = qpnp_adc_get_devicetree_data(spmi, adc_tm->adc);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to read device tree\n");
+		return rc;
+	}
+
+	/* Register the ADC peripheral interrupt */
+	adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
+						NULL, "high-thr-en-set");
+	if (adc_tm->adc->adc_high_thr_irq < 0) {
+		pr_err("Invalid irq\n");
+		return -ENXIO;
+	}
+
+	adc_tm->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
+						NULL, "low-thr-en-set");
+	if (adc_tm->adc->adc_low_thr_irq < 0) {
+		pr_err("Invalid irq\n");
+		return -ENXIO;
+	}
+
+	rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_irq_eoc,
+				qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
+				"qpnp_adc_tm_interrupt", adc_tm);
+	if (rc) {
+		dev_err(&spmi->dev,
+			"failed to request adc irq with error %d\n", rc);
+		return rc;
+	} else {
+		enable_irq_wake(adc_tm->adc->adc_irq_eoc);
+	}
+
+	rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_high_thr_irq,
+				qpnp_adc_tm_high_thr_isr,
+		IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", adc_tm);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to request adc irq\n");
+		return rc;
+	} else {
+		enable_irq_wake(adc_tm->adc->adc_high_thr_irq);
+	}
+
+	rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_low_thr_irq,
+				qpnp_adc_tm_low_thr_isr,
+		IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", adc_tm);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to request adc irq\n");
+		return rc;
+	} else {
+		enable_irq_wake(adc_tm->adc->adc_low_thr_irq);
+	}
+
+	for_each_child_of_node(node, child) {
+		char name[25];
+		int btm_channel_num;
+		rc = of_property_read_u32(child,
+				"qcom,btm-channel-number", &btm_channel_num);
+		if (rc) {
+			pr_err("Invalid btm channel number\n");
+			return -EINVAL;
+		}
+
+		if ((btm_channel_num != QPNP_ADC_TM_M0_ADC_CH_SEL_CTL) &&
+			(btm_channel_num != QPNP_ADC_TM_M1_ADC_CH_SEL_CTL)) {
+			/* Register with the thermal zone */
+			adc_tm->sensor[i].mode = THERMAL_DEVICE_DISABLED;
+			snprintf(name, sizeof(name), "qpnp_adc_tm_sensor%d", i);
+			adc_tm->sensor[i].sensor_num =
+				adc_tm->adc->adc_channels[j].channel_num;
+			adc_tm->sensor[i].btm_channel_num = btm_channel_num;
+			adc_tm->sensor[i].meas_interval =
+				QPNP_ADC_TM_MEAS_INTERVAL;
+			adc_tm->sensor[i].low_thr = QPNP_ADC_TM_M0_LOW_THR;
+			adc_tm->sensor[i].high_thr = QPNP_ADC_TM_M0_HIGH_THR;
+			adc_tm->sensor[i].tz_dev =
+				thermal_zone_device_register(name,
+				ADC_TM_TRIP_NUM,
+				&adc_tm->sensor[i],
+				&qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
+			if (IS_ERR(adc_tm->sensor[i].tz_dev))
+				pr_err("thermal device register failed.\n");
+				INIT_WORK(&adc_tm->sensor[i].work,
+					notify_uspace_qpnp_adc_tm_fn);
+			i++;
+		}
+		j++;
+	}
+	INIT_WORK(&adc_tm->usbid_work, notify_usb_fn);
+	INIT_WORK(&adc_tm->batt_work, notify_batt_fn);
+	qpnp_adc_tm = adc_tm;
+	dev_set_drvdata(&spmi->dev, adc_tm);
+	rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_HIGH_THR_INT_EN, thr_init);
+	if (rc < 0) {
+		pr_err("high thr init failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_LOW_THR_INT_EN, thr_init);
+	if (rc < 0) {
+		pr_err("low thr init failed\n");
+		return rc;
+	}
+
+	rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MULTI_MEAS_EN, thr_init);
+	if (rc < 0) {
+		pr_err("multi meas en failed\n");
+		return rc;
+	}
+
+	adc_tm->adc_tm_initialized = true;
+
+	return 0;
+}
+
+static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
+{
+	struct qpnp_adc_tm_drv *adc_tm = dev_get_drvdata(&spmi->dev);
+	struct device_node *node = spmi->dev.of_node;
+	struct device_node *child;
+	int i = 0;
+
+	for_each_child_of_node(node, child) {
+		thermal_zone_device_unregister(adc_tm->sensor[i].tz_dev);
+		i++;
+	}
+
+	adc_tm->adc_tm_initialized = false;
+	dev_set_drvdata(&spmi->dev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id qpnp_adc_tm_match_table[] = {
+	{	.compatible = "qcom,qpnp-adc-tm" },
+	{}
+};
+
+static struct spmi_driver qpnp_adc_tm_driver = {
+	.driver		= {
+		.name	= "qcom,qpnp-adc-tm",
+		.of_match_table = qpnp_adc_tm_match_table,
+	},
+	.probe		= qpnp_adc_tm_probe,
+	.remove		= qpnp_adc_tm_remove,
+};
+
+static int __init qpnp_adc_tm_init(void)
+{
+	return spmi_driver_register(&qpnp_adc_tm_driver);
+}
+module_init(qpnp_adc_tm_init);
+
+static void __exit qpnp_adc_tm_exit(void)
+{
+	spmi_driver_unregister(&qpnp_adc_tm_driver);
+}
+module_exit(qpnp_adc_tm_exit);
+
+MODULE_DESCRIPTION("QPNP PMIC ADC Threshold Monitoring driver");
+MODULE_LICENSE("GPL v2");
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/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index cc9ffaa..72a12d1 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -18,6 +18,8 @@
  * This file is based on msm_serial.c, originally
  * Written by Robert Love <rlove@google.com>  */
 
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 #if defined(CONFIG_SERIAL_MSM_HSL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
 #endif
@@ -62,6 +64,7 @@
 	unsigned int            old_snap_state;
 	unsigned int		ver_id;
 	int			tx_timeout;
+	struct mutex		clk_mutex;
 };
 
 #define UARTDM_VERSION_11_13	0
@@ -188,11 +191,12 @@
 	unsigned long flags;
 	int ret = 0;
 
-	ret = clk_set_rate(msm_hsl_port->clk, 7372800);
-	if (!ret)
+	ret = clk_set_rate(msm_hsl_port->clk, port->uartclk);
+	if (!ret) {
 		clk_en(port, 1);
-	else {
-		pr_err("%s(): Error: Setting the clock rate\n", __func__);
+	} else {
+		pr_err("Error: setting uartclk rate as %u\n",
+						port->uartclk);
 		return -EINVAL;
 	}
 
@@ -221,11 +225,12 @@
 	unsigned long flags;
 	int ret = 0;
 
-	ret = clk_set_rate(msm_hsl_port->clk, 7372800);
-	if (!ret)
+	ret = clk_set_rate(msm_hsl_port->clk, port->uartclk);
+	if (!ret) {
 		clk_en(port, 1);
-	else {
-		pr_err("%s(): Error setting clk rate\n", __func__);
+	} else {
+		pr_err("Error setting uartclk rate as %u\n",
+						port->uartclk);
 		return -EINVAL;
 	}
 
@@ -258,8 +263,7 @@
 					&loopback_enable_fops);
 
 	if (IS_ERR_OR_NULL(msm_uport->loopback_dir))
-		pr_err("%s(): Cannot create loopback.%d debug entry",
-							__func__, id);
+		pr_err("Cannot create loopback.%d debug entry", id);
 }
 static void msm_hsl_stop_tx(struct uart_port *port)
 {
@@ -561,7 +565,13 @@
 		msm_hsl_write(port, STOP_BREAK, regmap[vid][UARTDM_CR]);
 }
 
-static void msm_hsl_set_baud_rate(struct uart_port *port, unsigned int baud)
+/**
+ * msm_hsl_set_baud_rate: set requested baud rate
+ * @port: uart port
+ * @baud: baud rate to set (in bps)
+ */
+static void msm_hsl_set_baud_rate(struct uart_port *port,
+						unsigned int baud)
 {
 	unsigned int baud_code, rxstale, watermark;
 	unsigned int data;
@@ -625,18 +635,54 @@
 		baud_code = UARTDM_CSR_115200;
 		rxstale = 31;
 		break;
-	default: /* 115200 baud rate */
+	case 4000000:
+	case 3686400:
+	case 3200000:
+	case 3500000:
+	case 3000000:
+	case 2500000:
+	case 1500000:
+	case 1152000:
+	case 1000000:
+	case 921600:
+		baud_code = 0xff;
+		rxstale = 31;
+		break;
+	default: /*115200 baud rate */
 		baud_code = UARTDM_CSR_28800;
 		rxstale = 31;
 		break;
 	}
 
-	/* Set timeout to be ~600x the character transmit time */
-	msm_hsl_port->tx_timeout = (1000000000 / baud) * 6;
-
 	vid = msm_hsl_port->ver_id;
 	msm_hsl_write(port, baud_code, regmap[vid][UARTDM_CSR]);
 
+	/*
+	 * uart baud rate depends on CSR and MND Values
+	 * we are updating CSR before and then calling
+	 * clk_set_rate which updates MND Values. Hence
+	 * dsb requires here.
+	 */
+	mb();
+
+	/*
+	 * Check requested baud rate and for higher baud rate than 460800,
+	 * calculate required uart clock frequency and set the same.
+	 */
+	if (baud > 460800)
+		port->uartclk = baud * 16;
+	else
+		port->uartclk = 7372800;
+
+	if (clk_set_rate(msm_hsl_port->clk, port->uartclk)) {
+		pr_err("Error: setting uartclk rate %u\n", port->uartclk);
+		WARN_ON(1);
+		return;
+	}
+
+	/* Set timeout to be ~600x the character transmit time */
+	msm_hsl_port->tx_timeout = (1000000000 / baud) * 6;
+
 	/* RX stale watermark */
 	watermark = UARTDM_IPR_STALE_LSB_BMSK & rxstale;
 	watermark |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
@@ -646,9 +692,9 @@
 	 * Configure Rx Watermark as 3/4 size of Rx FIFO.
 	 * RFWR register takes value in Words for UARTDM Core
 	 * whereas it is consider to be in Bytes for UART Core.
-	 * Hence configuring Rx Watermark as 12 Words.
+	 * Hence configuring Rx Watermark as 48 Words.
 	 */
-	watermark = (port->fifosize * 3) / (4*4);
+	watermark = (port->fifosize * 3) / 4;
 	msm_hsl_write(port, watermark, regmap[vid][UARTDM_RFWR]);
 
 	/* set TX watermark */
@@ -710,15 +756,15 @@
 			ret = gpio_request(pdata->uart_tx_gpio,
 						"UART_TX_GPIO");
 			if (unlikely(ret)) {
-				pr_err("%s: gpio request failed for:%d\n",
-						__func__, pdata->uart_tx_gpio);
+				pr_err("gpio request failed for:%d\n",
+							pdata->uart_tx_gpio);
 				return ret;
 			}
 
 			ret = gpio_request(pdata->uart_rx_gpio, "UART_RX_GPIO");
 			if (unlikely(ret)) {
-				pr_err("%s: gpio request failed for:%d\n",
-						__func__, pdata->uart_rx_gpio);
+				pr_err("gpio request failed for:%d\n",
+							pdata->uart_rx_gpio);
 				gpio_free(pdata->uart_tx_gpio);
 				return ret;
 			}
@@ -729,18 +775,15 @@
 #endif
 	pm_runtime_get_sync(port->dev);
 
-	/* Set RFR Level as 3/4 of UARTDM FIFO Size */
+	/*
+	 * Set RFR Level as 3/4 of UARTDM FIFO Size
+	 * i.e. 48 Words = 192 bytes as Rx FIFO is 64 words ( 256 bytes).
+	 */
 	if (likely(port->fifosize > 48))
 		rfr_level = port->fifosize - 16;
 	else
 		rfr_level = port->fifosize;
 
-	/*
-	 * Use rfr_level value in Words to program
-	 * MR1 register for UARTDM Core.
-	 */
-	rfr_level = (rfr_level / 4);
-
 	spin_lock_irqsave(&port->lock, flags);
 
 	vid = msm_hsl_port->ver_id;
@@ -756,7 +799,7 @@
 	ret = request_irq(port->irq, msm_hsl_irq, IRQF_TRIGGER_HIGH,
 			  msm_hsl_port->name, port);
 	if (unlikely(ret)) {
-		printk(KERN_ERR "%s: failed to request_irq\n", __func__);
+		pr_err("failed to request_irq\n");
 		return ret;
 	}
 	return 0;
@@ -792,17 +835,28 @@
 				struct ktermios *termios,
 				struct ktermios *old)
 {
-	unsigned long flags;
 	unsigned int baud, mr;
 	unsigned int vid;
+	struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
 
 	if (!termios->c_cflag)
 		return;
 
-	spin_lock_irqsave(&port->lock, flags);
+	mutex_lock(&msm_hsl_port->clk_mutex);
 
-	/* calculate and set baud rate */
-	baud = uart_get_baud_rate(port, termios, old, 300, 460800);
+	/*
+	 * Calculate and set baud rate
+	 * 300 is the minimum and 4 Mbps is the maximum baud rate
+	 * supported by driver.
+	 */
+	baud = uart_get_baud_rate(port, termios, old, 200, 4000000);
+
+	/*
+	 * Due to non-availability of 3.2 Mbps baud rate as standard baud rate
+	 * with TTY/serial core. Map 200 BAUD to 3.2 Mbps
+	 */
+	if (baud == 200)
+		baud = 3200000;
 
 	msm_hsl_set_baud_rate(port, baud);
 
@@ -865,7 +919,7 @@
 
 	uart_update_timeout(port, termios->c_cflag, baud);
 
-	spin_unlock_irqrestore(&port->lock, flags);
+	mutex_unlock(&msm_hsl_port->clk_mutex);
 }
 
 static const char *msm_hsl_type(struct uart_port *port)
@@ -913,14 +967,14 @@
 	if (!uart_resource)
 		uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (unlikely(!uart_resource)) {
-		pr_err("%s: can't get uartdm resource\n", __func__);
+		pr_err("can't get uartdm resource\n");
 		return -ENXIO;
 	}
 	size = uart_resource->end - uart_resource->start + 1;
 
 	if (unlikely(!request_mem_region(port->mapbase, size,
 					 "msm_serial_hsl"))) {
-		pr_err("%s: can't get mem region for uartdm\n", __func__);
+		pr_err("can't get mem region for uartdm\n");
 		return -EBUSY;
 	}
 
@@ -938,7 +992,7 @@
 			gsbi_resource = platform_get_resource(pdev,
 						IORESOURCE_MEM, 1);
 		if (unlikely(!gsbi_resource)) {
-			pr_err("%s: can't get gsbi resource\n", __func__);
+			pr_err("can't get gsbi resource\n");
 			return -ENXIO;
 		}
 
@@ -991,22 +1045,20 @@
 
 	switch (state) {
 	case 0:
-		ret = clk_set_rate(msm_hsl_port->clk, 7372800);
+		ret = clk_set_rate(msm_hsl_port->clk, port->uartclk);
 		if (ret)
-			pr_err("%s(): Error setting UART clock rate\n",
-								__func__);
+			pr_err("Error setting UART clock rate to %u\n",
+							port->uartclk);
 		clk_en(port, 1);
 		break;
 	case 3:
 		clk_en(port, 0);
 		ret = clk_set_rate(msm_hsl_port->clk, 0);
 		if (ret)
-			pr_err("%s(): Error setting UART clock rate to zero.\n",
-								__func__);
+			pr_err("Error setting UART clock rate to zero.\n");
 		break;
 	default:
-		pr_err("%s(): msm_serial_hsl: Unknown PM state %d\n",
-							__func__, state);
+		pr_err("Unknown PM state %d\n", state);
 	}
 }
 
@@ -1093,15 +1145,15 @@
 	msm_hsl_console_state[6] = rxfs;
 	msm_hsl_console_state[7] = con_state;
 
-	pr_info("%s(): Timeout: %d uS\n", __func__, msm_hsl_port->tx_timeout);
-	pr_info("%s(): SR:  %08x\n", __func__, sr);
-	pr_info("%s(): ISR: %08x\n", __func__, isr);
-	pr_info("%s(): MR1: %08x\n", __func__, mr1);
-	pr_info("%s(): MR2: %08x\n", __func__, mr2);
-	pr_info("%s(): NCF: %08x\n", __func__, ncf);
-	pr_info("%s(): TXFS: %08x\n", __func__, txfs);
-	pr_info("%s(): RXFS: %08x\n", __func__, rxfs);
-	pr_info("%s(): Console state: %d\n", __func__, con_state);
+	pr_info("Timeout: %d uS\n", msm_hsl_port->tx_timeout);
+	pr_info("SR:  %08x\n", sr);
+	pr_info("ISR: %08x\n", isr);
+	pr_info("MR1: %08x\n", mr1);
+	pr_info("MR2: %08x\n", mr2);
+	pr_info("NCF: %08x\n", ncf);
+	pr_info("TXFS: %08x\n", txfs);
+	pr_info("RXFS: %08x\n", rxfs);
+	pr_info("Console state: %d\n", con_state);
 }
 
 /*
@@ -1228,8 +1280,7 @@
 	msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
 	msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
 
-	printk(KERN_INFO "msm_serial_hsl: console setup on port #%d\n",
-	       port->line);
+	pr_info("console setup on port #%d\n", port->line);
 
 	return ret;
 }
@@ -1302,9 +1353,9 @@
 
 	switch (enable) {
 	case 0:
-		pr_debug("%s(): Calling stop_console\n", __func__);
+		pr_debug("Calling stop_console\n");
 		console_stop(port->cons);
-		pr_debug("%s(): Calling unregister_console\n", __func__);
+		pr_debug("Calling unregister_console\n");
 		unregister_console(port->cons);
 		pm_runtime_put_sync(&pdev->dev);
 		pm_runtime_disable(&pdev->dev);
@@ -1316,7 +1367,7 @@
 		msm_hsl_power(port, 3, 1);
 		break;
 	case 1:
-		pr_debug("%s(): Calling register_console\n", __func__);
+		pr_debug("Calling register_console\n");
 		/*
 		 * Disable UART Core clk
 		 * 0 - to enable the UART clock
@@ -1379,11 +1430,11 @@
 	if (unlikely(line < 0 || line >= UART_NR))
 		return -ENXIO;
 
-	printk(KERN_INFO "msm_serial_hsl: detected port #%d (ttyHSL%d)\n",
-	       pdev->id, line);
+	pr_info("detected port #%d (ttyHSL%d)\n", pdev->id, line);
 
 	port = get_port_from_line(line);
 	port->dev = &pdev->dev;
+	port->uartclk = 7372800;
 	msm_hsl_port = UART_TO_MSM(port);
 
 	match = of_match_device(msm_hsl_match_table, &pdev->dev);
@@ -1406,11 +1457,11 @@
 		msm_hsl_port->is_uartdm = 0;
 
 	if (unlikely(IS_ERR(msm_hsl_port->clk))) {
-		printk(KERN_ERR "%s: Error getting clk\n", __func__);
+		pr_err("Error getting clk\n");
 		return PTR_ERR(msm_hsl_port->clk);
 	}
 	if (unlikely(IS_ERR(msm_hsl_port->pclk))) {
-		printk(KERN_ERR "%s: Error getting pclk\n", __func__);
+		pr_err("Error getting pclk\n");
 		return PTR_ERR(msm_hsl_port->pclk);
 	}
 
@@ -1420,14 +1471,14 @@
 	if (!uart_resource)
 		uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (unlikely(!uart_resource)) {
-		printk(KERN_ERR "getting uartdm_resource failed\n");
+		pr_err("getting uartdm_resource failed\n");
 		return -ENXIO;
 	}
 	port->mapbase = uart_resource->start;
 
 	port->irq = platform_get_irq(pdev, 0);
 	if (unlikely((int)port->irq < 0)) {
-		printk(KERN_ERR "%s: getting irq failed\n", __func__);
+		pr_err("getting irq failed\n");
 		return -ENXIO;
 	}
 
@@ -1437,9 +1488,10 @@
 #ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
 	ret = device_create_file(&pdev->dev, &dev_attr_console);
 	if (unlikely(ret))
-		pr_err("%s():Can't create console attribute\n", __func__);
+		pr_err("Can't create console attribute\n");
 #endif
 	msm_hsl_debugfs_init(msm_hsl_port, get_line(pdev));
+	mutex_init(&msm_hsl_port->clk_mutex);
 
 	/* Temporarily increase the refcount on the GSBI clock to avoid a race
 	 * condition with the earlyprintk handover mechanism.
@@ -1466,6 +1518,7 @@
 
 	device_set_wakeup_capable(&pdev->dev, 0);
 	platform_set_drvdata(pdev, NULL);
+	mutex_destroy(&msm_hsl_port->clk_mutex);
 	uart_remove_one_port(&msm_hsl_uart_driver, port);
 
 	clk_put(msm_hsl_port->pclk);
@@ -1568,13 +1621,13 @@
 
 	debug_base = debugfs_create_dir("msm_serial_hsl", NULL);
 	if (IS_ERR_OR_NULL(debug_base))
-		pr_err("%s():Cannot create debugfs dir\n", __func__);
+		pr_err("Cannot create debugfs dir\n");
 
 	ret = platform_driver_register(&msm_hsl_platform_driver);
 	if (unlikely(ret))
 		uart_unregister_driver(&msm_hsl_uart_driver);
 
-	printk(KERN_INFO "msm_serial_hsl: driver initialized\n");
+	pr_info("driver initialized\n");
 
 	return ret;
 }
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/core.c b/drivers/usb/dwc3/core.c
index c0b4b57..265a685 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -300,19 +300,7 @@
 	}
 }
 
-/* XHCI reset, resets other CORE registers as well, re-init those */
-void dwc3_post_host_reset_core_init(struct dwc3 *dwc)
-{
-	/*
-	 * XHCI reset clears EVENT buffer register as well, re-init
-	 * EVENT buffers and also do device specific re-initialization
-	 */
-	dwc3_event_buffers_setup(dwc);
-
-	dwc3_gadget_restart(dwc);
-}
-
-static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
+static void dwc3_cache_hwparams(struct dwc3 *dwc)
 {
 	struct dwc3_hwparams	*parms = &dwc->hwparams;
 
@@ -333,7 +321,7 @@
  *
  * Returns 0 on success otherwise negative errno.
  */
-static int __devinit dwc3_core_init(struct dwc3 *dwc)
+static int dwc3_core_init(struct dwc3 *dwc)
 {
 	unsigned long		timeout;
 	u32			reg;
@@ -434,11 +422,13 @@
 		dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 	}
 
-	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
-	if (ret) {
-		dev_err(dwc->dev, "failed to allocate event buffers\n");
-		ret = -ENOMEM;
-		goto err1;
+	if (!dwc->ev_buffs) {
+		ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
+		if (ret) {
+			dev_err(dwc->dev, "failed to allocate event buffers\n");
+			ret = -ENOMEM;
+			goto err1;
+		}
 	}
 
 	ret = dwc3_event_buffers_setup(dwc);
@@ -462,6 +452,13 @@
 	dwc3_free_event_buffers(dwc);
 }
 
+/* XHCI reset, resets other CORE registers as well, re-init those */
+void dwc3_post_host_reset_core_init(struct dwc3 *dwc)
+{
+	dwc3_core_init(dwc);
+	dwc3_gadget_restart(dwc);
+}
+
 #define DWC3_ALIGN_MASK		(16 - 1)
 
 static int __devinit dwc3_probe(struct platform_device *pdev)
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/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 7430e5a..cb1da06 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.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
@@ -34,16 +34,31 @@
 #include <linux/usb/msm_hsusb.h>
 #include <linux/regulator/consumer.h>
 #include <linux/power_supply.h>
+#include <linux/qpnp/qpnp-adc.h>
 
 #include <mach/rpm-regulator.h>
 #include <mach/rpm-regulator-smd.h>
 #include <mach/msm_xo.h>
 #include <mach/msm_bus.h>
+#include <mach/clk.h>
 
 #include "dwc3_otg.h"
 #include "core.h"
 #include "gadget.h"
 
+/* ADC threshold values */
+static int adc_low_threshold = 700;
+module_param(adc_low_threshold, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(adc_low_threshold, "ADC ID Low voltage threshold");
+
+static int adc_high_threshold = 950;
+module_param(adc_high_threshold, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(adc_high_threshold, "ADC ID High voltage threshold");
+
+static int adc_meas_interval = ADC_MEAS1_INTERVAL_1S;
+module_param(adc_meas_interval, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(adc_meas_interval, "ADC ID polling period");
+
 /**
  *  USB DBM Hardware registers.
  *
@@ -114,6 +129,12 @@
 #define ALT_INTERRUPT_EN_REG	(QSCRATCH_REG_OFFSET + 0x20)
 #define HS_PHY_IRQ_STAT_REG	(QSCRATCH_REG_OFFSET + 0x24)
 #define SS_PHY_CTRL_REG		(QSCRATCH_REG_OFFSET + 0x30)
+#define SS_CR_PROTOCOL_DATA_IN_REG  (QSCRATCH_REG_OFFSET + 0x3C)
+#define SS_CR_PROTOCOL_DATA_OUT_REG (QSCRATCH_REG_OFFSET + 0x40)
+#define SS_CR_PROTOCOL_CAP_ADDR_REG (QSCRATCH_REG_OFFSET + 0x44)
+#define SS_CR_PROTOCOL_CAP_DATA_REG (QSCRATCH_REG_OFFSET + 0x48)
+#define SS_CR_PROTOCOL_READ_REG     (QSCRATCH_REG_OFFSET + 0x4C)
+#define SS_CR_PROTOCOL_WRITE_REG    (QSCRATCH_REG_OFFSET + 0x50)
 
 struct dwc3_msm_req_complete {
 	struct list_head list_item;
@@ -154,6 +175,9 @@
 	struct usb_phy		*otg_xceiv;
 	struct delayed_work	chg_work;
 	enum usb_chg_state	chg_state;
+	struct qpnp_adc_tm_usbid_param	adc_param;
+	struct delayed_work	init_adc_work;
+	bool			id_adc_detect;
 	u8			dcd_retries;
 	u32			bus_perf_client;
 	struct msm_bus_scale_pdata	*bus_scale_table;
@@ -280,6 +304,54 @@
 }
 
 /**
+ *
+ * Write SSPHY register with debug info.
+ *
+ * @base - DWC3 base virtual address.
+ * @addr - SSPHY address to write.
+ * @val - value to write.
+ *
+ */
+static void dwc3_msm_ssusb_write_phycreg(void *base, u32 addr, u32 val)
+{
+	iowrite32(addr, base + SS_CR_PROTOCOL_DATA_IN_REG);
+	iowrite32(0x1, base + SS_CR_PROTOCOL_CAP_ADDR_REG);
+	while (ioread32(base + SS_CR_PROTOCOL_CAP_ADDR_REG))
+		cpu_relax();
+
+	iowrite32(val, base + SS_CR_PROTOCOL_DATA_IN_REG);
+	iowrite32(0x1, base + SS_CR_PROTOCOL_CAP_DATA_REG);
+	while (ioread32(base + SS_CR_PROTOCOL_CAP_DATA_REG))
+		cpu_relax();
+
+	iowrite32(0x1, base + SS_CR_PROTOCOL_WRITE_REG);
+	while (ioread32(base + SS_CR_PROTOCOL_WRITE_REG))
+		cpu_relax();
+}
+
+/**
+ *
+ * Read SSPHY register with debug info.
+ *
+ * @base - DWC3 base virtual address.
+ * @addr - SSPHY address to read.
+ *
+ */
+static u32 dwc3_msm_ssusb_read_phycreg(void *base, u32 addr)
+{
+	iowrite32(addr, base + SS_CR_PROTOCOL_DATA_IN_REG);
+	iowrite32(0x1, base + SS_CR_PROTOCOL_CAP_ADDR_REG);
+	while (ioread32(base + SS_CR_PROTOCOL_CAP_ADDR_REG))
+		cpu_relax();
+
+	iowrite32(0x1, base + SS_CR_PROTOCOL_READ_REG);
+	while (ioread32(base + SS_CR_PROTOCOL_READ_REG))
+		cpu_relax();
+
+	return ioread32(base + SS_CR_PROTOCOL_DATA_OUT_REG);
+}
+
+/**
  * Return DBM EP number according to usb endpoint number.
  *
  */
@@ -1045,6 +1117,95 @@
 	return rc < 0 ? rc : 0;
 }
 
+static int dwc3_msm_link_clk_reset(bool assert)
+{
+	int ret = 0;
+	struct dwc3_msm *mdwc = context;
+
+	if (assert) {
+		/* Using asynchronous block reset to the hardware */
+		dev_dbg(mdwc->dev, "block_reset ASSERT\n");
+		clk_disable_unprepare(mdwc->ref_clk);
+		clk_disable_unprepare(mdwc->iface_clk);
+		clk_disable_unprepare(mdwc->core_clk);
+		ret = clk_reset(mdwc->core_clk, CLK_RESET_ASSERT);
+		if (ret)
+			dev_err(mdwc->dev, "dwc3 core_clk assert failed\n");
+	} else {
+		dev_dbg(mdwc->dev, "block_reset DEASSERT\n");
+		ret = clk_reset(mdwc->core_clk, CLK_RESET_DEASSERT);
+		ndelay(200);
+		clk_prepare_enable(mdwc->core_clk);
+		clk_prepare_enable(mdwc->ref_clk);
+		clk_prepare_enable(mdwc->iface_clk);
+		if (ret)
+			dev_err(mdwc->dev, "dwc3 core_clk deassert failed\n");
+	}
+
+	return ret;
+}
+
+/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
+static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *msm)
+{
+	u32 data = 0;
+
+	/* SSPHY Initialization: Use ref_clk from pads and set its parameters */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
+	msleep(30);
+	/* Assert SSPHY reset */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210082);
+	usleep_range(2000, 2200);
+	/* De-assert SSPHY reset - power and ref_clock must be ON */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
+	usleep_range(2000, 2200);
+	/* Ref clock must be stable now, enable ref clock for HS mode */
+	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210102);
+	usleep_range(2000, 2200);
+	/*
+	 * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
+	 * and disable RETENTION (power-on default is ENABLED)
+	 */
+	dwc3_msm_write_reg(msm->base, HS_PHY_CTRL_REG, 0x5220bb2);
+	usleep_range(2000, 2200);
+	/* Disable (bypass) VBUS and ID filters */
+	dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x78);
+
+	/*
+	 * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
+	 * in HS mode instead of SS mode. Workaround it by asserting
+	 * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
+	 */
+	data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x102D);
+	data |= (1 << 7);
+	dwc3_msm_ssusb_write_phycreg(msm->base, 0x102D, data);
+
+	data = dwc3_msm_ssusb_read_phycreg(msm->base, 0x1010);
+	data &= ~0xFF0;
+	data |= 0x40;
+	dwc3_msm_ssusb_write_phycreg(msm->base, 0x1010, data);
+}
+
+static void dwc3_msm_block_reset(void)
+{
+	struct dwc3_msm *mdwc = context;
+	int ret  = 0;
+
+	ret = dwc3_msm_link_clk_reset(1);
+	if (ret)
+		return;
+
+	usleep_range(1000, 1200);
+	ret = dwc3_msm_link_clk_reset(0);
+	if (ret)
+		return;
+
+	usleep_range(10000, 12000);
+
+	/* Reinitialize QSCRATCH registers after block reset */
+	dwc3_msm_qscratch_reg_init(mdwc);
+}
+
 static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
 {
 	u32 chg_ctrl;
@@ -1194,6 +1355,10 @@
 		/* fall through */
 	case USB_CHG_STATE_DETECTED:
 		dwc3_chg_block_reset(mdwc);
+		/* Enable VDP_SRC */
+		if (mdwc->charger.chg_type == DWC3_DCP_CHARGER)
+			dwc3_msm_write_readback(mdwc->base,
+					CHARGING_DET_CTRL_REG, 0x1F, 0x10);
 		dev_dbg(mdwc->dev, "chg_type = %s\n",
 			chg_to_string(mdwc->charger.chg_type));
 		mdwc->charger.notify_detection_complete(mdwc->otg_xceiv->otg,
@@ -1225,6 +1390,7 @@
 static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
 {
 	int ret;
+	bool dcp;
 
 	dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
 
@@ -1233,23 +1399,29 @@
 		return 0;
 	}
 
+	if (mdwc->hs_phy_irq)
+		disable_irq(mdwc->hs_phy_irq);
+
 	if (cancel_delayed_work_sync(&mdwc->chg_work))
 		dev_dbg(mdwc->dev, "%s: chg_work was pending\n", __func__);
 	if (mdwc->chg_state != USB_CHG_STATE_DETECTED) {
 		/* charger detection wasn't complete; re-init flags */
 		mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
 		mdwc->charger.chg_type = DWC3_INVALID_CHARGER;
+		dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG,
+								0x37, 0x0);
 	}
 
+	dcp = mdwc->charger.chg_type == DWC3_DCP_CHARGER;
+
 	/* Sequence to put hardware in low power state:
 	 * 1. Set OTGDISABLE to disable OTG block in HSPHY (saves power)
-	 * 2. Clear charger detection control fields
+	 * 2. Clear charger detection control fields (performed above)
 	 * 3. SUSPEND PHY and turn OFF core clock after some delay
 	 * 4. Clear interrupt latch register and enable BSV, ID HV interrupts
 	 * 5. Enable PHY retention
 	 */
 	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x1000, 0x1000);
-	dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x37, 0x0);
 	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
 						0xC00000, 0x800000);
 
@@ -1269,7 +1441,8 @@
 
 	dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
 	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x18000, 0x18000);
-	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x0);
+	if (!dcp)
+		dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x0);
 
 	/* make sure above writes are completed before turning off clocks */
 	wmb();
@@ -1289,7 +1462,7 @@
 			dev_err(mdwc->dev, "Failed to reset bus bw vote\n");
 	}
 
-	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability)
+	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp)
 		dwc3_hsusb_ldo_enable(0);
 
 	dwc3_ssusb_ldo_enable(0);
@@ -1300,12 +1473,16 @@
 
 	dev_info(mdwc->dev, "DWC3 in low power mode\n");
 
+	if (mdwc->hs_phy_irq)
+		enable_irq(mdwc->hs_phy_irq);
+
 	return 0;
 }
 
 static int dwc3_msm_resume(struct dwc3_msm *mdwc)
 {
 	int ret;
+	bool dcp;
 
 	dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
 
@@ -1329,7 +1506,8 @@
 		dev_err(mdwc->dev, "%s failed to vote for TCXO buffer%d\n",
 						__func__, ret);
 
-	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability)
+	dcp = mdwc->charger.chg_type == DWC3_DCP_CHARGER;
+	if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp)
 		dwc3_hsusb_ldo_enable(1);
 
 	dwc3_ssusb_ldo_enable(1);
@@ -1411,7 +1589,7 @@
 	}
 }
 
-static u32 debug_id, debug_bsv, debug_connect;
+static u32 debug_id = true, debug_bsv, debug_connect;
 
 static int dwc3_connect_show(struct seq_file *s, void *unused)
 {
@@ -1557,7 +1735,6 @@
 		if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability ||
 							!init)) {
 			mdwc->ext_xceiv.bsv = val->intval;
-			mdwc->ext_xceiv.id = DWC3_ID_FLOAT;
 			if (atomic_read(&mdwc->in_lpm)) {
 				dev_dbg(mdwc->dev,
 					"%s received in LPM\n", __func__);
@@ -1598,6 +1775,88 @@
 	POWER_SUPPLY_PROP_SCOPE,
 };
 
+static void dwc3_adc_notification(enum qpnp_tm_state state, void *ctx)
+{
+	struct dwc3_msm *mdwc = ctx;
+
+	if (state >= ADC_TM_STATE_NUM) {
+		pr_err("%s: invalid notification %d\n", __func__, state);
+		return;
+	}
+
+	dev_dbg(mdwc->dev, "%s: state = %s\n", __func__,
+			state == ADC_TM_HIGH_STATE ? "high" : "low");
+
+	if (state == ADC_TM_HIGH_STATE) {
+		mdwc->ext_xceiv.id = DWC3_ID_FLOAT;
+		mdwc->adc_param.state_request = ADC_TM_LOW_THR_ENABLE;
+	} else {
+		mdwc->ext_xceiv.id = DWC3_ID_GROUND;
+		mdwc->adc_param.state_request = ADC_TM_HIGH_THR_ENABLE;
+	}
+
+	/* notify OTG */
+	queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
+
+	/* re-arm notification interrupt */
+	qpnp_adc_tm_usbid_configure(&mdwc->adc_param);
+}
+
+static void dwc3_init_adc_work(struct work_struct *w)
+{
+	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
+							init_adc_work.work);
+	int ret;
+
+	ret = qpnp_adc_tm_is_ready();
+	if (ret == -EPROBE_DEFER) {
+		queue_delayed_work(system_nrt_wq, to_delayed_work(w), 100);
+		return;
+	}
+
+	mdwc->adc_param.low_thr = adc_low_threshold;
+	mdwc->adc_param.high_thr = adc_high_threshold;
+	mdwc->adc_param.timer_interval = adc_meas_interval;
+	mdwc->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+	mdwc->adc_param.usbid_ctx = mdwc;
+	mdwc->adc_param.threshold_notification = dwc3_adc_notification;
+
+	ret = qpnp_adc_tm_usbid_configure(&mdwc->adc_param);
+	if (ret) {
+		dev_err(mdwc->dev, "%s: request ADC error %d\n", __func__, ret);
+		return;
+	}
+
+	mdwc->id_adc_detect = true;
+}
+
+static ssize_t adc_enable_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", context->id_adc_detect ?
+						"enabled" : "disabled");
+}
+
+static ssize_t adc_enable_store(struct device *dev,
+		struct device_attribute *attr, const char
+		*buf, size_t size)
+{
+	if (!strnicmp(buf, "enable", 6)) {
+		if (!context->id_adc_detect)
+			dwc3_init_adc_work(&context->init_adc_work.work);
+		return size;
+	} else if (!strnicmp(buf, "disable", 7)) {
+		qpnp_adc_tm_usbid_end();
+		context->id_adc_detect = false;
+		return size;
+	}
+
+	return -EINVAL;
+}
+
+static DEVICE_ATTR(adc_enable, S_IRUGO | S_IWUSR, adc_enable_show,
+		adc_enable_store);
+
 static int __devinit dwc3_msm_probe(struct platform_device *pdev)
 {
 	struct device_node *node = pdev->dev.of_node;
@@ -1622,6 +1881,7 @@
 	INIT_LIST_HEAD(&msm->req_complete_list);
 	INIT_DELAYED_WORK(&msm->chg_work, dwc3_chg_detect_work);
 	INIT_DELAYED_WORK(&msm->resume_work, dwc3_resume_work);
+	INIT_DELAYED_WORK(&msm->init_adc_work, dwc3_init_adc_work);
 
 	msm->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
 	if (IS_ERR(msm->xo_handle)) {
@@ -1760,6 +2020,7 @@
 		goto free_hs_ldo_init;
 	}
 
+	msm->ext_xceiv.id = DWC3_ID_FLOAT;
 	msm->ext_xceiv.otg_capability = of_property_read_bool(node,
 				"qcom,otg-capability");
 	msm->charger.charging_disabled = of_property_read_bool(node,
@@ -1780,6 +2041,10 @@
 			}
 			enable_irq_wake(msm->hs_phy_irq);
 		}
+	} else {
+		/* Use ADC for ID pin detection */
+		queue_delayed_work(system_nrt_wq, &msm->init_adc_work, 0);
+		device_create_file(&pdev->dev, &dev_attr_adc_enable);
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1830,26 +2095,7 @@
 	msm->resource_size = resource_size(res);
 	msm->dwc3 = dwc3;
 
-	/* SSPHY Initialization: Use ref_clk from pads and set its parameters */
-	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
-	msleep(30);
-	/* Assert SSPHY reset */
-	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210082);
-	usleep_range(2000, 2200);
-	/* De-assert SSPHY reset - power and ref_clock must be ON */
-	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210002);
-	usleep_range(2000, 2200);
-	/* Ref clock must be stable now, enable ref clock for HS mode */
-	dwc3_msm_write_reg(msm->base, SS_PHY_CTRL_REG, 0x10210102);
-	usleep_range(2000, 2200);
-	/*
-	 * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
-	 * and disable RETENTION (power-on default is ENABLED)
-	 */
-	dwc3_msm_write_reg(msm->base, HS_PHY_CTRL_REG, 0x5220bb2);
-	usleep_range(2000, 2200);
-	/* Disable (bypass) VBUS and ID filters */
-	dwc3_msm_write_reg(msm->base, QSCRATCH_GENERAL_CFG, 0x78);
+	dwc3_msm_qscratch_reg_init(msm);
 
 	pm_runtime_set_active(msm->dev);
 	pm_runtime_enable(msm->dev);
@@ -1932,6 +2178,8 @@
 			goto put_xcvr;
 		}
 
+		if (msm->ext_xceiv.otg_capability)
+			msm->ext_xceiv.ext_block_reset = dwc3_msm_block_reset;
 		ret = dwc3_set_ext_xceiv(msm->otg_xceiv->otg, &msm->ext_xceiv);
 		if (ret || !msm->ext_xceiv.notify_ext_events) {
 			dev_err(&pdev->dev, "failed to register xceiver: %d\n",
@@ -1994,12 +2242,15 @@
 {
 	struct dwc3_msm	*msm = platform_get_drvdata(pdev);
 
+	if (msm->id_adc_detect)
+		qpnp_adc_tm_usbid_end();
 	if (dwc3_debugfs_root)
 		debugfs_remove_recursive(dwc3_debugfs_root);
 	if (msm->otg_xceiv) {
 		dwc3_start_chg_det(&msm->charger, false);
 		usb_put_transceiver(msm->otg_xceiv);
 	}
+
 	pm_runtime_disable(msm->dev);
 	platform_device_unregister(msm->dwc3);
 	wake_lock_destroy(&msm->wlock);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index fab443c..136cc5d 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -1,7 +1,7 @@
 /**
  * dwc3_otg.c - DesignWare USB3 DRD Controller OTG
  *
- * 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
@@ -38,12 +38,21 @@
  */
 static void dwc3_otg_set_host_regs(struct dwc3_otg *dotg)
 {
-	u32 octl;
+	u32 reg;
+	struct dwc3 *dwc = dotg->dwc;
+	struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
 
-	/* Set OCTL[6](PeriMode) to 0 (host) */
-	octl = dwc3_readl(dotg->regs, DWC3_OCTL);
-	octl &= ~DWC3_OTG_OCTL_PERIMODE;
-	dwc3_writel(dotg->regs, DWC3_OCTL, octl);
+	if (ext_xceiv && !ext_xceiv->otg_capability) {
+		/* Set OCTL[6](PeriMode) to 0 (host) */
+		reg = dwc3_readl(dotg->regs, DWC3_OCTL);
+		reg &= ~DWC3_OTG_OCTL_PERIMODE;
+		dwc3_writel(dotg->regs, DWC3_OCTL, reg);
+	} else {
+		reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+		reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
+		reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST);
+		dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+	}
 }
 
 /**
@@ -76,17 +85,25 @@
  */
 static void dwc3_otg_set_peripheral_regs(struct dwc3_otg *dotg)
 {
-	u32 octl;
+	u32 reg;
+	struct dwc3 *dwc = dotg->dwc;
+	struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
 
-	/* Set OCTL[6](PeriMode) to 1 (peripheral) */
-	octl = dwc3_readl(dotg->regs, DWC3_OCTL);
-	octl |= DWC3_OTG_OCTL_PERIMODE;
-	dwc3_writel(dotg->regs, DWC3_OCTL, octl);
-
-	/*
-	 * TODO: add more OTG registers writes for PERIPHERAL mode here,
-	 * see figure 12-19 B-device flow in dwc3 Synopsis spec
-	 */
+	if (ext_xceiv && !ext_xceiv->otg_capability) {
+		/* Set OCTL[6](PeriMode) to 1 (peripheral) */
+		reg = dwc3_readl(dotg->regs, DWC3_OCTL);
+		reg |= DWC3_OTG_OCTL_PERIMODE;
+		dwc3_writel(dotg->regs, DWC3_OCTL, reg);
+		/*
+		 * TODO: add more OTG registers writes for PERIPHERAL mode here,
+		 * see figure 12-19 B-device flow in dwc3 Synopsis spec
+		 */
+	} else {
+		reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+		reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
+		reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+		dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+	}
 }
 
 /**
@@ -100,6 +117,7 @@
 static int dwc3_otg_start_host(struct usb_otg *otg, int on)
 {
 	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+	struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
 	struct dwc3 *dwc = dotg->dwc;
 	int ret = 0;
 
@@ -148,7 +166,8 @@
 		}
 
 		/* re-init OTG EVTEN register as XHCI reset clears it */
-		dwc3_otg_reset(dotg);
+		if (ext_xceiv && !ext_xceiv->otg_capability)
+			dwc3_otg_reset(dotg);
 	} else {
 		dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__);
 
@@ -161,9 +180,15 @@
 		}
 		dwc3_otg_notify_host_mode(otg, on);
 
+		/* Do block reset for Host <-> peripheral switching to work */
+		if (ext_xceiv && ext_xceiv->otg_capability &&
+						ext_xceiv->ext_block_reset)
+			ext_xceiv->ext_block_reset();
+
 		/* re-init core and OTG register as XHCI reset clears it */
 		dwc3_post_host_reset_core_init(dwc);
-		dwc3_otg_reset(dotg);
+		if (ext_xceiv && !ext_xceiv->otg_capability)
+			dwc3_otg_reset(dotg);
 	}
 
 	return 0;
@@ -312,6 +337,7 @@
 	struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
 	struct usb_phy *phy = dotg->otg.phy;
 	int ret = 0;
+	int work = 0;
 
 	if (event == DWC3_EVENT_PHY_RESUME) {
 		if (!pm_runtime_status_suspended(phy->dev)) {
@@ -331,17 +357,28 @@
 			}
 		}
 	} else if (event == DWC3_EVENT_XCEIV_STATE) {
-		if (ext_xceiv->id == DWC3_ID_FLOAT)
-			set_bit(ID, &dotg->inputs);
-		else
-			clear_bit(ID, &dotg->inputs);
+		if (ext_xceiv->id == DWC3_ID_FLOAT) {
+			if (!test_and_set_bit(ID, &dotg->inputs)) {
+				dev_dbg(phy->dev, "XCVR: ID set\n");
+				work = 1;
+			}
+		} else {
+			if (test_and_clear_bit(ID, &dotg->inputs)) {
+				dev_dbg(phy->dev, "XCVR: ID clear\n");
+				work = 1;
+			}
+		}
 
 		if (ext_xceiv->bsv) {
-			dev_dbg(phy->dev, "XCVR: BSV set\n");
-			set_bit(B_SESS_VLD, &dotg->inputs);
+			if (!test_and_set_bit(B_SESS_VLD, &dotg->inputs)) {
+				dev_dbg(phy->dev, "XCVR: BSV set\n");
+				work = 1;
+			}
 		} else {
-			dev_dbg(phy->dev, "XCVR: BSV clear\n");
-			clear_bit(B_SESS_VLD, &dotg->inputs);
+			if (test_and_clear_bit(B_SESS_VLD, &dotg->inputs)) {
+				dev_dbg(phy->dev, "XCVR: BSV clear\n");
+				work = 1;
+			}
 		}
 
 		if (!init) {
@@ -350,7 +387,8 @@
 			dev_dbg(phy->dev, "XCVR: BSV init complete\n");
 			return;
 		}
-		schedule_work(&dotg->sm_work);
+		if (work)
+			schedule_work(&dotg->sm_work);
 	}
 }
 
@@ -457,6 +495,7 @@
 	u32 osts, oevt_reg;
 	int ret = IRQ_NONE;
 	int handled_irqs = 0;
+	struct usb_phy *phy = dotg->otg.phy;
 
 	oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT);
 
@@ -472,23 +511,30 @@
 		 * function, switch from A to B or from B to A.
 		 */
 
-		if (osts & DWC3_OTG_OSTS_CONIDSTS)
-			set_bit(ID, &dotg->inputs);
-		else
-			clear_bit(ID, &dotg->inputs);
+		if (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) {
+			if (osts & DWC3_OTG_OSTS_CONIDSTS) {
+				dev_dbg(phy->dev, "ID set\n");
+				set_bit(ID, &dotg->inputs);
+			} else {
+				dev_dbg(phy->dev, "ID clear\n");
+				clear_bit(ID, &dotg->inputs);
+			}
+			handled_irqs |= DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT;
+		}
 
-		if (osts & DWC3_OTG_OSTS_BSESVALID)
-			set_bit(B_SESS_VLD, &dotg->inputs);
-		else
-			clear_bit(B_SESS_VLD, &dotg->inputs);
+		if (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) {
+			if (osts & DWC3_OTG_OSTS_BSESVALID) {
+				dev_dbg(phy->dev, "BSV set\n");
+				set_bit(B_SESS_VLD, &dotg->inputs);
+			} else {
+				dev_dbg(phy->dev, "BSV clear\n");
+				clear_bit(B_SESS_VLD, &dotg->inputs);
+			}
+			handled_irqs |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT;
+		}
 
 		schedule_work(&dotg->sm_work);
 
-		handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ?
-				DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT : 0;
-		handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) ?
-				DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT : 0;
-
 		ret = IRQ_HANDLED;
 
 		/* Clear the interrupts we handled */
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index c93ce5f..5a36a4f 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -103,6 +103,8 @@
 	/* to notify OTG about LPM exit event, provided by OTG */
 	void	(*notify_ext_events)(struct usb_otg *otg,
 					enum dwc3_ext_events ext_event);
+	/* for block reset USB core */
+	void	(*ext_block_reset)(void);
 };
 
 /* for external transceiver driver */
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 3679191..c2bc3f3 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1546,11 +1546,63 @@
 {
 	struct dwc3_ep		*dep;
 	int			ret = 0;
+	u32			reg;
 
-	/* reinitialize physical ep0-1 */
+	/* Enable all but Start and End of Frame IRQs */
+	reg = (DWC3_DEVTEN_EVNTOVERFLOWEN |
+			DWC3_DEVTEN_CMDCMPLTEN |
+			DWC3_DEVTEN_ERRTICERREN |
+			DWC3_DEVTEN_WKUPEVTEN |
+			DWC3_DEVTEN_ULSTCNGEN |
+			DWC3_DEVTEN_CONNECTDONEEN |
+			DWC3_DEVTEN_USBRSTEN |
+			DWC3_DEVTEN_DISCONNEVTEN);
+	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+
+	/* Enable USB2 LPM and automatic phy suspend only on recent versions */
+	if (dwc->revision >= DWC3_REVISION_194A) {
+		reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+		reg |= DWC3_DCFG_LPM_CAP;
+		dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
+
+		/* TODO: This should be configurable */
+		reg |= DWC3_DCTL_HIRD_THRES(28);
+
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+	}
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_SPEED_MASK);
+
+	/**
+	 * WORKAROUND: DWC3 revision < 2.20a have an issue
+	 * which would cause metastability state on Run/Stop
+	 * bit if we try to force the IP to USB2-only mode.
+	 *
+	 * Because of that, we cannot configure the IP to any
+	 * speed other than the SuperSpeed
+	 *
+	 * Refers to:
+	 *
+	 * STAR#9000525659: Clock Domain Crossing on DCTL in
+	 * USB 2.0 Mode
+	 */
+	if (dwc->revision < DWC3_REVISION_220A)
+		reg |= DWC3_DCFG_SUPERSPEED;
+	else
+		reg |= dwc->maximum_speed;
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	dwc->start_config_issued = false;
+
+	/* Start with SuperSpeed Default */
+	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
 	dwc->delayed_status = false;
-
+	/* reinitialize physical ep0-1 */
 	dep = dwc->eps[0];
 	dep->flags = 0;
 	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
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/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 85240ef..65b4890 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -216,7 +216,7 @@
 	.bcdMbbVersion =	cpu_to_le16(0x0100),
 
 	.wMaxControlMessage =	cpu_to_le16(0x1000),
-	.bNumberFilters =	0x10,
+	.bNumberFilters =	0x20,
 	.bMaxFilterSize =	0x80,
 	.wMaxSegmentSize =	cpu_to_le16(0xfe0),
 	.bmNetworkCapabilities = 0x20,
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index f86bf12..82ef2a8 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -85,6 +85,7 @@
 	u8				ethaddr[ETH_ALEN];
 	u32				vendorID;
 	u8				max_pkt_per_xfer;
+	u32				max_pkt_size;
 	const char			*manufacturer;
 	int				config;
 	atomic_t		ioctl_excl;
@@ -125,6 +126,7 @@
 
 #define RNDIS_QC_IOCTL_MAGIC		'i'
 #define RNDIS_QC_GET_MAX_PKT_PER_XFER   _IOR(RNDIS_QC_IOCTL_MAGIC, 1, u8)
+#define RNDIS_QC_GET_MAX_PKT_SIZE	_IOR(RNDIS_QC_IOCTL_MAGIC, 2, u32)
 
 
 /* interface descriptor: */
@@ -552,14 +554,22 @@
 static void rndis_qc_command_complete(struct usb_ep *ep,
 							struct usb_request *req)
 {
-	struct f_rndis_qc			*rndis = req->context;
+	struct f_rndis_qc		*rndis = req->context;
 	int				status;
+	rndis_init_msg_type		*buf;
 
 	/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
 	status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
 	if (status < 0)
 		pr_err("RNDIS command error %d, %d/%d\n",
 			status, req->actual, req->length);
+
+	buf = (rndis_init_msg_type *)req->buf;
+
+	if (buf->MessageType == REMOTE_NDIS_INITIALIZE_MSG) {
+		rndis->max_pkt_size = buf->MaxTransferSize;
+		pr_debug("MaxTransferSize: %d\n", buf->MaxTransferSize);
+	}
 }
 
 static int
@@ -1110,6 +1120,17 @@
 		pr_info("Sent max packets per xfer %d",
 				rndis->max_pkt_per_xfer);
 		break;
+	case RNDIS_QC_GET_MAX_PKT_SIZE:
+		ret = copy_to_user((void __user *)arg,
+					&rndis->max_pkt_size,
+					sizeof(rndis->max_pkt_size));
+		if (ret) {
+			pr_err("copying to user space failed");
+			ret = -EFAULT;
+		}
+		pr_debug("Sent max packet size %d",
+				rndis->max_pkt_size);
+		break;
 	default:
 		pr_err("Unsupported IOCTL");
 		ret = -EINVAL;
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 79aac27..32fc79e 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -50,9 +50,6 @@
 	struct list_head		cpkt_resp_q;
 	atomic_t			notify_count;
 	unsigned long			cpkts_len;
-
-	/* IPA / RmNet Bridge support*/
-	struct usb_bam_connect_ipa_params ipa_params;
 };
 
 #define NR_RMNET_PORTS	3
@@ -433,18 +430,9 @@
 	switch (dxport) {
 	case USB_GADGET_XPORT_BAM:
 	case USB_GADGET_XPORT_BAM2BAM:
-		ret = gbam_connect(&dev->port, port_num,
-						   dxport, port_num, NULL);
-		if (ret) {
-			pr_err("%s: gbam_connect failed: err:%d\n",
-					__func__, ret);
-			gsmd_ctrl_disconnect(&dev->port, port_num);
-			return ret;
-		}
-		break;
 	case USB_GADGET_XPORT_BAM2BAM_IPA:
 		ret = gbam_connect(&dev->port, port_num,
-					dxport, port_num, &(dev->ipa_params));
+						   dxport, port_num);
 		if (ret) {
 			pr_err("%s: gbam_connect failed: err:%d\n",
 					__func__, ret);
@@ -514,11 +502,8 @@
 	switch (dxport) {
 	case USB_GADGET_XPORT_BAM:
 	case USB_GADGET_XPORT_BAM2BAM:
-		gbam_disconnect(&dev->port, port_num, dxport, NULL);
-		break;
 	case USB_GADGET_XPORT_BAM2BAM_IPA:
-		gbam_disconnect(&dev->port, port_num, dxport,
-						&(dev->ipa_params));
+		gbam_disconnect(&dev->port, port_num, dxport);
 		break;
 	case USB_GADGET_XPORT_HSIC:
 		ghsic_data_disconnect(&dev->port, port_num);
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 02f044e..288611d 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -840,7 +840,6 @@
 
 	rndis_deregister(rndis->config);
 	rndis_exit();
-	rndis_string_defs[0].id = 0;
 
 	if (gadget_is_superspeed(c->cdev->gadget))
 		usb_free_descriptors(f->ss_descriptors);
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 7f3713f..aa93a7d 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -102,7 +102,7 @@
 	u32					dst_pipe_idx;
 	u8					connection_idx;
 	enum transport_type trans;
-	struct usb_bam_connect_ipa_params *ipa_params;
+	struct usb_bam_connect_ipa_params ipa_params;
 
 	/* stats */
 	unsigned int		pending_with_bam;
@@ -649,7 +649,7 @@
 	int ret;
 
 	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
-		ret = usb_bam_disconnect_ipa(d->connection_idx, d->ipa_params);
+		ret = usb_bam_disconnect_ipa(d->connection_idx, &d->ipa_params);
 		if (ret)
 			pr_err("%s: usb_bam_disconnect_ipa failed: err:%d\n",
 				__func__, ret);
@@ -706,29 +706,29 @@
 			return;
 		}
 	} else if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
-		d->ipa_params->client = IPA_CLIENT_USB_CONS;
-		d->ipa_params->dir = PEER_PERIPHERAL_TO_USB;
-		ret = usb_bam_connect_ipa(d->ipa_params);
+		d->ipa_params.client = IPA_CLIENT_USB_CONS;
+		d->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
+		ret = usb_bam_connect_ipa(&d->ipa_params);
 		if (ret) {
 			pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
 				__func__, ret);
 			return;
 		}
 
-		d->ipa_params->client = IPA_CLIENT_USB_PROD;
-		d->ipa_params->dir = USB_TO_PEER_PERIPHERAL;
+		d->ipa_params.client = IPA_CLIENT_USB_PROD;
+		d->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
 		/* Currently only DMA mode is supported */
-		d->ipa_params->ipa_ep_cfg.mode.mode = IPA_DMA;
-		d->ipa_params->ipa_ep_cfg.mode.dst =
+		d->ipa_params.ipa_ep_cfg.mode.mode = IPA_DMA;
+		d->ipa_params.ipa_ep_cfg.mode.dst =
 				IPA_CLIENT_A2_TETHERED_CONS;
-		ret = usb_bam_connect_ipa(d->ipa_params);
+		ret = usb_bam_connect_ipa(&d->ipa_params);
 		if (ret) {
 			pr_err("%s: usb_bam_connect_ipa failed: err:%d\n",
 				__func__, ret);
 			return;
 		}
-		rmnet_bridge_connect(d->ipa_params->prod_clnt_hdl,
-				d->ipa_params->cons_clnt_hdl, 0);
+		rmnet_bridge_connect(d->ipa_params.prod_clnt_hdl,
+				d->ipa_params.cons_clnt_hdl, 0);
 	}
 
 	d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_KERNEL);
@@ -1037,8 +1037,7 @@
 static void gam_debugfs_init(void) { }
 #endif
 
-void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans,
-			struct usb_bam_connect_ipa_params *ipa_params)
+void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
 {
 	struct gbam_port	*port;
 	unsigned long		flags;
@@ -1096,8 +1095,7 @@
 }
 
 int gbam_connect(struct grmnet *gr, u8 port_num,
-				 enum transport_type trans, u8 connection_idx,
-				 struct usb_bam_connect_ipa_params *ipa_params)
+				 enum transport_type trans, u8 connection_idx)
 {
 	struct gbam_port	*port;
 	struct bam_ch_info	*d;
@@ -1166,11 +1164,10 @@
 		port->gr = gr;
 		d->connection_idx = connection_idx;
 	} else if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
-		d->ipa_params = ipa_params;
 		port->gr = gr;
-		d->ipa_params->src_pipe = &(d->src_pipe_idx);
-		d->ipa_params->dst_pipe = &(d->dst_pipe_idx);
-		d->ipa_params->idx = connection_idx;
+		d->ipa_params.src_pipe = &(d->src_pipe_idx);
+		d->ipa_params.dst_pipe = &(d->dst_pipe_idx);
+		d->ipa_params.idx = connection_idx;
 	}
 
 	d->trans = trans;
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index a3d42fa..0f7c4fb 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -48,10 +48,8 @@
 
 int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port);
 int gbam_connect(struct grmnet *gr, u8 port_num,
-				 enum transport_type trans, u8 connection_idx,
-				 struct usb_bam_connect_ipa_params *ipa_params);
-void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans,
-				struct usb_bam_connect_ipa_params *ipa_params);
+				 enum transport_type trans, u8 connection_idx);
+void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans);
 void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans);
 void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
 int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 8c22f8e..57598c8 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -31,9 +31,11 @@
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 
+#include <linux/usb/ulpi.h>
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/usb/msm_hsusb.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <linux/spinlock.h>
 #include <linux/irq.h>
 #include <linux/kthread.h>
@@ -106,6 +108,7 @@
 static bool debug_bus_voting_enabled = true;
 static u64 ehci_msm_hsic_dma_mask = DMA_BIT_MASK(32);
 
+static struct platform_driver ehci_msm_hsic_driver;
 
 static unsigned int enable_payload_log = 1;
 module_param(enable_payload_log, uint, S_IRUGO | S_IWUSR);
@@ -611,15 +614,17 @@
 {
 	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
 	int ret;
+	void __iomem *reg;
 
 	/* HSIC init sequence when HSIC signals (Strobe/Data) are
 	routed via GPIOs */
 	if (pdata && pdata->strobe && pdata->data) {
 
-		/* Enable LV_MODE in HSIC_CAL_PAD_CTL register */
-		writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL);
-
-		mb();
+		if (!pdata->ignore_cal_pad_config) {
+			/* Enable LV_MODE in HSIC_CAL_PAD_CTL register */
+			writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL);
+			mb();
+		}
 
 		/*set periodic calibration interval to ~2.048sec in
 		  HSIC_IO_CAL_REG */
@@ -634,9 +639,25 @@
 			dev_err(mehci->dev, " gpio configuarion failed\n");
 			return ret;
 		}
-		/* Set LV_MODE=0x1 and DCC=0x2 in HSIC_GPIO PAD_CTL register */
-		writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_STROBE_GPIO_PAD_CTL);
-		writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_DATA_GPIO_PAD_CTL);
+		if (pdata->strobe_pad_offset) {
+			/* Set CORE_CTL_EN in STROBE GPIO PAD_CTL register */
+			reg = MSM_TLMM_BASE + pdata->strobe_pad_offset;
+			writel_relaxed(readl_relaxed(reg) | 0x2000000, reg);
+		} else {
+			/* Set LV_MODE=0x1 and DCC=0x2 in STROBE GPIO PAD_CTL */
+			reg = HSIC_STROBE_GPIO_PAD_CTL;
+			writel_relaxed(HSIC_GPIO_PAD_VAL, reg);
+		}
+
+		if (pdata->data_pad_offset) {
+			/* Set CORE_CTL_EN in HSIC_DATA GPIO PAD_CTL register */
+			reg = MSM_TLMM_BASE + pdata->data_pad_offset;
+			writel_relaxed(readl_relaxed(reg) | 0x2000000, reg);
+		} else {
+			/* Set LV_MODE=0x1 and DCC=0x2 in STROBE GPIO PAD_CTL */
+			reg = HSIC_DATA_GPIO_PAD_CTL;
+			writel_relaxed(HSIC_GPIO_PAD_VAL, reg);
+		}
 
 		mb();
 
@@ -1268,11 +1289,8 @@
 	/* alt_core_clk is for LINK to be used during PHY RESET
 	 * clock rate appropriately set by target specific clock driver */
 	mehci->alt_core_clk = clk_get(mehci->dev, "alt_core_clk");
-	if (IS_ERR(mehci->alt_core_clk)) {
-		dev_err(mehci->dev, "failed to core_clk\n");
-		ret = PTR_ERR(mehci->alt_core_clk);
-		goto put_core_clk;
-	}
+	if (IS_ERR(mehci->alt_core_clk))
+		dev_dbg(mehci->dev, "failed to get alt_core_clk\n");
 
 	/* phy_clk is required for HSIC PHY operation
 	 * clock rate appropriately set by target specific clock driver */
@@ -1290,7 +1308,6 @@
 		ret = PTR_ERR(mehci->cal_clk);
 		goto put_phy_clk;
 	}
-	clk_set_rate(mehci->cal_clk, 10000000);
 
 	/* ahb_clk is required for data transfers */
 	mehci->ahb_clk = clk_get(mehci->dev, "iface_clk");
@@ -1320,8 +1337,8 @@
 put_phy_clk:
 	clk_put(mehci->phy_clk);
 put_alt_core_clk:
-	clk_put(mehci->alt_core_clk);
-put_core_clk:
+	if (!IS_ERR(mehci->alt_core_clk))
+		clk_put(mehci->alt_core_clk);
 	clk_put(mehci->core_clk);
 
 	return ret;
@@ -1569,6 +1586,36 @@
 	debugfs_remove_recursive(ehci_hsic_msm_dbg_root);
 }
 
+struct msm_hsic_host_platform_data *msm_hsic_dt_to_pdata(
+				struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_hsic_host_platform_data *pdata;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(&pdev->dev, "unable to allocate platform data\n");
+		return NULL;
+	}
+	pdata->strobe = of_get_named_gpio(node, "hsic,strobe-gpio", 0);
+	if (pdata->strobe < 0)
+		pdata->strobe = 0;
+
+	pdata->data = of_get_named_gpio(node, "hsic,data-gpio", 0);
+	if (pdata->data < 0)
+		pdata->data = 0;
+
+	pdata->ignore_cal_pad_config = of_property_read_bool(node,
+					"hsic,ignore-cal-pad-config");
+	of_property_read_u32(node, "hsic,strobe-pad-offset",
+					&pdata->strobe_pad_offset);
+	of_property_read_u32(node, "hsic,data-pad-offset",
+					&pdata->data_pad_offset);
+
+	return pdata;
+}
+
+
 static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
@@ -1579,6 +1626,14 @@
 
 	dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n");
 
+	if (pdev->dev.of_node) {
+		dev_dbg(&pdev->dev, "device tree enabled\n");
+		pdev->dev.platform_data = msm_hsic_dt_to_pdata(pdev);
+		dev_set_name(&pdev->dev, ehci_msm_hsic_driver.driver.name);
+	}
+	if (!pdev->dev.platform_data)
+		dev_dbg(&pdev->dev, "No platform data given\n");
+
 	if (!pdev->dev.dma_mask)
 		pdev->dev.dma_mask = &ehci_msm_hsic_dma_mask;
 	if (!pdev->dev.coherent_dma_mask)
@@ -1886,7 +1941,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..3ad05b06 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)
@@ -3115,8 +3133,16 @@
 	struct msm_otg *motg = the_msm_otg;
 
 	/* Ignore received BSV interrupts, if ID pin is GND */
-	if (!test_bit(ID, &motg->inputs))
-		return;
+	if (!test_bit(ID, &motg->inputs)) {
+		/*
+		 * state machine work waits for initial VBUS
+		 * completion in UNDEFINED state.  Process
+		 * the initial VBUS event in ID_GND state.
+		 */
+		if (init)
+			return;
+		goto complete;
+	}
 
 	if (online) {
 		pr_debug("PMIC: BSV set\n");
@@ -3125,7 +3151,7 @@
 		pr_debug("PMIC: BSV clear\n");
 		clear_bit(B_SESS_VLD, &motg->inputs);
 	}
-
+complete:
 	if (!init) {
 		init = true;
 		complete(&pmic_vbus_init);
@@ -3475,6 +3501,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 +4096,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/mdp.c b/drivers/video/msm/mdp.c
index a827d6a..fefab27 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -886,7 +886,7 @@
 	outp32(MDP_INTR_CLEAR, mgmt->intr);
 	mdp_intr_mask &= ~mgmt->intr;
 	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
-	mdp_disable_irq(mgmt->irq_term);
+	mdp_disable_irq_nosync(mgmt->irq_term);
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
 	if (mdp_rev >= MDP_REV_42)
@@ -1378,34 +1378,49 @@
 #define MAX_VSYNC_GAP		4
 #define DEFAULT_FRAME_RATE	60
 
-static u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd)
+u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd)
 {
-	u32 frame_rate = 0, total_pixel;
+	u32 frame_rate = 0, pixel_rate = 0, total_pixel;
 	struct msm_panel_info *panel_info = &mfd->panel_info;
+
+	pixel_rate =
+		(panel_info->type == MIPI_CMD_PANEL ||
+		 panel_info->type == MIPI_VIDEO_PANEL) ?
+		panel_info->mipi.dsi_pclk_rate :
+		panel_info->clk_rate;
+
+	if (!pixel_rate)
+		pr_warn("%s pixel rate is zero\n", __func__);
+
+	total_pixel =
+		(panel_info->lcdc.h_back_porch +
+		 panel_info->lcdc.h_front_porch +
+		 panel_info->lcdc.h_pulse_width +
+		 panel_info->xres) *
+		(panel_info->lcdc.v_back_porch +
+		 panel_info->lcdc.v_front_porch +
+		 panel_info->lcdc.v_pulse_width +
+		 panel_info->yres);
+
+	if (total_pixel)
+		frame_rate = pixel_rate / total_pixel;
+	else
+		pr_warn("%s total pixels are zero\n", __func__);
+
 	if (mfd->dest == DISPLAY_LCD) {
 		if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1)
 			frame_rate = panel_info->lcd.refx100 / (100 * 2);
-		else
+		else if (panel_info->type != MIPI_CMD_PANEL)
 			frame_rate = panel_info->lcd.refx100 / 100;
-	} else {
-		if (panel_info->type == MIPI_VIDEO_PANEL) {
-			frame_rate = panel_info->mipi.frame_rate;
-		} else {
-			total_pixel = (panel_info->lcdc.h_back_porch +
-				  panel_info->lcdc.h_front_porch +
-				  panel_info->lcdc.h_pulse_width +
-				  panel_info->xres) *
-				 (panel_info->lcdc.v_back_porch +
-				  panel_info->lcdc.v_front_porch +
-				  panel_info->lcdc.v_pulse_width +
-				  panel_info->yres);
-			if (total_pixel)
-				frame_rate = panel_info->clk_rate /
-					total_pixel;
-		}
 	}
-	if (frame_rate == 0)
+
+	if (frame_rate == 0) {
 		frame_rate = DEFAULT_FRAME_RATE;
+		pr_warn("%s frame rate=%d is default\n", __func__, frame_rate);
+	}
+	pr_debug("%s frame rate=%d total_pixel=%d, pixel_rate=%d\n", __func__,
+		frame_rate, total_pixel, pixel_rate);
+
 	return frame_rate;
 }
 
@@ -1677,7 +1692,9 @@
 			mdp_clk_cnt--;
 			if (mdp_clk_cnt == 0)
 				mdp_clk_disable_unprepare();
-		}
+		} else
+			pr_err("%s: %d: mdp clk off is invalid\n",
+			       __func__, __LINE__);
 	}
 	pr_debug("%s: on=%d cnt=%d\n", __func__, on, mdp_clk_cnt);
 	mutex_unlock(&mdp_suspend_mutex);
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 0bc2532..d7f707f 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -932,6 +932,8 @@
 	unsigned long srcp1_addr, unsigned long srcp1_size);
 void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync);
 
+u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd);
+
 #ifdef CONFIG_FB_MSM_DTV
 void mdp_vid_quant_set(void);
 #else
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_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index aa50d94..0f29522 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -61,6 +61,7 @@
 	struct msm_fb_data_type *mfd;
 	struct mdp4_overlay_pipe *base_pipe;
 	struct vsync_update vlist[2];
+	struct work_struct clk_work;
 } vsync_ctrl_db[MAX_CONTROLLER];
 
 static void vsync_irq_enable(int intr, int term)
@@ -375,6 +376,8 @@
 		}
 	}
 
+	mdp_clk_ctrl(1);
+
 	mdp4_mixer_stage_commit(mixer);
 
 	pipe = vctrl->base_pipe;
@@ -399,6 +402,13 @@
 	return cnt;
 }
 
+static void clk_ctrl_work(struct work_struct *work)
+{
+	struct vsycn_ctrl *vctrl =
+		container_of(work, typeof(*vctrl), clk_work);
+	mdp_clk_ctrl(0);
+}
+
 void mdp4_wfd_init(int cndx)
 {
 	struct vsycn_ctrl *vctrl;
@@ -417,6 +427,7 @@
 	mutex_init(&vctrl->update_lock);
 	init_completion(&vctrl->ov_comp);
 	spin_lock_init(&vctrl->spin_lock);
+	INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
 }
 
 static void mdp4_wfd_wait4ov(int cndx)
@@ -450,7 +461,7 @@
 	vsync_irq_disable(INTR_OVERLAY2_DONE, MDP_OVERLAY2_TERM);
 	vctrl->ov_done++;
 	complete(&vctrl->ov_comp);
-
+	schedule_work(&vctrl->clk_work);
 	pr_debug("%s ovdone interrupt\n", __func__);
 	spin_unlock(&vctrl->spin_lock);
 }
@@ -475,16 +486,11 @@
 
 	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
-	mdp_clk_ctrl(1);
-
 	mdp4_wfd_pipe_commit(mfd, 0, 1);
 
 	mdp4_overlay_mdp_perf_upd(mfd, 0);
 
-	mdp_clk_ctrl(0);
-
 	mutex_unlock(&mfd->dma->ov_mutex);
-
 }
 
 static int mdp4_overlay_writeback_register_buffer(
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/Makefile b/drivers/video/msm/mdss/Makefile
index 88a7c45..a0d707e 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -7,6 +7,7 @@
 mdss-mdp-objs += mdss_mdp_wb.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+obj-$(CONFIG_DEBUG_FS) += mdss_debug.o
 
 mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o
 mdss-dsi-objs += mdss_dsi_panel.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index d041125..9e13418 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -61,6 +61,7 @@
 	struct delayed_work clk_ctrl_worker;
 	struct platform_device *pdev;
 	char __iomem *mdp_base;
+	size_t mdp_reg_size;
 	char __iomem *vbif_base;
 
 	u32 irq;
@@ -93,6 +94,7 @@
 	struct mdss_iommu_map_type *iommu_map;
 
 	struct early_suspend early_suspend;
+	void *debug_data;
 };
 extern struct mdss_data_type *mdss_res;
 
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
new file mode 100644
index 0000000..abef27d
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -0,0 +1,348 @@
+/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "mdss.h"
+#include "mdss_mdp.h"
+#include "mdss_debug.h"
+
+#define DEFAULT_BASE_REG_CNT 128
+#define GROUP_BYTES 4
+#define ROW_BYTES 16
+
+struct mdss_debug_data {
+	struct dentry *root;
+	struct list_head base_list;
+};
+
+struct mdss_debug_base {
+	struct mdss_debug_data *mdd;
+	void __iomem *base;
+	size_t off;
+	size_t cnt;
+	size_t max_offset;
+	char *buf;
+	size_t buf_len;
+	struct list_head head;
+};
+
+static int mdss_debug_base_open(struct inode *inode, struct file *file)
+{
+	/* non-seekable */
+	file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int mdss_debug_base_release(struct inode *inode, struct file *file)
+{
+	struct mdss_debug_base *dbg = file->private_data;
+	if (dbg && dbg->buf) {
+		kfree(dbg->buf);
+		dbg->buf_len = 0;
+		dbg->buf = NULL;
+	}
+	return 0;
+}
+
+static ssize_t mdss_debug_base_offset_write(struct file *file,
+		    const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct mdss_debug_base *dbg = file->private_data;
+	u32 off, cnt;
+	char buf[24];
+
+	if (!dbg)
+		return -ENODEV;
+
+	if (count >= sizeof(buf))
+		return -EFAULT;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	buf[count] = 0;	/* end of string */
+
+	sscanf(buf, "%5x %d", &off, &cnt);
+
+	if (off > dbg->max_offset)
+		return -EINVAL;
+
+	if (cnt <= 0)
+		cnt = DEFAULT_BASE_REG_CNT;
+
+	if (cnt > (dbg->max_offset - off))
+		cnt = dbg->max_offset - off;
+
+	dbg->off = off;
+	dbg->cnt = cnt;
+
+	pr_debug("offset=%x cnt=%x\n", off, cnt);
+
+	return count;
+}
+
+static ssize_t mdss_debug_base_offset_read(struct file *file,
+			char __user *buff, size_t count, loff_t *ppos)
+{
+	struct mdss_debug_base *dbg = file->private_data;
+	int len = 0;
+	char buf[24];
+
+	if (!dbg)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;	/* the end */
+
+	len = snprintf(buf, sizeof(buf), "0x%08x %d\n", dbg->off, dbg->off);
+	if (len < 0)
+		return 0;
+
+	if (copy_to_user(buff, buf, len))
+		return -EFAULT;
+
+	*ppos += len;	/* increase offset */
+
+	return len;
+}
+
+static ssize_t mdss_debug_base_reg_write(struct file *file,
+		const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct mdss_debug_base *dbg = file->private_data;
+	size_t off;
+	u32 data, cnt;
+	char buf[24];
+
+	if (!dbg)
+		return -ENODEV;
+
+	if (count >= sizeof(buf))
+		return -EFAULT;
+
+	if (copy_from_user(buf, user_buf, count))
+		return -EFAULT;
+
+	buf[count] = 0;	/* end of string */
+
+	cnt = sscanf(buf, "%x %x", &off, &data);
+
+	if (cnt < 2)
+		return -EFAULT;
+
+	if (off >= dbg->max_offset)
+		return -EFAULT;
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	writel_relaxed(data, dbg->base + off);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	pr_debug("addr=%x data=%x\n", off, data);
+
+	return count;
+}
+
+static ssize_t mdss_debug_base_reg_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct mdss_debug_base *dbg = file->private_data;
+	size_t len;
+
+	if (!dbg) {
+		pr_err("invalid handle\n");
+		return -ENODEV;
+	}
+
+	if (!dbg->buf) {
+		char dump_buf[64];
+		char *ptr;
+		int cnt, tot;
+
+		dbg->buf_len = sizeof(dump_buf) *
+			DIV_ROUND_UP(dbg->cnt, ROW_BYTES);
+		dbg->buf = kzalloc(dbg->buf_len, GFP_KERNEL);
+
+		if (!dbg->buf) {
+			pr_err("not enough memory to hold reg dump\n");
+			return -ENOMEM;
+		}
+
+		ptr = dbg->base + dbg->off;
+		tot = 0;
+
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		for (cnt = dbg->cnt; cnt > 0; cnt -= ROW_BYTES) {
+			hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES),
+					   ROW_BYTES, GROUP_BYTES, dump_buf,
+					   sizeof(dump_buf), false);
+			len = scnprintf(dbg->buf + tot, dbg->buf_len - tot,
+					"0x%08x: %s\n",
+					((int)ptr) - ((int)dbg->base),
+					dump_buf);
+
+			ptr += ROW_BYTES;
+			tot += len;
+			if (tot >= dbg->buf_len)
+				break;
+		}
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+		dbg->buf_len = tot;
+	}
+
+	if (*ppos >= dbg->buf_len)
+		return 0; /* done reading */
+
+	len = min(count, dbg->buf_len - (size_t) *ppos);
+	if (copy_to_user(user_buf, dbg->buf + *ppos, len)) {
+		pr_err("failed to copy to user\n");
+		return -EFAULT;
+	}
+
+	*ppos += len; /* increase offset */
+
+	return len;
+}
+
+static const struct file_operations mdss_off_fops = {
+	.open = mdss_debug_base_open,
+	.release = mdss_debug_base_release,
+	.read = mdss_debug_base_offset_read,
+	.write = mdss_debug_base_offset_write,
+};
+
+static const struct file_operations mdss_reg_fops = {
+	.open = mdss_debug_base_open,
+	.release = mdss_debug_base_release,
+	.read = mdss_debug_base_reg_read,
+	.write = mdss_debug_base_reg_write,
+};
+
+int mdss_debug_register_base(const char *name, void __iomem *base,
+			     size_t max_offset)
+{
+	struct mdss_data_type *mdata = mdss_res;
+	struct mdss_debug_data *mdd;
+	struct mdss_debug_base *dbg;
+	struct dentry *ent_off, *ent_reg;
+	char dn[80] = "";
+	int prefix_len = 0;
+
+	if (!mdata || !mdata->debug_data)
+		return -ENODEV;
+
+	mdd = mdata->debug_data;
+
+	dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
+	if (!dbg)
+		return -ENOMEM;
+
+	dbg->base = base;
+	dbg->max_offset = max_offset;
+	dbg->off = 0;
+	dbg->cnt = DEFAULT_BASE_REG_CNT;
+
+	if (name)
+		prefix_len = snprintf(dn, sizeof(dn), "%s_", name);
+
+	strlcpy(dn + prefix_len, "off", sizeof(dn) - prefix_len);
+	ent_off = debugfs_create_file(dn, 0644, mdd->root, dbg, &mdss_off_fops);
+	if (IS_ERR_OR_NULL(ent_off)) {
+		pr_err("debugfs_create_file: offset fail\n");
+		goto off_fail;
+	}
+
+	strlcpy(dn + prefix_len, "reg", sizeof(dn) - prefix_len);
+	ent_reg = debugfs_create_file(dn, 0644, mdd->root, dbg, &mdss_reg_fops);
+	if (IS_ERR_OR_NULL(ent_reg)) {
+		pr_err("debugfs_create_file: reg fail\n");
+		goto reg_fail;
+	}
+
+	list_add(&dbg->head, &mdd->base_list);
+
+	return 0;
+reg_fail:
+	debugfs_remove(ent_off);
+off_fail:
+	kfree(dbg);
+	return -ENODEV;
+}
+
+static int mdss_debugfs_cleanup(struct mdss_debug_data *mdd)
+{
+	struct mdss_debug_base *base, *tmp;
+
+	if (!mdd)
+		return 0;
+
+	list_for_each_entry_safe(base, tmp, &mdd->base_list, head) {
+		list_del(&base->head);
+		kfree(base);
+	}
+
+	if (mdd->root)
+		debugfs_remove_recursive(mdd->root);
+
+	kfree(mdd);
+
+	return 0;
+}
+
+int mdss_debugfs_init(struct mdss_data_type *mdata)
+{
+	struct mdss_debug_data *mdd;
+
+	if (mdata->debug_data) {
+		pr_warn("mdss debugfs already initialized\n");
+		return -EBUSY;
+	}
+
+	mdd = kzalloc(sizeof(*mdd), GFP_KERNEL);
+	if (!mdd) {
+		pr_err("no memory to create mdss debug data\n");
+		return -ENOMEM;
+	}
+	INIT_LIST_HEAD(&mdd->base_list);
+
+	mdd->root = debugfs_create_dir("mdp", NULL);
+	if (IS_ERR_OR_NULL(mdd->root)) {
+		pr_err("debugfs_create_dir fail, error %ld\n",
+		       PTR_ERR(mdd->root));
+		mdd->root = NULL;
+		mdss_debugfs_cleanup(mdd);
+		return -ENODEV;
+	}
+
+	mdata->debug_data = mdd;
+
+	return 0;
+}
+
+int mdss_debugfs_remove(struct mdss_data_type *mdata)
+{
+	struct mdss_debug_data *mdd = mdata->debug_data;
+
+	mdss_debugfs_cleanup(mdd);
+
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_debug.h b/drivers/video/msm/mdss/mdss_debug.h
new file mode 100644
index 0000000..167fa8a
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_debug.h
@@ -0,0 +1,39 @@
+/* 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 MDSS_DEBUG_H
+#define MDSS_DEBUG_H
+
+#include "mdss.h"
+
+#ifdef CONFIG_DEBUG_FS
+int mdss_debugfs_init(struct mdss_data_type *mdata);
+int mdss_debugfs_remove(struct mdss_data_type *mdata);
+int mdss_debug_register_base(const char *name, void __iomem *base,
+				    size_t max_offset);
+#else
+static inline int mdss_debugfs_init(struct mdss_data_type *mdata)
+{
+	return 0;
+}
+static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
+{
+	return 0;
+}
+static inline int mdss_debug_register_base(const char *name, void __iomem *base,
+				    size_t max_offset)
+{
+	return 0;
+}
+#endif
+#endif /* MDSS_DEBUG_H */
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 1cf3101..227619f 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -303,10 +303,10 @@
 	}
 
 	mdss_edp_prepare_clocks(edp_drv);
-	mdss_edp_clk_enable(edp_drv);
 	mdss_edp_phy_sw_reset(edp_drv->edp_base);
 	mdss_edp_hw_powerup(edp_drv->edp_base, 1);
 	mdss_edp_pll_configure(edp_drv->edp_base, edp_drv->edid.timing[0].pclk);
+	mdss_edp_clk_enable(edp_drv);
 
 	for (i = 0; i < edp_drv->dpcd.max_lane_count; ++i)
 		mdss_edp_enable_lane_bist(edp_drv->edp_base, i, 1);
@@ -346,8 +346,8 @@
 	for (i = 0; i < edp_drv->dpcd.max_lane_count; ++i)
 		mdss_edp_enable_lane_bist(edp_drv->edp_base, i, 0);
 
-	mdss_edp_hw_powerup(edp_drv->edp_base, 0);
 	mdss_edp_clk_disable(edp_drv);
+	mdss_edp_hw_powerup(edp_drv->edp_base, 0);
 	mdss_edp_unprepare_clocks(edp_drv);
 
 	return ret;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 4ec4046..581ec17 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -131,8 +131,8 @@
 
 	/* This maps android backlight level 0 to 255 into
 	   driver backlight level 0 to bl_max with rounding */
-	bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS)
-		 /(2 * MAX_BACKLIGHT_BRIGHTNESS);
+	bl_lvl = (2 * value * mfd->panel_info->bl_max +
+		  MAX_BACKLIGHT_BRIGHTNESS) / (2 * MAX_BACKLIGHT_BRIGHTNESS);
 
 	if (!bl_lvl && value)
 		bl_lvl = 1;
@@ -155,7 +155,7 @@
 	struct fb_info *fbi = dev_get_drvdata(dev);
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
 
-	switch (mfd->panel_info.type) {
+	switch (mfd->panel.type) {
 	case NO_PANEL:
 		ret = snprintf(buf, PAGE_SIZE, "no panel\n");
 		break;
@@ -239,13 +239,13 @@
 	mfd = (struct msm_fb_data_type *)fbi->par;
 	mfd->key = MFD_KEY;
 	mfd->fbi = fbi;
-	mfd->panel_info = pdata->panel_info;
+	mfd->panel_info = &pdata->panel_info;
 	mfd->panel.type = pdata->panel_info.type;
 	mfd->panel.id = mfd->index;
 	mfd->fb_page = MDSS_FB_NUM;
 	mfd->index = fbi_list_index;
 	mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
-	mfd->panel_info.frame_count = 0;
+
 	mfd->bl_level = 0;
 	mfd->bl_scale = 1024;
 	mfd->bl_min_lvl = 30;
@@ -263,14 +263,6 @@
 	if (rc)
 		return rc;
 
-	/*
-	 * todo: Currently mfd keeps a full copy of panel data rather than
-	 *       pointer to it.
-	 *       Following line shares the fbi with panel drivers for their
-	 *       sysfs or any external communications with the panel driver.
-	 */
-	pdata->panel_info.fbi = fbi;
-
 	rc = pm_runtime_set_active(mfd->fbi->dev);
 	if (rc < 0)
 		pr_err("pm_runtime: fail to set active.\n");
@@ -325,7 +317,8 @@
 	return 0;
 }
 
-static inline int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd, int e)
+static inline int mdss_fb_send_panel_event(
+	struct msm_fb_data_type *mfd, int e, void *arg)
 {
 	struct mdss_panel_data *pdata;
 
@@ -338,7 +331,7 @@
 	pr_debug("sending event=%d for fb%d\n", e, mfd->index);
 
 	if (pdata->event_handler)
-		return pdata->event_handler(pdata, e, NULL);
+		return pdata->event_handler(pdata, e, arg);
 
 	return 0;
 }
@@ -352,7 +345,7 @@
 
 	pr_debug("mdss_fb suspend index=%d\n", mfd->index);
 
-	ret = mdss_fb_send_panel_event(mfd, MDSS_EVENT_SUSPEND);
+	ret = mdss_fb_send_panel_event(mfd, MDSS_EVENT_SUSPEND, NULL);
 	if (ret) {
 		pr_warn("unable to suspend fb%d (%d)\n", mfd->index, ret);
 		return ret;
@@ -383,7 +376,7 @@
 
 	pr_debug("mdss_fb resume index=%d\n", mfd->index);
 
-	ret = mdss_fb_send_panel_event(mfd, MDSS_EVENT_RESUME);
+	ret = mdss_fb_send_panel_event(mfd, MDSS_EVENT_RESUME, NULL);
 	if (ret) {
 		pr_warn("unable to resume fb%d (%d)\n", mfd->index, ret);
 		return ret;
@@ -439,52 +432,11 @@
 	return result;
 }
 
-#if defined(CONFIG_PM) && defined(CONFIG_SUSPEND)
-static int mdss_fb_ext_suspend(struct device *dev)
-{
-	struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
-	int ret = 0;
-
-	if ((!mfd) || (mfd->key != MFD_KEY))
-		return 0;
-
-	if (mfd->panel_info.type == HDMI_PANEL ||
-	    mfd->panel_info.type == DTV_PANEL)
-		ret = mdss_fb_suspend_sub(mfd);
-
-	return ret;
-}
-
-static int mdss_fb_ext_resume(struct device *dev)
-{
-	struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
-	int ret = 0;
-
-	if ((!mfd) || (mfd->key != MFD_KEY))
-		return 0;
-
-	if (mfd->panel_info.type == HDMI_PANEL ||
-	    mfd->panel_info.type == DTV_PANEL)
-		ret = mdss_fb_resume_sub(mfd);
-
-	return ret;
-}
-#else
-#define mdss_fb_ext_suspend NULL
-#define mdss_fb_ext_resume NULL
-#endif
-
-static const struct dev_pm_ops mdss_fb_dev_pm_ops = {
-	.suspend = mdss_fb_ext_suspend,
-	.resume = mdss_fb_ext_resume,
-};
-
 static struct platform_driver mdss_fb_driver = {
 	.probe = mdss_fb_probe,
 	.remove = mdss_fb_remove,
 	.driver = {
 		.name = "mdss_fb",
-		.pm = &mdss_fb_dev_pm_ops,
 	},
 };
 
@@ -716,9 +668,9 @@
 	void *virt = NULL;
 	unsigned long phys = 0;
 	size_t size;
+	u32 yres = mfd->fbi->var.yres_virtual;
 
-	size = PAGE_ALIGN(mfd->fbi->fix.line_length * mfd->panel_info.yres);
-	size *= mfd->fb_page;
+	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
 
 	if (mfd->index == 0) {
 		int dom;
@@ -751,7 +703,7 @@
 {
 	int ret = -ENODEV;
 	int bpp;
-	struct mdss_panel_info *panel_info = &mfd->panel_info;
+	struct mdss_panel_info *panel_info = mfd->panel_info;
 	struct fb_info *fbi = mfd->fbi;
 	struct fb_fix_screeninfo *fix;
 	struct fb_var_screeninfo *var;
@@ -903,10 +855,6 @@
 	var->hsync_len = panel_info->lcdc.h_pulse_width;
 	var->pixclock = panel_info->clk_rate / 1000;
 
-	mfd->var_xres = var->xres;
-	mfd->var_yres = var->yres;
-	mfd->var_pixclock = var->pixclock;
-
 	if (panel_info->type == MIPI_VIDEO_PANEL) {
 		var->reserved[4] = panel_info->mipi.frame_rate;
 	} else {
@@ -1050,11 +998,25 @@
 				mfd->panel.type);
 
 	mdss_fb_update_backlight(mfd);
-
-	++mfd->panel_info.frame_count;
 	return 0;
 }
 
+static void mdss_fb_var_to_panelinfo(struct fb_var_screeninfo *var,
+	struct mdss_panel_info *pinfo)
+{
+	pinfo->xres = var->xres;
+	pinfo->yres = var->yres;
+	pinfo->lcdc.v_front_porch = var->upper_margin;
+	pinfo->lcdc.v_back_porch = var->lower_margin;
+	pinfo->lcdc.v_pulse_width = var->vsync_len;
+	pinfo->lcdc.h_front_porch = var->left_margin;
+	pinfo->lcdc.h_back_porch = var->right_margin;
+	pinfo->lcdc.h_pulse_width = var->hsync_len;
+	pinfo->clk_rate = var->pixclock;
+	/* todo: find how to pass CEA vic through framebuffer APIs */
+	pinfo->vic = var->reserved[3];
+}
+
 static int mdss_fb_check_var(struct fb_var_screeninfo *var,
 			     struct fb_info *info)
 {
@@ -1147,16 +1109,25 @@
 	if ((var->xres == 0) || (var->yres == 0))
 		return -EINVAL;
 
-	if ((var->xres > mfd->panel_info.xres) ||
-	    (var->yres > mfd->panel_info.yres))
-		return -EINVAL;
-
 	if (var->xoffset > (var->xres_virtual - var->xres))
 		return -EINVAL;
 
 	if (var->yoffset > (var->yres_virtual - var->yres))
 		return -EINVAL;
 
+	if (mfd->panel_info) {
+		struct mdss_panel_info panel_info;
+		int rc;
+
+		memcpy(&panel_info, mfd->panel_info, sizeof(panel_info));
+		mdss_fb_var_to_panelinfo(var, &panel_info);
+		rc = mdss_fb_send_panel_event(mfd, MDSS_EVENT_CHECK_PARAMS,
+			&panel_info);
+		if (IS_ERR_VALUE(rc))
+			return rc;
+		mfd->panel_reconfig = rc;
+	}
+
 	return 0;
 }
 
@@ -1165,7 +1136,6 @@
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	struct fb_var_screeninfo *var = &info->var;
 	int old_imgType;
-	int blank = 0;
 
 	old_imgType = mfd->fb_imgType;
 	switch (var->bits_per_pixel) {
@@ -1197,22 +1167,14 @@
 		return -EINVAL;
 	}
 
-	if ((mfd->var_pixclock != var->pixclock) ||
-	    (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) ||
-				 (mfd->var_pixclock != var->pixclock) ||
-				 (mfd->var_xres != var->xres) ||
-				 (mfd->var_yres != var->yres)))) {
-		mfd->var_xres = var->xres;
-		mfd->var_yres = var->yres;
-		mfd->var_pixclock = var->pixclock;
-		blank = 1;
-	}
 	mfd->fbi->fix.line_length = mdss_fb_line_length(mfd->index, var->xres,
 						var->bits_per_pixel / 8);
 
-	if (blank) {
+	if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
 		mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
+		mdss_fb_var_to_panelinfo(var, mfd->panel_info);
 		mdss_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable);
+		mfd->panel_reconfig = false;
 	}
 
 	return 0;
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index b760388..11bb859 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -55,15 +55,20 @@
 	u32 fb_page;
 
 	struct panel_id panel;
-	struct mdss_panel_info panel_info;
+	struct mdss_panel_info *panel_info;
 
 	u32 dest;
 	struct fb_info *fbi;
 
 	int op_enable;
 	u32 fb_imgType;
+	int panel_reconfig;
+
 	u32 dst_format;
 	int vsync_pending;
+	ktime_t vsync_time;
+	struct completion vsync_comp;
+	spinlock_t vsync_lock;
 
 	int hw_refresh;
 
@@ -97,10 +102,6 @@
 
 	struct platform_device *pdev;
 
-	u32 var_xres;
-	u32 var_yres;
-	u32 var_pixclock;
-
 	u32 mdp_fb_page_protection;
 
 	struct mdss_mdp_ctl *ctl;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index 8db38d6..50750e1 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -16,7 +16,7 @@
 #include "mdss_hdmi_edid.h"
 
 #define DBC_START_OFFSET 4
-#define HDMI_VSDB_3D_DATA_OFFSET(vsd) \
+#define HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd) \
 	(!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
 
 struct hdmi_edid_sink_data {
@@ -180,6 +180,10 @@
 	{HDMI_VFRMT_1920x1080i120_16_9, 1920, 1080, true,  2200, 280, 1125,
 	 22, 67500, 120000, 148500, 120000, false},
 
+	/* All 2560 H Active */
+	{HDMI_VFRMT_2560x1600p60_16_9, 2560, 1600, false, 2720, 160, 1646,
+	 46, 98700, 60000, 268500, 60000, false},
+
 	/* All 2880 H Active */
 	{HDMI_VFRMT_2880x576i50_4_3, 2880, 576, true,  3456, 576, 625, 24,
 	 15625, 50000, 54000, 50000, true},
@@ -437,7 +441,7 @@
 		u8 block_len = in_buf[offset] & 0x1F;
 		if ((in_buf[offset] >> 5) == type) {
 			*len = block_len;
-			DEV_DBG("%s: EDID: block=%d found @ %d w/ length=%d\n",
+			DEV_DBG("%s: EDID: block=%d found @ 0x%x w/ len=%d\n",
 				__func__, type, offset, block_len);
 
 			return in_buf + offset;
@@ -533,8 +537,8 @@
 		return;
 	}
 
-	offset = HDMI_VSDB_3D_DATA_OFFSET(vsd);
-	DEV_DBG("%s: EDID: 3D present @ %d = %02x\n", __func__,
+	offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
+	DEV_DBG("%s: EDID: 3D present @ 0x%x = %02x\n", __func__,
 		offset, vsd[offset]);
 
 	if (vsd[offset] >> 7) { /* 3D format indication present */
@@ -835,7 +839,7 @@
 				3, &len) : NULL;
 	int i;
 
-	offset = HDMI_VSDB_3D_DATA_OFFSET(vsd);
+	offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
 	present_multi_3d = (vsd[offset] & 0x60) >> 5;
 
 	offset += 1;
@@ -897,17 +901,16 @@
 
 	i = 0;
 	while (hdmi_3d_len > 0) {
-		DEV_DBG("%s: EDID[3D]: 3D_Structure_%d @ %d: %02x\n", __func__,
-			i + 1, offset, vsd[offset]);
+		DEV_DBG("%s: EDID: 3D_Structure_%d @ 0x%x: %02x\n",
+			__func__, i + 1, offset, vsd[offset]);
 
 		if ((vsd[offset] >> 4) >=
 			sink_data->disp_multi_3d_mode_list_cnt) {
 			if ((vsd[offset] & 0x0F) >= 8) {
 				offset += 1;
 				hdmi_3d_len -= 1;
-				DEV_DBG("%s:EDID[3D]:3D_Detail_%d @ %d: %02x\n",
-					__func__, i + 1, offset,
-					vsd[offset]);
+				DEV_DBG("%s:EDID:3D_Detail_%d @ 0x%x: %02x\n",
+					__func__, i + 1, offset, vsd[offset]);
 			}
 			i += 1;
 			offset += 1;
@@ -941,7 +944,7 @@
 		if ((vsd[offset] & 0x0F) >= 8) {
 			offset += 1;
 			hdmi_3d_len -= 1;
-			DEV_DBG("%s: EDID[3D]: 3D_Detail_%d @ %d: %02x\n",
+			DEV_DBG("%s: EDID[3D]: 3D_Detail_%d @ 0x%x: %02x\n",
 				__func__, i + 1, offset,
 				vsd[offset]);
 		}
@@ -951,6 +954,49 @@
 	}
 } /* hdmi_edid_get_display_vsd_3d_mode */
 
+static void hdmi_edid_get_extended_video_formats(
+	struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf)
+{
+	u8 db_len, offset, i;
+	u8 hdmi_vic_len;
+	u32 video_format;
+	const u8 *vsd = NULL;
+
+	if (!edid_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &db_len);
+
+	if (vsd == NULL || db_len < 9) {
+		DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+			__func__);
+		return;
+	}
+
+	/* check if HDMI_Video_present flag is set or not */
+	if (!(vsd[8] & BIT(5))) {
+		DEV_DBG("%s: extended vfmts are not supported by the sink.\n",
+			__func__);
+		return;
+	}
+
+	offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
+
+	hdmi_vic_len = vsd[offset + 1] >> 5;
+	if (hdmi_vic_len) {
+		DEV_DBG("%s: EDID: EVFRMT @ 0x%x of block 3, len = %02x\n",
+			__func__, offset, hdmi_vic_len);
+
+		for (i = 0; i < hdmi_vic_len; i++) {
+			video_format = HDMI_VFRMT_END + vsd[offset + 2 + i];
+			hdmi_edid_add_sink_video_format(&edid_ctrl->sink_data,
+				video_format);
+		}
+	}
+} /* hdmi_edid_get_extended_video_formats */
+
 static void hdmi_edid_get_display_mode(struct hdmi_edid_ctrl *edid_ctrl,
 	const u8 *data_buf, u32 num_of_cea_blocks)
 {
@@ -1113,6 +1159,8 @@
 		}
 	}
 
+	hdmi_edid_get_extended_video_formats(edid_ctrl, data_buf+0x80);
+
 	/* mandaroty 3d format */
 	if (edid_ctrl->present_3d) {
 		if (has60hz_mode) {
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 539cd49..9235856 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -32,7 +32,7 @@
 #define DRV_NAME "hdmi-tx"
 #define COMPATIBLE_NAME "qcom,hdmi-tx"
 
-#define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9;
+#define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9
 
 /* HDMI PHY/PLL bit field macros */
 #define SW_RESET BIT(2)
@@ -91,35 +91,46 @@
 	}
 } /* hdmi_pm_name */
 
-static u8 hdmi_tx_avi_iframe_lut[][16] = {
-/*	480p60	480i60	576p50	576i50	720p60	 720p50	1080p60	1080i60	1080p50
-	1080i50	1080p24	1080p30	1080p25	640x480p 480p60_16_9 576p50_4_3 */
-	{0x10,	0x10,	0x10,	0x10,	0x10,	 0x10,	0x10,	0x10,	0x10,
-	 0x10,	0x10,	0x10,	0x10,	0x10, 0x10, 0x10}, /*00*/
-	{0x18,	0x18,	0x28,	0x28,	0x28,	 0x28,	0x28,	0x28,	0x28,
-	 0x28,	0x28,	0x28,	0x28,	0x18, 0x28, 0x18}, /*01*/
-	{0x00,	0x04,	0x04,	0x04,	0x04,	 0x04,	0x04,	0x04,	0x04,
-	 0x04,	0x04,	0x04,	0x04,	0x88, 0x00, 0x04}, /*02*/
-	{0x02,	0x06,	0x11,	0x15,	0x04,	 0x13,	0x10,	0x05,	0x1F,
-	 0x14,	0x20,	0x22,	0x21,	0x01, 0x03, 0x11}, /*03*/
-	{0x00,	0x01,	0x00,	0x01,	0x00,	 0x00,	0x00,	0x00,	0x00,
-	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*04*/
-	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
-	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*05*/
-	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
-	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*06*/
-	{0xE1,	0xE1,	0x41,	0x41,	0xD1,	 0xd1,	0x39,	0x39,	0x39,
-	 0x39,	0x39,	0x39,	0x39,	0xe1, 0xE1, 0x41}, /*07*/
-	{0x01,	0x01,	0x02,	0x02,	0x02,	 0x02,	0x04,	0x04,	0x04,
-	 0x04,	0x04,	0x04,	0x04,	0x01, 0x01, 0x02}, /*08*/
-	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
-	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*09*/
-	{0x00,	0x00,	0x00,	0x00,	0x00,	 0x00,	0x00,	0x00,	0x00,
-	 0x00,	0x00,	0x00,	0x00,	0x00, 0x00, 0x00}, /*10*/
-	{0xD1,	0xD1,	0xD1,	0xD1,	0x01,	 0x01,	0x81,	0x81,	0x81,
-	 0x81,	0x81,	0x81,	0x81,	0x81, 0xD1, 0xD1}, /*11*/
-	{0x02,	0x02,	0x02,	0x02,	0x05,	 0x05,	0x07,	0x07,	0x07,
-	 0x07,	0x07,	0x07,	0x07,	0x02, 0x02, 0x02}  /*12*/
+static u8 hdmi_tx_avi_iframe_lut[][20] = {
+	{0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,
+	 0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,
+	 0x10,	0x10}, /*00*/
+	{0x18,	0x18,	0x28,	0x28,	0x28,	0x28,	0x28,	0x28,	0x28,
+	 0x28,	0x28,	0x28,	0x28,	0x18,	0x28,	0x18,	0x28,	0x28,
+	 0x28,	0x28}, /*01*/
+	{0x00,	0x04,	0x04,	0x04,	0x04,	0x04,	0x04,	0x04,	0x04,
+	 0x04,	0x04,	0x04,	0x04,	0x88,	0x00,	0x04,	0x04,	0x04,
+	 0x04,	0x04}, /*02*/
+	{0x02,	0x06,	0x11,	0x15,	0x04,	0x13,	0x10,	0x05,	0x1F,
+	 0x14,	0x20,	0x22,	0x21,	0x01,	0x03,	0x11,	0x00,	0x00,
+	 0x00,	0x00}, /*03*/
+	{0x00,	0x01,	0x00,	0x01,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00}, /*04*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00}, /*05*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00}, /*06*/
+	{0xE1,	0xE1,	0x41,	0x41,	0xD1,	0xd1,	0x39,	0x39,	0x39,
+	 0x39,	0x39,	0x39,	0x39,	0xe1,	0xE1,	0x41,	0x71,	0x71,
+	 0x71,	0x71}, /*07*/
+	{0x01,	0x01,	0x02,	0x02,	0x02,	0x02,	0x04,	0x04,	0x04,
+	 0x04,	0x04,	0x04,	0x04,	0x01,	0x01,	0x02,	0x08,	0x08,
+	 0x08,	0x08}, /*08*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00}, /*09*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00}, /*10*/
+	{0xD1,	0xD1,	0xD1,	0xD1,	0x01,	0x01,	0x81,	0x81,	0x81,
+	 0x81,	0x81,	0x81,	0x81,	0x81,	0xD1,	0xD1,	0x01,	0x01,
+	 0x01,	0x01}, /*11*/
+	{0x02,	0x02,	0x02,	0x02,	0x05,	0x05,	0x07,	0x07,	0x07,
+	 0x07,	0x07,	0x07,	0x07,	0x02,	0x02,	0x02,	0x0F,	0x0F,
+	 0x0F,	0x10}  /*12*/
 };
 
 /* Audio constants lookup table for hdmi_tx_audio_acr_setup */
@@ -141,6 +152,10 @@
 	{148500, {{4096, 148500}, {6272, 165000}, {6144, 148500},
 		{12544, 165000}, {12288, 148500}, {25088, 165000},
 		{24576, 148500} } },
+	/* 297.000MHz */
+	{297000, {{3072, 222750}, {4704, 247500}, {5120, 247500},
+		{9408, 247500}, {10240, 247500}, {18816, 247500},
+		{20480, 247500} } },
 };
 
 const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
@@ -163,6 +178,66 @@
 	}
 } /* hdmi_tx_io_name */
 
+static int hdmi_tx_get_vic_from_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl,
+	struct mdss_panel_info *pinfo)
+{
+	int new_vic = -1;
+	u32 h_total, v_total;
+	struct hdmi_disp_mode_timing_type timing;
+
+	if (!hdmi_ctrl || !pinfo) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	if (pinfo->vic) {
+		if (hdmi_get_supported_mode(pinfo->vic - 1)) {
+			new_vic = pinfo->vic - 1;
+			DEV_DBG("%s: %s is supported\n", __func__,
+				hdmi_get_video_fmt_2string(new_vic));
+		} else {
+			DEV_ERR("%s: invalid or not supported vic\n",
+				__func__);
+			return -EPERM;
+		}
+	} else {
+		timing.active_h = pinfo->xres;
+		timing.back_porch_h = pinfo->lcdc.h_back_porch;
+		timing.front_porch_h = pinfo->lcdc.h_front_porch;
+		timing.pulse_width_h = pinfo->lcdc.h_pulse_width;
+		h_total = timing.active_h + timing.back_porch_h +
+			timing.front_porch_h + timing.pulse_width_h;
+		DEV_DBG("%s: ah=%d bph=%d fph=%d pwh=%d ht=%d\n", __func__,
+			timing.active_h, timing.back_porch_h,
+			timing.front_porch_h, timing.pulse_width_h, h_total);
+
+		timing.active_v = pinfo->yres;
+		timing.back_porch_v = pinfo->lcdc.v_back_porch;
+		timing.front_porch_v = pinfo->lcdc.v_front_porch;
+		timing.pulse_width_v = pinfo->lcdc.v_pulse_width;
+		v_total = timing.active_v + timing.back_porch_v +
+			timing.front_porch_v + timing.pulse_width_v;
+		DEV_DBG("%s: av=%d bpv=%d fpv=%d pwv=%d vt=%d\n", __func__,
+			timing.active_v, timing.back_porch_v,
+			timing.front_porch_v, timing.pulse_width_v, v_total);
+
+		timing.pixel_freq = pinfo->clk_rate / 1000;
+		if (h_total && v_total) {
+			timing.refresh_rate = ((timing.pixel_freq * 1000) /
+				(h_total * v_total)) * 1000;
+		} else {
+			DEV_ERR("%s: cannot cal refresh rate\n", __func__);
+			return -EPERM;
+		}
+		DEV_DBG("%s: pixel_freq=%d refresh_rate=%d\n", __func__,
+			timing.pixel_freq, timing.refresh_rate);
+
+		new_vic = hdmi_get_video_id_code(&timing);
+	}
+
+	return new_vic;
+} /* hdmi_tx_get_vic_from_panel_info */
+
 static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_panel_data(
 	struct mdss_panel_data *mpd)
 {
@@ -170,14 +245,8 @@
 
 	if (mpd) {
 		hdmi_ctrl = container_of(mpd, struct hdmi_tx_ctrl, panel_data);
-		if (hdmi_ctrl) {
-			hdmi_ctrl->pixel_clk =
-				mpd->panel_info.fbi->var.pixclock;
-			hdmi_ctrl->xres = mpd->panel_info.fbi->var.xres;
-			hdmi_ctrl->yres = mpd->panel_info.fbi->var.yres;
-		} else {
+		if (!hdmi_ctrl)
 			DEV_ERR("%s: hdmi_ctrl = NULL\n", __func__);
-		}
 	} else {
 		DEV_ERR("%s: mdss_panel_data = NULL\n", __func__);
 	}
@@ -428,9 +497,11 @@
 } /* hdmi_tx_init_panel_info */
 
 /* Table indicating the video format supported by the HDMI TX Core */
-/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */
+/* Valid pclk rates (Mhz): 25.2, 27, 27.03, 74.25, 148.5, 268.5, 297 */
 static void hdmi_tx_setup_video_mode_lut(void)
 {
+	hdmi_init_supported_video_timings();
+
 	hdmi_set_supported_mode(HDMI_VFRMT_640x480p60_4_3);
 	hdmi_set_supported_mode(HDMI_VFRMT_720x480p60_4_3);
 	hdmi_set_supported_mode(HDMI_VFRMT_720x480p60_16_9);
@@ -448,6 +519,11 @@
 	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p50_16_9);
 	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080i60_16_9);
 	hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p60_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_2560x1600p60_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_3840x2160p30_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_3840x2160p25_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_3840x2160p24_16_9);
+	hdmi_set_supported_mode(HDMI_VFRMT_4096x2160p24_16_9);
 } /* hdmi_tx_setup_video_mode_lut */
 
 static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -546,93 +622,43 @@
 	return 0;
 } /* hdmi_tx_check_capability */
 
-static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl)
+static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl,
+	struct mdss_panel_info *pinfo)
 {
-	int rc = 0;
+	int new_vic = -1;
 	const struct hdmi_disp_mode_timing_type *timing = NULL;
-	struct hdmi_tx_platform_data *pdata = NULL;
-	u32 format = DEFAULT_VIDEO_RESOLUTION;
 
-	if (!hdmi_ctrl) {
+	if (!hdmi_ctrl || !pinfo) {
 		DEV_ERR("%s: invalid input\n", __func__);
-		rc = -EINVAL;
-		goto end;
+		return -EINVAL;
 	}
 
-	pdata = &hdmi_ctrl->pdata;
-
-	DEV_DBG("%s: Resolution wanted=%dx%d\n", __func__, hdmi_ctrl->xres,
-		hdmi_ctrl->yres);
-	switch (hdmi_ctrl->xres) {
-	default:
-	case 640:
-		format = HDMI_VFRMT_640x480p60_4_3;
-		break;
-	case 720:
-		format = (hdmi_ctrl->yres == 480)
-			? HDMI_VFRMT_720x480p60_16_9
-			: HDMI_VFRMT_720x576p50_16_9;
-		break;
-	case 1280:
-		if (hdmi_ctrl->frame_rate == 50000)
-			format = HDMI_VFRMT_1280x720p50_16_9;
-		else
-			format = HDMI_VFRMT_1280x720p60_16_9;
-		break;
-	case 1440:
-		/* interlaced has half of y res. */
-		format = (hdmi_ctrl->yres == 240)
-			? HDMI_VFRMT_1440x480i60_16_9
-			: HDMI_VFRMT_1440x576i50_16_9;
-		break;
-	case 1920:
-		if (hdmi_ctrl->yres == 540) {/* interlaced */
-			format = HDMI_VFRMT_1920x1080i60_16_9;
-		} else if (hdmi_ctrl->yres == 1080) {
-			if (hdmi_ctrl->frame_rate == 50000)
-				format = HDMI_VFRMT_1920x1080p50_16_9;
-			else if (hdmi_ctrl->frame_rate == 24000)
-				format = HDMI_VFRMT_1920x1080p24_16_9;
-			else if (hdmi_ctrl->frame_rate == 25000)
-				format = HDMI_VFRMT_1920x1080p25_16_9;
-			else if (hdmi_ctrl->frame_rate == 30000)
-				format = HDMI_VFRMT_1920x1080p30_16_9;
-			else
-				format = HDMI_VFRMT_1920x1080p60_16_9;
-		}
-		break;
+	new_vic = hdmi_tx_get_vic_from_panel_info(hdmi_ctrl, pinfo);
+	if ((new_vic < 0) || (new_vic > HDMI_VFRMT_MAX)) {
+		DEV_ERR("%s: invalid or not supported vic\n", __func__);
+		return -EPERM;
 	}
 
-	if (hdmi_ctrl->video_resolution != format)
-		DEV_DBG("%s: switching %s => %s", __func__,
-			hdmi_get_video_fmt_2string(
-			hdmi_ctrl->video_resolution),
-			hdmi_get_video_fmt_2string(format));
-	else
-		DEV_DBG("resolution %s", hdmi_get_video_fmt_2string(
-			hdmi_ctrl->video_resolution));
+	DEV_DBG("%s: switching from %s => %s", __func__,
+		hdmi_get_video_fmt_2string(hdmi_ctrl->video_resolution),
+		hdmi_get_video_fmt_2string(new_vic));
 
-	timing = hdmi_get_supported_mode(format);
-	if (!timing) {
-		DEV_ERR("%s: invalid video fmt=%d\n", __func__,
-			hdmi_ctrl->video_resolution);
-		rc = -EPERM;
-		goto end;
-	}
+	hdmi_ctrl->video_resolution = (u32)new_vic;
+
+	timing = hdmi_get_supported_mode(hdmi_ctrl->video_resolution);
 
 	/* todo: find a better way */
 	hdmi_ctrl->pdata.power_data[HDMI_TX_CORE_PM].clk_config[0].rate =
 		timing->pixel_freq * 1000;
 
-	hdmi_ctrl->video_resolution = format;
 	hdmi_edid_set_video_resolution(
-		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], format);
+		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
+		hdmi_ctrl->video_resolution);
 
-end:
-	return rc;
+	return 0;
 } /* hdmi_tx_set_video_fmt */
 
-static void hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
+static int hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
 	int video_format)
 {
 	u32 total_v   = 0;
@@ -648,47 +674,53 @@
 	if (timing == NULL) {
 		DEV_ERR("%s: video format not supported: %d\n", __func__,
 			video_format);
-		return;
+		return -EPERM;
 	}
 
 	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
-		return;
+		return -EINVAL;
 	}
 
 	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
 	if (!io->base) {
 		DEV_ERR("%s: Core io is not initialized\n", __func__);
-		return;
+		return -EPERM;
 	}
 
 	total_h = timing->active_h + timing->front_porch_h +
 		timing->back_porch_h + timing->pulse_width_h - 1;
 	total_v = timing->active_v + timing->front_porch_v +
 		timing->back_porch_v + timing->pulse_width_v - 1;
-	DSS_REG_W(io, HDMI_TOTAL,
-		((total_v << 16) & 0x0FFF0000) |
-		((total_h << 0) & 0x00000FFF));
+	if (((total_v << 16) & 0xE0000000) || (total_h & 0xFFFFE000)) {
+		DEV_ERR("%s: total v=%d or h=%d is larger than supported\n",
+			__func__, total_v, total_h);
+		return -EPERM;
+	}
+	DSS_REG_W(io, HDMI_TOTAL, (total_v << 16) | (total_h << 0));
 
 	start_h = timing->back_porch_h + timing->pulse_width_h;
 	end_h   = (total_h + 1) - timing->front_porch_h;
-	DSS_REG_W(io, HDMI_ACTIVE_H,
-		((end_h << 16) & 0x0FFF0000) |
-		((start_h << 0) & 0x00000FFF));
+	if (((end_h << 16) & 0xE0000000) || (start_h & 0xFFFFE000)) {
+		DEV_ERR("%s: end_h=%d or start_h=%d is larger than supported\n",
+			__func__, end_h, start_h);
+		return -EPERM;
+	}
+	DSS_REG_W(io, HDMI_ACTIVE_H, (end_h << 16) | (start_h << 0));
 
 	start_v = timing->back_porch_v + timing->pulse_width_v - 1;
 	end_v   = total_v - timing->front_porch_v;
-	DSS_REG_W(io, HDMI_ACTIVE_V,
-		((end_v << 16) & 0x0FFF0000) |
-		((start_v << 0) & 0x00000FFF));
+	if (((end_v << 16) & 0xE0000000) || (start_v & 0xFFFFE000)) {
+		DEV_ERR("%s: end_v=%d or start_v=%d is larger than supported\n",
+			__func__, end_v, start_v);
+		return -EPERM;
+	}
+	DSS_REG_W(io, HDMI_ACTIVE_V, (end_v << 16) | (start_v << 0));
 
 	if (timing->interlaced) {
-		DSS_REG_W(io, HDMI_V_TOTAL_F2,
-			((total_v + 1) << 0) & 0x00000FFF);
-
+		DSS_REG_W(io, HDMI_V_TOTAL_F2, (total_v + 1) << 0);
 		DSS_REG_W(io, HDMI_ACTIVE_V_F2,
-			(((start_v + 1) << 0) & 0x00000FFF) |
-			(((end_v + 1) << 16) & 0x0FFF0000));
+			((end_v + 1) << 16) | ((start_v + 1) << 0));
 	} else {
 		DSS_REG_W(io, HDMI_V_TOTAL_F2, 0);
 		DSS_REG_W(io, HDMI_ACTIVE_V_F2, 0);
@@ -698,6 +730,8 @@
 		((timing->interlaced << 31) & 0x80000000) |
 		((timing->active_low_h << 29) & 0x20000000) |
 		((timing->active_low_v << 28) & 0x10000000));
+
+	return 0;
 } /* hdmi_tx_video_setup */
 
 static void hdmi_tx_set_avi_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -768,6 +802,18 @@
 	case HDMI_VFRMT_720x576p50_4_3:
 		mode = 15;
 		break;
+	case HDMI_VFRMT_3840x2160p30_16_9:
+		mode = 16;
+		break;
+	case HDMI_VFRMT_3840x2160p25_16_9:
+		mode = 17;
+		break;
+	case HDMI_VFRMT_3840x2160p24_16_9:
+		mode = 18;
+		break;
+	case HDMI_VFRMT_4096x2160p24_16_9:
+		mode = 19;
+		break;
 	default:
 		DEV_INFO("%s: mode %d not supported\n", __func__,
 			hdmi_ctrl->video_resolution);
@@ -842,12 +888,87 @@
 	regVal = regVal << 8 | avi_iframe[14];
 	DSS_REG_W(io, HDMI_AVI_INFO3, regVal);
 
-	/* 0x3 for AVI InfFrame enable (every frame) */
+	/* AVI InfFrame enable (every frame) */
 	DSS_REG_W(io, HDMI_INFOFRAME_CTRL0,
-		DSS_REG_R(io, HDMI_INFOFRAME_CTRL0) |
-		0x00000003L);
+		DSS_REG_R(io, HDMI_INFOFRAME_CTRL0) | BIT(1) | BIT(0));
 } /* hdmi_tx_set_avi_infoframe */
 
+/* todo: add 3D support */
+static void hdmi_tx_set_vendor_specific_infoframe(
+	struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+	int i;
+	u8 vs_iframe[9]; /* two header + length + 6 data */
+	u32 sum, reg_val;
+	u32 hdmi_vic, hdmi_video_format;
+	struct dss_io_data *io = NULL;
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return;
+	}
+
+	io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	if (!io->base) {
+		DEV_ERR("%s: Core io is not initialized\n", __func__);
+		return;
+	}
+
+	/* HDMI Spec 1.4a Table 8-10 */
+	vs_iframe[0] = 0x81; /* type */
+	vs_iframe[1] = 0x1;  /* version */
+	vs_iframe[2] = 0x8;  /* length */
+
+	vs_iframe[3] = 0x0; /* PB0: checksum */
+
+	/* PB1..PB3: 24 Bit IEEE Registration Code 00_0C_03 */
+	vs_iframe[4] = 0x03;
+	vs_iframe[5] = 0x0C;
+	vs_iframe[6] = 0x00;
+
+	hdmi_video_format = 0x1;
+	switch (hdmi_ctrl->video_resolution) {
+	case HDMI_VFRMT_3840x2160p30_16_9:
+		hdmi_vic = 0x1;
+		break;
+	case HDMI_VFRMT_3840x2160p25_16_9:
+		hdmi_vic = 0x2;
+		break;
+	case HDMI_VFRMT_3840x2160p24_16_9:
+		hdmi_vic = 0x3;
+		break;
+	case HDMI_VFRMT_4096x2160p24_16_9:
+		hdmi_vic = 0x4;
+		break;
+	default:
+		hdmi_video_format = 0x0;
+		hdmi_vic = 0x0;
+	}
+
+	/* PB4: HDMI Video Format[7:5],  Reserved[4:0] */
+	vs_iframe[7] = (hdmi_video_format << 5) & 0xE0;
+
+	/* PB5: HDMI_VIC or 3D_Structure[7:4], Reserved[3:0] */
+	vs_iframe[8] = hdmi_vic;
+
+	/* compute checksum */
+	sum = 0;
+	for (i = 0; i < 9; i++)
+		sum += vs_iframe[i];
+
+	sum &= 0xFF;
+	sum = 256 - sum;
+	vs_iframe[3] = (u8)sum;
+
+	reg_val = (hdmi_vic << 16) | (vs_iframe[3] << 8) |
+		(hdmi_video_format << 5) | vs_iframe[2];
+	DSS_REG_W(io, HDMI_VENSPEC_INFO0, reg_val);
+
+	/* vendor specific info-frame enable (every frame) */
+	DSS_REG_W(io, HDMI_INFOFRAME_CTRL0,
+		DSS_REG_R(io, HDMI_INFOFRAME_CTRL0) | BIT(13) | BIT(12));
+} /* hdmi_tx_set_vendor_specific_infoframe */
+
 static void hdmi_tx_set_spd_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
 	u32 packet_header  = 0;
@@ -1606,7 +1727,13 @@
 
 	hdmi_tx_set_mode(hdmi_ctrl, true);
 
-	hdmi_tx_video_setup(hdmi_ctrl, hdmi_ctrl->video_resolution);
+	rc = hdmi_tx_video_setup(hdmi_ctrl, hdmi_ctrl->video_resolution);
+	if (rc) {
+		DEV_ERR("%s: hdmi_tx_video_setup failed. rc=%d\n",
+			__func__, rc);
+		hdmi_tx_set_mode(hdmi_ctrl, false);
+		return rc;
+	}
 
 	if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) {
 		rc = hdmi_tx_audio_setup(hdmi_ctrl);
@@ -1620,11 +1747,11 @@
 		switch_set_state(&hdmi_ctrl->audio_sdev, 1);
 		DEV_INFO("%s: hdmi_audio state switch to %d\n", __func__,
 			hdmi_ctrl->audio_sdev.state);
-	}
 
-	hdmi_tx_set_avi_infoframe(hdmi_ctrl);
-	/* todo: CONFIG_FB_MSM_HDMI_3D */
-	hdmi_tx_set_spd_infoframe(hdmi_ctrl);
+		hdmi_tx_set_avi_infoframe(hdmi_ctrl);
+		hdmi_tx_set_vendor_specific_infoframe(hdmi_ctrl);
+		hdmi_tx_set_spd_infoframe(hdmi_ctrl);
+	}
 
 	/* todo: HDCP/CEC */
 
@@ -1710,8 +1837,6 @@
 	if (hdmi_ctrl->hpd_off_pending) {
 		hdmi_tx_hpd_off(hdmi_ctrl);
 		hdmi_ctrl->hpd_off_pending = false;
-	} else {
-		hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_CONNECT_POLARITY);
 	}
 
 	DEV_INFO("%s: HDMI Core: OFF\n", __func__);
@@ -1764,15 +1889,15 @@
 	/* If a power down is already underway, wait for it to finish */
 	flush_work_sync(&hdmi_ctrl->power_off_work);
 
-	DEV_INFO("power: ON (%dx%d %ld)\n", hdmi_ctrl->xres, hdmi_ctrl->yres,
-		hdmi_ctrl->pixel_clk);
-
-	rc = hdmi_tx_set_video_fmt(hdmi_ctrl);
+	rc = hdmi_tx_set_video_fmt(hdmi_ctrl, &panel_data->panel_info);
 	if (rc) {
 		DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc);
 		return rc;
 	}
 
+	DEV_INFO("power: ON (%s)\n", hdmi_get_video_fmt_2string(
+		hdmi_ctrl->video_resolution));
+
 	rc = hdmi_tx_core_on(hdmi_ctrl);
 	if (rc) {
 		DEV_ERR("%s: hdmi_msm_core_on failed\n", __func__);
@@ -2044,7 +2169,7 @@
 static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data,
 	int event, void *arg)
 {
-	int rc = 0;
+	int rc = 0, new_vic = -1;
 	struct hdmi_tx_ctrl *hdmi_ctrl =
 		hdmi_tx_get_drvdata_from_panel_data(panel_data);
 
@@ -2057,6 +2182,25 @@
 		event, hdmi_ctrl->panel_suspend, hdmi_ctrl->hpd_feature_on);
 
 	switch (event) {
+	case MDSS_EVENT_CHECK_PARAMS:
+		new_vic = hdmi_tx_get_vic_from_panel_info(hdmi_ctrl,
+			(struct mdss_panel_info *)arg);
+		if ((new_vic < 0) || (new_vic > HDMI_VFRMT_MAX)) {
+			DEV_ERR("%s: invalid or not supported vic\n", __func__);
+			return -EPERM;
+		}
+
+		/*
+		 * return value of 1 lets mdss know that panel
+		 * needs a reconfig due to new resolution and
+		 * it will issue close and open subsequently.
+		 */
+		if (new_vic != hdmi_ctrl->video_resolution)
+			rc = 1;
+		else
+			DEV_DBG("%s: no res change.\n", __func__);
+		break;
+
 	case MDSS_EVENT_RESUME:
 		if (hdmi_ctrl->hpd_feature_on) {
 			INIT_COMPLETION(hdmi_ctrl->hpd_done);
@@ -2104,8 +2248,6 @@
 		if (!hdmi_ctrl->panel_power_on) {
 			if (hdmi_ctrl->hpd_feature_on)
 				hdmi_tx_hpd_off(hdmi_ctrl);
-			else
-				DEV_ERR("%s: invalid state\n", __func__);
 
 			hdmi_ctrl->panel_suspend = false;
 		} else {
@@ -2131,6 +2273,12 @@
 		if (hdmi_ctrl->panel_suspend)
 			flush_work_sync(&hdmi_ctrl->power_off_work);
 		break;
+
+	case MDSS_EVENT_CLOSE:
+		if (hdmi_ctrl->hpd_feature_on)
+			hdmi_tx_hpd_polarity_setup(hdmi_ctrl,
+				HPD_CONNECT_POLARITY);
+		break;
 	}
 
 	return rc;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 2d431b7..5f8094f 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -50,6 +50,7 @@
 	struct workqueue_struct *workq;
 
 	uint32_t video_resolution;
+
 	u32 panel_power_on;
 	u32 panel_suspend;
 
@@ -62,11 +63,6 @@
 
 	struct work_struct power_off_work;
 
-	unsigned long pixel_clk;
-	u32 xres;
-	u32 yres;
-	u32 frame_rate;
-
 	u32 present_hdcp;
 
 	u8 spd_vendor_name[8];
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index e7ea8c9..ad63605 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -16,73 +16,24 @@
 #include "mdss_hdmi_util.h"
 
 static struct hdmi_disp_mode_timing_type
-	hdmi_supported_video_mode_lut[HDMI_VFRMT_MAX] = {
-	HDMI_SETTINGS_640x480p60_4_3,
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p60_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i60_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p60_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p24_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p25_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p30_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1250i50_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i100_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p100_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i120_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p120_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3),
-	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9),
-}; /* hdmi_supported_video_mode_lut */
+	hdmi_supported_video_mode_lut[HDMI_VFRMT_MAX];
 
 #define HDMI_SETUP_LUT(MODE) do {					\
 	struct hdmi_disp_mode_timing_type mode = HDMI_SETTINGS_##MODE;	\
 	hdmi_supported_video_mode_lut[mode.video_format] = mode;	\
 	} while (0)
 
+void hdmi_init_supported_video_timings(void)
+{
+	int i;
+
+	for (i = 0; i < HDMI_VFRMT_MAX; i++) {
+		struct hdmi_disp_mode_timing_type mode = VFRMT_NOT_SUPPORTED(i);
+
+		hdmi_supported_video_mode_lut[i] = mode;
+	}
+} /* hdmi_init_supported_video_timings */
+
 const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode)
 {
 	const struct hdmi_disp_mode_timing_type *ret = NULL;
@@ -98,6 +49,57 @@
 	return ret;
 } /* hdmi_get_supported_mode */
 
+int hdmi_get_video_id_code(struct hdmi_disp_mode_timing_type *timing_in)
+{
+	int i, vic = -1;
+
+	if (!timing_in) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		goto exit;
+	}
+
+	/* active_low_h, active_low_v and interlaced are not checked against */
+	for (i = 0; i < HDMI_VFRMT_MAX; i++) {
+		struct hdmi_disp_mode_timing_type *supported_timing =
+			&hdmi_supported_video_mode_lut[i];
+
+		if (!supported_timing->supported)
+			continue;
+		if (timing_in->active_h != supported_timing->active_h)
+			continue;
+		if (timing_in->front_porch_h != supported_timing->front_porch_h)
+			continue;
+		if (timing_in->pulse_width_h != supported_timing->pulse_width_h)
+			continue;
+		if (timing_in->back_porch_h != supported_timing->back_porch_h)
+			continue;
+		if (timing_in->active_v != supported_timing->active_v)
+			continue;
+		if (timing_in->front_porch_v != supported_timing->front_porch_v)
+			continue;
+		if (timing_in->pulse_width_v != supported_timing->pulse_width_v)
+			continue;
+		if (timing_in->back_porch_v != supported_timing->back_porch_v)
+			continue;
+		if (timing_in->pixel_freq != supported_timing->pixel_freq)
+			continue;
+		if (timing_in->refresh_rate != supported_timing->refresh_rate)
+			continue;
+
+		vic = (int)supported_timing->video_format;
+		break;
+	}
+
+	if (vic < 0)
+		DEV_ERR("%s: timing asked is not yet supported\n", __func__);
+
+exit:
+	DEV_DBG("%s: vic = %d timing = %s\n", __func__, vic,
+		hdmi_get_video_fmt_2string((u32)vic));
+
+	return vic;
+} /* hdmi_get_video_id_code */
+
 void hdmi_set_supported_mode(u32 mode)
 {
 	switch (mode) {
@@ -152,6 +154,21 @@
 	case HDMI_VFRMT_1920x1080p60_16_9:
 		HDMI_SETUP_LUT(1920x1080p60_16_9);
 		break;
+	case HDMI_VFRMT_2560x1600p60_16_9:
+		HDMI_SETUP_LUT(2560x1600p60_16_9);
+		break;
+	case HDMI_VFRMT_3840x2160p30_16_9:
+		HDMI_SETUP_LUT(3840x2160p30_16_9);
+		break;
+	case HDMI_VFRMT_3840x2160p25_16_9:
+		HDMI_SETUP_LUT(3840x2160p25_16_9);
+		break;
+	case HDMI_VFRMT_3840x2160p24_16_9:
+		HDMI_SETUP_LUT(3840x2160p24_16_9);
+		break;
+	case HDMI_VFRMT_4096x2160p24_16_9:
+		HDMI_SETUP_LUT(4096x2160p24_16_9);
+		break;
 	default:
 		DEV_ERR("%s: unsupported mode=%d\n", __func__, mode);
 	}
@@ -219,6 +236,11 @@
 	case HDMI_VFRMT_720x480p240_16_9:  return " 720x 480 p240 16/9";
 	case HDMI_VFRMT_1440x480i240_4_3:  return "1440x 480 i240  4/3";
 	case HDMI_VFRMT_1440x480i240_16_9: return "1440x 480 i240 16/9";
+	case HDMI_VFRMT_2560x1600p60_16_9: return "2560x1600 p60 16/9";
+	case HDMI_VFRMT_3840x2160p30_16_9: return "3840x2160 p30 16/9";
+	case HDMI_VFRMT_3840x2160p25_16_9: return "3840x2160 p25 16/9";
+	case HDMI_VFRMT_3840x2160p24_16_9: return "3840x2160 p24 16/9";
+	case HDMI_VFRMT_4096x2160p24_16_9: return "4096x2160 p24 16/9";
 	default:                           return "???";
 	}
 } /* hdmi_get_video_fmt_2string */
@@ -499,8 +521,8 @@
 	 */
 	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_SETUP, 0xFF000000);
 
-	/* Enable reference timer to 27 micro-seconds */
-	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_REF, (1 << 16) | (27 << 0));
+	/* Enable reference timer to 19 micro-seconds */
+	DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_REF, (1 << 16) | (19 << 0));
 } /* hdmi_ddc_config */
 
 int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
index 852a93c..cd7b7dd 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -216,7 +216,7 @@
 #define QFPROM_RAW_FEAT_CONFIG_ROW0_LSB  (0x000000F8)
 #define QFPROM_RAW_FEAT_CONFIG_ROW0_MSB  (0x000000FC)
 
-/* all video formats defined by EIA CEA 861D */
+/* all video formats defined by EIA CEA-861-E */
 #define HDMI_VFRMT_640x480p60_4_3	0
 #define HDMI_VFRMT_720x480p60_4_3	1
 #define HDMI_VFRMT_720x480p60_16_9	2
@@ -292,7 +292,18 @@
 #define HDMI_VFRMT_1440x480i240_4_3	HDMI_VFRMT_720x480i240_4_3
 #define HDMI_VFRMT_720x480i240_16_9	58
 #define HDMI_VFRMT_1440x480i240_16_9	HDMI_VFRMT_720x480i240_16_9
-#define HDMI_VFRMT_MAX			59
+/* Video Identification Codes from 65-127 are reserved for the future */
+#define HDMI_VFRMT_END			127
+/* extended video formats */
+#define HDMI_VFRMT_3840x2160p30_16_9	(HDMI_VFRMT_END + 1)
+#define HDMI_VFRMT_3840x2160p25_16_9	(HDMI_VFRMT_END + 2)
+#define HDMI_VFRMT_3840x2160p24_16_9	(HDMI_VFRMT_END + 3)
+#define HDMI_VFRMT_4096x2160p24_16_9	(HDMI_VFRMT_END + 4)
+#define HDMI_EVFRMT_END			HDMI_VFRMT_4096x2160p24_16_9
+/* DVI only resolutions */
+#define HDMI_VFRMT_2560x1600p60_16_9	(HDMI_EVFRMT_END + 1)
+#define DVI_VFRMT_END			HDMI_VFRMT_2560x1600p60_16_9
+#define HDMI_VFRMT_MAX			(DVI_VFRMT_END + 1)
 #define HDMI_VFRMT_FORCE_32BIT		0x7FFFFFFF
 
 #define VFRMT_NOT_SUPPORTED(VFRMT) \
@@ -349,6 +360,21 @@
 #define HDMI_SETTINGS_1920x1080p30_16_9					\
 	{HDMI_VFRMT_1920x1080p30_16_9,   1920,  88,   44,  148,  false,	\
 	 1080, 4, 5, 36, false, 74250, 30000, false, true}
+#define HDMI_SETTINGS_2560x1600p60_16_9					\
+	{HDMI_VFRMT_2560x1600p60_16_9,   2560,  48,   32,  80,  false,	\
+	 1600, 3, 6, 37, false, 268500, 60000, false, true}
+#define HDMI_SETTINGS_3840x2160p30_16_9					\
+	{HDMI_VFRMT_3840x2160p30_16_9, 3840, 176, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 30000, false, true}
+#define HDMI_SETTINGS_3840x2160p25_16_9					\
+	{HDMI_VFRMT_3840x2160p25_16_9, 3840, 1056, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 25000, false, true}
+#define HDMI_SETTINGS_3840x2160p24_16_9					\
+	{HDMI_VFRMT_3840x2160p24_16_9, 3840, 1276, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 24000, false, true}
+#define HDMI_SETTINGS_4096x2160p24_16_9					\
+	{HDMI_VFRMT_4096x2160p24_16_9, 4096, 1020, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 24000, false, true}
 
 #define TOP_AND_BOTTOM		0x10
 #define FRAME_PACKING		0x20
@@ -397,6 +423,9 @@
 	int retry;
 };
 
+/* video timing related utility routines */
+void hdmi_init_supported_video_timings(void);
+int hdmi_get_video_id_code(struct hdmi_disp_mode_timing_type *timing_in);
 const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode);
 void hdmi_set_supported_mode(u32 mode);
 const char *hdmi_get_video_fmt_2string(u32 format);
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index bcb3aee..7ca06ff 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -49,6 +49,7 @@
 #include "mdss.h"
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
+#include "mdss_debug.h"
 
 struct mdss_data_type *mdss_res;
 
@@ -665,7 +666,7 @@
 }
 
 static int mdss_iommu_fault_handler(struct iommu_domain *domain,
-		struct device *dev, unsigned long iova, int flags)
+		struct device *dev, unsigned long iova, int flags, void *token)
 {
 	pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
 	return 0;
@@ -757,7 +758,7 @@
 				iomap->domain_idx);
 			return -EINVAL;
 		}
-		iommu_set_fault_handler(domain, mdss_iommu_fault_handler);
+		iommu_set_fault_handler(domain, mdss_iommu_fault_handler, NULL);
 
 		iomap->ctx = msm_iommu_get_ctx(iomap->ctx_name);
 		if (!iomap->ctx) {
@@ -772,6 +773,19 @@
 	return 0;
 }
 
+static int mdss_mdp_debug_init(struct mdss_data_type *mdata)
+{
+	int rc;
+
+	rc = mdss_debugfs_init(mdata);
+	if (rc)
+		return rc;
+
+	mdss_debug_register_base(NULL, mdata->mdp_base, mdata->mdp_reg_size);
+
+	return 0;
+}
+
 static int mdss_hw_init(struct mdss_data_type *mdata)
 {
 	char *base = mdata->vbif_base;
@@ -875,8 +889,9 @@
 		goto probe_done;
 	}
 
+	mdata->mdp_reg_size = resource_size(res);
 	mdata->mdp_base = devm_ioremap(&pdev->dev, res->start,
-				       resource_size(res));
+				       mdata->mdp_reg_size);
 	if (unlikely(!mdata->mdp_base)) {
 		pr_err("unable to map MDP base\n");
 		rc = -ENOMEM;
@@ -933,6 +948,11 @@
 		pr_err("unable to register early suspend\n");
 		goto probe_done;
 	}
+
+	rc = mdss_mdp_debug_init(mdata);
+	if (rc)
+		pr_err("unable to initialize mdp debugging\n");
+
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
 		mdss_res = NULL;
@@ -1099,6 +1119,7 @@
 	mdss_mdp_pp_term(&pdev->dev);
 	mdss_mdp_bus_scale_unregister(mdata);
 	mdss_mdp_remove_early_suspend(mdata);
+	mdss_debugfs_remove(mdata);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 2e92591..d273201 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -137,6 +137,8 @@
 	struct mdss_mdp_mixer *mixer_right;
 	struct mutex lock;
 
+	struct mdss_panel_data *panel_data;
+
 	int (*start_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
@@ -241,7 +243,9 @@
 
 	unsigned long smp[MAX_PLANES];
 
-	struct mdss_mdp_data buffers[2];
+	struct mdss_mdp_data back_buf;
+	struct mdss_mdp_data front_buf;
+
 	struct list_head used_list;
 	struct list_head cleanup_list;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 00f5874..31cc527 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -107,7 +107,7 @@
 		int is_writeback = false;
 		if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
 			struct mdss_panel_info *pinfo;
-			pinfo = &mixer->ctl->mfd->panel_info;
+			pinfo = &mixer->ctl->panel_data->panel_info;
 			v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
 				   pinfo->lcdc.v_front_porch +
 				   pinfo->lcdc.v_pulse_width);
@@ -378,14 +378,21 @@
 static int mdss_mdp_ctl_init(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_ctl *ctl;
+	struct mdss_panel_data *pdata;
 	u32 width, height;
 	int ret = 0;
 
 	if (!mfd)
 		return -ENODEV;
 
-	width = mfd->fbi->var.xres;
-	height = mfd->fbi->var.yres;
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected for fb%d\n", mfd->index);
+		return -ENODEV;
+	}
+
+	width = pdata->panel_info.xres;
+	height = pdata->panel_info.yres;
 
 	if (width > (2 * MAX_MIXER_WIDTH)) {
 		pr_err("unsupported resolution\n");
@@ -400,6 +407,7 @@
 		}
 		ctl->mfd = mfd;
 		mfd->ctl = ctl;
+		ctl->panel_data = pdata;
 	} else {
 		ctl = mfd->ctl;
 	}
@@ -441,7 +449,7 @@
 		mdss_mdp_mixer_free(ctl->mixer_right);
 	}
 
-	switch (mfd->panel_info.type) {
+	switch (pdata->panel_info.type) {
 	case EDP_PANEL:
 		ctl->intf_num = MDSS_MDP_INTF0;
 		ctl->intf_type = MDSS_INTF_EDP;
@@ -449,7 +457,7 @@
 		ctl->start_fnc = mdss_mdp_video_start;
 		break;
 	case MIPI_VIDEO_PANEL:
-		if (mfd->panel_info.pdest == DISPLAY_1)
+		if (pdata->panel_info.pdest == DISPLAY_1)
 			ctl->intf_num = MDSS_MDP_INTF1;
 		else
 			ctl->intf_num = MDSS_MDP_INTF2;
@@ -469,7 +477,7 @@
 		ctl->start_fnc = mdss_mdp_writeback_start;
 		break;
 	default:
-		pr_err("unsupported panel type (%d)\n", mfd->panel_info.type);
+		pr_err("unsupported panel type (%d)\n", pdata->panel_info.type);
 		ret = -EINVAL;
 		goto ctl_init_fail;
 	}
@@ -477,14 +485,14 @@
 	ctl->opmode |= (ctl->intf_num << 4);
 
 	if (ctl->intf_num == MDSS_MDP_NO_INTF) {
-		ctl->dst_format = mfd->panel_info.out_format;
+		ctl->dst_format = pdata->panel_info.out_format;
 	} else {
 		struct mdp_dither_cfg_data dither = {
 			.block = mfd->index + MDP_LOGICAL_BLOCK_DISP_0,
 			.flags = MDP_PP_OPS_DISABLE,
 		};
 
-		switch (mfd->panel_info.bpp) {
+		switch (pdata->panel_info.bpp) {
 		case 18:
 			ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB666;
 			dither.flags = MDP_PP_OPS_ENABLE | MDP_PP_OPS_WRITE;
@@ -539,14 +547,10 @@
 int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg)
 {
 	struct mdss_panel_data *pdata;
-	if (!ctl || !ctl->mfd)
+	if (!ctl || !ctl->panel_data)
 		return -ENODEV;
 
-	pdata = dev_get_platdata(&ctl->mfd->pdev->dev);
-	if (!pdata) {
-		pr_err("no panel connected\n");
-		return -ENODEV;
-	}
+	pdata = ctl->panel_data;
 
 	pr_debug("sending ctl=%d event=%d\n", ctl->num, event);
 
@@ -596,7 +600,7 @@
 		ret = ctl->start_fnc(ctl);
 	else
 		pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
-				mfd->panel_info.type);
+				ctl->panel_data->panel_info.type);
 
 	if (ret) {
 		pr_err("unable to start intf\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 9508846..4757c63 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,26 +329,21 @@
 		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;
 }
 
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
 {
-	struct msm_fb_data_type *mfd;
 	struct mdss_panel_info *pinfo;
 	struct mdss_mdp_video_ctx *ctx;
 	struct mdss_mdp_mixer *mixer;
 	struct intf_timing_params itp = {0};
-	struct fb_info *fbi;
 	int i;
 
-	mfd = ctl->mfd;
-	fbi = mfd->fbi;
-	pinfo = &mfd->panel_info;
+	pinfo = &ctl->panel_data->panel_info;
 	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
 
 	if (!mixer) {
@@ -376,17 +365,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..5b6d009 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))))
 
@@ -429,35 +430,24 @@
 {
 	struct mdss_mdp_pipe *pipe, *tmp;
 	LIST_HEAD(destroy_pipes);
-	int i;
 
-	mutex_lock(&mfd->ov_lock);
 	mutex_lock(&mfd->lock);
 	list_for_each_entry_safe(pipe, tmp, &mfd->pipes_cleanup, cleanup_list) {
 		list_move(&pipe->cleanup_list, &destroy_pipes);
-		for (i = 0; i < ARRAY_SIZE(pipe->buffers); i++)
-			mdss_mdp_overlay_free_buf(&pipe->buffers[i]);
+		mdss_mdp_overlay_free_buf(&pipe->back_buf);
+		mdss_mdp_overlay_free_buf(&pipe->front_buf);
 	}
 
-	if (!list_empty(&mfd->pipes_used)) {
-		struct mdss_mdp_data *data;
-		int buf_ndx;
-
-		list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
-			buf_ndx = (pipe->play_cnt - 1) & 1; /* prev buffer */
-			data = &pipe->buffers[buf_ndx];
-
-			if (data->num_planes) {
-				pr_debug("free buffer ndx=%d pnum=%d\n",
-						buf_ndx, pipe->num);
-				mdss_mdp_overlay_free_buf(data);
-			}
+	list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+		if (pipe->back_buf.num_planes) {
+			/* make back buffer active */
+			mdss_mdp_overlay_free_buf(&pipe->front_buf);
+			swap(pipe->back_buf, pipe->front_buf);
 		}
 	}
 	mutex_unlock(&mfd->lock);
 	list_for_each_entry_safe(pipe, tmp, &destroy_pipes, cleanup_list)
 		mdss_mdp_pipe_destroy(pipe);
-	mutex_unlock(&mfd->ov_lock);
 
 	return 0;
 }
@@ -467,12 +457,16 @@
 	struct msm_fb_data_type *mfd = ctl->mfd;
 	int ret;
 
+	mutex_lock(&mfd->ov_lock);
+
 	if (mfd->kickoff_fnc)
 		ret = mfd->kickoff_fnc(ctl);
 	else
 		ret = mdss_mdp_display_commit(ctl, NULL);
-	if (IS_ERR_VALUE(ret))
+	if (IS_ERR_VALUE(ret)) {
+		mutex_unlock(&mfd->ov_lock);
 		return ret;
+	}
 
 	complete(&mfd->update.comp);
 	mutex_lock(&mfd->no_update.lock);
@@ -485,6 +479,8 @@
 
 	ret = mdss_mdp_overlay_cleanup(mfd);
 
+	mutex_unlock(&mfd->ov_lock);
+
 	return ret;
 }
 
@@ -629,7 +625,7 @@
 	struct mdss_mdp_ctl *ctl;
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_mdp_data *src_data;
-	int ret, buf_ndx;
+	int ret;
 	u32 flags;
 
 	pipe = mdss_mdp_pipe_get_locked(req->id);
@@ -642,9 +638,12 @@
 
 	flags = (pipe->flags & MDP_SECURE_OVERLAY_SESSION);
 
-	buf_ndx = (pipe->play_cnt + 1) & 1; /* next buffer */
-	src_data = &pipe->buffers[buf_ndx];
-	mdss_mdp_overlay_free_buf(src_data);
+	src_data = &pipe->back_buf;
+	if (src_data->num_planes) {
+		pr_warn("dropped buffer pnum=%d play=%d addr=0x%x\n",
+			pipe->num, pipe->play_cnt, src_data->p[0].addr);
+		mdss_mdp_overlay_free_buf(src_data);
+	}
 
 	ret = mdss_mdp_overlay_get_buf(mfd, src_data, &req->data, 1, flags);
 	if (IS_ERR_VALUE(ret)) {
@@ -681,7 +680,7 @@
 	} else {
 		ret = mdss_mdp_overlay_queue(mfd, req);
 
-		if ((ret == 0) && (mfd->panel_info.type == WRITEBACK_PANEL)) {
+		if ((ret == 0) && (mfd->panel.type == WRITEBACK_PANEL)) {
 			mutex_unlock(&mfd->ov_lock);
 			ret = mdss_mdp_overlay_kickoff(mfd->ctl);
 			return ret;
@@ -837,30 +836,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 +864,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 +891,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)
 {
@@ -1118,7 +1165,7 @@
 		ret = mdss_mdp_overlay_kickoff(mfd->ctl);
 		break;
 	default:
-		if (mfd->panel_info.type == WRITEBACK_PANEL)
+		if (mfd->panel.type == WRITEBACK_PANEL)
 			ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
 		break;
 	}
@@ -1154,6 +1201,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;
@@ -1163,12 +1213,23 @@
 	mfd->dma_fnc = mdss_mdp_overlay_pan_display;
 	mfd->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
 
-	if (mfd->panel_info.type == WRITEBACK_PANEL)
+	if (mfd->panel.type == WRITEBACK_PANEL)
 		mfd->kickoff_fnc = mdss_mdp_wb_kickoff;
 
 	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/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 28d7051..d807493 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -64,6 +64,7 @@
 	MDSS_EVENT_CLOSE,
 	MDSS_EVENT_SUSPEND,
 	MDSS_EVENT_RESUME,
+	MDSS_EVENT_CHECK_PARAMS,
 };
 
 /* panel info type */
@@ -179,6 +180,7 @@
 	u32 frame_count;
 	u32 is_3d_panel;
 	u32 out_format;
+	u32 vic; /* video identification code */
 
 	struct lcd_panel_info lcd;
 	struct lcdc_panel_info lcdc;
diff --git a/drivers/video/msm/mdss/mdss_wb.c b/drivers/video/msm/mdss/mdss_wb.c
index c3dc06b..47dc2c8 100644
--- a/drivers/video/msm/mdss/mdss_wb.c
+++ b/drivers/video/msm/mdss/mdss_wb.c
@@ -25,11 +25,49 @@
 
 #include "mdss_panel.h"
 
+/**
+ * mdss_wb_check_params - check new panel info params
+ * @pdata: current panel information
+ * @new: updates to panel info
+ *
+ * Checks if there are any changes that require panel reconfiguration
+ * in order to be reflected on writeback buffer.
+ *
+ * Return negative errno if invalid input, zero if there is no panel reconfig
+ * needed and non-zero if reconfiguration is needed.
+ */
+static int mdss_wb_check_params(struct mdss_panel_data *pdata,
+	struct mdss_panel_info *new)
+{
+	struct mdss_panel_info *old;
+
+	if (!pdata || !new) {
+		pr_err("%s: Invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	old = &pdata->panel_info;
+
+	if ((old->xres != new->xres) || (old->yres != new->yres))
+		return 1;
+
+	return 0;
+}
+
 static int mdss_wb_event_handler(struct mdss_panel_data *pdata,
 				 int event, void *arg)
 {
-	pr_debug("%s: event=%d\n", __func__, event);
-	return 0;
+	int rc = 0;
+
+	switch (event) {
+	case MDSS_EVENT_CHECK_PARAMS:
+		rc = mdss_wb_check_params(pdata, (struct mdss_panel_info *)arg);
+		break;
+	default:
+		pr_debug("%s: panel event (%d) not handled\n", __func__, event);
+		break;
+	}
+	return rc;
 }
 
 static int mdss_wb_parse_dt(struct platform_device *pdev,
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index 2711c1a..d4d7288 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -264,7 +264,8 @@
 typedef void (*fxn)(u32 data);
 
 #define CMD_REQ_RX	0x0001
-#define CMD_REQ_COMMIT 0x0002
+#define CMD_REQ_COMMIT	0x0002
+#define CMD_CLK_CTRL	0x0004
 #define CMD_REQ_NO_MAX_PKT_SIZE 0x0008
 
 struct dcs_cmd_req {
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index bea6b4e..ee4a578 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -1249,7 +1249,6 @@
 	/* transmit read comamnd to client */
 	mipi_dsi_cmd_dma_tx(tp);
 
-	mipi_dsi_disable_irq(DSI_CMD_TERM);
 	/*
 	 * once cmd_dma_done interrupt received,
 	 * return data from client is ready and stored
@@ -1359,7 +1358,6 @@
 	/* transmit read comamnd to client */
 	mipi_dsi_cmd_dma_tx(tp);
 
-	mipi_dsi_disable_irq(DSI_CMD_TERM);
 	/*
 	 * once cmd_dma_done interrupt received,
 	 * return data from client is ready and stored
@@ -1580,7 +1578,6 @@
 void mipi_dsi_cmdlist_commit(int from_mdp)
 {
 	struct dcs_cmd_req *req;
-	int video;
 	u32 dsi_ctrl;
 
 	mutex_lock(&cmd_mutex);
@@ -1592,12 +1589,6 @@
 	if (req == NULL)
 		goto need_lock;
 
-	video = MIPI_INP(MIPI_DSI_BASE + 0x0000);
-	video &= 0x02; /* VIDEO_MODE */
-
-	if (!video)
-		mipi_dsi_clk_cfg(1);
-
 	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
 
 	dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000);
@@ -1619,9 +1610,6 @@
 	else
 		mipi_dsi_cmdlist_tx(req);
 
-	if (!video)
-		mipi_dsi_clk_cfg(0);
-
 need_lock:
 
 	if (from_mdp) /* from pipe_commit */
@@ -1655,9 +1643,15 @@
 	pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
 		cmdlist.tot, cmdlist.put, cmdlist.get);
 
+	if (req->flags & CMD_CLK_CTRL)
+		mipi_dsi_clk_cfg(1);
+
 	if (req->flags & CMD_REQ_COMMIT)
 		mipi_dsi_cmdlist_commit(0);
 
+	if (req->flags & CMD_CLK_CTRL)
+		mipi_dsi_clk_cfg(0);
+
 	return ret;
 }
 
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index ecac82d..68bc65e 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -476,7 +476,7 @@
 
 	cmdreq.cmds = &backlight_cmd;
 	cmdreq.cmds_cnt = 1;
-	cmdreq.flags = CMD_REQ_COMMIT;
+	cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL;
 	cmdreq.rlen = 0;
 	cmdreq.cb = NULL;
 
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 993ec01..b7e0bbf 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1286,27 +1286,8 @@
 	var->yres_virtual = panel_info->yres * mfd->fb_page +
 		((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page;
 	var->bits_per_pixel = bpp * 8;	/* FrameBuffer color depth */
-	if (mfd->dest == DISPLAY_LCD) {
-		if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1)
-			var->reserved[4] = panel_info->lcd.refx100 / (100 * 2);
-		else
-			var->reserved[4] = panel_info->lcd.refx100 / 100;
-	} else {
-		if (panel_info->type == MIPI_VIDEO_PANEL) {
-			var->reserved[4] = panel_info->mipi.frame_rate;
-		} else {
-			var->reserved[4] = panel_info->clk_rate /
-				((panel_info->lcdc.h_back_porch +
-				  panel_info->lcdc.h_front_porch +
-				  panel_info->lcdc.h_pulse_width +
-				  panel_info->xres) *
-				 (panel_info->lcdc.v_back_porch +
-				  panel_info->lcdc.v_front_porch +
-				  panel_info->lcdc.v_pulse_width +
-				  panel_info->yres));
-		}
-	}
-	pr_debug("reserved[4] %u\n", var->reserved[4]);
+
+	var->reserved[4] = mdp_get_panel_framerate(mfd);
 
 		/*
 		 * id field for fb app
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..8836b33 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -275,6 +275,7 @@
 	struct ddl_enc_buffers  hw_bufs;
 	struct ddl_yuv_buffer_size  input_buf_size;
 	struct vidc_1080p_enc_frame_info enc_frame_info;
+	u32  plusptype_enable;
 	u32  meta_data_enable_flag;
 	u32  suffix;
 	u32  meta_data_offset;
@@ -293,6 +294,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..d189408 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..2b65d7e 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,35 @@
 		}
 		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;
+	}
+	case VCD_I_H263_PLUSPTYPE:
+	{
+		struct vcd_property_plusptype *plusptype =
+			(struct vcd_property_plusptype *)property_value;
+
+		if ((sizeof(struct vcd_property_plusptype) ==
+			property_hdr->sz) && encoder->codec.codec ==
+			VCD_CODEC_H263) {
+			encoder->plusptype_enable = plusptype->plusptype_enable;
+			DDL_MSG_LOW("\nencoder->plusptype_enable = %u",
+						encoder->plusptype_enable);
+			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 +1582,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 +1753,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)
@@ -2145,5 +2184,6 @@
 		encoder->frame_rate.fps_denominator = 1;
 		ddl_set_default_enc_property(ddl);
 		encoder->sps_pps.sps_pps_for_idr_enable_flag = false;
+		encoder->plusptype_enable = 0;
 	}
 }
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..4963874 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
@@ -38,13 +38,15 @@
 #define DDL_MSG_LOW(x...)    printk(KERN_INFO x)
 #define DDL_MSG_MED(x...)    printk(KERN_INFO x)
 #define DDL_MSG_HIGH(x...)   printk(KERN_INFO x)
+#define DDL_MSG_ERROR(x...)  printk(KERN_INFO x)
 #else
 #define DDL_MSG_LOW(x...)
 #define DDL_MSG_MED(x...)
 #define DDL_MSG_HIGH(x...)
+#define DDL_MSG_ERROR(x...)
 #endif
 
-#define DDL_MSG_ERROR(x...)  printk(KERN_INFO x)
+
 #define DDL_MSG_FATAL(x...)  printk(KERN_INFO x)
 
 #define DDL_ALIGN_SIZE(sz, guard_bytes, align_mask) \
@@ -62,7 +64,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..1bf242d 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);
 		}
@@ -590,13 +599,20 @@
 			encoder->frame_rate.fps_denominator;
 	if ((encoder->codec.codec == VCD_CODEC_H263) &&
 		(DDL_FRAMERATE_SCALE(DDL_INITIAL_FRAME_RATE)
-		 != scaled_frame_rate))
+		 != scaled_frame_rate) && encoder->plusptype_enable)
 		h263_cpfc_enable = true;
 	vidc_sm_set_extended_encoder_control(&ddl->shared_mem
 		[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/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index c7237e4..763fbda 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -1624,6 +1624,29 @@
 		}
 		break;
 	}
+	case VEN_IOCTL_SET_H263_PLUSPTYPE:
+	{
+		struct vcd_property_hdr vcd_property_hdr;
+		struct venc_plusptype plusptype;
+		u32 enable;
+		u32 vcd_status = VCD_ERR_FAIL;
+		if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+			return -EFAULT;
+		if (copy_from_user(&plusptype, venc_msg.in,
+			sizeof(plusptype)))
+			return -EFAULT;
+		vcd_property_hdr.prop_id = VCD_I_H263_PLUSPTYPE;
+		vcd_property_hdr.sz = sizeof(u32);
+		enable = plusptype.plusptype_enable;
+		DBG("VEN_IOCTL_SET PLUSPTYPE = %d\n", enable);
+		vcd_status = vcd_set_property(client_ctx->vcd_handle,
+						&vcd_property_hdr, &enable);
+		if (vcd_status) {
+			pr_err(" Setting plusptype failed");
+			return -EIO;
+		}
+		break;
+	}
 	case VEN_IOCTL_SET_AC_PREDICTION:
 	case VEN_IOCTL_GET_AC_PREDICTION:
 	case VEN_IOCTL_SET_RVLC:
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/drivers/video/msm/vidc/common/vcd/vcd_util.h b/drivers/video/msm/vidc/common/vcd/vcd_util.h
index 7164029..ed7fc1a 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_util.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_util.h
@@ -20,16 +20,16 @@
 #define VCD_MSG_LOW(xx_fmt...)		printk(KERN_INFO "\n\t* " xx_fmt)
 #define VCD_MSG_MED(xx_fmt...)		printk(KERN_INFO "\n  * " xx_fmt)
 #define VCD_MSG_HIGH(xx_fmt...)		printk(KERN_WARNING "\n" xx_fmt)
-
+#define VCD_MSG_ERROR(xx_fmt...)	printk(KERN_ERR "\n err: " xx_fmt)
 #else
 
 #define VCD_MSG_LOW(xx_fmt...)
 #define VCD_MSG_MED(xx_fmt...)
 #define VCD_MSG_HIGH(xx_fmt...)
-
+#define VCD_MSG_ERROR(xx_fmt...)
 #endif
 
-#define VCD_MSG_ERROR(xx_fmt...)	printk(KERN_ERR "\n err: " xx_fmt)
+
 #define VCD_MSG_FATAL(xx_fmt...)	printk(KERN_ERR "\n<FATAL> " xx_fmt)
 
 #define VCD_FAILED_RETURN(rc, xx_fmt...)		\
diff --git a/fs/buffer.c b/fs/buffer.c
index ad5938c..35ac651 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1399,12 +1399,49 @@
 	return 0;
 }
 
+static void __evict_bh_lru(void *arg)
+{
+	struct bh_lru *b = &get_cpu_var(bh_lrus);
+	struct buffer_head *bh = arg;
+	int i;
+
+	for (i = 0; i < BH_LRU_SIZE; i++) {
+		if (b->bhs[i] == bh) {
+			brelse(b->bhs[i]);
+			b->bhs[i] = NULL;
+			goto out;
+		}
+	}
+out:
+	put_cpu_var(bh_lrus);
+}
+
+static bool bh_exists_in_lru(int cpu, void *arg)
+{
+	struct bh_lru *b = per_cpu_ptr(&bh_lrus, cpu);
+	struct buffer_head *bh = arg;
+	int i;
+
+	for (i = 0; i < BH_LRU_SIZE; i++) {
+		if (b->bhs[i] == bh)
+			return 1;
+	}
+
+	return 0;
+
+}
 void invalidate_bh_lrus(void)
 {
 	on_each_cpu_cond(has_bh_in_lru, invalidate_bh_lru, NULL, 1, GFP_KERNEL);
 }
 EXPORT_SYMBOL_GPL(invalidate_bh_lrus);
 
+void evict_bh_lrus(struct buffer_head *bh)
+{
+	on_each_cpu_cond(bh_exists_in_lru, __evict_bh_lru, bh, 1, GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(evict_bh_lrus);
+
 void set_bh_page(struct buffer_head *bh,
 		struct page *page, unsigned long offset)
 {
@@ -3054,8 +3091,15 @@
 	do {
 		if (buffer_write_io_error(bh) && page->mapping)
 			set_bit(AS_EIO, &page->mapping->flags);
-		if (buffer_busy(bh))
-			goto failed;
+		if (buffer_busy(bh)) {
+			/*
+			 * Check if the busy failure was due to an
+			 * outstanding LRU reference
+			 */
+			evict_bh_lrus(bh);
+			if (buffer_busy(bh))
+				goto failed;
+		}
 		bh = bh->b_this_page;
 	} while (bh != head);
 
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 504e61b..6e0f58b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -663,6 +663,42 @@
 			return PTR_ERR(req);
 		}
 	}
+
+#ifdef CONFIG_DMA_CMA
+	if (is_cma_pageblock(page)) {
+		struct page *oldpage = page, *newpage;
+		int err;
+
+		/* make sure that old page is not free in-between the calls */
+		page_cache_get(oldpage);
+
+		newpage = alloc_page(GFP_HIGHUSER);
+		if (!newpage) {
+			page_cache_release(oldpage);
+			return -ENOMEM;
+		}
+
+		err = replace_page_cache_page(oldpage, newpage, GFP_KERNEL);
+		if (err) {
+			__free_page(newpage);
+			page_cache_release(oldpage);
+			return err;
+		}
+
+		/*
+		 * Decrement the count on new page to make page cache the only
+		 * owner of it
+		 */
+		lock_page(newpage);
+		put_page(newpage);
+
+		/* finally release the old page and swap pointers */
+		unlock_page(oldpage);
+		page_cache_release(oldpage);
+		page = newpage;
+	}
+#endif
+
 	page_cache_get(page);
 	req->pages[req->num_pages] = page;
 	req->num_pages++;
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 98cce5b..46ae59f 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -445,4 +445,6 @@
 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
+header-y += avtimer.h
diff --git a/include/linux/avtimer.h b/include/linux/avtimer.h
new file mode 100644
index 0000000..e68da6a
--- /dev/null
+++ b/include/linux/avtimer.h
@@ -0,0 +1,21 @@
+#ifndef AVTIMER_H
+#define AVTIMER_H
+
+#include <linux/ioctl.h>
+
+#define MAJOR_NUM 100
+
+#define IOCTL_GET_AVTIMER_TICK _IOR(MAJOR_NUM, 0, char *)
+/*
+ * This IOCTL is used read the avtimer tick value.
+ * Avtimer is a 64 bit timer tick, hence the expected
+ * argument is of type uint64_t
+ */
+struct dev_avtimer_data {
+	uint32_t avtimer_msw_phy_addr;
+	uint32_t avtimer_lsw_phy_addr;
+};
+int avcs_core_open(void);
+int avcs_core_disable_power_collapse(int disable);/* true or flase */
+
+#endif
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index e76b0ae..6502841 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -282,6 +282,7 @@
 	struct request_list	rq;
 
 	request_fn_proc		*request_fn;
+	request_fn_proc		*urgent_request_fn;
 	make_request_fn		*make_request_fn;
 	prep_rq_fn		*prep_rq_fn;
 	unprep_rq_fn		*unprep_rq_fn;
@@ -365,6 +366,8 @@
 	struct list_head	icq_list;
 
 	struct queue_limits	limits;
+	bool			notified_urgent;
+	bool			dispatched_urgent;
 
 	/*
 	 * sg stuff
@@ -673,6 +676,8 @@
 extern struct request *blk_make_request(struct request_queue *, struct bio *,
 					gfp_t);
 extern void blk_requeue_request(struct request_queue *, struct request *);
+extern int blk_reinsert_request(struct request_queue *q, struct request *rq);
+extern bool blk_reinsert_req_sup(struct request_queue *q);
 extern void blk_add_request_payload(struct request *rq, struct page *page,
 		unsigned int len);
 extern int blk_rq_check_limits(struct request_queue *q, struct request *rq);
@@ -822,6 +827,7 @@
 extern struct request_queue *blk_init_queue(request_fn_proc *, spinlock_t *);
 extern struct request_queue *blk_init_allocated_queue(struct request_queue *,
 						      request_fn_proc *, spinlock_t *);
+extern void blk_urgent_request(struct request_queue *q, request_fn_proc *fn);
 extern void blk_cleanup_queue(struct request_queue *);
 extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
 extern void blk_queue_bounce_limit(struct request_queue *, u64);
diff --git a/include/linux/device.h b/include/linux/device.h
index 9fca83b..40374ce 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -35,6 +35,7 @@
 struct bus_type;
 struct device_node;
 struct iommu_ops;
+struct iommu_group;
 
 struct bus_attribute {
 	struct attribute	attr;
@@ -686,6 +687,7 @@
 	const struct attribute_group **groups;	/* optional groups */
 
 	void	(*release)(struct device *dev);
+	struct iommu_group	*iommu_group;
 };
 
 /* Get the wakeup routines, which depend on struct device */
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 7d4e035..b36b28f 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -22,6 +22,9 @@
 typedef int (elevator_dispatch_fn) (struct request_queue *, int);
 
 typedef void (elevator_add_req_fn) (struct request_queue *, struct request *);
+typedef int (elevator_reinsert_req_fn) (struct request_queue *,
+					struct request *);
+typedef bool (elevator_is_urgent_fn) (struct request_queue *);
 typedef struct request *(elevator_request_list_fn) (struct request_queue *, struct request *);
 typedef void (elevator_completed_req_fn) (struct request_queue *, struct request *);
 typedef int (elevator_may_queue_fn) (struct request_queue *, int);
@@ -46,6 +49,9 @@
 
 	elevator_dispatch_fn *elevator_dispatch_fn;
 	elevator_add_req_fn *elevator_add_req_fn;
+	elevator_reinsert_req_fn *elevator_reinsert_req_fn;
+	elevator_is_urgent_fn *elevator_is_urgent_fn;
+
 	elevator_activate_req_fn *elevator_activate_req_fn;
 	elevator_deactivate_req_fn *elevator_deactivate_req_fn;
 
@@ -122,6 +128,7 @@
 extern void elv_bio_merged(struct request_queue *q, struct request *,
 				struct bio *);
 extern void elv_requeue_request(struct request_queue *, struct request *);
+extern int elv_reinsert_request(struct request_queue *, struct request *);
 extern struct request *elv_former_request(struct request_queue *, struct request *);
 extern struct request *elv_latter_request(struct request_queue *, struct request *);
 extern int elv_register_queue(struct request_queue *q);
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index ca1a425..14cb148 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -13,55 +13,54 @@
 	int32_t physical;
 };
 
-#ifdef __KERNEL__
 struct epm_psoc_init_resp {
-	u8	cmd;
-	u8	version;
-	u8	compatible_ver;
-	u8	firm_ver[3];
-	u8	num_dev;
-	u8	num_channel;
+	uint8_t	cmd;
+	uint8_t	version;
+	uint8_t	compatible_ver;
+	uint8_t	firm_ver[3];
+	uint8_t	num_dev;
+	uint8_t	num_channel;
 };
 
 struct epm_psoc_channel_configure {
-	u8		cmd;
-	u8		device_num;
+	uint8_t		cmd;
+	uint8_t		device_num;
 	uint32_t	channel_num;
 };
 
 struct epm_psoc_set_avg {
-	u8	cmd;
-	u8	avg_period;
-	u8	return_code;
+	uint8_t	cmd;
+	uint8_t	avg_period;
+	uint8_t	return_code;
 };
 
 struct epm_psoc_get_data {
-	u8		cmd;
-	u8		dev_num;
-	u8		chan_num;
+	uint8_t		cmd;
+	uint8_t		dev_num;
+	uint8_t		chan_num;
 	uint32_t	timestamp_resp_value;
 	uint32_t	reading_value;
 };
 
 struct epm_psoc_get_buffered_data {
-	u8		cmd;
-	u8		dev_num;
-	u8		status_mask;
-	u8		chan_idx;
+	uint8_t		cmd;
+	uint8_t		dev_num;
+	uint8_t		status_mask;
+	uint8_t		chan_idx;
 	uint32_t	chan_mask;
 	uint32_t	timestamp_start;
 	uint32_t	timestamp_end;
-	u8		buff_data[48];
+	uint8_t		buff_data[48];
 };
 
 struct epm_psoc_system_time_stamp {
-	u8		cmd;
+	uint8_t		cmd;
 	uint32_t	timestamp;
 };
 
 struct epm_psoc_set_channel {
-	u8		cmd;
-	u8		dev_num;
+	uint8_t		cmd;
+	uint8_t		dev_num;
 	uint32_t	channel_mask;
 };
 
@@ -72,23 +71,23 @@
 };
 
 struct epm_psoc_get_avg_buffered_switch_data {
-	u8			cmd;
-	u8			status;
+	uint8_t			cmd;
+	uint8_t			status;
 	uint32_t		timestamp_start;
 	uint32_t		channel_mask;
-	u8			avg_data[54];
+	uint8_t			avg_data[54];
 	struct result_buffer	data[54];
 };
 
 struct epm_psoc_set_channel_switch {
-	u8		cmd;
-	u8		dev;
+	uint8_t		cmd;
+	uint8_t		dev;
 	uint32_t	delay;
 };
 
 struct epm_psoc_set_vadc {
-	u8		cmd;
-	u8		vadc_dev;
+	uint8_t		cmd;
+	uint8_t		vadc_dev;
 	uint32_t	vadc_voltage;
 };
 
@@ -97,6 +96,7 @@
 	uint32_t gain;
 };
 
+#ifdef __KERNEL__
 struct epm_adc_platform_data {
 	struct epm_chan_properties *channel;
 	uint32_t num_channels;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 95b15d6..d4fa3aa 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -22,12 +22,14 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/scatterlist.h>
+#include <linux/err.h>
 
 #define IOMMU_READ	(1)
 #define IOMMU_WRITE	(2)
 #define IOMMU_CACHE	(4) /* DMA cache coherency */
 
 struct iommu_ops;
+struct iommu_group;
 struct bus_type;
 struct device;
 struct iommu_domain;
@@ -37,12 +39,13 @@
 #define IOMMU_FAULT_WRITE	0x1
 
 typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
-				struct device *, unsigned long, int);
+			struct device *, unsigned long, int, void *);
 
 struct iommu_domain {
 	struct iommu_ops *ops;
 	void *priv;
 	iommu_fault_handler_t handler;
+	void *handler_token;
 };
 
 #define IOMMU_CAP_CACHE_COHERENCY	0x1
@@ -61,6 +64,8 @@
  * @iova_to_phys: translate iova to physical address
  * @domain_has_cap: domain capabilities query
  * @commit: commit iommu domain
+ * @add_device: add device to iommu grouping
+ * @remove_device: remove device from iommu grouping
  * @pgsize_bitmap: bitmap of supported page sizes
  */
 struct iommu_ops {
@@ -81,10 +86,18 @@
 	int (*domain_has_cap)(struct iommu_domain *domain,
 			      unsigned long cap);
 	phys_addr_t (*get_pt_base_addr)(struct iommu_domain *domain);
-	int (*device_group)(struct device *dev, unsigned int *groupid);
+	int (*add_device)(struct device *dev);
+	void (*remove_device)(struct device *dev);
 	unsigned long pgsize_bitmap;
 };
 
+#define IOMMU_GROUP_NOTIFY_ADD_DEVICE		1 /* Device added */
+#define IOMMU_GROUP_NOTIFY_DEL_DEVICE		2 /* Pre Device removed */
+#define IOMMU_GROUP_NOTIFY_BIND_DRIVER		3 /* Pre Driver bind */
+#define IOMMU_GROUP_NOTIFY_BOUND_DRIVER		4 /* Post Driver bind */
+#define IOMMU_GROUP_NOTIFY_UNBIND_DRIVER	5 /* Pre Driver unbind */
+#define IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER	6 /* Post Driver unbind */
+
 extern int bus_set_iommu(struct bus_type *bus, struct iommu_ops *ops);
 extern bool iommu_present(struct bus_type *bus);
 extern struct iommu_domain *iommu_domain_alloc(struct bus_type *bus, int flags);
@@ -107,8 +120,30 @@
 				unsigned long cap);
 extern phys_addr_t iommu_get_pt_base_addr(struct iommu_domain *domain);
 extern void iommu_set_fault_handler(struct iommu_domain *domain,
-					iommu_fault_handler_t handler);
-extern int iommu_device_group(struct device *dev, unsigned int *groupid);
+			iommu_fault_handler_t handler, void *token);
+
+extern int iommu_attach_group(struct iommu_domain *domain,
+			      struct iommu_group *group);
+extern void iommu_detach_group(struct iommu_domain *domain,
+			       struct iommu_group *group);
+extern struct iommu_group *iommu_group_alloc(void);
+extern void *iommu_group_get_iommudata(struct iommu_group *group);
+extern void iommu_group_set_iommudata(struct iommu_group *group,
+				      void *iommu_data,
+				      void (*release)(void *iommu_data));
+extern int iommu_group_set_name(struct iommu_group *group, const char *name);
+extern int iommu_group_add_device(struct iommu_group *group,
+				  struct device *dev);
+extern void iommu_group_remove_device(struct device *dev);
+extern int iommu_group_for_each_dev(struct iommu_group *group, void *data,
+				    int (*fn)(struct device *, void *));
+extern struct iommu_group *iommu_group_get(struct device *dev);
+extern void iommu_group_put(struct iommu_group *group);
+extern int iommu_group_register_notifier(struct iommu_group *group,
+					 struct notifier_block *nb);
+extern int iommu_group_unregister_notifier(struct iommu_group *group,
+					   struct notifier_block *nb);
+extern int iommu_group_id(struct iommu_group *group);
 
 /**
  * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework
@@ -144,7 +179,8 @@
 	 * invoke it.
 	 */
 	if (domain->handler)
-		ret = domain->handler(domain, dev, iova, flags);
+		ret = domain->handler(domain, dev, iova, flags,
+						domain->handler_token);
 
 	return ret;
 }
@@ -152,6 +188,7 @@
 #else /* CONFIG_IOMMU_API */
 
 struct iommu_ops {};
+struct iommu_group {};
 
 static inline bool iommu_present(struct bus_type *bus)
 {
@@ -221,15 +258,85 @@
 }
 
 static inline void iommu_set_fault_handler(struct iommu_domain *domain,
-					iommu_fault_handler_t handler)
+				iommu_fault_handler_t handler, void *token)
 {
 }
 
-static inline int iommu_device_group(struct device *dev, unsigned int *groupid)
+static inline int iommu_attach_group(struct iommu_domain *domain,
+				     struct iommu_group *group)
 {
 	return -ENODEV;
 }
 
+static inline void iommu_detach_group(struct iommu_domain *domain,
+				      struct iommu_group *group)
+{
+}
+
+static inline struct iommu_group *iommu_group_alloc(void)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline void *iommu_group_get_iommudata(struct iommu_group *group)
+{
+	return NULL;
+}
+
+static inline void iommu_group_set_iommudata(struct iommu_group *group,
+					     void *iommu_data,
+					     void (*release)(void *iommu_data))
+{
+}
+
+static inline int iommu_group_set_name(struct iommu_group *group,
+				       const char *name)
+{
+	return -ENODEV;
+}
+
+static inline int iommu_group_add_device(struct iommu_group *group,
+					 struct device *dev)
+{
+	return -ENODEV;
+}
+
+static inline void iommu_group_remove_device(struct device *dev)
+{
+}
+
+static inline int iommu_group_for_each_dev(struct iommu_group *group,
+					   void *data,
+					   int (*fn)(struct device *, void *))
+{
+	return -ENODEV;
+}
+
+static inline struct iommu_group *iommu_group_get(struct device *dev)
+{
+	return NULL;
+}
+
+static inline void iommu_group_put(struct iommu_group *group)
+{
+}
+
+static inline int iommu_group_register_notifier(struct iommu_group *group,
+				  struct notifier_block *nb)
+{
+	return -ENODEV;
+}
+
+static inline int iommu_group_unregister_notifier(struct iommu_group *group,
+				    struct notifier_block *nb)
+{
+	return 0;
+}
+
+static inline int iommu_group_id(struct iommu_group *group)
+{
+	return -ENODEV;
+}
 #endif /* CONFIG_IOMMU_API */
 
 #endif /* __LINUX_IOMMU_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..44f8538 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
@@ -126,6 +123,21 @@
  *			resistance of the pads, connectors, battery terminals
  *			and rsense.
  * @led_src_config:	Power source for anode of charger indicator LED.
+ * @btc_override:	disable the comparators for conifugrations where a
+ *			suitable voltages don't appear on vbatt therm line
+ *			for the charger to detect battery is either cold / hot.
+ * @btc_override_cold_degc:	Temperature in degCelcius when the battery is
+ *				deemed cold and charging never happens. Used
+ *				only if btc_override = 1
+ * @btc_override_hot_degc:	Temperature in degCelcius when the battery is
+ *				deemed hot and charging never happens. Used
+ *				only if btc_override = 1
+ * @btc_delay_ms:	Delay in milliseconds to monitor the battery temperature
+ *			while charging when btc_override = 1
+ * @btc_panic_if_cant_stop_chg:	flag to instruct the driver to panic if the
+ *				driver couldn't stop charging when battery
+ *				temperature is out of bounds. Used only if
+ *				btc_override = 1
  */
 struct pm8921_charger_platform_data {
 	struct pm8xxx_charger_core_data	charger_cdata;
@@ -144,6 +156,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 +165,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;
@@ -166,6 +178,11 @@
 	int				rconn_mohm;
 	enum pm8921_chg_led_src_config	led_src_config;
 	int				battery_less_hardware;
+	int				btc_override;
+	int				btc_override_cold_degc;
+	int				btc_override_hot_degc;
+	int				btc_delay_ms;
+	int				btc_panic_if_cant_stop_chg;
 };
 
 enum pm8921_charger_source {
@@ -178,15 +195,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 +320,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/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 4e9e1ce..2874a3b 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -22,10 +22,6 @@
 #define WCD9XXX_NUM_IRQ_REGS 4
 
 #define WCD9XXX_SLIM_NUM_PORT_REG 3
-
-#define WCD9XXX_INTERFACE_TYPE_SLIMBUS	0x00
-#define WCD9XXX_INTERFACE_TYPE_I2C	0x01
-
 #define TABLA_VERSION_1_0	0
 #define TABLA_VERSION_1_1	1
 #define TABLA_VERSION_2_0	2
@@ -135,6 +131,12 @@
 	wait_queue_head_t dai_wait;
 };
 
+enum wcd9xxx_intf_status {
+	WCD9XXX_INTERFACE_TYPE_PROBING,
+	WCD9XXX_INTERFACE_TYPE_SLIMBUS,
+	WCD9XXX_INTERFACE_TYPE_I2C,
+};
+
 #define WCD9XXX_CH(xport, xshift) \
 	{.port = xport, .shift = xshift}
 
@@ -177,6 +179,7 @@
 	u32 num_tx_port;
 	struct wcd9xxx_ch *rx_chs;
 	struct wcd9xxx_ch *tx_chs;
+	u32 mclk_rate;
 };
 
 int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
@@ -192,7 +195,7 @@
 int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx);
 void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx);
 int wcd9xxx_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
-int wcd9xxx_get_intf_type(void);
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
 
 bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx);
 void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx);
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index a7ca417..bfd95a6 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -154,6 +154,7 @@
 	struct wcd9xxx_micbias_setting micbias;
 	struct wcd9xxx_ocp_setting ocp;
 	struct wcd9xxx_regulator regulator[MAX_REGULATOR];
+	u32 mclk_rate;
 };
 
 #endif
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 2046198..ec1d619 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -88,6 +88,7 @@
 	bool			boot_ro_lockable;
 	u8			raw_exception_status;	/* 53 */
 	u8			raw_partition_support;	/* 160 */
+	u8			raw_rpmb_size_mult;	/* 168 */
 	u8			raw_erased_mem_count;	/* 181 */
 	u8			raw_ext_csd_structure;	/* 194 */
 	u8			raw_card_type;		/* 196 */
@@ -228,6 +229,7 @@
 #define MMC_BLK_DATA_AREA_MAIN	(1<<0)
 #define MMC_BLK_DATA_AREA_BOOT	(1<<1)
 #define MMC_BLK_DATA_AREA_GP	(1<<2)
+#define MMC_BLK_DATA_AREA_RPMB	(1<<3)
 };
 
 #define BKOPS_NUM_OF_SEVERITY_LEVELS	3
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 7247696..24b9790 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -178,6 +178,8 @@
 extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
 
 extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+extern int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
+			      bool is_rel_write);
 extern int mmc_hw_reset(struct mmc_host *host);
 extern int mmc_hw_reset_check(struct mmc_host *host);
 extern int mmc_can_reset(struct mmc_card *card);
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/mmc/mmc.h b/include/linux/mmc/mmc.h
index 237a92e..46479a7 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -290,6 +290,7 @@
 #define EXT_CSD_BKOPS_START		164	/* W */
 #define EXT_CSD_SANITIZE_START		165     /* W */
 #define EXT_CSD_WR_REL_PARAM		166	/* RO */
+#define EXT_CSD_RPMB_MULT		168	/* RO */
 #define EXT_CSD_BOOT_WP			173	/* R/W */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
 #define EXT_CSD_PART_CONFIG		179	/* R/W */
@@ -346,6 +347,7 @@
 #define EXT_CSD_PART_CONFIG_ACC_MASK	(0x7)
 #define EXT_CSD_PART_CONFIG_ACC_BOOT0	(0x1)
 #define EXT_CSD_PART_CONFIG_ACC_BOOT1	(0x2)
+#define EXT_CSD_PART_CONFIG_ACC_RPMB	(0x3)
 #define EXT_CSD_PART_CONFIG_ACC_GP0	(0x4)
 
 #define EXT_CSD_PART_SUPPORT_PART_EN	(0x1)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 08f74e6..7bdd3f2 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -61,18 +61,12 @@
 	MIGRATE_TYPES
 };
 
-/*
- * Returns a list which contains the migrate types on to which
- * an allocation falls back when the free list for the migrate
- * type mtype is depleted.
- * The end of the list is delimited by the type MIGRATE_RESERVE.
- */
-extern int *get_migratetype_fallbacks(int mtype);
-
 #ifdef CONFIG_CMA
+bool is_cma_pageblock(struct page *page);
 #  define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
 #  define cma_wmark_pages(zone)	zone->min_cma_pages
 #else
+#  define is_cma_pageblock(page) false
 #  define is_migrate_cma(migratetype) false
 #  define cma_wmark_pages(zone) 0
 #endif
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_ion.h b/include/linux/msm_ion.h
index ec043dd..d423b26 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -137,6 +137,7 @@
  *			goes from 1 -> 0
  * @setup_region:	function to be called upon ion registration
  * @memory_type:Memory type used for the heap
+ * @no_nonsecure_alloc: don't allow non-secure allocations from this heap
  *
  */
 struct ion_cp_heap_pdata {
@@ -146,6 +147,7 @@
 	size_t secure_size; /* Size used for securing heap when heap is shared*/
 	int reusable;
 	int mem_is_fmem;
+	int is_cma;
 	enum ion_fixed_position fixed_position;
 	int iommu_map_all;
 	int iommu_2x_map_domain;
@@ -154,6 +156,7 @@
 	int (*release_region)(void *);
 	void *(*setup_region)(void);
 	enum ion_memory_types memory_type;
+	int no_nonsecure_alloc;
 };
 
 /**
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/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index 519c537..ea7db81 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -458,6 +458,9 @@
 #define VEN_IOCTL_SET_SLICE_DELIVERY_MODE \
 	_IO(VEN_IOCTLBASE_ENC, 50)
 
+#define VEN_IOCTL_SET_H263_PLUSPTYPE \
+	_IOW(VEN_IOCTLBASE_ENC, 51, struct venc_ioctl_msg)
+
 struct venc_switch{
 	unsigned char	status;
 };
@@ -519,6 +522,11 @@
 	unsigned long	maxqp;
 	unsigned long	minqp;
 };
+
+struct venc_plusptype {
+	unsigned long	plusptype_enable;
+};
+
 struct venc_intraperiod{
 	unsigned long	num_pframes;
 	unsigned long	num_bframes;
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 077ccfc..7ba91f1 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -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,137 @@
 };
 
 /**
+ * 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.
+ * @usbid_ctx: A context of void type.
+ */
+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					*usbid_ctx;
+	void	(*threshold_notification) (enum qpnp_tm_state state,
+				void *ctx);
+};
+
+/**
+ * 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.
@@ -510,16 +746,32 @@
  *			   input channel.
  * @offset_gain_denominator: The inverse denominator of the gain applied to the
  *			     input channel.
+ * @high_thr: High threshold voltage that is requested to be set.
+ * @low_thr: Low threshold voltage that is requested to be set.
+ * @timer_select: Choosen from one of the 3 timers to set the polling rate for
+ *		  the VADC_BTM channel.
+ * @meas_interval1: Polling rate to set for timer 1.
+ * @meas_interval2: Polling rate to set for timer 2.
+ * @tm_channel_select: BTM channel number for the 5 VADC_BTM channels.
+ * @state_request: User can select either enable or disable high/low or both
+ * activation levels based on the qpnp_state_request type.
  * @adc_graph: ADC graph for the channel of struct type qpnp_adc_linear_graph.
  */
 struct qpnp_vadc_chan_properties {
 	uint32_t			offset_gain_numerator;
 	uint32_t			offset_gain_denominator;
+	uint32_t				high_thr;
+	uint32_t				low_thr;
+	enum qpnp_adc_meas_timer_select		timer_select;
+	enum qpnp_adc_meas_timer_1		meas_interval1;
+	enum qpnp_adc_meas_timer_2		meas_interval2;
+	enum qpnp_adc_tm_channel_select		tm_channel_select;
+	enum qpnp_state_request			state_request;
 	struct qpnp_vadc_linear_graph	adc_graph[2];
 };
 
 /**
- * struct qpnp_adc_result - Represent the result of the QPNP ADC.
+ * struct qpnp_vadc_result - Represent the result of the QPNP ADC.
  * @chan: The channel number of the requested conversion.
  * @adc_code: The pre-calibrated digital output of a given ADC relative to the
  *	      the ADC reference.
@@ -550,7 +802,7 @@
  *		 each individual channel whether it is voltage, current,
  *		 temperature, etc and compensates the channel properties.
  */
-struct qpnp_vadc_amux {
+struct qpnp_adc_amux {
 	char					*name;
 	enum qpnp_vadc_channels			channel_num;
 	enum qpnp_adc_channel_scaling_param	chan_path_prescaling;
@@ -624,7 +876,12 @@
  * @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_irq_fifo_not_empty - Conversion sequencer request written
+ *			to FIFO when not empty.
+ * @adc_irq_conv_seq_timeout - Conversion sequencer trigger timeout.
+ * @adc_high_thr_irq - Output higher than high threshold set for measurement.
+ * @adc_low_thr_irq - Output lower than low threshold set for measurement.
  * @adc_lock - ADC lock for access to the peripheral.
  * @adc_rslt_completion - ADC result notification after interrupt
  *			  is received.
@@ -636,8 +893,12 @@
 	uint16_t			offset;
 	struct qpnp_adc_properties	*adc_prop;
 	struct qpnp_adc_amux_properties	*amux_prop;
-	struct qpnp_vadc_amux		*adc_channels;
-	int				adc_irq;
+	struct qpnp_adc_amux		*adc_channels;
+	int				adc_irq_eoc;
+	int				adc_irq_fifo_not_empty;
+	int				adc_irq_conv_seq_timeout;
+	int				adc_high_thr_irq;
+	int				adc_low_thr_irq;
 	struct mutex			adc_lock;
 	struct completion		adc_rslt_completion;
 	struct qpnp_iadc_calib		calib;
@@ -828,6 +1089,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 +1199,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 */
@@ -914,4 +1262,65 @@
 { return -ENXIO; }
 #endif
 
+/* Public API */
+#if defined(CONFIG_THERMAL_QPNP_ADC_TM)				\
+			|| defined(CONFIG_THERMAL_QPNP_ADC_TM_MODULE)
+/**
+ * qpnp_adc_tm_usbid_configure() - Configures Channel 0 of VADC_BTM to
+ *		monitor USB_ID channel using 100k internal pull-up.
+ *		USB driver passes the high/low voltage threshold along
+ *		with the notification callback once the set thresholds
+ *		are crossed.
+ * @param:	Structure pointer of qpnp_adc_tm_usbid_param type.
+ *		Clients pass the low/high voltage along with the threshold
+ *		notification callback.
+ */
+int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_usbid_param *param);
+/**
+ * qpnp_adc_tm_usbid_end() - Disables the monitoring of channel 0 thats
+ *		assigned for monitoring USB_ID. Disables the low/high
+ *		threshold activation for channel 0 as well.
+ * @param:	none.
+ */
+int32_t qpnp_adc_tm_usbid_end(void);
+/**
+ * qpnp_adc_tm_usbid_configure() - Configures Channel 1 of VADC_BTM to
+ *		monitor batt_therm channel using 100k internal pull-up.
+ *		Battery driver passes the high/low voltage threshold along
+ *		with the notification callback once the set thresholds
+ *		are crossed.
+ * @param:	Structure pointer of qpnp_adc_tm_btm_param type.
+ *		Clients pass the low/high temperature along with the threshold
+ *		notification callback.
+ */
+int32_t qpnp_adc_tm_btm_configure(struct qpnp_adc_tm_btm_param *param);
+/**
+ * qpnp_adc_tm_btm_end() - Disables the monitoring of channel 1 thats
+ *		assigned for monitoring batt_therm. Disables the low/high
+ *		threshold activation for channel 1 as well.
+ * @param:	none.
+ */
+int32_t qpnp_adc_tm_btm_end(void);
+/**
+ * qpnp_adc_tm_is_ready() - Clients can use this API to check if the
+ *			  device is ready to use.
+ * @result:	0 on success and -EPROBE_DEFER when probe for the device
+ *		has not occured.
+ */
+int32_t	qpnp_adc_tm_is_ready(void);
+#else
+static inline int32_t qpnp_adc_tm_usbid_configure(
+			struct qpnp_adc_tm_usbid_param *param)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_usbid_end(void)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_btm_configure(
+		struct qpnp_adc_tm_btm_param *param)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_btm_end(void)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_is_ready(void)
+{ return -ENXIO; }
+#endif
+
 #endif
diff --git a/include/linux/smsc3503.h b/include/linux/smsc3503.h
index 66ba003..857ad1f 100644
--- a/include/linux/smsc3503.h
+++ b/include/linux/smsc3503.h
@@ -43,6 +43,8 @@
 
 struct smsc_hub_platform_data {
 	unsigned hub_reset;
+	unsigned refclk_gpio;
+	unsigned int_gpio;
 };
 
 #endif
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index d6fbc64..f2eda50 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;
@@ -395,6 +394,10 @@
 struct msm_hsic_host_platform_data {
 	unsigned strobe;
 	unsigned data;
+	bool ignore_cal_pad_config;
+	int strobe_pad_offset;
+	int data_pad_offset;
+
 	struct msm_bus_scale_pdata *bus_scale_table;
 	unsigned log2_irq_thresh;
 
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b1f534d..3858022 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1833,6 +1833,18 @@
 	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
+};
+
+#define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 26)
+enum v4l2_mpeg_vidc_perf_level {
+	V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE		= 0,
+	V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO			= 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..2ce1a88 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -56,6 +56,9 @@
 #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_I_H263_PLUSPTYPE (VCD_START_BASE + 0x2C)
+
 
 #define VCD_START_REQ      (VCD_START_BASE + 0x1000)
 #define VCD_I_REQ_IFRAME   (VCD_START_REQ + 0x1)
@@ -292,6 +295,10 @@
 	u32              min_qp;
 };
 
+struct vcd_property_plusptype {
+	u32              plusptype_enable;
+};
+
 struct vcd_property_session_qp {
 	u32 i_frame_qp;
 	u32 p_frame_qp;
@@ -378,4 +385,8 @@
 	u32 avc_delimiter_enable_flag;
 };
 
+struct vcd_property_vui_timing_info_enable {
+	u32 vui_timing_info;
+};
+
 #endif
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index a932011..971c9b3 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1032,7 +1032,13 @@
 #define CAMERA_EFFECT_EMBOSS		9
 #define CAMERA_EFFECT_SKETCH		10
 #define CAMERA_EFFECT_NEON		11
-#define CAMERA_EFFECT_MAX		12
+#define CAMERA_EFFECT_FADED		12
+#define CAMERA_EFFECT_VINTAGECOOL	13
+#define CAMERA_EFFECT_VINTAGEWARM	14
+#define CAMERA_EFFECT_ACCENT_BLUE       15
+#define CAMERA_EFFECT_ACCENT_GREEN      16
+#define CAMERA_EFFECT_ACCENT_ORANGE     17
+#define CAMERA_EFFECT_MAX               18
 
 /* QRD */
 #define CAMERA_EFFECT_BW		10
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
index 13ce043..ab76d79 100644
--- a/include/media/msm_media_info.h
+++ b/include/media/msm_media_info.h
@@ -97,7 +97,7 @@
 	uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
 	switch (color_fmt) {
 	case COLOR_FMT_NV12:
-		uv_alignment = 0;
+		uv_alignment = 4096;
 		y_plane = y_stride * y_sclines;
 		uv_plane = uv_stride * uv_sclines + uv_alignment;
 		size = y_plane + uv_plane;
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 84d9b42..2787e8d 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 {
@@ -47,6 +47,11 @@
 	HAL_VCAP_RGB,
 };
 
+enum nr_threshold_mode {
+	NR_THRESHOLD_STATIC = 0,
+	NR_THRESHOLD_DYNAMIC,
+};
+
 enum nr_mode {
 	NR_DISABLE = 0,
 	NR_AUTO,
@@ -73,6 +78,7 @@
 };
 
 struct nr_param {
+	enum nr_threshold_mode threshold;
 	enum nr_mode mode;
 	enum nr_decay_ratio decay_ratio;
 	uint8_t window;
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..88acdfc 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -281,6 +281,26 @@
 	 */
 } __packed;
 
+/* Defined specifically for in-band use, includes params */
+struct adm_cmd_set_pp_params_inband_v5 {
+	struct apr_hdr hdr;
+	/* LSW of parameter data payload address.*/
+	u32		payload_addr_lsw;
+	/* MSW of parameter data payload address.*/
+	u32		payload_addr_msw;
+	/* Memory map handle returned by ADM_CMD_SHARED_MEM_MAP_REGIONS */
+	/* command. If mem_map_handle is zero implies the message is in */
+	/* the payload */
+	u32		mem_map_handle;
+	/* Size in bytes of the variable payload accompanying this */
+	/* message or in shared memory. This is used for parsing the */
+	/* parameter payload. */
+	u32		payload_size;
+	/* Parameters passed for in band payload */
+	struct adm_param_data_v5	params;
+} __packed;
+
+
 /* Returns the status and COPP ID to an #ADM_CMD_DEVICE_OPEN_V5 command.
  */
 #define ADM_CMDRSP_DEVICE_OPEN_V5                      0x00010329
@@ -712,8 +732,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
@@ -1884,6 +1904,67 @@
 	/* For 32 bit alignment. */
 } __packed;
 
+
+/* This param id is used to configure the Pseudoport interface */
+
+#define AFE_PARAM_ID_PSEUDO_PORT_CONFIG	0x00010219
+
+/* Version information used to handle future additions to the configuration
+ * interface (for backward compatibility).
+ */
+#define AFE_API_VERSION_PSEUDO_PORT_CONFIG                          0x1
+
+/* Enumeration for setting the timing_mode parameter to faster than real
+ * time.
+ */
+#define AFE_PSEUDOPORT_TIMING_MODE_FTRT                             0x0
+
+/* Enumeration for setting the timing_mode parameter to real time using
+ * timers.
+ */
+#define AFE_PSEUDOPORT_TIMING_MODE_TIMER                            0x1
+
+/* Payload of the AFE_PARAM_ID_PSEUDO_PORT_CONFIG parameter used by
+    AFE_MODULE_AUDIO_DEV_INTERFACE.
+*/
+struct afe_param_id_pseudo_port_cfg {
+	u32                  pseud_port_cfg_minor_version;
+	/*
+	 * Minor version used for tracking the version of the pseudoport
+	 * configuration interface.
+	 */
+
+	u16                  bit_width;
+	/* Bit width of the sample at values 16, 24 */
+
+	u16                  num_channels;
+	/* Number of channels at values  1 to 8 */
+
+	u16                  data_format;
+	/* Non-linear data format supported by the pseudoport (for future use).
+	 * At values #AFE_LINEAR_PCM_DATA
+	 */
+
+	u16                  timing_mode;
+	/* Indicates whether the pseudoport synchronizes to the clock or
+	 * operates faster than real time.
+	 * at values
+	 * - #AFE_PSEUDOPORT_TIMING_MODE_FTRT
+	 * - #AFE_PSEUDOPORT_TIMING_MODE_TIMER @tablebulletend
+	 */
+
+	u32                  sample_rate;
+	/* Sample rate at which the pseudoport will run.
+	 * at values
+	 * - #AFE_PORT_SAMPLE_RATE_8K
+	 * - #AFE_PORT_SAMPLE_RATE_32K
+	 * - #AFE_PORT_SAMPLE_RATE_48K
+	 * - #AFE_PORT_SAMPLE_RATE_96K
+	 * - #AFE_PORT_SAMPLE_RATE_192K @tablebulletend
+	 */
+} __packed;
+
+
 union afe_port_config {
 	struct afe_param_id_pcm_cfg               pcm;
 	struct afe_param_id_i2s_cfg               i2s;
@@ -1891,6 +1972,12 @@
 	struct afe_param_id_slimbus_cfg           slim_sch;
 	struct afe_param_id_rt_proxy_port_cfg     rtproxy;
 	struct afe_param_id_internal_bt_fm_cfg    int_bt_fm;
+	struct afe_param_id_pseudo_port_cfg       pseudo_port;
+} __packed;
+
+struct afe_audioif_config_command_no_payload {
+	struct apr_hdr			hdr;
+	struct afe_port_cmd_set_param_v2 param;
 } __packed;
 
 struct afe_audioif_config_command {
@@ -6129,6 +6216,111 @@
 #define VOICE_EVT_GET_PARAM_ACK				0x00011008
 
 
+/* SRS TRUMEDIA start */
+/* topology */
+#define SRS_TRUMEDIA_TOPOLOGY_ID			0x00010D90
+/* module */
+#define SRS_TRUMEDIA_MODULE_ID				0x10005010
+/* parameters */
+#define SRS_TRUMEDIA_PARAMS				0x10005011
+#define SRS_TRUMEDIA_PARAMS_WOWHD			0x10005012
+#define SRS_TRUMEDIA_PARAMS_CSHP			0x10005013
+#define SRS_TRUMEDIA_PARAMS_HPF				0x10005014
+#define SRS_TRUMEDIA_PARAMS_PEQ				0x10005015
+#define SRS_TRUMEDIA_PARAMS_HL				0x10005016
+
+#define SRS_ID_GLOBAL	0x00000001
+#define SRS_ID_WOWHD	0x00000002
+#define SRS_ID_CSHP	0x00000003
+#define SRS_ID_HPF	0x00000004
+#define SRS_ID_PEQ	0x00000005
+#define SRS_ID_HL	0x00000006
+
+#define SRS_CMD_UPLOAD		0x7FFF0000
+#define SRS_PARAM_INDEX_MASK	0x80000000
+#define SRS_PARAM_OFFSET_MASK	0x3FFF0000
+#define SRS_PARAM_VALUE_MASK	0x0000FFFF
+
+struct srs_trumedia_params_GLOBAL {
+	uint8_t                  v1;
+	uint8_t                  v2;
+	uint8_t                  v3;
+	uint8_t                  v4;
+	uint8_t                  v5;
+	uint8_t                  v6;
+	uint8_t                  v7;
+	uint8_t                  v8;
+} __packed;
+
+struct srs_trumedia_params_WOWHD {
+	uint32_t				v1;
+	uint16_t				v2;
+	uint16_t				v3;
+	uint16_t				v4;
+	uint16_t				v5;
+	uint16_t				v6;
+	uint16_t				v7;
+	uint16_t				v8;
+	uint16_t				v____A1;
+	uint32_t				v9;
+	uint16_t				v10;
+	uint16_t				v11;
+	uint32_t				v12[16];
+} __packed;
+
+struct srs_trumedia_params_CSHP {
+	uint32_t				v1;
+	uint16_t				v2;
+	uint16_t				v3;
+	uint16_t				v4;
+	uint16_t				v5;
+	uint16_t				v6;
+	uint16_t				v____A1;
+	uint32_t				v7;
+	uint16_t				v8;
+	uint16_t				v9;
+	uint32_t				v10[16];
+} __packed;
+
+struct srs_trumedia_params_HPF {
+	uint32_t				v1;
+	uint32_t				v2[26];
+} __packed;
+
+struct srs_trumedia_params_PEQ {
+	uint32_t				v1;
+	uint16_t				v2;
+	uint16_t				v3;
+	uint16_t				v4;
+	uint16_t				v____A1;
+	uint32_t				v5[26];
+	uint32_t				v6[26];
+} __packed;
+
+struct srs_trumedia_params_HL {
+	uint16_t				v1;
+	uint16_t				v2;
+	uint16_t				v3;
+	uint16_t				v____A1;
+	int32_t					v4;
+	uint32_t				v5;
+	uint16_t				v6;
+	uint16_t				v____A2;
+	uint32_t				v7;
+} __packed;
+
+struct srs_trumedia_params {
+	struct srs_trumedia_params_GLOBAL	global;
+	struct srs_trumedia_params_WOWHD	wowhd;
+	struct srs_trumedia_params_CSHP		cshp;
+	struct srs_trumedia_params_HPF		hpf;
+	struct srs_trumedia_params_PEQ		peq;
+	struct srs_trumedia_params_HL		hl;
+} __packed;
+/* SRS TruMedia end */
+
+
+
 /* ERROR CODES */
 /* Success. The operation completed with no errors. */
 #define ADSP_EOK          0x00000000
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index bfd7208..5afbfad 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -697,18 +697,6 @@
 #define ASM_OPEN_READ_PERF_MODE_BIT			(1<<29)
 #define ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT		(1<<13)
 
-/* SRS TRUMEDIA GUIDS */
-/* topology */
-#define SRS_TRUMEDIA_TOPOLOGY_ID			0x00010D90
-/* module */
-#define SRS_TRUMEDIA_MODULE_ID				0x10005010
-/* parameters */
-#define SRS_TRUMEDIA_PARAMS				0x10005011
-#define SRS_TRUMEDIA_PARAMS_WOWHD			0x10005012
-#define SRS_TRUMEDIA_PARAMS_CSHP			0x10005013
-#define SRS_TRUMEDIA_PARAMS_HPF				0x10005014
-#define SRS_TRUMEDIA_PARAMS_PEQ				0x10005015
-#define SRS_TRUMEDIA_PARAMS_HL				0x10005016
 
 #define ASM_MAX_EQ_BANDS 12
 
@@ -1767,18 +1755,36 @@
 #define ADSP_ENOTIMPL     0x00000011 /* Operation is not implemented. */
 #define ADSP_ENEEDMORE    0x00000012 /* Operation needs more data or resources*/
 
-/* SRS TRUMEDIA start */
-#define SRS_ID_GLOBAL	0x00000001
-#define SRS_ID_WOWHD	0x00000002
-#define SRS_ID_CSHP	0x00000003
-#define SRS_ID_HPF	0x00000004
-#define SRS_ID_PEQ	0x00000005
-#define SRS_ID_HL	0x00000006
+/* SRS TRUMEDIA GUIDS */
+#define SRS_TRUMEDIA_TOPOLOGY_ID    0x00010D90
+#define SRS_TRUMEDIA_MODULE_ID      0x10005010
+#define SRS_TRUMEDIA_PARAMS         0x10005011
+#define SRS_TRUMEDIA_PARAMS_WOWHD   0x10005012
+#define SRS_TRUMEDIA_PARAMS_CSHP    0x10005013
+#define SRS_TRUMEDIA_PARAMS_HPF     0x10005014
+#define SRS_TRUMEDIA_PARAMS_PEQ     0x10005015
+#define SRS_TRUMEDIA_PARAMS_HL      0x10005016
 
-#define SRS_CMD_UPLOAD		0x7FFF0000
-#define SRS_PARAM_INDEX_MASK	0x80000000
-#define SRS_PARAM_OFFSET_MASK	0x3FFF0000
-#define SRS_PARAM_VALUE_MASK	0x0000FFFF
+/* SRS STUDIO SOUND 3D GUIDS */
+#define SRS_SS3D_TOPOLOGY_ID        0x00010720
+#define SRS_SS3D_MODULE_ID          0x10005020
+#define SRS_SS3D_PARAMS             0x10005021
+#define SRS_SS3D_PARAMS_CTRL        0x10005022
+#define SRS_SS3D_PARAMS_FILTER      0x10005023
+
+/* SRS ALSA CMD MASKS */
+#define SRS_CMD_UPLOAD              0x7FFF0000
+#define SRS_PARAM_INDEX_MASK        0x80000000
+#define SRS_PARAM_OFFSET_MASK       0x3FFF0000
+#define SRS_PARAM_VALUE_MASK        0x0000FFFF
+
+/* SRS TRUMEDIA start */
+#define SRS_ID_GLOBAL               0x00000001
+#define SRS_ID_WOWHD                0x00000002
+#define SRS_ID_CSHP                 0x00000003
+#define SRS_ID_HPF                  0x00000004
+#define SRS_ID_PEQ                  0x00000005
+#define SRS_ID_HL                   0x00000006
 
 struct srs_trumedia_params_GLOBAL {
 	uint8_t                  v1;
@@ -1856,7 +1862,41 @@
 	struct srs_trumedia_params_PEQ		peq;
 	struct srs_trumedia_params_HL		hl;
 } __packed;
+
 int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
 /* SRS TruMedia end */
 
+/* SRS Studio Sound 3D start */
+#define SRS_ID_SS3D_GLOBAL	0x00000001
+#define SRS_ID_SS3D_CTRL	0x00000002
+#define SRS_ID_SS3D_FILTER	0x00000003
+
+struct srs_SS3D_params_GLOBAL {
+	uint8_t                  v1;
+	uint8_t                  v2;
+	uint8_t                  v3;
+	uint8_t                  v4;
+	uint8_t                  v5;
+	uint8_t                  v6;
+	uint8_t                  v7;
+	uint8_t                  v8;
+} __packed;
+
+struct srs_SS3D_ctrl_params {
+	uint8_t				v[236];
+} __packed;
+
+struct srs_SS3D_filter_params {
+	uint8_t				v[28 + 2752];
+} __packed;
+
+struct srs_SS3D_params {
+	struct srs_SS3D_params_GLOBAL   global;
+	struct srs_SS3D_ctrl_params     ss3d;
+	struct srs_SS3D_filter_params   ss3d_f;
+} __packed;
+
+int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
+/* SRS Studio Sound 3D end */
+
 #endif /*_APR_AUDIO_H_*/
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..fdc3cb9 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -16,17 +16,19 @@
 #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;
 };
 
+int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
+
 int adm_open(int port, int path, int rate, int mode, int topology);
 
 int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
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/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 182da1c..a436a6e 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -140,6 +140,7 @@
 	atomic_t	       cmd_state;
 	/* Relative or absolute TS */
 	uint32_t	       time_flag;
+	atomic_t	       nowait_cmd_cnt;
 	void		       *priv;
 	uint32_t               io_mode;
 	uint64_t	       time_stamp;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 45a8d86..a2bad88 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -401,9 +401,16 @@
 static void __hrtick_start(void *arg)
 {
 	struct rq *rq = arg;
+	struct hrtimer *timer = &rq->hrtick_timer;
+	ktime_t soft, hard;
+	unsigned long delta;
+
+	soft = hrtimer_get_softexpires(timer);
+	hard = hrtimer_get_expires(timer);
+	delta = ktime_to_ns(ktime_sub(hard, soft));
 
 	raw_spin_lock(&rq->lock);
-	hrtimer_restart(&rq->hrtick_timer);
+	__hrtimer_start_range_ns(timer, soft, delta, HRTIMER_MODE_ABS, 0);
 	rq->hrtick_csd_pending = 0;
 	raw_spin_unlock(&rq->lock);
 }
@@ -421,7 +428,8 @@
 	hrtimer_set_expires(timer, time);
 
 	if (rq == this_rq()) {
-		hrtimer_restart(timer);
+		__hrtimer_start_range_ns(timer, ns_to_ktime(delay), 0,
+						 HRTIMER_MODE_REL_PINNED, 0);
 	} else if (!rq->hrtick_csd_pending) {
 		__smp_call_function_single(cpu_of(rq), &rq->hrtick_csd, 0);
 		rq->hrtick_csd_pending = 1;
diff --git a/mm/filemap.c b/mm/filemap.c
index 79c4b2b..8ed5c5c 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2343,9 +2343,17 @@
 	if (page)
 		goto found;
 
+retry:
 	page = __page_cache_alloc(gfp_mask & ~gfp_notmask);
 	if (!page)
 		return NULL;
+
+	if (is_cma_pageblock(page)) {
+		__free_page(page);
+		gfp_notmask |= __GFP_MOVABLE;
+		goto retry;
+	}
+
 	status = add_to_page_cache_lru(page, mapping, index,
 						GFP_KERNEL & ~gfp_notmask);
 	if (unlikely(status)) {
diff --git a/mm/memory.c b/mm/memory.c
index 174fcaa..c130853 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -49,6 +49,7 @@
 #include <linux/rmap.h>
 #include <linux/export.h>
 #include <linux/delayacct.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/writeback.h>
 #include <linux/memcontrol.h>
@@ -2912,6 +2913,16 @@
 	entry = pte_to_swp_entry(orig_pte);
 	if (unlikely(non_swap_entry(entry))) {
 		if (is_migration_entry(entry)) {
+#ifdef CONFIG_DMA_CMA
+			/*
+			 * FIXME: mszyprow: cruel, brute-force method for
+			 * letting cma/migration to finish it's job without
+			 * stealing the lock migration_entry_wait() and creating
+			 * a live-lock on the faulted page
+			 * (page->_count == 2 migration failure issue)
+			 */
+			mdelay(10);
+#endif
 			migration_entry_wait(mm, pmd, address);
 		} else if (is_hwpoison_entry(entry)) {
 			ret = VM_FAULT_HWPOISON;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index c3142e8..bd3f0f3 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -758,6 +758,11 @@
 }
 
 #ifdef CONFIG_CMA
+bool is_cma_pageblock(struct page *page)
+{
+	return get_pageblock_migratetype(page) == MIGRATE_CMA;
+}
+
 /* Free whole pageblock and set it's migration type to MIGRATE_CMA. */
 void __init init_cma_reserved_pageblock(struct page *page)
 {
@@ -913,11 +918,6 @@
 	[MIGRATE_ISOLATE]     = { MIGRATE_RESERVE }, /* Never used */
 };
 
-int *get_migratetype_fallbacks(int mtype)
-{
-	return fallbacks[mtype];
-}
-
 /*
  * Move the free pages in a range to the free lists of the requested type.
  * Note that start_page and end_pages are not aligned on a pageblock
@@ -1400,15 +1400,18 @@
 	unsigned int order;
 	unsigned long watermark;
 	struct zone *zone;
+	int mt;
 
 	BUG_ON(!PageBuddy(page));
 
 	zone = page_zone(page);
 	order = page_order(page);
+	mt = get_pageblock_migratetype(page);
 
 	/* Obey watermarks as if the page was being allocated */
 	watermark = low_wmark_pages(zone) + (1 << order);
-	if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+	if (!is_migrate_cma(mt) && mt != MIGRATE_ISOLATE &&
+	    !zone_watermark_ok(zone, 0, watermark, 0, 0))
 		return 0;
 
 	/* Remove page from free list */
@@ -1424,7 +1427,7 @@
 	if (order >= pageblock_order - 1) {
 		struct page *endpage = page + (1 << order) - 1;
 		for (; page < endpage; page += pageblock_nr_pages) {
-			int mt = get_pageblock_migratetype(page);
+			mt = get_pageblock_migratetype(page);
 			if (mt != MIGRATE_ISOLATE && !is_migrate_cma(mt))
 				set_pageblock_migratetype(page,
 							  MIGRATE_MOVABLE);
@@ -5424,7 +5427,7 @@
 	pfn &= (PAGES_PER_SECTION-1);
 	return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
 #else
-	pfn = pfn - zone->zone_start_pfn;
+	pfn = pfn - round_down(zone->zone_start_pfn, pageblock_nr_pages);
 	return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
 #endif /* CONFIG_SPARSEMEM */
 }
@@ -5679,7 +5682,7 @@
 	};
 	INIT_LIST_HEAD(&cc.migratepages);
 
-	migrate_prep_local();
+	migrate_prep();
 
 	while (pfn < end || !list_empty(&cc.migratepages)) {
 		if (fatal_signal_pending(current)) {
@@ -5703,7 +5706,7 @@
 
 		ret = migrate_pages(&cc.migratepages,
 				    __alloc_contig_migrate_alloc,
-				    0, false, true);
+				    0, false, MIGRATE_SYNC);
 	}
 
 	putback_lru_pages(&cc.migratepages);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index e5f43ec..ea116e9 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1840,15 +1840,6 @@
 			struct hci_cp_auth_requested cp;
 			hci_remove_link_key(hdev, &conn->dst);
 			cp.handle = cpu_to_le16(conn->handle);
-			/*Initiates dedicated bonding as pin or key is missing
-			on remote device*/
-			/*In case if remote device is ssp supported,
-			reduce the security level to MEDIUM if it is HIGH*/
-			if (conn->ssp_mode && conn->auth_initiator &&
-				conn->io_capability != 0x03) {
-				conn->pending_sec_level = BT_SECURITY_HIGH;
-				conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM;
-			}
 			hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
 							sizeof(cp), &cp);
 			hci_dev_unlock(hdev);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index fa2469e..44e2feb 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -93,6 +93,13 @@
 static void l2cap_conn_del(struct hci_conn *hcon, int err, u8 is_process);
 static u16 l2cap_get_smallest_flushto(struct l2cap_chan_list *l);
 static void l2cap_set_acl_flushto(struct hci_conn *hcon, u16 flush_to);
+static void l2cap_queue_acl_data(struct work_struct *worker);
+static struct att_channel_parameters{
+	struct sk_buff *skb;
+	struct l2cap_conn *conn;
+	__le16 cid;
+	int dir;
+} att_chn_params;
 
 /* ---- L2CAP channels ---- */
 static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
@@ -1209,6 +1216,8 @@
 
 		kfree(conn);
 	}
+	att_chn_params.conn = NULL;
+	BT_DBG("att_chn_params.conn set to NULL");
 }
 
 static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk)
@@ -3600,8 +3609,7 @@
 		if (mtu < L2CAP_DEFAULT_MIN_MTU) {
 			result = L2CAP_CONF_UNACCEPT;
 			pi->omtu = L2CAP_DEFAULT_MIN_MTU;
-		}
-		else {
+		} else {
 			pi->omtu = mtu;
 			pi->conf_state |= L2CAP_CONF_MTU_DONE;
 		}
@@ -7275,6 +7283,7 @@
 	struct sk_buff *skb_rsp;
 	struct l2cap_hdr *lh;
 	int dir;
+	struct work_struct *open_worker;
 	u8 err_rsp[] = {L2CAP_ATT_ERROR, 0x00, 0x00, 0x00,
 						L2CAP_ATT_NOT_SUPPORTED};
 
@@ -7310,8 +7319,18 @@
 
 	BT_DBG("sk %p, len %d", sk, skb->len);
 
-	if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
-		goto drop;
+	if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) {
+		att_chn_params.cid = cid;
+		att_chn_params.conn = conn;
+		att_chn_params.dir = dir;
+		att_chn_params.skb = skb;
+		open_worker = kzalloc(sizeof(*open_worker), GFP_ATOMIC);
+		if (!open_worker)
+			BT_ERR("Out of memory");
+		INIT_WORK(open_worker, l2cap_queue_acl_data);
+		schedule_work(open_worker);
+		goto done;
+	}
 
 	if (l2cap_pi(sk)->imtu < skb->len)
 		goto drop;
@@ -7787,6 +7806,80 @@
 	return 0;
 }
 
+static void l2cap_queue_acl_data(struct work_struct *worker)
+{
+	struct sock *sk = NULL;
+	int attempts = 0;
+	struct sk_buff *skb_rsp;
+	struct l2cap_hdr *lh;
+	u8 err_rsp[] = {L2CAP_ATT_ERROR, 0x00, 0x00, 0x00,
+						L2CAP_ATT_NOT_SUPPORTED};
+
+	for (attempts = 0; attempts < 40; attempts++) {
+		msleep(50);
+		if (!att_chn_params.conn) {
+			BT_DBG("att_chn_params.conn is NULL");
+			return;
+		}
+		sk = l2cap_find_sock_by_fixed_cid_and_dir
+				(att_chn_params.cid,
+				att_chn_params.conn->src,
+				att_chn_params.conn->dst,
+				att_chn_params.dir);
+		bh_lock_sock(sk);
+		if (sk->sk_state == BT_CONNECTED) {
+			sock_queue_rcv_skb(sk, att_chn_params.skb);
+			if (sk)
+				bh_unlock_sock(sk);
+			return;
+		}
+		bh_unlock_sock(sk);
+	}
+	bh_lock_sock(sk);
+
+	if (att_chn_params.skb->data[0] != L2CAP_ATT_INDICATE)
+		goto not_indicate;
+
+	/* If this is an incoming Indication, we are required to confirm */
+	skb_rsp = bt_skb_alloc(sizeof(u8) + L2CAP_HDR_SIZE, GFP_ATOMIC);
+	if (!skb_rsp)
+		goto free_skb;
+
+	lh = (struct l2cap_hdr *) skb_put(skb_rsp, L2CAP_HDR_SIZE);
+	lh->len = cpu_to_le16(sizeof(u8));
+	lh->cid = cpu_to_le16(L2CAP_CID_LE_DATA);
+	err_rsp[0] = L2CAP_ATT_CONFIRM;
+	memcpy(skb_put(skb_rsp, sizeof(u8)), err_rsp, sizeof(u8));
+	hci_send_acl(att_chn_params.conn->hcon, NULL, skb_rsp, 0);
+	goto free_skb;
+
+not_indicate:
+	if (att_chn_params.skb->data[0] & L2CAP_ATT_RESPONSE_BIT ||
+			att_chn_params.skb->data[0] == L2CAP_ATT_CONFIRM)
+		goto free_skb;
+
+	/* If this is an incoming PDU that requires a response, respond with
+	 * a generic error so remote device doesn't hang */
+
+	skb_rsp = bt_skb_alloc(sizeof(err_rsp) + L2CAP_HDR_SIZE, GFP_ATOMIC);
+	if (!skb_rsp)
+		goto free_skb;
+
+	lh = (struct l2cap_hdr *) skb_put(skb_rsp, L2CAP_HDR_SIZE);
+	lh->len = cpu_to_le16(sizeof(err_rsp));
+	lh->cid = cpu_to_le16(L2CAP_CID_LE_DATA);
+	err_rsp[1] = att_chn_params.skb->data[0];
+	memcpy(skb_put(skb_rsp, sizeof(err_rsp)), err_rsp, sizeof(err_rsp));
+	hci_send_acl(att_chn_params.conn->hcon, NULL, skb_rsp, 0);
+
+free_skb:
+	kfree_skb(att_chn_params.skb);
+
+	if (sk)
+		bh_unlock_sock(sk);
+
+}
+
 static int l2cap_debugfs_open(struct inode *inode, struct file *file)
 {
 	return single_open(file, l2cap_debugfs_show, inode->i_private);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 28eb7ea..8568dae7 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -390,12 +390,17 @@
 		goto failed;
 	}
 
+	hci_dev_unlock_bh(hdev);
+
 	if (cp->val)
 		queue_work(hdev->workqueue, &hdev->power_on);
 	else
 		queue_work(hdev->workqueue, &hdev->power_off);
 
 	err = 0;
+	hci_dev_put(hdev);
+
+	return err;
 
 failed:
 	hci_dev_unlock_bh(hdev);
@@ -1956,6 +1961,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 +2226,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 +2238,8 @@
 
 		mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
 
+		hdev->disco_state = SCAN_IDLE;
+
 		if (hdev)
 			goto done;
 		else
@@ -2315,6 +2355,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 +2436,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 +2702,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;
@@ -3048,6 +3094,12 @@
 		goto no_auto_confirm;
 	}
 
+	/* Show bonding dialog if neither side requires no bonding */
+	if ((conn->auth_type > 0x01) && (conn->remote_auth > 0x01)) {
+		if (!loc_mitm && !rem_mitm)
+			value = 0;
+		goto no_auto_confirm;
+	}
 
 	if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
 		ev.auto_confirm = 1;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 276ff71..56b2cfa 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -756,8 +756,7 @@
 
 	hcon->smp_conn = conn;
 	hcon->pending_sec_level = sec_level;
-
-	if ((hcon->link_mode & HCI_LM_MASTER) && !hcon->sec_req) {
+	if (hcon->link_mode & HCI_LM_MASTER) {
 		struct link_key *key;
 
 		key = hci_find_link_key_type(hcon->hdev, conn->dst,
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..c59ffae 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -35,13 +35,14 @@
 import subprocess
 import os
 import os.path
+import re
 import shutil
 import sys
 
 version = 'build-all.py, version 0.01'
 
 build_dir = '../all-kernels'
-make_command = ["vmlinux", "modules"]
+make_command = ["vmlinux", "modules", "dtbs"]
 make_env = os.environ
 make_env.update({
         'ARCH': 'arm',
@@ -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/msm_stub.c b/sound/soc/codecs/msm_stub.c
index 7e603b4..0143e51 100644
--- a/sound/soc/codecs/msm_stub.c
+++ b/sound/soc/codecs/msm_stub.c
@@ -34,7 +34,7 @@
 		.capture = { /* Support maximum range */
 			.stream_name = "Record",
 			.channels_min = 1,
-			.channels_max = 4,
+			.channels_max = 8,
 			.rates = SNDRV_PCM_RATE_8000_48000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		},
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/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index e11b985..e672cdb 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -295,6 +295,11 @@
 	(1 << AIF1_CAP) | (1 << AIF2_CAP),	/* AIF2_CAP */
 };
 
+static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
+	0, /* AIF1_PB */
+	0, /* AIF1_CAP */
+};
+
 struct tabla_priv {
 	struct snd_soc_codec *codec;
 	struct tabla_reg_address reg_addr;
@@ -1746,6 +1751,7 @@
 	u32 dai_id = widget->shift;
 	u32 port_id = mixer->shift;
 	u32 enable = ucontrol->value.integer.value[0];
+	u32 vtable = vport_check_table[dai_id];
 
 	pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
 		widget->name, ucontrol->id.name, widget->value, widget->shift,
@@ -1767,8 +1773,13 @@
 		/* only add to the list if value not set
 		 */
 		if (enable && !(widget->value & 1 << port_id)) {
+			if (tabla_p->intf_type ==
+				WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+				vtable = vport_check_table[dai_id];
+			if (tabla_p->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
+				vtable = vport_i2s_check_table[dai_id];
 			if (wcd9xxx_tx_vport_validation(
-						vport_check_table[dai_id],
+						vtable,
 						port_id,
 						tabla_p->dai)) {
 				pr_info("%s: TX%u is used by other virtual port\n",
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 5ffb60a..76623b1 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -54,7 +54,8 @@
 #define TAIKO_SLIM_IRQ_OVERFLOW (1 << 0)
 #define TAIKO_SLIM_IRQ_UNDERFLOW (1 << 1)
 #define TAIKO_SLIM_IRQ_PORT_CLOSED (1 << 2)
-
+#define TAIKO_MCLK_CLK_12P288MHZ 12288000
+#define TAIKO_MCLK_CLK_9P6HZ 9600000
 enum {
 	AIF1_PB = 0,
 	AIF1_CAP,
@@ -181,6 +182,11 @@
 	(1 << AIF1_CAP) | (1 << AIF2_CAP),	/* AIF2_CAP */
 };
 
+static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
+	0,	/* AIF1_PB */
+	0,	/* AIF1_CAP */
+};
+
 struct taiko_priv {
 	struct snd_soc_codec *codec;
 	u32 adc_count;
@@ -1523,6 +1529,7 @@
 	u32 dai_id = widget->shift;
 	u32 port_id = mixer->shift;
 	u32 enable = ucontrol->value.integer.value[0];
+	u32 vtable = vport_check_table[dai_id];
 
 
 	pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
@@ -1539,7 +1546,6 @@
 			return -EINVAL;
 		}
 	}
-	if (taiko_p->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
 		switch (dai_id) {
 		case AIF1_CAP:
 		case AIF2_CAP:
@@ -1547,8 +1553,16 @@
 			/* only add to the list if value not set
 			 */
 			if (enable && !(widget->value & 1 << port_id)) {
+
+				if (taiko_p->intf_type ==
+					WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+					vtable = vport_check_table[dai_id];
+				if (taiko_p->intf_type ==
+					WCD9XXX_INTERFACE_TYPE_I2C)
+					vtable = vport_i2s_check_table[dai_id];
+
 				if (wcd9xxx_tx_vport_validation(
-						vport_check_table[dai_id],
+						vtable,
 						port_id,
 						taiko_p->dai)) {
 					pr_debug("%s: TX%u is used by other\n"
@@ -1583,7 +1597,6 @@
 			mutex_unlock(&codec->mutex);
 			return -EINVAL;
 		}
-	}
 	pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
 		widget->name, widget->sname, widget->value, widget->shift);
 
@@ -3108,11 +3121,7 @@
 static int taiko_set_dai_sysclk(struct snd_soc_dai *dai,
 		int clk_id, unsigned int freq, int dir)
 {
-	struct snd_soc_codec *codec = dai->codec;
-	if (freq == TAIKO_MCLK_CLK_12P288MHZ)
-		snd_soc_write(codec, TAIKO_A_CHIP_CTL, 0x04);
-	else if (freq == TAIKO_MCLK_CLK_9P6HZ)
-		snd_soc_write(codec, TAIKO_A_CHIP_CTL, 0x0A);
+	pr_debug("%s\n", __func__);
 	return 0;
 }
 
@@ -4625,6 +4634,8 @@
 	 */
 	{TAIKO_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
 	{TAIKO_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+	{TAIKO_A_RX_HPH_L_TEST, 0x01, 0x01},
+	{TAIKO_A_RX_HPH_R_TEST, 0x01, 0x01},
 
 	/* Initialize gain registers to use register gain */
 	{TAIKO_A_RX_HPH_L_GAIN, 0x20, 0x20},
@@ -4796,6 +4807,11 @@
 	taiko->aux_l_gain = 0x1F;
 	taiko->aux_r_gain = 0x1F;
 	taiko_update_reg_defaults(codec);
+	pr_debug("%s: MCLK Rate = %x\n", __func__, wcd9xxx->mclk_rate);
+	if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ)
+		snd_soc_write(codec, TAIKO_A_CHIP_CTL, 0x04);
+	else if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_9P6HZ)
+		snd_soc_write(codec, TAIKO_A_CHIP_CTL, 0x0A);
 	taiko_codec_init_reg(codec);
 	ret = taiko_handle_pdata(taiko);
 	if (IS_ERR_VALUE(ret)) {
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index d5cada7..04ca56a 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -107,7 +107,7 @@
 
 config SND_SOC_MSM_QDSP6V2_INTF
 	bool "SoC Q6 audio driver for MSM8974"
-	depends on MSM_QDSP6_APR
+	depends on MSM_QDSP6_APRV2
 	help
 	 To add support for SoC audio on MSM8974.
 	 This will enable all the platform specific
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 4fe002b..a351f7b 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -92,7 +92,7 @@
 
 static int msm_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm_btsco_ch = 1;
-
+static int hdmi_rate_variable;
 static int rec_mode = INCALL_REC_MONO;
 
 static struct clk *codec_clk;
@@ -642,11 +642,13 @@
 static const char *spk_function[] = {"Off", "On"};
 static const char *slim0_rx_ch_text[] = {"One", "Two"};
 static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+static const char * const hdmi_rate[] = {"Default", "Variable"};
 
 static const struct soc_enum msm_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+	SOC_ENUM_SINGLE_EXT(2, hdmi_rate),
 };
 
 static const char *btsco_rate_text[] = {"8000", "16000"};
@@ -756,6 +758,21 @@
 	return 0;
 }
 
+static int msm_hdmi_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	hdmi_rate_variable = ucontrol->value.integer.value[0];
+	pr_debug("%s: hdmi_rate_variable = %d\n", __func__, hdmi_rate_variable);
+	return 0;
+}
+
+static int msm_hdmi_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = hdmi_rate_variable;
+	return 0;
+}
+
 static const struct snd_kcontrol_new tabla_msm_controls[] = {
 	SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
 		msm_set_spk),
@@ -769,6 +786,9 @@
 			msm_incall_rec_mode_get, msm_incall_rec_mode_put),
 	SOC_ENUM_EXT("SLIM_3_RX Channels", msm_enum[1],
 		msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put),
+	SOC_ENUM_EXT("HDMI RX Rate", msm_enum[3],
+					msm_hdmi_rate_get,
+					msm_hdmi_rate_put),
 };
 
 static void *def_tabla_mbhc_cal(void)
@@ -1328,7 +1348,8 @@
 
 	if (channels->max < 2)
 		channels->min = channels->max = 2;
-	rate->min = rate->max = 48000;
+	if (!hdmi_rate_variable)
+		rate->min = rate->max = 48000;
 
 	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/mdm9625.c b/sound/soc/msm/mdm9625.c
index b1822f6..4c7b69d 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -68,7 +68,6 @@
 	unsigned gpio_no;
 	char *gpio_name;
 };
-static bool cdc_mclk_init;
 static struct mutex cdc_mclk_mutex;
 static int mdm9625_mi2s_rx_ch = 1;
 static int mdm9625_mi2s_tx_ch = 1;
@@ -292,25 +291,6 @@
 	return ret;
 }
 
-static int set_codec_mclk(struct snd_soc_pcm_runtime *rtd)
-{
-	int ret = 0;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_card *card = rtd->card;
-	struct mdm9625_machine_data *pdata = snd_soc_card_get_drvdata(card);
-
-	if (cdc_mclk_init == true)
-		return 0;
-	ret = snd_soc_dai_set_sysclk(codec_dai, TAIKO_MCLK_ID, pdata->mclk_freq,
-				     SND_SOC_CLOCK_IN);
-	if (ret < 0) {
-		pr_err("%s: Set codec sys clk failed %x", __func__, ret);
-		return ret;
-	}
-	cdc_mclk_init = true;
-	return 0;
-}
-
 static int mdm9625_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					     struct snd_pcm_hw_params *params)
 {
@@ -320,7 +300,6 @@
 					SNDRV_PCM_HW_PARAM_CHANNELS);
 	rate->min = rate->max = 48000;
 	channels->min = channels->max = mdm9625_mi2s_rx_ch;
-	set_codec_mclk(rtd);
 	return 0;
 }
 
@@ -333,7 +312,6 @@
 						SNDRV_PCM_HW_PARAM_CHANNELS);
 	rate->min = rate->max = 48000;
 	channels->min = channels->max = mdm9625_mi2s_tx_ch;
-	set_codec_mclk(rtd);
 	return 0;
 }
 
@@ -713,7 +691,6 @@
 
 	mutex_init(&cdc_mclk_mutex);
 	gpio_enable = false;
-	cdc_mclk_init = false;
 	if (!pdev->dev.of_node) {
 		dev_err(&pdev->dev, "No platform supplied from device tree\n");
 		return -EINVAL;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 4165254..cf0d4cd 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -56,7 +56,7 @@
 					SNDRV_PCM_RATE_KNOT),
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 6,
+			.channels_max = 8,
 			.rate_min =     8000,
 			.rate_max =	48000,
 		},
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 79ce671..841d313 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -49,7 +49,8 @@
 
 static int fm_switch_enable;
 static int fm_pcmrx_switch_enable;
-static int srs_alsa_ctrl_ever_called;
+static short int srs_alsa_ctrl_ever_called_tm;
+static short int srs_alsa_ctrl_ever_called_ss3d;
 
 #define INT_RX_VOL_MAX_STEPS 0x2000
 #define INT_RX_VOL_GAIN 0x2000
@@ -125,19 +126,13 @@
 	unsigned short int raw_params[1];
 };
 static union srs_trumedia_params_u msm_srs_trumedia_params[2];
-static int srs_port_id = -1;
 
-static void srs_send_params(int port_id, unsigned int techs,
+static void srs_send_params_trumedia(int port_id, unsigned int techs,
 		int param_block_idx) {
-
-	/* only send commands to dsp if srs alsa ctrl was used
-	   at least one time */
-	if (!srs_alsa_ctrl_ever_called)
-		return;
-
 	pr_debug("SRS %s: called, port_id = %d, techs flags = %u,"
 			" paramblockidx %d", __func__, port_id, techs,
 			param_block_idx);
+
 	/* force all if techs is set to 1 */
 	if (techs == 1)
 		techs = 0xFFFFFFFF;
@@ -162,6 +157,46 @@
 	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.global);
 }
 
+union srs_SS3D_params_u {
+	struct srs_SS3D_params srs_params;
+	unsigned short int raw_params[1];
+};
+static union srs_SS3D_params_u msm_srs_SS3D_params[2];
+
+static void srs_send_params_SS3D(int port_id, unsigned int techs,
+					int param_block_idx) {
+	pr_debug("SRS %s: called, port_id = %d, techs flags = %u,\n"
+		" paramblockidx %d", __func__, port_id, techs,
+		param_block_idx);
+
+	/* force all if techs is set to 1 */
+	if (techs == 1)
+		techs = 0xFFFFFFFF;
+
+	if (techs & (1 << SRS_ID_SS3D_CTRL))
+		srs_ss3d_open(port_id, SRS_ID_SS3D_CTRL,
+		(void *)&msm_srs_SS3D_params[param_block_idx].srs_params.ss3d);
+	if (techs & (1 << SRS_ID_SS3D_FILTER))
+		srs_ss3d_open(port_id, SRS_ID_SS3D_FILTER,
+	    (void *)&msm_srs_SS3D_params[param_block_idx].srs_params.ss3d_f);
+	if (techs & (1 << SRS_ID_SS3D_GLOBAL))
+		srs_ss3d_open(port_id, SRS_ID_SS3D_GLOBAL,
+	(void *)&msm_srs_SS3D_params[param_block_idx].srs_params.global);
+	return;
+}
+
+static int srs_port_id = -1;
+static void srs_send_params(int port_id, unsigned int techs,
+				int param_block_id) {
+	if (srs_alsa_ctrl_ever_called_tm)
+		srs_send_params_trumedia(port_id, techs, param_block_id);
+	if (srs_alsa_ctrl_ever_called_ss3d)
+		srs_send_params_SS3D(port_id, techs, param_block_id);
+}
+
+/* This array is indexed by back-end DAI ID defined in msm-pcm-routing.h
+ * If new back-end is defined, add new back-end DAI ID at the end of enum
+ */
 static struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
 	{ PRIMARY_I2S_RX, 0, 0, 0, 0, 0},
 	{ PRIMARY_I2S_TX, 0, 0, 0, 0, 0},
@@ -994,7 +1029,7 @@
 	unsigned int techs = 0;
 	unsigned short offset, value, max, index;
 
-	srs_alsa_ctrl_ever_called = 1;
+	srs_alsa_ctrl_ever_called_tm = 1;
 
 	max = sizeof(msm_srs_trumedia_params) >> 1;
 	index = (unsigned short)((ucontrol->value.integer.value[0] &
@@ -1005,7 +1040,7 @@
 		pr_debug("SRS %s: send params request, flags = %u",
 			__func__, techs);
 		if (srs_port_id >= 0 && techs)
-			srs_send_params(srs_port_id, techs, index);
+			srs_send_params_trumedia(srs_port_id, techs, index);
 		return 0;
 	}
 	offset = (unsigned short)((ucontrol->value.integer.value[0] &
@@ -1014,32 +1049,10 @@
 			SRS_PARAM_VALUE_MASK);
 	if (offset < max) {
 		msm_srs_trumedia_params[index].raw_params[offset] = value;
-		pr_debug("SRS %s: index set... (max %d, requested %d,"
-			" val %d, paramblockidx %d)", __func__, max, offset,
-			value, index);
 	} else {
 		pr_err("SRS %s: index out of bounds! (max %d, requested %d)",
 				__func__, max, offset);
 	}
-	if (offset == 4) {
-		int i;
-		for (i = 0; i < max; i++) {
-			if (i == 0) {
-				pr_debug("SRS %s: global block start",
-						__func__);
-			}
-			if (i ==
-			(sizeof(struct srs_trumedia_params_GLOBAL) >> 1)) {
-				break;
-				pr_debug("SRS %s: wowhd block start at"
-					" offset %d word offset %d", __func__,
-					i, i>>1);
-			}
-			pr_debug("SRS %s: param_index %d index %d val %d",
-				__func__, index, i,
-				msm_srs_trumedia_params[index].raw_params[i]);
-		}
-	}
 	return 0;
 }
 
@@ -1047,7 +1060,6 @@
 				struct snd_ctl_elem_value *ucontrol) {
 	int ret;
 
-	pr_debug("SRS control normal called");
 	mutex_lock(&routing_lock);
 	srs_port_id = SLIMBUS_0_RX;
 	ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
@@ -1060,7 +1072,6 @@
 		struct snd_ctl_elem_value *ucontrol) {
 	int ret;
 
-	pr_debug("SRS control I2S called");
 	mutex_lock(&routing_lock);
 	srs_port_id = PRIMARY_I2S_RX;
 	ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
@@ -1073,7 +1084,6 @@
 		struct snd_ctl_elem_value *ucontrol) {
 	int ret;
 
-	pr_debug("SRS control HDMI called");
 	mutex_lock(&routing_lock);
 	srs_port_id = HDMI_RX;
 	ret =  msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
@@ -1081,6 +1091,83 @@
 	return ret;
 }
 
+static int msm_routing_get_srs_SS3D_control(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+
+static int msm_routing_set_srs_SS3D_control_(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned int techs = 0;
+	unsigned short offset, value, max, index;
+
+	srs_alsa_ctrl_ever_called_ss3d = 1;
+
+	max = sizeof(msm_srs_SS3D_params) >> 1;
+	index = (unsigned short)((ucontrol->value.integer.value[0] &
+					 SRS_PARAM_INDEX_MASK) >> 31);
+	if (SRS_CMD_UPLOAD ==
+		 (ucontrol->value.integer.value[0] & SRS_CMD_UPLOAD)) {
+		techs = ucontrol->value.integer.value[0] & 0xFF;
+		pr_debug("SRS %s: send params request, flags = %u", __func__,
+			 techs);
+		if (srs_port_id >= 0 && techs)
+			srs_send_params_SS3D(srs_port_id, techs, index);
+		return 0;
+	}
+
+	offset = (unsigned short)((ucontrol->value.integer.value[0] &
+			SRS_PARAM_OFFSET_MASK) >> 16);
+	value = (unsigned short)(ucontrol->value.integer.value[0] &
+			 SRS_PARAM_VALUE_MASK);
+	if (offset < max) {
+		msm_srs_SS3D_params[index].raw_params[offset] = value;
+	} else {
+		pr_err("SRS %s: index out of bounds! (max %d, requested %d)",
+			 __func__, max, offset);
+	}
+	return 0;
+}
+
+static int msm_routing_set_srs_SS3D_control(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol) {
+	int ret;
+
+	mutex_lock(&routing_lock);
+	srs_port_id = SLIMBUS_0_RX;
+	ret = msm_routing_set_srs_SS3D_control_(kcontrol, ucontrol);
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
+static int msm_routing_set_srs_SS3D_control_I2S(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol) {
+	int ret;
+
+	mutex_lock(&routing_lock);
+	srs_port_id = PRIMARY_I2S_RX;
+	ret = msm_routing_set_srs_SS3D_control_(kcontrol, ucontrol);
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
+static int msm_routing_set_srs_SS3D_control_HDMI(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol) {
+	int ret;
+
+	mutex_lock(&routing_lock);
+	srs_port_id = HDMI_RX;
+	ret = msm_routing_set_srs_SS3D_control_(kcontrol, ucontrol);
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
 static void msm_send_eq_values(int eq_idx)
 {
 	int result;
@@ -2109,6 +2196,66 @@
 	}
 };
 
+static const struct snd_kcontrol_new lpa_SRS_SS3D_controls[] = {
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "SRS SS3D",
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = snd_soc_info_volsw, \
+	.get = msm_routing_get_srs_SS3D_control,
+	.put = msm_routing_set_srs_SS3D_control,
+	.private_value = ((unsigned long)&(struct soc_mixer_control)
+	{.reg = SND_SOC_NOPM,
+	.rreg = SND_SOC_NOPM,
+	.shift = 0,
+	.rshift = 0,
+	.max = 0xFFFFFFFF,
+	.platform_max = 0xFFFFFFFF,
+	.invert = 0
+	})
+	}
+};
+
+static const struct snd_kcontrol_new lpa_SRS_SS3D_controls_HDMI[] = {
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "SRS SS3D HDMI",
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = snd_soc_info_volsw, \
+	.get = msm_routing_get_srs_SS3D_control,
+	.put = msm_routing_set_srs_SS3D_control_HDMI,
+	.private_value = ((unsigned long)&(struct soc_mixer_control)
+	{.reg = SND_SOC_NOPM,
+	.rreg = SND_SOC_NOPM,
+	.shift = 0,
+	.rshift = 0,
+	.max = 0xFFFFFFFF,
+	.platform_max = 0xFFFFFFFF,
+	.invert = 0
+	})
+	}
+};
+
+static const struct snd_kcontrol_new lpa_SRS_SS3D_controls_I2S[] = {
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "SRS SS3D I2S",
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+		SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = snd_soc_info_volsw, \
+	.get = msm_routing_get_srs_SS3D_control,
+	.put = msm_routing_set_srs_SS3D_control_I2S,
+	.private_value = ((unsigned long)&(struct soc_mixer_control)
+	{.reg = SND_SOC_NOPM,
+	.rreg = SND_SOC_NOPM,
+	.shift = 0,
+	.rshift = 0,
+	.max = 0xFFFFFFFF,
+	.platform_max = 0xFFFFFFFF,
+	.invert = 0
+	})
+	}
+};
+
 static const struct snd_kcontrol_new eq_enable_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1 EQ Enable", SND_SOC_NOPM,
 	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_eq_enable_mixer,
@@ -3060,6 +3207,18 @@
 			ARRAY_SIZE(lpa_SRS_trumedia_controls_I2S));
 
 	snd_soc_add_platform_controls(platform,
+				lpa_SRS_SS3D_controls,
+			ARRAY_SIZE(lpa_SRS_SS3D_controls));
+
+	snd_soc_add_platform_controls(platform,
+				lpa_SRS_SS3D_controls_HDMI,
+			ARRAY_SIZE(lpa_SRS_SS3D_controls_HDMI));
+
+	snd_soc_add_platform_controls(platform,
+				lpa_SRS_SS3D_controls_I2S,
+			ARRAY_SIZE(lpa_SRS_SS3D_controls_I2S));
+
+	snd_soc_add_platform_controls(platform,
 				ec_ref_rx_mixer_controls,
 			ARRAY_SIZE(ec_ref_rx_mixer_controls));
 
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 42699c9..bb9f2be 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -58,7 +58,7 @@
 static int msm8930_ext_spk_pamp;
 static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm8930_btsco_ch = 1;
-
+static int hdmi_rate_variable;
 static struct clk *codec_clk;
 static int clk_users;
 
@@ -395,10 +395,13 @@
 static const char *slim0_rx_ch_text[] = {"One", "Two"};
 static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
 
+static const char * const hdmi_rate[] = {"Default", "Variable"};
+
 static const struct soc_enum msm8930_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+	SOC_ENUM_SINGLE_EXT(2, hdmi_rate),
 };
 
 static const char *btsco_rate_text[] = {"8000", "16000"};
@@ -505,6 +508,21 @@
 	return ret;
 }
 
+static int msm8930_hdmi_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	hdmi_rate_variable = ucontrol->value.integer.value[0];
+	pr_debug("%s: hdmi_rate_variable = %d\n", __func__, hdmi_rate_variable);
+	return 0;
+}
+
+static int msm8930_hdmi_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = hdmi_rate_variable;
+	return 0;
+}
+
 static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
 	SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
 		msm8930_set_spk),
@@ -516,6 +534,9 @@
 		msm8930_pmic_gain_get, msm8930_pmic_gain_put),
 	SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8930_btsco_enum[0],
 		msm8930_btsco_rate_get, msm8930_btsco_rate_put),
+	SOC_ENUM_EXT("HDMI RX Rate", msm8930_enum[3],
+					msm8930_hdmi_rate_get,
+					msm8930_hdmi_rate_put),
 };
 
 static void *def_sitar_mbhc_cal(void)
@@ -751,7 +772,8 @@
 	struct snd_interval *channels = hw_param_interval(params,
 					SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	rate->min = rate->max = 48000;
+	if (!hdmi_rate_variable)
+		rate->min = rate->max = 48000;
 	channels->min = channels->max = 2;
 
 	return 0;
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index ad78255..da62729 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -73,7 +73,7 @@
 
 static int msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
 static int msm8960_btsco_ch = 1;
-
+static int hdmi_rate_variable;
 static int msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
 
 static struct clk *codec_clk;
@@ -549,11 +549,13 @@
 static const char *spk_function[] = {"Off", "On"};
 static const char *slim0_rx_ch_text[] = {"One", "Two"};
 static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+static const char * const hdmi_rate[] = {"Default", "Variable"};
 
 static const struct soc_enum msm8960_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
 	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
+	SOC_ENUM_SINGLE_EXT(2, hdmi_rate),
 };
 
 static const char *btsco_rate_text[] = {"8000", "16000"};
@@ -660,6 +662,21 @@
 	return 0;
 }
 
+static int msm8960_hdmi_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	hdmi_rate_variable = ucontrol->value.integer.value[0];
+	pr_debug("%s: hdmi_rate_variable = %d\n", __func__, hdmi_rate_variable);
+	return 0;
+}
+
+static int msm8960_hdmi_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = hdmi_rate_variable;
+	return 0;
+}
+
 static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
 	SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
 		msm8960_set_spk),
@@ -671,6 +688,9 @@
 		msm8960_btsco_rate_get, msm8960_btsco_rate_put),
 	SOC_ENUM_EXT("AUX PCM SampleRate", msm8960_auxpcm_enum[0],
 		msm8960_auxpcm_rate_get, msm8960_auxpcm_rate_put),
+	SOC_ENUM_EXT("HDMI RX Rate", msm8960_enum[3],
+					msm8960_hdmi_rate_get,
+					msm8960_hdmi_rate_put),
 };
 
 static void *def_tabla_mbhc_cal(void)
@@ -1003,7 +1023,8 @@
 
 	if (channels->max < 2)
 		channels->min = channels->max = 2;
-	rate->min = rate->max = 48000;
+	if (!hdmi_rate_variable)
+		rate->min = rate->max = 48000;
 
 	return 0;
 }
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 58205e9..cf1202e 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);
 
@@ -1116,6 +1076,22 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{
+		.name = "VoLTE",
+		.stream_name = "VoLTE",
+		.cpu_dai_name   = "VoLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOLTE,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1350,6 +1326,30 @@
 		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
 		.ops = &msm8974_be_ops,
 	},
+	/* Incall Record Uplink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_TX,
+		.stream_name = "Voice Uplink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32772",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+	},
+	/* Incall Record Downlink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_RX,
+		.stream_name = "Voice Downlink Capture",
+		.cpu_dai_name = "msm-dai-q6-dev.32771",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+	},
 };
 
 struct snd_soc_card snd_soc_card_msm8974 = {
@@ -1458,9 +1458,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 +1476,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..2d8d9ca 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -230,6 +230,182 @@
 	return ret;
 }
 
+struct SS3D {
+	int     _1;  int     _2;  short   _3;  short   _4;
+	short   _5;  short   _6;  int     _7;  int     _X[32];
+	short   _8;  short   _9;  short   _10; short   _11;
+	short   _12; short   _13; short   _14; short   _15;
+	short   _16; short   _17; short   _18; short	_19;
+	short   _20; short   _21; short   _22; short   _23;
+	short   _24; short   _25; short   _26[5];
+	short   _27; short   _28; short	  _29; short   _30;
+	short   _31; short   _32; short   _33; int     _34; int   _35;
+	int     _36; int     _37; int     _38; int     _39; int   _40;
+};
+
+struct SS3D_F {
+	int	_1; int _2; int _3; int _4; int _5; int _6; int _7; int _X[];
+};
+
+int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params)
+{
+	struct asm_pp_params_command *open = NULL;
+	int ret = 0, sz = 0;
+
+	int index;
+
+	pr_debug("SRS - %s: called.", __func__);
+
+	switch (srs_tech_id) {
+	case SRS_ID_SS3D_GLOBAL: {
+		struct srs_SS3D_params_GLOBAL *glb_params = NULL;
+		sz = sizeof(struct asm_pp_params_command) +
+			 sizeof(struct srs_SS3D_params_GLOBAL);
+		open = kzalloc(sz, GFP_KERNEL);
+
+		open->payload_size = sizeof(struct srs_SS3D_params_GLOBAL) +
+					 sizeof(struct asm_pp_param_data_hdr);
+		open->params.param_id = SRS_SS3D_PARAMS;
+		open->params.param_size =
+				 sizeof(struct srs_SS3D_params_GLOBAL);
+
+		glb_params = (struct srs_SS3D_params_GLOBAL *)((u8 *)open +
+				 sizeof(struct asm_pp_params_command));
+		memcpy(glb_params, srs_params,
+				 sizeof(struct srs_SS3D_params_GLOBAL));
+
+		pr_debug("SRS - ss3d global params - 1 = %x, 2 = %x, 3 = %x\n"
+			" 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x\n",
+			(int)glb_params->v1, (int)glb_params->v2,
+			(int)glb_params->v3, (int)glb_params->v4,
+			(int)glb_params->v5, (int)glb_params->v6,
+			(int)glb_params->v7, (int)glb_params->v8);
+		break;
+	}
+	case SRS_ID_SS3D_CTRL: {
+		struct srs_SS3D_ctrl_params *whd_params = NULL;
+		sz = sizeof(struct asm_pp_params_command) +
+			 sizeof(struct srs_SS3D_ctrl_params);
+		open = kzalloc(sz, GFP_KERNEL);
+
+		open->payload_size = sizeof(struct srs_SS3D_ctrl_params) +
+			 sizeof(struct asm_pp_param_data_hdr);
+		open->params.param_id = SRS_SS3D_PARAMS_CTRL;
+		open->params.param_size = sizeof(struct srs_SS3D_ctrl_params);
+
+		whd_params = (struct srs_SS3D_ctrl_params *)((u8 *)open +
+				 sizeof(struct asm_pp_params_command));
+		memcpy(whd_params, srs_params,
+			 sizeof(struct srs_SS3D_ctrl_params));
+
+		{
+			struct SS3D *D = (struct SS3D *)whd_params->v;
+			pr_debug("SRS - ss3d ctrl params\n"
+				"1 = 0x%08X, 2 = 0x%08X, 3 = 0x%04X,\n"
+				"4 = 0x%04X, 5 = 0x%04X, 6 = 0x%04X,\n"
+				"7 = 0x%08X, 8 = 0x%04X, 9 = 0x%04X,\n"
+				"10 = 0x%04X, 11 = 0x%04X, 12 = 0x%04X,\n"
+				"13 = 0x%04X, 14 = 0x%04X, 15 = 0x%04X,\n"
+				"16 = 0x%04X, 17 = 0x%04X, 18 = 0x%04X,\n"
+				"19 = 0x%04X, 20 = 0x%04X, 21 = 0x%04X,\n"
+				"22 = 0x%04X, 23 = 0x%04X, 24 = 0x%04X,\n"
+				"25 = 0x%04X, 26.0 = 0x%04X, 26.1 = 0x%04X,\n"
+				"26.2 = 0x%04X, 26.3 = 0x%04X,\n"
+				"26.4 = 0x%04X, 27 = 0x%04X, 28 = 0x%04X,\n"
+				"29 = 0x%04X, 30 = 0x%04X, 31 = 0x%04X,\n"
+				"32 = 0x%04X, 33 = 0x%04X, 34 = 0x%08X,\n"
+				"35 = 0x%08X, 36 = 0x%08X, 37 = 0x%08X,\n"
+				"38 = 0x%08X, 39 = 0x%08X, 40 = 0x%08X",
+				D->_1, D->_2, D->_3, D->_4, D->_5, D->_6, D->_7,
+				D->_8, D->_9, D->_10, D->_11, D->_12, D->_13,
+				D->_14, D->_15, D->_16, D->_17, D->_18, D->_19,
+				D->_20,	D->_21, D->_22,	D->_23, D->_24, D->_25,
+				D->_26[0], D->_26[1], D->_26[2], D->_26[3],
+				D->_26[4], D->_27, D->_28, D->_29, D->_30,
+				D->_31, D->_32, D->_33, D->_34, D->_35, D->_36,
+				D->_37,	D->_38, D->_39, D->_40);
+		}
+		break;
+	}
+	case SRS_ID_SS3D_FILTER: {
+		struct srs_SS3D_filter_params *chp_params = NULL;
+		sz = sizeof(struct asm_pp_params_command) +
+			 sizeof(struct srs_SS3D_filter_params);
+		open = kzalloc(sz, GFP_KERNEL);
+
+		open->payload_size = sizeof(struct srs_SS3D_filter_params) +
+					sizeof(struct asm_pp_param_data_hdr);
+		open->params.param_id = SRS_SS3D_PARAMS_FILTER;
+		open->params.param_size =
+				 sizeof(struct srs_SS3D_filter_params);
+
+		chp_params = (struct srs_SS3D_filter_params *)((u8 *)open +
+				 sizeof(struct asm_pp_params_command));
+		memcpy(chp_params, srs_params,
+			 sizeof(struct srs_SS3D_filter_params));
+
+		{
+			struct SS3D_F *D = (struct SS3D_F *)chp_params->v;
+			pr_debug("SRS - ss3d filter params\n"
+				"1 = 0x%08X, 2 = 0x%08X, 3 = 0x%08X\n"
+				"4 = 0x%08X, 5 = 0x%08X, 6 = 0x%08X\n"
+				"7 = 0x%08X", D->_1, D->_2, D->_3, D->_4, D->_5,
+				D->_6, D->_7);
+		}
+		break;
+	}
+	default:
+		pr_debug("SRS - bad param!\n");
+		goto fail_cmd;
+	}
+
+	open->payload = NULL;
+
+	open->params.module_id = SRS_SS3D_MODULE_ID;
+	open->params.reserved = 0;
+
+	open->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				 APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	open->hdr.pkt_size = sz;
+	open->hdr.src_svc = APR_SVC_ADM;
+	open->hdr.src_domain = APR_DOMAIN_APPS;
+	open->hdr.src_port = port_id;
+	open->hdr.dest_svc = APR_SVC_ADM;
+	open->hdr.dest_domain = APR_DOMAIN_ADSP;
+
+	index = afe_get_port_index(port_id);
+	open->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+		 /* port_id;//atomic_read(&this_adm.copp_id[port_id]); */
+	open->hdr.token = port_id;
+	open->hdr.opcode = ADM_CMD_SET_PARAMS;
+
+	pr_debug("SRS - %s: Command was sent now check Q6 - port id = %d,\n"
+		"size %d, module id %x, param id %x.\n",
+		 __func__, open->hdr.dest_port, open->payload_size,
+		 open->params.module_id, open->params.param_id);
+
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *)open);
+	if (ret < 0) {
+		pr_err("SRS - %s: ADM enable for port %d failed\n",
+			 __func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	/* Wait for the callback with copp id */
+	ret = wait_event_timeout(this_adm.wait, 1,
+		 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("SRS - %s: ADM open failed for port %d\n",
+			 __func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+fail_cmd:
+	kfree(open);
+	return ret;
+}
+
 static int32_t adm_callback(struct apr_client_data *data, void *priv)
 {
 	uint32_t *payload;
@@ -853,24 +1029,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..2f4c256 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -432,12 +432,11 @@
 	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
 		switch (dai->id) {
 		case VOICE_PLAYBACK_TX:
-		case VOICE_RECORD_TX:
-		case VOICE_RECORD_RX:
 			rc = afe_start_pseudo_port(dai->id);
+			break;
 		default:
 			rc = afe_port_start(dai->id, &dai_data->port_config,
-					    dai_data->rate);
+					dai_data->rate);
 		}
 
 		if (IS_ERR_VALUE(rc))
@@ -606,6 +605,36 @@
 	return 0;
 }
 
+static int msm_dai_q6_psuedo_port_hw_params(struct snd_pcm_hw_params *params,
+				    struct snd_soc_dai *dai, int stream)
+{
+	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+	dai_data->channels = params_channels(params);
+	dai_data->rate = params_rate(params);
+
+	/* Q6 only supports 16 as now */
+	dai_data->port_config.pseudo_port.pseud_port_cfg_minor_version =
+				AFE_API_VERSION_PSEUDO_PORT_CONFIG;
+	dai_data->port_config.pseudo_port.num_channels =
+				params_channels(params);
+	dai_data->port_config.pseudo_port.bit_width = 16;
+	dai_data->port_config.pseudo_port.data_format = 0;
+	dai_data->port_config.pseudo_port.timing_mode =
+				AFE_PSEUDOPORT_TIMING_MODE_TIMER;
+	dai_data->port_config.pseudo_port.sample_rate = params_rate(params);
+
+	dev_dbg(dai->dev, "%s: bit_wd[%hu] num_channels [%hu] format[%hu]\n"
+		"timing Mode %hu sample_rate %d\n", __func__,
+		dai_data->port_config.pseudo_port.bit_width,
+		dai_data->port_config.pseudo_port.num_channels,
+		dai_data->port_config.pseudo_port.data_format,
+		dai_data->port_config.pseudo_port.timing_mode,
+		dai_data->port_config.pseudo_port.sample_rate);
+
+	return 0;
+}
+
 /* Current implementation assumes hw_param is called once
  * This may not be the case but what to do when ADM and AFE
  * port are already opened and parameter changes
@@ -649,9 +678,12 @@
 		rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
 		break;
 	case VOICE_PLAYBACK_TX:
+		rc = 0;
+		break;
 	case VOICE_RECORD_RX:
 	case VOICE_RECORD_TX:
-		rc = 0;
+		rc = msm_dai_q6_psuedo_port_hw_params(params,
+						dai, substream->stream);
 		break;
 	default:
 		dev_err(dai->dev, "invalid AFE port ID\n");
@@ -671,8 +703,6 @@
 	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
 		switch (dai->id) {
 		case VOICE_PLAYBACK_TX:
-		case VOICE_RECORD_TX:
-		case VOICE_RECORD_RX:
 			pr_debug("%s, stop pseudo port:%d\n",
 						__func__,  dai->id);
 			rc = afe_stop_pseudo_port(dai->id);
@@ -832,8 +862,6 @@
 	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
 		switch (dai->id) {
 		case VOICE_PLAYBACK_TX:
-		case VOICE_RECORD_TX:
-		case VOICE_RECORD_RX:
 			pr_debug("%s, stop pseudo port:%d\n",
 				 __func__,  dai->id);
 			rc = afe_stop_pseudo_port(dai->id);
@@ -872,7 +900,7 @@
 		SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
-		.channels_max = 4,
+		.channels_max = 8,
 		.rate_min =     8000,
 		.rate_max =	48000,
 	},
@@ -969,6 +997,21 @@
 	.remove = msm_dai_q6_dai_remove,
 };
 
+static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =     48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
 static int __devinit msm_auxpcm_dev_probe(struct platform_device *pdev)
 {
 	int id;
@@ -1310,6 +1353,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 +1373,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 +1392,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 +1408,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 +1446,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 +1517,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 +1579,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 +1787,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 +1810,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) {
@@ -1851,6 +1922,12 @@
 	case RT_PROXY_DAI_002_TX:
 		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
 		break;
+	case VOICE_RECORD_RX:
+	case VOICE_RECORD_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+						&msm_dai_q6_incall_record_dai);
+		break;
+
 	default:
 		rc = -ENODEV;
 		break;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 73a04c2..1aa12e3 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -33,8 +33,10 @@
 #include <mach/msm_subsystem_map.h>
 #include "msm-pcm-afe-v2.h"
 
-#define MIN_PERIOD_SIZE (128 * 2)
-#define MAX_PERIOD_SIZE (128 * 2 * 2 * 6)
+#define MIN_PERIOD_SIZE (128 * 2 * 8)
+#define MAX_PERIOD_SIZE (128 * 2 * 2 * 6 * 8)
+#define MAX_NUM_PERIODS 384
+#define MIN_NUM_PERIODS 32
 static struct snd_pcm_hardware msm_afe_hardware = {
 	.info =			(SNDRV_PCM_INFO_MMAP |
 				SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -47,12 +49,12 @@
 	.rate_min =             8000,
 	.rate_max =             48000,
 	.channels_min =         1,
-	.channels_max =         2,
+	.channels_max =         8,
 	.buffer_bytes_max =     MAX_PERIOD_SIZE * 32,
 	.period_bytes_min =     MIN_PERIOD_SIZE,
 	.period_bytes_max =     MAX_PERIOD_SIZE,
-	.periods_min =          32,
-	.periods_max =          384,
+	.periods_min =          MIN_NUM_PERIODS,
+	.periods_max =          MAX_NUM_PERIODS,
 	.fifo_size =            0,
 };
 static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt);
@@ -353,6 +355,17 @@
 	if (ret < 0)
 		pr_err("snd_pcm_hw_constraint_integer failed\n");
 
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		ret = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			MAX_NUM_PERIODS * MIN_PERIOD_SIZE,
+			MIN_NUM_PERIODS * MAX_PERIOD_SIZE);
+		if (ret < 0) {
+			pr_err("constraint for buffer bytes min max ret = %d\n",
+									ret);
+		}
+	}
+
 	return 0;
 }
 
@@ -497,8 +510,8 @@
 		dir = OUT;
 	rc = q6afe_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
-			runtime->hw.period_bytes_min,
-			runtime->hw.periods_max);
+			(params_buffer_bytes(params) / params_periods(params)),
+			params_periods(params));
 	if (rc < 0) {
 		pr_err("Audio Start: Buffer Allocation failed rc = %d\n", rc);
 		mutex_unlock(&prtd->lock);
@@ -517,14 +530,14 @@
 	dma_buf->private_data = NULL;
 	dma_buf->area = buf[0].data;
 	dma_buf->addr = buf[0].phys;
-	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	dma_buf->bytes = params_buffer_bytes(params);
 	if (!dma_buf->area) {
 		pr_err("%s:MSM AFE physical memory allocation failed\n",
 							__func__);
 		mutex_unlock(&prtd->lock);
 		return -ENOMEM;
 	}
-	memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
+	memset(dma_buf->area, 0, params_buffer_bytes(params));
 	prtd->dma_addr = (u32) dma_buf->addr;
 
 	mutex_unlock(&prtd->lock);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 1e6fc04..1d6e106 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -41,7 +41,8 @@
 };
 
 #define PLAYBACK_NUM_PERIODS	8
-#define PLAYBACK_PERIOD_SIZE	2048
+#define PLAYBACK_MAX_PERIOD_SIZE    12288
+#define PLAYBACK_MIN_PERIOD_SIZE    2048
 #define CAPTURE_NUM_PERIODS	16
 #define CAPTURE_PERIOD_SIZE	512
 
@@ -76,10 +77,10 @@
 	.rate_min =             8000,
 	.rate_max =             48000,
 	.channels_min =         1,
-	.channels_max =         2,
-	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_PERIOD_SIZE,
-	.period_bytes_min =	PLAYBACK_PERIOD_SIZE,
-	.period_bytes_max =     PLAYBACK_PERIOD_SIZE,
+	.channels_max =         8,
+	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+	.period_bytes_min =	PLAYBACK_MIN_PERIOD_SIZE,
+	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
 	.periods_min =          PLAYBACK_NUM_PERIODS,
 	.periods_max =          PLAYBACK_NUM_PERIODS,
 	.fifo_size =            0,
@@ -352,6 +353,17 @@
 	if (ret < 0)
 		pr_info("snd_pcm_hw_constraint_integer failed\n");
 
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			PLAYBACK_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
+			PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
+		if (ret < 0) {
+			pr_err("constraint for buffer bytes min max ret = %d\n",
+									ret);
+		}
+	}
+
 	prtd->dsp_cnt = 0;
 	runtime->private_data = prtd;
 
@@ -642,8 +654,8 @@
 
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
-			runtime->hw.period_bytes_min,
-			runtime->hw.periods_max);
+			(params_buffer_bytes(params) / params_periods(params)),
+			 params_periods(params));
 	if (ret < 0) {
 		pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
 							ret);
@@ -659,7 +671,7 @@
 	dma_buf->private_data = NULL;
 	dma_buf->area = buf[0].data;
 	dma_buf->addr =  buf[0].phys;
-	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	dma_buf->bytes = params_buffer_bytes(params);
 	if (!dma_buf->area)
 		return -ENOMEM;
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 2e0c229..58300c4 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -50,6 +50,7 @@
 
 static int fm_switch_enable;
 static int fm_pcmrx_switch_enable;
+static int srs_alsa_ctrl_ever_called;
 
 #define INT_RX_VOL_MAX_STEPS 0x2000
 #define INT_RX_VOL_GAIN 0x2000
@@ -112,6 +113,49 @@
 /* This array is indexed by back-end DAI ID defined in msm-pcm-routing.h
  * If new back-end is defined, add new back-end DAI ID at the end of enum
  */
+
+
+union srs_trumedia_params_u {
+	struct srs_trumedia_params srs_params;
+	unsigned short int raw_params[1];
+};
+static union srs_trumedia_params_u msm_srs_trumedia_params[2];
+static int srs_port_id = -1;
+
+static void srs_send_params(int port_id, unsigned int techs,
+		int param_block_idx)
+{
+	/* only send commands to dsp if srs alsa ctrl was used
+	   at least one time */
+	if (!srs_alsa_ctrl_ever_called)
+		return;
+
+	pr_debug("SRS %s: called, port_id = %d, techs flags = %u, paramblockidx %d",
+		__func__, port_id, techs, param_block_idx);
+	/* force all if techs is set to 1 */
+	if (techs == 1)
+		techs = 0xFFFFFFFF;
+
+	if (techs & (1 << SRS_ID_WOWHD))
+		srs_trumedia_open(port_id, SRS_ID_WOWHD,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.wowhd);
+	if (techs & (1 << SRS_ID_CSHP))
+		srs_trumedia_open(port_id, SRS_ID_CSHP,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.cshp);
+	if (techs & (1 << SRS_ID_HPF))
+		srs_trumedia_open(port_id, SRS_ID_HPF,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.hpf);
+	if (techs & (1 << SRS_ID_PEQ))
+		srs_trumedia_open(port_id, SRS_ID_PEQ,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.peq);
+	if (techs & (1 << SRS_ID_HL))
+		srs_trumedia_open(port_id, SRS_ID_HL,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.hl);
+	if (techs & (1 << SRS_ID_GLOBAL))
+		srs_trumedia_open(port_id, SRS_ID_GLOBAL,
+	(void *)&msm_srs_trumedia_params[param_block_idx].srs_params.global);
+}
+
 #define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
 static struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
 	{ PRIMARY_I2S_RX, 0, 0, 0, 0, 0},
@@ -142,6 +186,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},
 };
 
 
@@ -283,6 +329,8 @@
 
 			payload.copp_ids[payload.num_copps++] =
 				msm_bedais[i].port_id;
+			srs_port_id = msm_bedais[i].port_id;
+			srs_send_params(srs_port_id, 1, 0);
 		}
 	}
 	if (payload.num_copps)
@@ -391,6 +439,8 @@
 
 			msm_pcm_routing_build_matrix(val,
 				fe_dai_map[val][session_type], path_type);
+			srs_port_id = msm_bedais[reg].port_id;
+			srs_send_params(srs_port_id, 1, 0);
 		}
 	} else {
 		if (test_bit(val, &msm_bedais[reg].fe_sessions) &&
@@ -753,6 +803,104 @@
 	return 0;
 }
 
+static int msm_routing_get_srs_trumedia_control(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_routing_set_srs_trumedia_control_(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned int techs = 0;
+	unsigned short offset, value, max, index;
+
+	srs_alsa_ctrl_ever_called = 1;
+
+	max = sizeof(msm_srs_trumedia_params) >> 1;
+	index = (unsigned short)((ucontrol->value.integer.value[0] &
+			SRS_PARAM_INDEX_MASK) >> 31);
+	if (SRS_CMD_UPLOAD ==
+		(ucontrol->value.integer.value[0] & SRS_CMD_UPLOAD)) {
+		techs = ucontrol->value.integer.value[0] & 0xFF;
+		pr_debug("SRS %s: send params request, flags = %u",
+			__func__, techs);
+		if (srs_port_id >= 0 && techs)
+			srs_send_params(srs_port_id, techs, index);
+		return 0;
+	}
+	offset = (unsigned short)((ucontrol->value.integer.value[0] &
+			SRS_PARAM_OFFSET_MASK) >> 16);
+	value = (unsigned short)(ucontrol->value.integer.value[0] &
+			SRS_PARAM_VALUE_MASK);
+	if (offset < max) {
+		msm_srs_trumedia_params[index].raw_params[offset] = value;
+		pr_debug("SRS %s: index set... (max %d, requested %d, val %d, paramblockidx %d)",
+			__func__, max, offset, value, index);
+	} else {
+		pr_err("SRS %s: index out of bounds! (max %d, requested %d)",
+				__func__, max, offset);
+	}
+	if (offset == 4) {
+		int i;
+		for (i = 0; i < max; i++) {
+			if (i == 0) {
+				pr_debug("SRS %s: global block start",
+						__func__);
+			}
+			if (i ==
+			(sizeof(struct srs_trumedia_params_GLOBAL) >> 1)) {
+				pr_debug("SRS %s: wowhd block start at offset %d word offset %d",
+					__func__, i, i>>1);
+				break;
+			}
+			pr_debug("SRS %s: param_index %d index %d val %d",
+				__func__, index, i,
+				msm_srs_trumedia_params[index].raw_params[i]);
+		}
+	}
+	return 0;
+}
+
+static int msm_routing_set_srs_trumedia_control(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol) {
+	int ret;
+
+	pr_debug("SRS control normal called");
+	mutex_lock(&routing_lock);
+	srs_port_id = SLIMBUS_0_RX;
+	ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
+static int msm_routing_set_srs_trumedia_control_I2S(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol) {
+	int ret;
+
+	pr_debug("SRS control I2S called");
+	mutex_lock(&routing_lock);
+	srs_port_id = PRIMARY_I2S_RX;
+	ret = msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
+static int msm_routing_set_srs_trumedia_control_HDMI(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol) {
+	int ret;
+
+	pr_debug("SRS control HDMI called");
+	mutex_lock(&routing_lock);
+	srs_port_id = HDMI_RX;
+	ret =  msm_routing_set_srs_trumedia_control_(kcontrol, ucontrol);
+	mutex_unlock(&routing_lock);
+	return ret;
+}
+
 static void msm_send_eq_values(int eq_idx)
 {
 	int result;
@@ -943,6 +1091,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 +1206,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),
@@ -1390,6 +1556,67 @@
 	INT_RX_VOL_GAIN, 0, msm_routing_get_compressed_vol_mixer,
 	msm_routing_set_compressed_vol_mixer, compressed_rx_vol_gain),
 };
+
+static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "SRS TruMedia",
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = snd_soc_info_volsw, \
+	.get = msm_routing_get_srs_trumedia_control,
+	.put = msm_routing_set_srs_trumedia_control,
+	.private_value = ((unsigned long)&(struct soc_mixer_control)
+	{.reg = SND_SOC_NOPM,
+	.rreg = SND_SOC_NOPM,
+	.shift = 0,
+	.rshift = 0,
+	.max = 0xFFFFFFFF,
+	.platform_max = 0xFFFFFFFF,
+	.invert = 0
+	})
+	}
+};
+
+static const struct snd_kcontrol_new lpa_SRS_trumedia_controls_HDMI[] = {
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "SRS TruMedia HDMI",
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = snd_soc_info_volsw, \
+	.get = msm_routing_get_srs_trumedia_control,
+	.put = msm_routing_set_srs_trumedia_control_HDMI,
+	.private_value = ((unsigned long)&(struct soc_mixer_control)
+	{.reg = SND_SOC_NOPM,
+	.rreg = SND_SOC_NOPM,
+	.shift = 0,
+	.rshift = 0,
+	.max = 0xFFFFFFFF,
+	.platform_max = 0xFFFFFFFF,
+	.invert = 0
+	})
+	}
+};
+
+static const struct snd_kcontrol_new lpa_SRS_trumedia_controls_I2S[] = {
+	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "SRS TruMedia I2S",
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+		SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = snd_soc_info_volsw, \
+	.get = msm_routing_get_srs_trumedia_control,
+	.put = msm_routing_set_srs_trumedia_control_I2S,
+	.private_value = ((unsigned long)&(struct soc_mixer_control)
+	{.reg = SND_SOC_NOPM,
+	.rreg = SND_SOC_NOPM,
+	.shift = 0,
+	.rshift = 0,
+	.max = 0xFFFFFFFF,
+	.platform_max = 0xFFFFFFFF,
+	.invert = 0
+	})
+	}
+};
+
 static const struct snd_kcontrol_new eq_enable_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1 EQ Enable", SND_SOC_NOPM,
 	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_eq_enable_mixer,
@@ -1623,8 +1850,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 +1916,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 +2062,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 +2248,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" },
@@ -2021,6 +2266,8 @@
 	{"BE_OUT", NULL, "SLIMBUS_3_RX"},
 	{"BE_OUT", NULL, "AUX_PCM_RX"},
 	{"AUX_PCM_TX", NULL, "BE_IN"},
+	{"INCALL_RECORD_TX", NULL, "BE_IN"},
+	{"INCALL_RECORD_RX", NULL, "BE_IN"},
 };
 
 static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
@@ -2062,6 +2309,7 @@
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
 		if (fe_dai_map[i][session_type] != INVALID_SESSION)
 			adm_close(bedai->port_id);
+			srs_port_id = -1;
 	}
 
 	bedai->active = 0;
@@ -2127,6 +2375,8 @@
 
 			msm_pcm_routing_build_matrix(i,
 				fe_dai_map[i][session_type], path_type);
+			srs_port_id = bedai->port_id;
+			srs_send_params(srs_port_id, 1, 0);
 		}
 	}
 
@@ -2194,6 +2444,18 @@
 	snd_soc_add_platform_controls(platform,
 				compressed_vol_mixer_controls,
 			ARRAY_SIZE(compressed_vol_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
+				lpa_SRS_trumedia_controls,
+			ARRAY_SIZE(lpa_SRS_trumedia_controls));
+
+	snd_soc_add_platform_controls(platform,
+				lpa_SRS_trumedia_controls_HDMI,
+			ARRAY_SIZE(lpa_SRS_trumedia_controls_HDMI));
+
+	snd_soc_add_platform_controls(platform,
+				lpa_SRS_trumedia_controls_I2S,
+			ARRAY_SIZE(lpa_SRS_trumedia_controls_I2S));
 	return 0;
 }
 
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/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index f1e0f3a..a1e461d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -33,7 +33,9 @@
 
 static struct snd_pcm_hardware msm_pcm_hardware = {
 
-	.info =                 SNDRV_PCM_INFO_INTERLEAVED,
+	.info =                 (SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE |
+				SNDRV_PCM_INFO_RESUME),
 	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
 	.rates =                SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
 	.rate_min =             8000,
@@ -205,6 +207,55 @@
 	return 0;
 }
 
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_voice *prtd = runtime->private_data;
+	uint16_t session_id = 0;
+
+	pr_debug("%s: cmd = %d\n", __func__, cmd);
+	if (is_volte(prtd))
+		session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+	else
+		session_id = voc_get_session_id(VOICE_SESSION_NAME);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("Start & Stop Voice call not handled in Trigger.\n");
+	break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("%s: resume call session_id = %d\n", __func__,
+			 session_id);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			ret = msm_pcm_playback_prepare(substream);
+		else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			ret = msm_pcm_capture_prepare(substream);
+		if (prtd->playback_start && prtd->capture_start)
+			voc_resume_voice_call(session_id);
+	break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("%s: pause call session_id=%d\n",
+			 __func__, session_id);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			if (prtd->playback_start)
+				prtd->playback_start = 0;
+		} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+			if (prtd->capture_start)
+				prtd->capture_start = 0;
+		}
+		voc_standby_voice_call(session_id);
+		break;
+	default:
+		ret = -EINVAL;
+	break;
+	}
+	return ret;
+}
+
 static int msm_voice_volume_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -437,6 +488,7 @@
 	.hw_params	= msm_pcm_hw_params,
 	.close          = msm_pcm_close,
 	.prepare        = msm_pcm_prepare,
+	.trigger	= msm_pcm_trigger,
 };
 
 
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index cc69123..663b7c0 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -34,23 +34,218 @@
 
 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];
+	wait_queue_head_t wait[AFE_MAX_PORTS];
 
-static struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
-static struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
+	struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
+	struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
 
 /* 0 - (MAX_AUDPROC_TYPES -1):				audproc handles */
 /* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1):	audvol handles */
-atomic_t mem_map_handles[(2 * MAX_AUDPROC_TYPES)];
-atomic_t mem_map_index;
+	atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES)];
+	atomic_t mem_map_cal_index;
+};
 
 static struct adm_ctl			this_adm;
 
+int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params)
+{
+	struct adm_cmd_set_pp_params_inband_v5 *adm_params = NULL;
+	int ret = 0, sz = 0;
+	int index;
+
+	pr_debug("SRS - %s", __func__);
+	switch (srs_tech_id) {
+	case SRS_ID_GLOBAL: {
+		struct srs_trumedia_params_GLOBAL *glb_params = NULL;
+		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+			sizeof(struct srs_trumedia_params_GLOBAL);
+		adm_params = kzalloc(sz, GFP_KERNEL);
+		adm_params->payload_size =
+			sizeof(struct srs_trumedia_params_GLOBAL) +
+			sizeof(struct adm_param_data_v5);
+		adm_params->params.param_id = SRS_TRUMEDIA_PARAMS;
+		adm_params->params.param_size =
+				sizeof(struct srs_trumedia_params_GLOBAL);
+		glb_params = (struct srs_trumedia_params_GLOBAL *)
+			((u8 *)adm_params +
+			sizeof(struct adm_cmd_set_pp_params_inband_v5));
+		memcpy(glb_params, srs_params,
+			sizeof(struct srs_trumedia_params_GLOBAL));
+		pr_debug("SRS - %s: Global params - 1 = %x, 2 = %x, 3 = %x, 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x\n",
+				__func__, (int)glb_params->v1,
+				(int)glb_params->v2, (int)glb_params->v3,
+				(int)glb_params->v4, (int)glb_params->v5,
+				(int)glb_params->v6, (int)glb_params->v7,
+				(int)glb_params->v8);
+		break;
+	}
+	case SRS_ID_WOWHD: {
+		struct srs_trumedia_params_WOWHD *whd_params = NULL;
+		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+			sizeof(struct srs_trumedia_params_WOWHD);
+		adm_params = kzalloc(sz, GFP_KERNEL);
+		adm_params->payload_size =
+			sizeof(struct srs_trumedia_params_WOWHD) +
+			sizeof(struct adm_param_data_v5);
+		adm_params->params.param_id = SRS_TRUMEDIA_PARAMS_WOWHD;
+		adm_params->params.param_size =
+				sizeof(struct srs_trumedia_params_WOWHD);
+		whd_params = (struct srs_trumedia_params_WOWHD *)
+			((u8 *)adm_params +
+			sizeof(struct adm_cmd_set_pp_params_inband_v5));
+		memcpy(whd_params, srs_params,
+				sizeof(struct srs_trumedia_params_WOWHD));
+		pr_debug("SRS - %s: WOWHD params - 1 = %x, 2 = %x, 3 = %x, 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x, 9 = %x, 10 = %x, 11 = %x\n",
+			 __func__, (int)whd_params->v1,
+			(int)whd_params->v2, (int)whd_params->v3,
+			(int)whd_params->v4, (int)whd_params->v5,
+			(int)whd_params->v6, (int)whd_params->v7,
+			(int)whd_params->v8, (int)whd_params->v9,
+			(int)whd_params->v10, (int)whd_params->v11);
+		break;
+	}
+	case SRS_ID_CSHP: {
+		struct srs_trumedia_params_CSHP *chp_params = NULL;
+		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+			sizeof(struct srs_trumedia_params_CSHP);
+		adm_params = kzalloc(sz, GFP_KERNEL);
+		adm_params->payload_size =
+			sizeof(struct srs_trumedia_params_CSHP) +
+			sizeof(struct adm_param_data_v5);
+		adm_params->params.param_id = SRS_TRUMEDIA_PARAMS_CSHP;
+		adm_params->params.param_size =
+				sizeof(struct srs_trumedia_params_CSHP);
+		chp_params = (struct srs_trumedia_params_CSHP *)
+			((u8 *)adm_params +
+			sizeof(struct adm_cmd_set_pp_params_inband_v5));
+		memcpy(chp_params, srs_params,
+				sizeof(struct srs_trumedia_params_CSHP));
+		pr_debug("SRS - %s: CSHP params - 1 = %x, 2 = %x, 3 = %x, 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x, 9 = %x\n",
+				__func__, (int)chp_params->v1,
+				(int)chp_params->v2, (int)chp_params->v3,
+				(int)chp_params->v4, (int)chp_params->v5,
+				(int)chp_params->v6, (int)chp_params->v7,
+				(int)chp_params->v8, (int)chp_params->v9);
+		break;
+	}
+	case SRS_ID_HPF: {
+		struct srs_trumedia_params_HPF *hpf_params = NULL;
+		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+			sizeof(struct srs_trumedia_params_HPF);
+		adm_params = kzalloc(sz, GFP_KERNEL);
+		adm_params->payload_size =
+			sizeof(struct srs_trumedia_params_HPF) +
+			sizeof(struct adm_param_data_v5);
+		adm_params->params.param_id = SRS_TRUMEDIA_PARAMS_HPF;
+		adm_params->params.param_size =
+				sizeof(struct srs_trumedia_params_HPF);
+		hpf_params = (struct srs_trumedia_params_HPF *)
+			((u8 *)adm_params +
+			sizeof(struct adm_cmd_set_pp_params_inband_v5));
+		memcpy(hpf_params, srs_params,
+			sizeof(struct srs_trumedia_params_HPF));
+		pr_debug("SRS - %s: HPF params - 1 = %x\n", __func__,
+				(int)hpf_params->v1);
+		break;
+	}
+	case SRS_ID_PEQ: {
+		struct srs_trumedia_params_PEQ *peq_params = NULL;
+		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+			sizeof(struct srs_trumedia_params_PEQ);
+		adm_params = kzalloc(sz, GFP_KERNEL);
+		adm_params->payload_size =
+				sizeof(struct srs_trumedia_params_PEQ) +
+				sizeof(struct adm_param_data_v5);
+		adm_params->params.param_id = SRS_TRUMEDIA_PARAMS_PEQ;
+		adm_params->params.param_size =
+				sizeof(struct srs_trumedia_params_PEQ);
+		peq_params = (struct srs_trumedia_params_PEQ *)
+			((u8 *)adm_params +
+			sizeof(struct adm_cmd_set_pp_params_inband_v5));
+		memcpy(peq_params, srs_params,
+				sizeof(struct srs_trumedia_params_PEQ));
+		pr_debug("SRS - %s: PEQ params - 1 = %x 2 = %x, 3 = %x, 4 = %x\n",
+			__func__, (int)peq_params->v1,
+			(int)peq_params->v2, (int)peq_params->v3,
+			(int)peq_params->v4);
+		break;
+	}
+	case SRS_ID_HL: {
+		struct srs_trumedia_params_HL *hl_params = NULL;
+		sz = sizeof(struct adm_cmd_set_pp_params_inband_v5) +
+			sizeof(struct srs_trumedia_params_HL);
+		adm_params = kzalloc(sz, GFP_KERNEL);
+		adm_params->payload_size =
+			sizeof(struct srs_trumedia_params_HL) +
+			sizeof(struct adm_param_data_v5);
+		adm_params->params.param_id = SRS_TRUMEDIA_PARAMS_HL;
+		adm_params->params.param_size =
+			sizeof(struct srs_trumedia_params_HL);
+		hl_params = (struct srs_trumedia_params_HL *)
+			((u8 *)adm_params +
+			sizeof(struct adm_cmd_set_pp_params_inband_v5));
+		memcpy(hl_params, srs_params,
+				sizeof(struct srs_trumedia_params_HL));
+		pr_debug("SRS - %s: HL params - 1 = %x, 2 = %x, 3 = %x, 4 = %x, 5 = %x, 6 = %x, 7 = %x\n",
+				__func__, (int)hl_params->v1,
+				(int)hl_params->v2, (int)hl_params->v3,
+				(int)hl_params->v4, (int)hl_params->v5,
+				(int)hl_params->v6, (int)hl_params->v7);
+		break;
+	}
+	default:
+		goto fail_cmd;
+	}
+
+	adm_params->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	adm_params->hdr.pkt_size = sz;
+	adm_params->hdr.src_svc = APR_SVC_ADM;
+	adm_params->hdr.src_domain = APR_DOMAIN_APPS;
+	adm_params->hdr.src_port = port_id;
+	adm_params->hdr.dest_svc = APR_SVC_ADM;
+	adm_params->hdr.dest_domain = APR_DOMAIN_ADSP;
+	index = afe_get_port_index(port_id);
+	adm_params->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	adm_params->hdr.token = port_id;
+	adm_params->hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+	adm_params->payload_addr_lsw = 0;
+	adm_params->payload_addr_msw = 0;
+	adm_params->mem_map_handle = 0;
+
+	adm_params->params.module_id = SRS_TRUMEDIA_MODULE_ID;
+	adm_params->params.reserved = 0;
+
+	pr_debug("SRS - %s: Command was sent now check Q6 - port id = %d, size %d, module id %x, param id %x.\n",
+			__func__, adm_params->hdr.dest_port,
+			adm_params->payload_size, adm_params->params.module_id,
+			adm_params->params.param_id);
+
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *)adm_params);
+	if (ret < 0) {
+		pr_err("SRS - %s: ADM enable for port %d failed\n", __func__,
+			port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	/* Wait for the callback with copp id */
+	ret = wait_event_timeout(this_adm.wait[index], 1,
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: SRS set params timed out port = %d\n",
+			__func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+
+fail_cmd:
+	kfree(adm_params);
+	return ret;
+}
+
 static void adm_callback_debug_print(struct apr_client_data *data)
 {
 	uint32_t *payload;
@@ -81,7 +276,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);
@@ -92,14 +287,14 @@
 		pr_debug("Resetting calibration blocks");
 		for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
 			/* Device calibration */
-			mem_addr_audproc[i].cal_size = 0;
-			mem_addr_audproc[i].cal_kvaddr = 0;
-			mem_addr_audproc[i].cal_paddr = 0;
+			this_adm.mem_addr_audproc[i].cal_size = 0;
+			this_adm.mem_addr_audproc[i].cal_kvaddr = 0;
+			this_adm.mem_addr_audproc[i].cal_paddr = 0;
 
 			/* Volume calibration */
-			mem_addr_audvol[i].cal_size = 0;
-			mem_addr_audvol[i].cal_kvaddr = 0;
-			mem_addr_audvol[i].cal_paddr = 0;
+			this_adm.mem_addr_audvol[i].cal_size = 0;
+			this_adm.mem_addr_audvol[i].cal_kvaddr = 0;
+			this_adm.mem_addr_audvol[i].cal_paddr = 0;
 		}
 		return 0;
 	}
@@ -107,7 +302,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;
@@ -199,8 +394,9 @@
 		case ADM_CMDRSP_SHARED_MEM_MAP_REGIONS:
 			pr_debug("%s: ADM_CMDRSP_SHARED_MEM_MAP_REGIONS\n",
 				__func__);
-			atomic_set(&mem_map_handles[
-				atomic_read(&mem_map_index)], *payload);
+			atomic_set(&this_adm.mem_map_cal_handles[
+				atomic_read(&this_adm.mem_map_cal_index)],
+				*payload);
 			atomic_set(&this_adm.copp_stat[0], 1);
 			wake_up(&this_adm.wait[index]);
 			break;
@@ -219,15 +415,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;
@@ -247,8 +443,8 @@
 	adm_params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
 	adm_params.payload_addr_lsw = aud_cal->cal_paddr;
 	adm_params.payload_addr_msw = 0;
-	adm_params.mem_map_handle = atomic_read(&mem_map_handles[
-					atomic_read(&mem_map_index)]);
+	adm_params.mem_map_handle = atomic_read(&this_adm.mem_map_cal_handles[
+				atomic_read(&this_adm.mem_map_cal_index)]);
 	adm_params.payload_size = aud_cal->cal_size;
 
 	atomic_set(&this_adm.copp_stat[index], 0);
@@ -257,7 +453,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 +463,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;
@@ -293,15 +489,16 @@
 	get_audproc_cal(acdb_path, &aud_cal);
 
 	/* map & cache buffers used */
-	atomic_set(&mem_map_index, acdb_path);
-	if (((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
-		(aud_cal.cal_size > 0)) ||
-		(aud_cal.cal_size > mem_addr_audproc[acdb_path].cal_size)) {
+	atomic_set(&this_adm.mem_map_cal_index, acdb_path);
+	if (((this_adm.mem_addr_audproc[acdb_path].cal_paddr !=
+		aud_cal.cal_paddr)  && (aud_cal.cal_size > 0)) ||
+		(aud_cal.cal_size >
+		this_adm.mem_addr_audproc[acdb_path].cal_size)) {
 
-		if (mem_addr_audproc[acdb_path].cal_paddr != 0)
+		if (this_adm.mem_addr_audproc[acdb_path].cal_paddr != 0)
 			adm_memory_unmap_regions(port_id,
-				&mem_addr_audproc[acdb_path].cal_paddr,
-				&size, 1);
+				&this_adm.mem_addr_audproc[acdb_path].
+				cal_paddr, &size, 1);
 
 		result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
 						0, &size, 1);
@@ -310,31 +507,33 @@
 				acdb_path, aud_cal.cal_paddr,
 				aud_cal.cal_size);
 		} else {
-			mem_addr_audproc[acdb_path].cal_paddr =
+			this_adm.mem_addr_audproc[acdb_path].cal_paddr =
 							aud_cal.cal_paddr;
-			mem_addr_audproc[acdb_path].cal_size = size;
+			this_adm.mem_addr_audproc[acdb_path].cal_size = size;
 		}
 	}
 
 	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__);
 	get_audvol_cal(acdb_path, &aud_cal);
 
 	/* map & cache buffers used */
-	atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
-	if (((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
-		(aud_cal.cal_size > 0))  ||
-		(aud_cal.cal_size > mem_addr_audvol[acdb_path].cal_size)) {
+	atomic_set(&this_adm.mem_map_cal_index,
+		(acdb_path + MAX_AUDPROC_TYPES));
+	if (((this_adm.mem_addr_audvol[acdb_path].cal_paddr !=
+		aud_cal.cal_paddr)  && (aud_cal.cal_size > 0))  ||
+		(aud_cal.cal_size >
+		this_adm.mem_addr_audvol[acdb_path].cal_size)) {
 
-		if (mem_addr_audvol[acdb_path].cal_paddr != 0)
+		if (this_adm.mem_addr_audvol[acdb_path].cal_paddr != 0)
 			adm_memory_unmap_regions(port_id,
-				&mem_addr_audvol[acdb_path].cal_paddr,
+				&this_adm.mem_addr_audvol[acdb_path].cal_paddr,
 				&size, 1);
 
 		result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
@@ -344,17 +543,17 @@
 				acdb_path, aud_cal.cal_paddr,
 				aud_cal.cal_size);
 		} else {
-			mem_addr_audvol[acdb_path].cal_paddr =
+			this_adm.mem_addr_audvol[acdb_path].cal_paddr =
 							aud_cal.cal_paddr;
-			mem_addr_audvol[acdb_path].cal_size = size;
+			this_adm.mem_addr_audvol[acdb_path].cal_size = size;
 		}
 	}
 
 	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 +583,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 +604,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 +614,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 +634,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 +742,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 +760,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 +798,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 +814,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 +857,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 +868,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 +877,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 +923,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;
 	}
 
@@ -817,8 +1016,8 @@
 	unmap_regions.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
 	unmap_regions.hdr.token = port_id;
 	unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
-	unmap_regions.mem_map_handle = atomic_read(&mem_map_handles[
-						atomic_read(&mem_map_index)]);
+	unmap_regions.mem_map_handle = atomic_read(&this_adm.
+		mem_map_cal_handles[atomic_read(&this_adm.mem_map_cal_index)]);
 	atomic_set(&this_adm.copp_stat[0], 0);
 	ret = apr_send_pkt(this_adm.apr, (uint32_t *) &unmap_regions);
 	if (ret < 0) {
@@ -864,10 +1063,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 +1089,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 +1106,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 +1124,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..9387d21 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -39,12 +39,14 @@
 	void *tx_private_data;
 	void *rx_private_data;
 	uint32_t mmap_handle;
+
+	struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
+	atomic_t mem_map_cal_handles[MAX_AUDPROC_TYPES];
+	atomic_t mem_map_cal_index;
 };
 
 static struct afe_ctl this_afe;
 
-static struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
-
 #define TIMEOUT_MS 1000
 #define Q6AFE_MAX_VOLUME 0x3FFF
 
@@ -113,7 +115,13 @@
 				AFE_SERVICE_CMDRSP_SHARED_MEM_MAP_REGIONS) {
 			pr_debug("%s: mmap_handle: 0x%x\n",
 						__func__, payload[0]);
-			this_afe.mmap_handle = (uint32_t)payload[0];
+			if (atomic_read(&this_afe.mem_map_cal_index) != -1)
+				atomic_set(&this_afe.mem_map_cal_handles[
+					atomic_read(
+					&this_afe.mem_map_cal_index)],
+					(uint32_t)payload[0]);
+			else
+				this_afe.mmap_handle = (uint32_t)payload[0];
 			atomic_set(&this_afe.state, 0);
 			wake_up(&this_afe.wait[data->token]);
 		} else if (data->opcode == AFE_EVENT_RT_PROXY_PORT_STATUS) {
@@ -165,6 +173,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 +192,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;
 	}
 
@@ -217,6 +227,10 @@
 	case SLIMBUS_1_TX:
 		ret_size = SIZEOF_CFG_CMD(afe_param_id_slimbus_cfg);
 		break;
+	case VOICE_RECORD_RX:
+	case VOICE_RECORD_TX:
+		ret_size = SIZEOF_CFG_CMD(afe_param_id_pseudo_port_cfg);
+		break;
 	case RT_PROXY_PORT_001_RX:
 	case RT_PROXY_PORT_001_TX:
 		ret_size = SIZEOF_CFG_CMD(afe_param_id_rt_proxy_port_cfg);
@@ -246,9 +260,77 @@
 	}
 	return ret;
 }
+
 static void afe_send_cal_block(int32_t path, u16 port_id)
 {
-	/* To come back */
+	int						result = 0;
+	int						index = 0;
+	int						size = 4096;
+	struct acdb_cal_block				cal_block;
+	struct afe_audioif_config_command_no_payload	afe_cal;
+	pr_debug("%s: path %d\n", __func__, path);
+
+	get_afe_cal(path, &cal_block);
+	if (cal_block.cal_size <= 0) {
+		pr_debug("%s: No AFE cal to send!\n", __func__);
+		goto done;
+	}
+
+	if ((this_afe.afe_cal_addr[path].cal_paddr != cal_block.cal_paddr) ||
+		(cal_block.cal_size > this_afe.afe_cal_addr[path].cal_size)) {
+		atomic_set(&this_afe.mem_map_cal_index, path);
+		if (this_afe.afe_cal_addr[path].cal_paddr != 0)
+			afe_cmd_memory_unmap(
+				this_afe.afe_cal_addr[path].cal_paddr);
+
+		afe_cmd_memory_map(cal_block.cal_paddr, size);
+		atomic_set(&this_afe.mem_map_cal_index, -1);
+		this_afe.afe_cal_addr[path].cal_paddr = cal_block.cal_paddr;
+		this_afe.afe_cal_addr[path].cal_size = size;
+	}
+
+	index = q6audio_get_port_index(port_id);
+	if (index < 0) {
+		pr_debug("%s: AFE port index invalid!\n", __func__);
+		goto done;
+	}
+
+	afe_cal.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	afe_cal.hdr.pkt_size = sizeof(afe_cal);
+	afe_cal.hdr.src_port = 0;
+	afe_cal.hdr.dest_port = 0;
+	afe_cal.hdr.token = index;
+	afe_cal.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+	afe_cal.param.port_id = port_id;
+	afe_cal.param.payload_size = cal_block.cal_size;
+	afe_cal.param.payload_address_lsw = cal_block.cal_paddr;
+	afe_cal.param.payload_address_msw = 0;
+	afe_cal.param.mem_map_handle =
+			atomic_read(&this_afe.mem_map_cal_handles[path]);
+
+	pr_debug("%s: AFE cal sent for device port = %d, path = %d, cal size = %d, cal addr = 0x%x\n",
+		__func__, port_id, path,
+		cal_block.cal_size, cal_block.cal_paddr);
+
+	atomic_set(&this_afe.state, 1);
+	result = apr_send_pkt(this_afe.apr, (uint32_t *) &afe_cal);
+	if (result < 0) {
+		pr_err("%s: AFE cal for port %d failed\n",
+			__func__, port_id);
+	}
+
+	result = wait_event_timeout(this_afe.wait[index],
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!result) {
+		pr_err("%s: wait_event timeout SET AFE CAL\n", __func__);
+		goto done;
+	}
+
+	pr_debug("%s: AFE cal sent for path %d device!\n", __func__, path);
+done:
+	return;
 }
 
 void afe_send_cal(u16 port_id)
@@ -283,10 +365,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 +377,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,11 +403,21 @@
 	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:
 		cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
 		break;
+	case VOICE_RECORD_RX:
+	case VOICE_RECORD_TX:
+		cfg_type = AFE_PARAM_ID_PSEUDO_PORT_CONFIG;
+		break;
 	case SLIMBUS_0_RX:
 	case SLIMBUS_0_TX:
 	case SLIMBUS_1_RX:
@@ -370,7 +462,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 +499,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 +560,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;
 	}
 }
@@ -1922,6 +2017,7 @@
 	int i = 0;
 	atomic_set(&this_afe.state, 0);
 	atomic_set(&this_afe.status, 0);
+	atomic_set(&this_afe.mem_map_cal_index, -1);
 	this_afe.apr = NULL;
 	this_afe.mmap_handle = 0;
 	for (i = 0; i < AFE_MAX_PORTS; i++)
@@ -1937,9 +2033,9 @@
 
 	config_debug_fs_exit();
 	for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
-		if (afe_cal_addr[i].cal_paddr != 0)
+		if (this_afe.afe_cal_addr[i].cal_paddr != 0)
 			afe_cmd_memory_unmap_nowait(
-				afe_cal_addr[i].cal_paddr);
+				this_afe.afe_cal_addr[i].cal_paddr);
 	}
 }
 
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 0ddaabe..85646cb 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -558,6 +558,7 @@
 		spin_lock_init(&ac->port[lcnt].dsp_lock);
 	}
 	atomic_set(&ac->cmd_state, 0);
+	atomic_set(&ac->nowait_cmd_cnt, 0);
 
 	pr_debug("%s: session[%d]\n", __func__, ac->session);
 
@@ -889,6 +890,25 @@
 	return 0;
 }
 
+static int32_t is_no_wait_cmd_rsp(uint32_t opcode, uint32_t *cmd_type)
+{
+	if (opcode == APR_BASIC_RSP_RESULT) {
+		if (cmd_type != NULL) {
+			switch (cmd_type[0]) {
+			case ASM_SESSION_CMD_RUN_V2:
+			case ASM_SESSION_CMD_PAUSE:
+			case ASM_DATA_CMD_EOS:
+				return 1;
+			default:
+				break;
+			}
+		} else
+			pr_err("%s: null pointer!", __func__);
+	} else if (opcode == ASM_DATA_EVENT_RENDERED_EOS)
+		return 1;
+
+	return 0;
+}
 
 static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
 {
@@ -897,6 +917,7 @@
 	uint32_t token;
 	unsigned long dsp_flags;
 	uint32_t *payload;
+	uint32_t wakeup_flag = 1;
 
 
 	if ((ac == NULL) || (data == NULL)) {
@@ -910,6 +931,14 @@
 	}
 
 	payload = data->payload;
+	if ((atomic_read(&ac->nowait_cmd_cnt) > 0) &&
+		is_no_wait_cmd_rsp(data->opcode, payload)) {
+		pr_debug("%s: nowait_cmd_cnt %d\n",
+				__func__,
+				atomic_read(&ac->nowait_cmd_cnt));
+		atomic_dec(&ac->nowait_cmd_cnt);
+		wakeup_flag = 0;
+	}
 
 	if (data->opcode == RESET_EVENTS) {
 		pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
@@ -961,7 +990,7 @@
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
 				__func__, payload[0], payload[1]);
-			if (atomic_read(&ac->cmd_state)) {
+			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
 				atomic_set(&ac->cmd_state, 0);
 				wake_up(&ac->cmd_wait);
 			}
@@ -1605,6 +1634,7 @@
 		pr_err("%s:Commmand run failed[%d]", __func__, rc);
 		return -EINVAL;
 	}
+	atomic_inc(&ac->nowait_cmd_cnt);
 	return 0;
 }
 
@@ -1825,7 +1855,7 @@
 		lchannel_mapping[3] = PCM_CHANNEL_FC;
 		lchannel_mapping[4] = PCM_CHANNEL_LB;
 		lchannel_mapping[5] = PCM_CHANNEL_RB;
-	} else if (channels == 6) {
+	} else if (channels == 8) {
 		lchannel_mapping[0] = PCM_CHANNEL_FL;
 		lchannel_mapping[1] = PCM_CHANNEL_FR;
 		lchannel_mapping[2] = PCM_CHANNEL_LFE;
@@ -3380,6 +3410,7 @@
 		pr_err("%s:Commmand 0x%x failed\n", __func__, hdr.opcode);
 		goto fail_cmd;
 	}
+	atomic_inc(&ac->nowait_cmd_cnt);
 	return 0;
 fail_cmd:
 	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;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index b799e59..349fcf2 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -505,9 +505,9 @@
 			cvs_session_cmd.hdr.opcode =
 				VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
 			if (is_volte_session(v->session_id)) {
-				strlcpy(mvm_session_cmd.mvm_session.name,
+				strlcpy(cvs_session_cmd.cvs_session.name,
 				"default volte voice",
-				sizeof(mvm_session_cmd.mvm_session.name));
+				sizeof(cvs_session_cmd.cvs_session.name));
 			} else {
 			strlcpy(cvs_session_cmd.cvs_session.name,
 				"default modem voice",
@@ -2928,23 +2928,25 @@
 		cvs_start_record.hdr.src_port = v->session_id;
 		cvs_start_record.hdr.dest_port = cvs_handle;
 		cvs_start_record.hdr.token = 0;
-		cvs_start_record.hdr.opcode = VSS_ISTREAM_CMD_START_RECORD;
+		cvs_start_record.hdr.opcode = VSS_IRECORD_CMD_START;
 
+		cvs_start_record.rec_mode.port_id =
+					VSS_IRECORD_PORT_ID_DEFAULT;
 		if (rec_mode == VOC_REC_UPLINK) {
 			cvs_start_record.rec_mode.rx_tap_point =
-						VSS_TAP_POINT_NONE;
+					VSS_IRECORD_TAP_POINT_NONE;
 			cvs_start_record.rec_mode.tx_tap_point =
-						VSS_TAP_POINT_STREAM_END;
+					VSS_IRECORD_TAP_POINT_STREAM_END;
 		} else if (rec_mode == VOC_REC_DOWNLINK) {
 			cvs_start_record.rec_mode.rx_tap_point =
-						VSS_TAP_POINT_STREAM_END;
+					VSS_IRECORD_TAP_POINT_STREAM_END;
 			cvs_start_record.rec_mode.tx_tap_point =
-						VSS_TAP_POINT_NONE;
+					VSS_IRECORD_TAP_POINT_NONE;
 		} else if (rec_mode == VOC_REC_BOTH) {
 			cvs_start_record.rec_mode.rx_tap_point =
-						VSS_TAP_POINT_STREAM_END;
+					VSS_IRECORD_TAP_POINT_STREAM_END;
 			cvs_start_record.rec_mode.tx_tap_point =
-						VSS_TAP_POINT_STREAM_END;
+					VSS_IRECORD_TAP_POINT_STREAM_END;
 		} else {
 			pr_err("%s: Invalid in-call rec_mode %d\n", __func__,
 				rec_mode);
@@ -3011,7 +3013,7 @@
 		cvs_stop_record.src_port = v->session_id;
 		cvs_stop_record.dest_port = cvs_handle;
 		cvs_stop_record.token = 0;
-		cvs_stop_record.opcode = VSS_ISTREAM_CMD_STOP_RECORD;
+		cvs_stop_record.opcode = VSS_IRECORD_CMD_STOP;
 
 		v->cvs_state = CMD_STATUS_FAIL;
 
@@ -3455,7 +3457,9 @@
 
 	v->dev_tx.mute = mute;
 
-	if (v->voc_state == VOC_RUN)
+	if ((v->voc_state == VOC_RUN) ||
+	    (v->voc_state == VOC_CHANGE) ||
+	    (v->voc_state == VOC_STANDBY))
 		ret = voice_send_mute_cmd(v);
 
 	mutex_unlock(&v->lock);
@@ -3661,7 +3665,9 @@
 
 	v->dev_rx.volume = vol_idx;
 
-	if (v->voc_state == VOC_RUN)
+	if ((v->voc_state == VOC_RUN) ||
+	    (v->voc_state == VOC_CHANGE) ||
+	    (v->voc_state == VOC_STANDBY))
 		ret = voice_send_vol_index_cmd(v);
 
 	mutex_unlock(&v->lock);
@@ -3753,7 +3759,9 @@
 
 	mutex_lock(&v->lock);
 
-	if (v->voc_state == VOC_RUN || v->voc_state == VOC_ERROR) {
+	if (v->voc_state == VOC_RUN || v->voc_state == VOC_ERROR ||
+	    v->voc_state == VOC_STANDBY) {
+
 		pr_debug("%s: VOC_STATE: %d\n", __func__, v->voc_state);
 
 		ret = voice_destroy_vocproc(v);
@@ -3767,6 +3775,69 @@
 	return ret;
 }
 
+int voc_standby_voice_call(uint16_t session_id)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	struct apr_hdr mvm_standby_voice_cmd;
+	void *apr_mvm;
+	u16 mvm_handle;
+	int ret = 0;
+
+	pr_debug("%s: voc state=%d", __func__, v->voc_state);
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	if (v->voc_state == VOC_RUN) {
+		apr_mvm = common.apr_q6_mvm;
+		if (!apr_mvm) {
+			pr_err("%s: apr_mvm is NULL.\n", __func__);
+			ret = -EINVAL;
+			goto fail;
+		}
+		mvm_handle = voice_get_mvm_handle(v);
+		mvm_standby_voice_cmd.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		mvm_standby_voice_cmd.pkt_size =
+			APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(mvm_standby_voice_cmd) - APR_HDR_SIZE);
+		pr_debug("send mvm_standby_voice_cmd pkt size = %d\n",
+			 mvm_standby_voice_cmd.pkt_size);
+		mvm_standby_voice_cmd.src_port = v->session_id;
+		mvm_standby_voice_cmd.dest_port = mvm_handle;
+		mvm_standby_voice_cmd.token = 0;
+		mvm_standby_voice_cmd.opcode = VSS_IMVM_CMD_STANDBY_VOICE;
+		v->mvm_state = CMD_STATUS_FAIL;
+		ret = apr_send_pkt(apr_mvm,
+				(uint32_t *)&mvm_standby_voice_cmd);
+		if (ret < 0) {
+			pr_err("Fail in sending VSS_IMVM_CMD_STANDBY_VOICE\n");
+			ret = -EINVAL;
+			goto fail;
+		}
+		v->voc_state = VOC_STANDBY;
+	}
+fail:
+	return ret;
+}
+
+int voc_resume_voice_call(uint16_t session_id)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	int ret = 0;
+
+	ret = voice_send_start_voice_cmd(v);
+	if (ret < 0) {
+		pr_err("Fail in sending START_VOICE\n");
+		goto fail;
+	}
+	v->voc_state = VOC_RUN;
+	return 0;
+fail:
+	return -EINVAL;
+}
+
 int voc_start_voice_call(uint16_t session_id)
 {
 	struct voice_data *v = voice_get_session(session_id);
@@ -3845,6 +3916,10 @@
 		}
 
 		v->voc_state = VOC_RUN;
+	} else if (v->voc_state == VOC_STANDBY) {
+		pr_err("Error: start voice in Standby\n");
+		ret = -EINVAL;
+		goto fail;
 	}
 fail:
 	mutex_unlock(&v->lock);
@@ -3961,6 +4036,7 @@
 			case VSS_IMVM_CMD_SET_CAL_NETWORK:
 			case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
 			case VSS_IMEMORY_CMD_UNMAP:
+			case VSS_IMVM_CMD_STANDBY_VOICE:
 				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
 				v->mvm_state = CMD_STATUS_SUCCESS;
 				wake_up(&v->mvm_wait);
@@ -4092,8 +4168,8 @@
 			case VSS_ICOMMON_CMD_SET_UI_PROPERTY:
 			case VSS_ISTREAM_CMD_START_PLAYBACK:
 			case VSS_ISTREAM_CMD_STOP_PLAYBACK:
-			case VSS_ISTREAM_CMD_START_RECORD:
-			case VSS_ISTREAM_CMD_STOP_RECORD:
+			case VSS_IRECORD_CMD_START:
+			case VSS_IRECORD_CMD_STOP:
 			case VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE:
 			case VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG:
 				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index aef463f..d19697a 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -68,6 +68,7 @@
 	VOC_CHANGE,
 	VOC_RELEASE,
 	VOC_ERROR,
+	VOC_STANDBY,
 };
 
 struct mem_buffer {
@@ -171,6 +172,9 @@
 #define VSS_IMVM_CMD_START_VOICE			0x00011190
 /**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
 
+#define VSS_IMVM_CMD_STANDBY_VOICE                       0x00011191
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
 #define VSS_IMVM_CMD_STOP_VOICE				0x00011192
 /**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
 
@@ -491,17 +495,26 @@
 #define VSS_ISTREAM_CMD_STOP_PLAYBACK                   0x00011239
 /* Stop the in-call music delivery on the Tx voice path. */
 
-#define VSS_ISTREAM_CMD_START_RECORD                    0x00011236
+#define VSS_IRECORD_CMD_START				0x000112BE
 /* Start in-call conversation recording. */
-#define VSS_ISTREAM_CMD_STOP_RECORD                     0x00011237
+#define VSS_IRECORD_CMD_STOP				0x00011237
 /* Stop in-call conversation recording. */
 
-#define VSS_TAP_POINT_NONE                              0x00010F78
+#define VSS_IRECORD_PORT_ID_DEFAULT			0x0000FFFF
+/* Default AFE port ID. */
+
+#define VSS_IRECORD_TAP_POINT_NONE			0x00010F78
 /* Indicates no tapping for specified path. */
 
-#define VSS_TAP_POINT_STREAM_END                        0x00010F79
+#define VSS_IRECORD_TAP_POINT_STREAM_END		0x00010F79
 /* Indicates that specified path should be tapped at the end of the stream. */
 
+#define VSS_IRECORD_MODE_TX_RX_STEREO			0x00010F7A
+/* Select Tx on left channel and Rx on right channel. */
+
+#define VSS_IRECORD_MODE_TX_RX_MIXING			0x00010F7B
+/* Select mixed Tx and Rx paths. */
+
 #define VSS_ISTREAM_EVT_NOT_READY			0x000110FD
 
 #define VSS_ISTREAM_EVT_READY				0x000110FC
@@ -525,16 +538,30 @@
 
 #define VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE	0x0001136A
 
-struct vss_istream_cmd_start_record_t {
+struct vss_irecord_cmd_start_t {
 	uint32_t rx_tap_point;
 	/* Tap point to use on the Rx path. Supported values are:
-	 * VSS_TAP_POINT_NONE : Do not record Rx path.
-	 * VSS_TAP_POINT_STREAM_END : Rx tap point is at the end of the stream.
+	 * VSS_IRECORD_TAP_POINT_NONE : Do not record Rx path.
+	 * VSS_IRECORD_TAP_POINT_STREAM_END : Rx tap point is at the end of
+	 * the stream.
 	 */
 	uint32_t tx_tap_point;
 	/* Tap point to use on the Tx path. Supported values are:
-	 * VSS_TAP_POINT_NONE : Do not record tx path.
-	 * VSS_TAP_POINT_STREAM_END : Tx tap point is at the end of the stream.
+	 * VSS_IRECORD_TAP_POINT_NONE : Do not record tx path.
+	 * VSS_IRECORD_TAP_POINT_STREAM_END : Tx tap point is at the end of
+	 * the stream.
+	 */
+	uint16_t port_id;
+	/* AFE Port ID to whcih the conversation recording stream needs to be
+	 * sent. Set this to #VSS_IRECORD_PORT_ID_DEFAULT to use default AFE
+	 * pseudo ports (0x8003 for Rx and 0x8004 for Tx).
+	 */
+	uint32_t mode;
+	/* Recording Mode. The mode parameter value is ignored if the port_id
+	 * is set to #VSS_IRECORD_PORT_ID_DEFAULT.
+	 * The supported values:
+	 * #VSS_IRECORD_MODE_TX_RX_STEREO
+	 * #VSS_IRECORD_MODE_TX_RX_MIXING
 	 */
 } __packed;
 
@@ -778,7 +805,7 @@
 } __packed;
 struct cvs_start_record_cmd {
 	struct apr_hdr hdr;
-	struct vss_istream_cmd_start_record_t rec_mode;
+	struct vss_irecord_cmd_start_t rec_mode;
 } __packed;
 
 struct cvs_dec_buffer_ready_cmd {
@@ -1227,6 +1254,8 @@
 int voc_set_tty_mode(uint16_t session_id, uint8_t tty_mode);
 int voc_start_voice_call(uint16_t session_id);
 int voc_end_voice_call(uint16_t session_id);
+int voc_standby_voice_call(uint16_t session_id);
+int voc_resume_voice_call(uint16_t session_id);
 int voc_set_rxtx_port(uint16_t session_id,
 		      uint32_t dev_port_id,
 		      uint32_t dev_type);