Merge "msm: lpm_levels: remove debug print"
diff --git a/Documentation/csdio.txt b/Documentation/csdio.txt
deleted file mode 100644
index 22d5e35..0000000
--- a/Documentation/csdio.txt
+++ /dev/null
@@ -1,189 +0,0 @@
-Introduction
-============
-The Char SDIO Device Driver is an interface which exposes an SDIO
-card/function from kernel space as a char device in user space.
-
-The driver doesn't interact with any HW directly. It relies on SDIO
-card/function interface provided as a part of Linux kernel.
-
-Hardware description
-====================
-Each SDIO device/card contains an SDIO client HW block.
-The host interacts with the device by sending byte sequences called
-command (CMD). Some commands can be followed by data blocks. The
-device sends back a byte sequence called response (R) and a data
-block if required. CMD3, CMD5 and CMD7 are used to initialize the
-device. CMD52 and CMD53 are used to access the device. Command
-format and properties are defined by SDIO Specification document
-published by SD Association:
-    http://www.sdcard.org/developers/tech/sdio/.
-
-CMD52 and CMD53 can access up to 8 address spaces called Functions.
-Function 0 contains system information predefined by SD/SDIO
-standard and Functions 1-7 are defined by the SDIO device
-manufacturer.
-
-An SDIO device/card can send an interrupt to SDIO host. This
-interrupt is intercepted and handled by SDIO host.
-
-Software description
-====================
-Linux provides a framework for handling SDIO devices. It implements
-kind of plug-and-play model in which the Linux SDIO Host Driver is
-responsible for initializing an SDIO device upon insertion. It also
-reads device/card identification information and enumerates functions
-provided by the device and then looks up in the list of
-preregistered user SDIO drivers for a suitable one.
-
-During its lifecycle the user SDIO driver interacts with the Linux
-SDIO Host Driver in order to send/receive information to/from SDIO
-device/card. The user SDIO driver doesn't work with CMD52/CMD53
-directly. Instead it uses an abstraction provided by the Linux SDIO
-Host Driver.
-
-The Linux SDIO Host Driver is also in charge of handling SDIO
-interrupts. User SDIO driver can register its own callback in SDIO
-Host Driver and get a notification about interrupt event.
-
-The Char SDIO Device Driver follows the design guidelines mentioned
-above. It provides the following functionality:
-
- - Register itself in the user SDIO drivers list;
- - Handle Probe event upon insertion of supported card/device;
- - Creates and maintains a char device driver for each SDIO Function
-   found in the card/device;
- - Translates read/write/ioctl calls to appropriate SDIO call
-   sequences;
-
-In order to handle general SDIO configuration functionality and
-Function 0 the Char SDIO Device Driver provides additional
-simplified char device driver.
-
-The Manufacturer and Device IDs of handled SDIO device should be
-provided as parameters for kernel module or as configuration
-parameters in case of statically linked driver.
-
-Design
-======
-The main goal of the Char SDIO Device Driver is to expose an SDIO
-card/device from kernel space to user space as a char device driver.
-The driver should be generic and simple as far as possible.
-
-The biggest design tradeoff is maintaining a balance between the
-system call overhead required to initiate an SDIO transaction from
-user space and overall SDIO communication performance. But luckily,
-because of nature of SDIO protocol, this overhead is negligible
-comparing to time required to execute SDIO transaction itself. So,
-each CMD52 (read or write) consists from single ioctl system call.
-And each CMD53 invokes single ioctl system call followed by read or
-write system call.
-
-The Char SDIO Device Driver registers its own class of the devices
-called 'csdio'. This class will serve as a common roof for all SDIO
-devices served by different instances of the Char SDIO Device Driver.
-Additional benefit from maintaining its own class is the driver
-ability to overwrite default permissions of the dev nodes created by
-the driver.
-
-Power Management
-================
-None
-
-SMP/multi-core
-==============
-The driver does not anticipate any issues related to multi-core
-since it is expected to run on one core only.
-
-Security
-========
-None
-
-Performance
-===========
-None
-
-Interface
-=========
-The Char SDIO Device Driver has two char device interfaces:
- - Control Interface;
- - Function Interface.
-
-Char SDIO Device Driver Control Interface consists of:
- - open()   - device node is /dev/csdio0;
- - close()
- - ioctl()  - the following options are available:
-   - CSDIO_IOC_ENABLE_HIGHSPEED_MODE;
-   - CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS;
-   - CSDIO_IOC_ENABLE_ISR;
-   - CSDIO_IOC_DISABLE_ISR.
-
-Char SDIO Device Driver Function Interface consists of:
- - open()  - device node is /dev/csdiofX, where X is Function Id;
- - close()
- - read()  - send CMD53 read;
- - write() - send CMD53 write;
- - ioctl() - the following options are available:
-   - CSDIO_IOC_SET_OP_CODE - 0 fixed adrress, 1 autoincrement.
-   - CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE;
-   - CSDIO_IOC_SET_BLOCK_MODE - 0 byte mode, 1 block mode;
-   - CSDIO_IOC_CMD52 - execute CMD52, receives the
-        following structure as a parameter:
-            struct csdio_cmd52_ctrl_t {
-	            uint32_t    m_write; // 0 - read, 1 -write
-	            uint32_t    m_address;
-	            uint32_t    m_data;  // data to write or read data
-	            uint32_t    m_ret;   // command execution status
-            }__attribute__ ((packed));
-   - CSDIO_IOC_CMD53 - setup CMD53 data transfer, receives the
-        following structure as a parameter:
-            struct csdio_cmd53_ctrl_t {
-	            uint32_t    m_block_mode;
-	            uint32_t    m_op_code;
-	            uint32_t    m_address;
-            }__attribute__ ((packed));
-   - CSDIO_IOC_CONNECT_ISR;
-   - CSDIO_IOC_DISCONNECT_ISR;
-   - CSDIO_IOC_GET_VDD;
-   - CSDIO_IOC_SET_VDD.
-
-Additionally, user space application can use fcntl system call with
-parameters F_SETOWN and F_SETFL in order to set an asynchronous
-callback for SDIO interrupt.
-
-Driver parameters
-=================
-If the driver is compiled as a kernel module, the following
-parameters can be used in order to provide Manufacturer and Device IDs
-upon module download:
- - csdio_vendor_id;
- - csdio_device_id.
-If the driver is intended to work with specific SDIO host the
-host_name parameter should be added followed by the name of the MMC
-host platform device.
-
-Config options
-==============
-These are the kernel configuration options:
- - CONFIG_CSDIO_VENDOR_ID;
- - CONFIG_CSDIO_DEVICE_ID.
-
-Dependencies
-============
-The Char SDIO Device Driver depends on Linux SDIO Host Driver.
-
-User space utilities
-====================
-None
-
-Other
-=====
-None
-
-Known issues
-============
-None
-
-To do
-=====
-Provide mechanism to support a number of SDIO devices simultaneously
-connected to different SDIO hosts.
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 99de826..3a293a3 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -198,16 +198,21 @@
 - qti,cpr-uplift-speed-bin:	The speed bin value corresponding to one type of processor which needs to apply the
 				pvs voltage uplift workaround.
 				This is required if cpr-fuse-uplift-disable-sel is present.
-- qti,cpr-quot-adjust-table:	Array of 4-tuples in which each 4-tuple indicates the speed bin
-				of the CPU, the frequency of the CPU, the quotient adjustment and the voltage corner to use.
-				The 4 elements in one 4-tuple are:
-				[0]: => the speed bin of the CPU;
-				[1]: => the frequency in kHz of the CPU;
-				[2]: => the quotient adjustment of the corresponding frequency;
-				[3]: => the voltage corner to use.
-				If the speed bin in a tuple is eqaul to the speed bin of the CPU, then the quotient
-				adjustment would be subtracted from the quotient value of the voltage corner
-				when the CPU is running at that frequency.
+- qti,cpr-quot-adjust-table:	Array of triples in which each triple indicates the speed bin of the CPU, the virtual
+				corner to use and the quotient adjustment.
+				The 3 elements in one triple are:
+				[0]: => the speed bin of the CPU.
+				[1]: => the virtual voltage corner to use.
+				[2]: => the quotient adjustment for the corresponding virtual corner.
+				If the speed bin in a triple is equal to the speed bin of the CPU, the adjustment would
+				be subtracted from the quotient value of the voltage corner when the CPU is running at
+				that virtual corner. Each virtual corner value must be in the range 1 to the number of
+				elements in qti,cpr-corner-map.
+- qti,cpr-corner-map:		Array of elements of fuse corner value for each virtual corner.
+				The location or 1-based index of an element in the list corresponds to
+				the virtual corner value. For example, the first element in the list is the fuse corner
+				value that virtual corner 1 maps to.
+				This is required if qti,cpr-quot-adjust-table is present.
 
 Example:
 	apc_vreg_corner: regulator@f9018000 {
@@ -270,9 +275,10 @@
 		qti,cpr-uplift-max-volt = <1350000>;
 		qti,cpr-uplift-speed-bin = <1>;
 		qti,speed-bin-fuse-sel = <22 0 3 0>;
-		qti,cpr-quot-adjust-table = <1 998400 450 3>,
-				<1 1094400 375 3>, <1 1190400 300 3>,
-				<1 1305600 225 3>, <1 1344000 187 3>,
-				<1 1401600 150 3>, <1 1497600 75 3>;
+		qti,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
+		qti,cpr-quot-adjust-table = <1 1 0>, <1 2 0>, <1 3 0>,
+						<1 4 0>, <1 5 450>, <1 6 375>,
+						<1 7 300>, <1 8 225>, <1 9 187>,
+						<1 10 150>, <1 11 75>, <1 12 0>;
 	};
 
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 56bdc59..6277054 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -4,23 +4,29 @@
 
 Required properties:
 
- - compatible : "qcom,msm-pcm-dsp"
+ - compatible : "qti,msm-pcm-dsp"
 
- - qcom,msm-pcm-dsp-id : device node id
+ - qti,msm-pcm-dsp-id : device node id
 
 * msm-pcm-low-latency
 
 Required properties:
 
- - compatible : "qcom,msm-pcm-dsp"
+ - compatible : "qti,msm-pcm-dsp"
 
- - qcom,msm-pcm-dsp-id : device node id
+ - qti,msm-pcm-dsp-id : device node id
 
    Optional properties
 
-      - qcom,msm-pcm-low-latency : Flag indicating whether
+      - qti,msm-pcm-low-latency : Flag indicating whether
         the device node is of type low latency.
 
+      - qti,latency-level : Flag indicating whether the device node
+                            is of type regular low latency or ultra
+                            low latency.
+                            regular : regular low latency stream
+                            ultra : ultra low latency stream
+
 * msm-pcm-routing
 
 Required properties:
@@ -102,6 +108,12 @@
 
  - compatible : "qcom,msm-lsm-client"
 
+* msm-pcm-loopback
+
+Required properties:
+
+ - compatible : "qti,msm-pcm-loopback"
+
 * msm-dai-q6
 
 [First Level Nodes]
@@ -220,16 +232,16 @@
 
 Example:
 
-        qcom,msm-pcm {
-		compatible = "qcom,msm-pcm-dsp";
-		qcom,msm-pcm-dsp-id = <0>;
+	qti,msm-pcm {
+		compatible = "qti,msm-pcm-dsp";
+		qti,msm-pcm-dsp-id = <0>;
 	};
 
-	qcom,msm-pcm-low-latency {
-		compatible = "qcom,msm-pcm-dsp";
-		qcom,msm-pcm-dsp-id = <1>;
-		qcom,msm-pcm-low-latency;
-        };
+	qti,msm-pcm-low-latency {
+		compatible = "qti,msm-pcm-dsp";
+		qti,msm-pcm-dsp-id = <1>;
+		qti,msm-pcm-low-latency;
+	};
 
         qcom,msm-pcm-routing {
                 compatible = "qcom,msm-pcm-routing";
diff --git a/Makefile b/Makefile
index be32c2f..0c11d69 100644
--- a/Makefile
+++ b/Makefile
@@ -864,6 +864,7 @@
 # Generate .S file with all kernel symbols
 quiet_cmd_kallsyms = KSYM    $@
       cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
+                     --page-offset=$(CONFIG_PAGE_OFFSET) \
                      $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
 
 .tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
diff --git a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
index 8c79bb9..25e5072 100755
--- a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
@@ -17,7 +17,7 @@
  *---------------------------------------------------------------------------*/
 &mdss_mdp {
 	dsi_hx8389b_qhd_vid: qcom,mdss_dsi_hx8389b_qhd_video {
-		qcom,mdss-dsi-panel-name = "HX8389b qhd video mode dsi panel";
+		qcom,mdss-dsi-panel-name = "hx8389b qhd video mode dsi panel";
 		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
 		qcom,mdss-dsi-panel-type = "dsi_video_mode";
 		qcom,mdss-dsi-panel-destination = "display_1";
@@ -26,89 +26,35 @@
 		qcom,mdss-dsi-stream = <0>;
 		qcom,mdss-dsi-panel-width = <540>;
 		qcom,mdss-dsi-panel-height = <960>;
-		qcom,mdss-dsi-h-front-porch = <48>;
-		qcom,mdss-dsi-h-back-porch = <96>;
-		qcom,mdss-dsi-h-pulse-width = <96>;
+		qcom,mdss-dsi-h-front-porch = <60>;
+		qcom,mdss-dsi-h-back-porch = <39>;
+		qcom,mdss-dsi-h-pulse-width = <39>;
 		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <13>;
 		qcom,mdss-dsi-v-front-porch = <9>;
 		qcom,mdss-dsi-v-pulse-width = <3>;
-		qcom,mdss-dsi-v-back-porch = <13>;
 		qcom,mdss-dsi-h-left-border = <0>;
 		qcom,mdss-dsi-h-right-border = <0>;
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
-		qcom,mdss-dsi-on-command = [
-				39 01 00 00 00 00 04
-					B9 FF 83 89
-				39 01 00 00 00 00 08
-					BA 41 93 00
-					16 A4 10 18
-				23 01 00 00 00 00 02
-					C6 08
-				39 01 00 00 00 00 03
-					BC 02 00
-				23 01 00 00 00 00 02
-					CC 02
-				39 01 00 00 00 00 14
-					B1 00 00 07
-					E8 50 10 11
-					98 f8 21 29
-					27 27 43 01
-					58 F0 00 E6
-				39 01 00 00 00 00 08
-					B2 00 00 78
-					0C 07 3F 80
-				39 01 00 00 00 00 18
-					b4 82 08 00
-					32 10 04 32
-					10 00 32 10
-					00 37 0a 40
-					08 37 0a 40
-					14 46 50 0a
-				39 01 00 00 00 00 39
-					d5 00 00 00
-					00 01 00 00
-					00 60 00 99
-					88 AA BB 88
-					23 88 01 88
-					67 88 45 01
-					23 88 88 88
-					88 88 88 99
-					BB AA 88 54
-					88 76 88 10
-					88 32 32 10
-					88 88 88 88
-					88 00 04 00
-					00 00 00 00
-					00
-				39 01 00 00 00 00 03
-					CB 07 07
-				39 01 00 00 00 00 05
-					BB 00 00 FF
-					80
-				39 01 00 00 00 00 04
-					DE 05 58 10
-				39 01 00 00 00 00 05
-					B6 00 8A 00
-					8A
-				39 01 00 00 00 00 23
-					E0 01 08 0C
-					1F 25 36 12
-					35 05 09 0D
-					10 11 0F 0F
-					1C 1D 01 08
-					0C 1F 25 36
-					12 35 05 09
-					0D 10 11 0F
-					0F 1C 1D
-				05 01 00 00 96 00 02
-					11 00
-				05 01 00 00 96 00 02
-					29 00
-		];
+		qcom,mdss-dsi-on-command = [39 01 00 00 0A 00 04 B9 FF 83 89
+				15 01 00 00 01 00 02 CC 02
+				39 01 00 00 01 00 03 C0 43 17
+				39 01 00 00 01 00 08 BA 41 93 00 16 A4 10 18
+				39 01 00 00 01 00 14 B1 00 00 06 EB 59 10 11 EE EE 3A 42 3F 3F 43 01 5A F6 00 E6
+				39 01 00 00 01 00 08 B2 00 00 78 0C 07 3F 80
+				39 01 00 00 01 00 04 b7 00 00 50
+				39 01 00 00 01 00 18 B4 80 08 00 32 10 04 32 10 00 32 10 00 37 0a 40 08 37 00 46 02 58 58 02
+				39 01 00 00 01 00 39 D5 00 00 00 00 01 00 00 00 60 00 99 88 AA BB 88 23 88 01 88 67 88 45 01 23 88 88 88 88 88 88 99 BB AA 88 54 88 76 88 10 88 32 32 10 88 88 88 88 88 3C 04 00 00 00 00 00 00
+				39 01 00 00 01 00 23 E0 05 11 16 35 3F 3F 21 43 07 0C 0F 11 12 10 10 1D 18 05 11 16 35 3F 3F 21 43 07 0C 0F 11 12 10 10 1D 18
+				39 01 00 00 05 00 80 C1 01 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0 00 07 13 21 29 2F 34 3B 42 48 50 58 61 69 71 79 81 88 90 98 A0 A9 B1 B9 C1 C8 CE D6 DF E6 EF F7 FF 0E 5A 73 69 36 8E 69 5F C0
+				39 01 00 00 01 00 05 B6 00 88 00 88
+				05 01 00 00 78 00 02 11 00
+				05 01 00 00 32 00 02 29 00];
 		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
 					05 01 00 00 78 00 02 10 00];
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
@@ -120,7 +66,7 @@
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
 		qcom,mdss-dsi-lane-1-state;
-		qcom,mdss-dsi-panel-timings = [97 23 17 00 4B 53 1C 27 27 03 04 00];
+		qcom,mdss-dsi-panel-timings = [87 1E 14 00 44 4B 19 21 22 03 04 00];
 		qcom,mdss-dsi-t-clk-post = <0x04>;
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <26>;
@@ -129,6 +75,5 @@
 		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
-
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 63da606..dbeaa97 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -36,7 +36,7 @@
 		interrupts = <0 15 0>;
 		regulator-name = "apc_corner";
 		regulator-min-microvolt = <1>;
-		regulator-max-microvolt = <3>;
+		regulator-max-microvolt = <12>;
 
 		qti,pvs-fuse-redun-sel = <22 24 3 2 0>;
 		qti,pvs-fuse = <22 6 5 0>;
@@ -91,13 +91,15 @@
 		qti,cpr-uplift-max-volt = <1350000>;
 		qti,cpr-uplift-speed-bin = <1>;
 		qti,speed-bin-fuse-sel = <22 0 3 0>;
-		qti,cpr-quot-adjust-table = <1 300000 0 1>,
-				<1 384000 0 1>, <1 600000 0 2>,
-				<1 787200 0 2>, <1 998400 450 3>,
-				<1 1094400 375 3>, <1 1190400 300 3>,
-				<1 1305600 225 3>, <1 1344000 187 3>,
-				<1 1401600 150 3>, <1 1497600 75 3>,
-				<1 1593600 0 3>;
+		qti,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
+		qti,cpr-quot-adjust-table =
+					<1 5 450>,
+					<1 6 375>,
+					<1 7 300>,
+					<1 8 225>,
+					<1 9 187>,
+					<1 10 150>,
+					<1 11 75>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8226-v1-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
index 38ca03b..a1a8480 100644
--- a/arch/arm/boot/dts/msm8226-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
@@ -160,7 +160,7 @@
 				qcom,ss-power = <315>;
 				qcom,energy-overhead = <1027150>;
 				qcom,time-overhead = <2400>;
-				qcom,min-cpu-mode= "spc";
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
diff --git a/arch/arm/boot/dts/msm8226-v2-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
index a0da9cc..2e9f6db 100644
--- a/arch/arm/boot/dts/msm8226-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
@@ -162,7 +162,7 @@
 				qcom,ss-power = <315>;
 				qcom,energy-overhead = <1027150>;
 				qcom,time-overhead = <2400>;
-				qcom,min-cpu-mode= "spc";
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index ddba542..4149169 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -102,12 +102,12 @@
 			<         0 0>,
 			< 384000000 1>,
 			< 787200000 2>,
-			<149700000 3>;
+			<1401600000 3>;
 		qcom,speed7-bin-v2 =
 			<         0 0>,
 			< 384000000 1>,
 			< 787200000 2>,
-			<1497600000 3>;
+			<1401600000 3>;
 		qcom,speed1-bin-v2 =
 			<         0 0>,
 			< 384000000 1>,
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 1250ed2..baa81cc 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -429,19 +429,20 @@
 		qcom,tapan-codec-9302;
 	};
 
-	qcom,msm-pcm {
-		compatible = "qcom,msm-pcm-dsp";
-		qcom,msm-pcm-dsp-id = <0>;
+	qti,msm-pcm {
+		compatible = "qti,msm-pcm-dsp";
+		qti,msm-pcm-dsp-id = <0>;
 	};
 
 	qcom,msm-pcm-routing {
 		compatible = "qcom,msm-pcm-routing";
 	};
 
-	qcom,msm-pcm-low-latency {
-		compatible = "qcom,msm-pcm-dsp";
-		qcom,msm-pcm-dsp-id = <1>;
-		qcom,msm-pcm-low-latency;
+	qti,msm-pcm-low-latency {
+		compatible = "qti,msm-pcm-dsp";
+		qti,msm-pcm-dsp-id = <1>;
+		qti,msm-pcm-low-latency;
+		qti,latency-level = "regular";
 	};
 
 	qcom,msm-pcm-lpa {
@@ -1024,8 +1025,8 @@
 		qcom,cpufreq-table =
 			<  300000 1600 /* 200 MHz */ >,
 			<  384000 1600 /* 200 MHz */ >,
-			<  600000 3200 /* 320 MHz */ >,
-			<  787200 4264 /* 533 MHz */ >,
+			<  600000 1600 /* 200 MHz */ >,
+			<  787200 3200 /* 400 MHz */ >,
 			<  998400 4264 /* 533 MHz */ >,
 			< 1094400 4264 /* 533 MHz */ >,
 			< 1190400 4264 /* 533 MHz */ >,
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index d63c6e5..04eca14 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -143,7 +143,11 @@
 			"MIC BIAS External", "Handset Mic",
 			"MIC BIAS Internal2", "Headset Mic",
 			"AMIC1", "MIC BIAS External",
-			"AMIC2", "MIC BIAS Internal2";
+			"AMIC2", "MIC BIAS Internal2",
+			"MIC BIAS External", "Digital Mic1",
+			"MIC BIAS External", "Digital Mic2",
+			"DMIC1", "MIC BIAS External",
+			"DMIC2", "MIC BIAS External";
 		qcom,headset-jack-type-NC;
     };
 };
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index f9bafb4..51a9516 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -36,7 +36,7 @@
 		interrupts = <0 15 0>;
 		regulator-name = "apc_corner";
 		regulator-min-microvolt = <1>;
-		regulator-max-microvolt = <3>;
+		regulator-max-microvolt = <12>;
 
 		qti,pvs-fuse-redun-sel = <53 25 3 2 1>;
 		qti,pvs-fuse = <23 6 5 1>;
@@ -50,8 +50,8 @@
 					1275000 1275000 1275000 1275000 1275000
 					1275000 1275000>;
 		qti,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
-		qti,pvs-corner-ceiling-nom  = <1075000 1075000 1200000>;
-		qti,pvs-corner-ceiling-fast = <1050000 1050000 1140000>;
+		qti,pvs-corner-ceiling-nom  = <1075000 1075000 1275000>;
+		qti,pvs-corner-ceiling-fast = <1050000 1050000 1275000>;
 		vdd-apc-supply = <&pm8110_s2>;
 
 		vdd-mx-supply = <&pm8110_l3_ao>;
@@ -83,6 +83,7 @@
 		qti,cpr-fuse-redun-bp-scheme = <25>;
 		qti,cpr-fuse-redun-target-quot = <32 12 0>;
 		qti,cpr-fuse-redun-ro-sel = <44 26 29>;
+		qti,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
 
 		qti,cpr-enable;
 	};
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index e5aa53c..ea37413 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -160,7 +160,7 @@
 				qcom,ss-power = <315>;
 				qcom,energy-overhead = <1027150>;
 				qcom,time-overhead = <2400>;
-				qcom,min-cpu-mode= "spc";
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index c819c49..19fb185 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -162,7 +162,7 @@
 				qcom,ss-power = <315>;
 				qcom,energy-overhead = <1027150>;
 				qcom,time-overhead = <2400>;
-				qcom,min-cpu-mode= "spc";
+				qcom,min-cpu-mode= "standalone_pc";
 				qcom,sync-cpus;
 			};
 
@@ -198,24 +198,40 @@
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
 			<2 216>, /* tsens_upper_lower_int */
 			<41 63>,  /* dino_gen_purpose_irq35 */
+			<0xff 18>,  /* APC_qgicQTmrSecPhysIrptReq */
+			<0xff 19>,  /* APC_qgicQTmrNonSecPhysIrptReq */
+			<0xff 35>,  /* WDT_barkInt */
+			<0xff 40>,  /* qtmr_phy_irq[0] */
+			<0xff 47>,  /* rbif_irq[0] */
 			<0xff 56>,  /* q6_wdog_expired_irq */
 			<0xff 57>,  /* mss_to_apps_irq(0) */
 			<0xff 58>,  /* mss_to_apps_irq(1) */
 			<0xff 59>,  /* mss_to_apps_irq(2) */
 			<0xff 60>,  /* mss_to_apps_irq(3) */
 			<0xff 61>,  /* mss_a2_bam_irq */
+			<0xff 65>,  /* o_gc_sys_irq[0] */
+			<0xff 74>,  /* venus0_mmu_cirpt[1] */
+			<0xff 75>,  /* venus0_mmu_cirpt[0] */
+			<0xff 78>,  /* mdss_mmu_cirpt[0] */
+			<0xff 79>,  /* mdss_mmu_cirpt[1] */
+			<0xff 97>,  /* camss_vfe_mmu_cirpt[1] */
+			<0xff 102>, /* camss_jpeg_mmu_cirpt[1] */
+			<0xff 109>, /* ocmem_dm_nonsec_irq */
+			<0xff 131>, /* blsp1_qup_5_irq */
+			<0xff 141>, /* blsp1_uart_3_irq */
+			<0xff 155>, /* sdc1_irq(0) */
+			<0xff 157>, /* sdc2_irq(0) */
+			<0xff 161>, /* lpass_irq_out_spare[4] */
+			<0xff 162>, /* lpass_irq_out_spare[5]*/
+			<0xff 170>, /* sdc1_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
 			<0xff 174>, /* o_wcss_apss_smd_med */
 			<0xff 175>, /* o_wcss_apss_smd_low */
 			<0xff 176>, /* o_wcss_apss_smsm_irq */
 			<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
 			<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
-			<0xff 179>, /* o_wcss_apss_asic_intr
+			<0xff 179>, /* o_wcss_apss_asic_intr */
 			<0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */
-			<0xff 161>, /* lpass_irq_out_spare[4] /
-			<0xff 162>, /* lpass_irq_out_spare[5]*/
-			<0xff 234>, /* lpass_irq_out_spare[6]*/
-			<0xff 235>, /* lpass_irq_out_spare[7]*/
 			<0xff 188>, /* lpass_irq_out_apcs(0) */
 			<0xff 189>, /* lpass_irq_out_apcs(1) */
 			<0xff 190>, /* lpass_irq_out_apcs(2) */
@@ -230,12 +246,16 @@
 			<0xff 205>, /* rpm_ipc(25) */
 			<0xff 206>, /* rpm_ipc(26) */
 			<0xff 207>, /* rpm_ipc(27) */
+			<0xff 234>, /* lpass_irq_out_spare[6]*/
+			<0xff 235>, /* lpass_irq_out_spare[7]*/
+			<0xff 240>, /* summary_irq_kpss */
+			<0xff 253>, /* sdc2_pwr_cmd_irq */
 			<0xff 258>, /* rpm_ipc(28) */
 			<0xff 259>, /* rpm_ipc(29) */
-			<0xff 275>, /* rpm_ipc(30) */
-			<0xff 276>, /* rpm_ipc(31) */
 			<0xff 269>, /* rpm_wdog_expired_irq */
-			<0xff 240>; /* summary_irq_kpss */
+			<0xff 270>, /* blsp1_bam_irq[0] */
+			<0xff 275>, /* rpm_ipc(30) */
+			<0xff 276>; /* rpm_ipc(31) */
 
 		qcom,gpio-parent = <&msmgpio>;
 		qcom,gpio-map = <3  1>,
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 94a9db0..03ef738 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -615,15 +615,16 @@
 		qcom,model = "msm8x10-snd-card";
 	};
 
-	qcom,msm-pcm {
-		compatible = "qcom,msm-pcm-dsp";
-		qcom,msm-pcm-dsp-id = <0>;
+	qti,msm-pcm {
+		compatible = "qti,msm-pcm-dsp";
+		qti,msm-pcm-dsp-id = <0>;
 	};
 
-	qcom,msm-pcm-low-latency {
-		compatible = "qcom,msm-pcm-dsp";
-		qcom,msm-pcm-dsp-id = <1>;
-		qcom,msm-pcm-low-latency;
+	qti,msm-pcm-low-latency {
+		compatible = "qti,msm-pcm-dsp";
+		qti,msm-pcm-dsp-id = <1>;
+		qti,msm-pcm-low-latency;
+		qti,latency-level = "ultra";
 	};
 
 	qcom,msm-pcm-routing {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index e2a774b..a912da8 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1628,15 +1628,16 @@
 		compatible = "qcom,msm-audio-ion";
 	};
 
-	qcom,msm-pcm {
-		compatible = "qcom,msm-pcm-dsp";
-		qcom,msm-pcm-dsp-id = <0>;
+	qti,msm-pcm {
+		compatible = "qti,msm-pcm-dsp";
+		qti,msm-pcm-dsp-id = <0>;
 	};
 
-	qcom,msm-pcm-low-latency {
-		compatible = "qcom,msm-pcm-dsp";
-		qcom,msm-pcm-dsp-id = <1>;
-		qcom,msm-pcm-low-latency;
+	qti,msm-pcm-low-latency {
+		compatible = "qti,msm-pcm-dsp";
+		qti,msm-pcm-dsp-id = <1>;
+		qti,msm-pcm-low-latency;
+		qti,latency-level = "regular";
 	};
 
 	qcom,msm-pcm-routing {
@@ -1684,6 +1685,10 @@
 		compatible = "qcom,msm-lsm-client";
 	};
 
+	qti,msm-pcm-loopback {
+		compatible = "qti,msm-pcm-loopback";
+	};
+
 	qcom,msm-dai-q6 {
 		compatible = "qcom,msm-dai-q6";
 		qcom,msm-dai-q6-sb-0-rx {
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index fa313bf..6b62391 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
@@ -22,5 +22,5 @@
 };
 
 &sdhc_1 {
-	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 };
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 366faef..63cb68b 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -214,6 +214,10 @@
 			<50 172>, /* usb1_hs_async_wakeup_irq */
 			<53 104>, /* mdss_irq */
 			<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+			<0xff 18>,  /* APCx_qgicQTmrSecPhysIrptReq */
+			<0xff 19>,  /* APCx_qgicQTmrSecPhysIrptReq */
+			<0xff 25>,  /* APCx_qgicExtFaultIrptReq */
+			<0xff 33>, /*l2_perf_mon*/
 			<0xff 34>,  /* APCC_qgicL2ErrorIrptReq */
 			<0xff 35>,  /* WDT_barkInt */
 			<0xff 40>,  /* qtimer_phy_irq */
@@ -236,7 +240,10 @@
 			<0xff 105>, /* iommu_pmon_nonsecure_irq */
 			<0xff 109>,  /* ocmem_dm_nonsec_irq */
 			<0xff 126>,  /* bam_irq[0] */
+			<0xff 140>,  /* uart_dm_intr */
 			<0xff 155>,  /* sdcc_irq[0] */
+			<0xff 157>,  /* sdcc_irq[0] */
+			<0xff 159>,  /* sdcc_irq[0] */
 			<0xff 163>,  /* usb30_ee1_irq */
 			<0xff 170>,  /* sdcc_pwr_cmd_irq */
 			<0xff 173>, /* o_wcss_apss_smd_hi */
@@ -269,6 +276,8 @@
 			<0xff 207>, /* rpm_ipc(27) */
 			<0xff 211>, /* usb_dwc3_otg */
 			<0xff 240>, /* summary_irq_kpss */
+			<0xff 253>, /* sdcc_pwr_cmd_irq */
+			<0xff 256>, /* sdcc_pwr_cmd_irq */
 			<0xff 268>, /* bam_irq[1] */
 			<0xff 270>, /* bam_irq[0] */
 			<0xff 271>; /* bam_irq[0] */
diff --git a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
index 2c06c3c..2783ffd 100644
--- a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
@@ -60,6 +60,10 @@
 	vdd_cx-supply = <&pm8841_s2_corner>;
 };
 
+&pm8841_s2_corner {
+	qcom,init-smps-mode = <0>;	/* Allow AUTO mode for VDD_CX. */
+};
+
 &krait_regulator_pmic {
 	status = "ok";
 
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index 8b13387..c06ebf8 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -183,10 +183,18 @@
 	qcom,use-phase-switching;
 };
 
+&mdss_mdp {
+	vdd-cx-supply = <&pma8084_s2_corner>;
+};
+
 &tspp {
 	vdd_cx-supply = <&pma8084_s2_corner>;
 };
 
+&pma8084_s2_corner {
+	qcom,init-smps-mode = <0>;	/* Allow AUTO mode for VDD_CX. */
+};
+
 &krait_regulator_pmic {
 	status = "ok";
 
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 0e7baf1..dee1f68 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -686,9 +686,9 @@
 		qcom,adsp-state = <2>;
 	};
 
-	qcom,msm-pcm {
-		compatible = "qcom,msm-pcm-dsp";
-		qcom,msm-pcm-dsp-id = <0>;
+	qti,msm-pcm {
+		compatible = "qti,msm-pcm-dsp";
+		qti,msm-pcm-dsp-id = <0>;
 	};
 
 	qcom,msm-pcm-routing {
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 37c9554..30b2346 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -185,3 +185,5 @@
 CONFIG_CRYPTO_DEV_QCE=y
 CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
 CONFIG_CRC_CCITT=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 431ac58..9af4009 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -399,3 +399,5 @@
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
 CONFIG_CRYPTO_TWOFISH=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 2a82d5b..1e32cfa 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -458,3 +458,5 @@
 CONFIG_TOUCHSCREEN_GT9XX=y
 CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
 CONFIG_MSM_RDBG=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 76c0f6a..e46bfef 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -64,11 +64,6 @@
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_ADSP_LOADER=y
-CONFIG_MSM_OCMEM=y
-CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
-CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
-CONFIG_MSM_OCMEM_POWER_DISABLE=y
 CONFIG_SENSORS_ADSP=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
 CONFIG_MSM_BOOT_STATS=y
@@ -431,3 +426,5 @@
 CONFIG_SENSORS_CAPELLA_CM36283=y
 CONFIG_NFC_QNCI=y
 CONFIG_MSM_RDBG=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index ff0c498..899ed30 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -61,11 +61,6 @@
 CONFIG_MSM_MEMORY_DUMP=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_ADSP_LOADER=y
-CONFIG_MSM_OCMEM=y
-CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
-CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
-CONFIG_MSM_OCMEM_POWER_DISABLE=y
 CONFIG_SENSORS_ADSP=y
 CONFIG_MSM_RTB=y
 CONFIG_MSM_RTB_SEPARATE_CPUS=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index da4de08..b4f21ad 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -461,3 +461,5 @@
 CONFIG_CRYPTO_DEV_QCRYPTO=m
 CONFIG_CRYPTO_DEV_QCE=m
 CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 4610597..fd8245f 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -554,3 +554,5 @@
 CONFIG_CRYPTO_DEV_QCE=m
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 200433d..10f2919 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -98,6 +98,7 @@
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
+CONFIG_SECURE_TOUCH=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -504,3 +505,5 @@
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
 CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
 CONFIG_MSM_RDBG=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index c106913..0b9ba76 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -104,6 +104,7 @@
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
+CONFIG_SECURE_TOUCH=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 9a5aaf0..4c0a82d 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -319,3 +319,5 @@
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index da3cfba..d42e798 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -60,64 +60,64 @@
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p1[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
 	{ 0 }
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p2[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
 	{ 0 }
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p4[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
+	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
 	{ 0 }
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8226_1p6[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1497600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
-	{ 1, 1593600, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_2,    0, 4 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_4, 0, 6 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_5,  0, 7 },
+	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_6,  0, 7 },
+	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_7,  0, 7 },
+	{ 1, 1305600, ACPUPLL, 5, 0,   CPR_CORNER_8,  0, 7 },
+	{ 1, 1344000, ACPUPLL, 5, 0,   CPR_CORNER_9,  0, 7 },
+	{ 1, 1401600, ACPUPLL, 5, 0,   CPR_CORNER_10,  0, 7 },
+	{ 1, 1497600, ACPUPLL, 5, 0,   CPR_CORNER_11,  0, 7 },
+	{ 1, 1593600, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 7 },
 	{ 0 }
 };
 
 static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
-	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 3 },
-	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 3 },
-	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 4 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 4 },
-	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
-	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 5 },
+	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_2,    0, 3 },
+	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_2,    0, 3 },
+	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_4, 0, 4 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_4, 0, 4 },
+	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 5 },
+	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_12,  0, 5 },
 	{ 0 }
 };
 
@@ -135,7 +135,7 @@
 	.freq_tbl = acpu_freq_tbl_8226_1p1,
 	.pvs_tables = pvs_tables_8226,
 	.bus_scale = &bus_client_pdata,
-	.vdd_max_cpu = CPR_CORNER_TURBO,
+	.vdd_max_cpu = CPR_CORNER_12,
 	.src_clocks = {
 		[PLL0].name = "gpll0",
 		[ACPUPLL].name = "a7sspll",
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 03f8837..affe6bd 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -631,6 +631,28 @@
 	},
 };
 
+static struct gpiomux_setting gpio_cdc_dmic_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_4MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct msm_gpiomux_config msm_cdc_dmic_configs[] __initdata = {
+	{
+		.gpio = 100,	/* DMIC CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_cdc_dmic_cfg,
+		},
+	},
+	{
+		.gpio = 101,	/* DMIC DATA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_cdc_dmic_cfg,
+		},
+	},
+};
+
 void __init msm8610_init_gpiomux(void)
 {
 	int rc;
@@ -668,4 +690,7 @@
 		msm_gpiomux_install(msm_non_qrd_configs,
 			ARRAY_SIZE(msm_non_qrd_configs));
 	}
+	if (of_board_is_cdp())
+		msm_gpiomux_install(msm_cdc_dmic_configs,
+			ARRAY_SIZE(msm_cdc_dmic_configs));
 }
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 1cf2e41..fa132fa 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -25,7 +25,6 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
-#include <linux/cpufreq.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/cpr-regulator.h>
@@ -33,6 +32,10 @@
 
 /* Register Offsets for RB-CPR and Bit Definitions */
 
+/* RBCPR Version Register */
+#define REG_RBCPR_VERSION		0
+#define RBCPR_VER_2			0x02
+
 /* RBCPR Gate Count and Target Registers */
 #define REG_RBCPR_GCNT_TARGET(n)	(0x60 + 4 * n)
 
@@ -131,14 +134,14 @@
 
 #define BYTES_PER_FUSE_ROW		8
 
+#define FLAGS_IGNORE_1ST_IRQ_STATUS	BIT(0)
 #define FLAGS_SET_MIN_VOLTAGE		BIT(1)
 #define FLAGS_UPLIFT_QUOT_VOLT		BIT(2)
-#define FLAGS_QUOT_ADJUST_WITH_FREQ	BIT(3)
 
-struct cpufreq_mapping_info {
-	int freq;
+struct quot_adjust_info {
+	int speed_bin;
+	int virtual_corner;
 	int quot_adjust;
-	int corner;
 };
 
 enum voltage_change_dir {
@@ -160,7 +163,7 @@
 
 	/* Process voltage parameters */
 	u32		pvs_init_v[CPR_PVS_EFUSE_BINS_MAX];
-	u32		pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
+	u32		pvs_corner_v[NUM_APC_PVS][CPR_FUSE_CORNER_MAX];
 	/* Process voltage variables */
 	u32		pvs_bin;
 	u32		process;
@@ -178,9 +181,8 @@
 	u64		cpr_fuse_bits;
 	bool		cpr_fuse_disable;
 	bool		cpr_fuse_local;
-	int		cpr_fuse_target_quot[CPR_CORNER_MAX];
-	int		cpr_fuse_original_quot[CPR_CORNER_MAX];
-	int		cpr_fuse_ro_sel[CPR_CORNER_MAX];
+	int		cpr_fuse_target_quot[CPR_FUSE_CORNER_MAX];
+	int		cpr_fuse_ro_sel[CPR_FUSE_CORNER_MAX];
 	int		gcnt;
 
 	unsigned int	cpr_irq;
@@ -188,13 +190,13 @@
 	phys_addr_t	rbcpr_clk_addr;
 	struct mutex	cpr_mutex;
 
-	int		ceiling_volt[CPR_CORNER_MAX];
-	int		floor_volt[CPR_CORNER_MAX];
-	int		last_volt[CPR_CORNER_MAX];
+	int		ceiling_volt[CPR_FUSE_CORNER_MAX];
+	int		floor_volt[CPR_FUSE_CORNER_MAX];
+	int		*last_volt;
 	int		step_volt;
 
-	int		save_ctl[CPR_CORNER_MAX];
-	int		save_irq[CPR_CORNER_MAX];
+	int		*save_ctl;
+	int		*save_irq;
 
 	u32		save_regs[CPR_NUM_SAVE_REGS];
 	u32		save_reg_val[CPR_NUM_SAVE_REGS];
@@ -214,10 +216,9 @@
 	u32		vdd_apc_step_up_limit;
 	u32		vdd_apc_step_down_limit;
 	u32		flags;
-	struct notifier_block freq_transition;
-	unsigned int	freq;
-	struct cpufreq_mapping_info *cpufreq_mapping;
-	u32		cpufreq_mapping_size;
+	int		*corner_map;
+	u32		num_corners;
+	int		*quot_adjust;
 };
 
 #define CPR_DEBUG_MASK_IRQ	BIT(0)
@@ -280,28 +281,6 @@
 	return efuse_bits;
 }
 
-static int cpr_get_freq_corner(struct cpr_regulator *cpr_vreg, int freq)
-{
-	int i;
-
-	for (i = 0; i < cpr_vreg->cpufreq_mapping_size; i++) {
-		if (freq == cpr_vreg->cpufreq_mapping[i].freq)
-			return cpr_vreg->cpufreq_mapping[i].corner;
-	}
-
-	return -EINVAL;
-}
-
-static int cpr_get_freq_quot_adjust(struct cpr_regulator *cpr_vreg, int freq)
-{
-	int i;
-
-	for (i = 0; i < cpr_vreg->cpufreq_mapping_size; i++) {
-		if (freq == cpr_vreg->cpufreq_mapping[i].freq)
-			return cpr_vreg->cpufreq_mapping[i].quot_adjust;
-	}
-	return 0;
-}
 
 static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
 {
@@ -362,9 +341,11 @@
 static void cpr_ctl_enable(struct cpr_regulator *cpr_vreg, int corner)
 {
 	u32 val;
+	int fuse_corner = cpr_vreg->corner_map[corner];
 
 	if (cpr_is_allowed(cpr_vreg) &&
-	    (cpr_vreg->ceiling_volt[corner] > cpr_vreg->floor_volt[corner]))
+	    (cpr_vreg->ceiling_volt[fuse_corner] >
+		cpr_vreg->floor_volt[fuse_corner]))
 		val = RBCPR_CTL_LOOP_EN;
 	else
 		val = 0;
@@ -376,13 +357,6 @@
 	cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0);
 }
 
-static bool cpr_ctl_is_enabled(struct cpr_regulator *cpr_vreg)
-{
-	u32 val;
-	val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
-	return ((val & RBCPR_CTL_LOOP_EN) == RBCPR_CTL_LOOP_EN);
-}
-
 static void cpr_regs_save(struct cpr_regulator *cpr_vreg)
 {
 	int i, offset;
@@ -415,16 +389,12 @@
 static void cpr_corner_restore(struct cpr_regulator *cpr_vreg, int corner)
 {
 	u32 gcnt, ctl, irq, ro_sel;
-	int adjust;
+	int fuse_corner = cpr_vreg->corner_map[corner];
 
-	if (cpr_vreg->flags & FLAGS_QUOT_ADJUST_WITH_FREQ) {
-		adjust = cpr_get_freq_quot_adjust(cpr_vreg, cpr_vreg->freq);
-		cpr_vreg->cpr_fuse_target_quot[corner] =
-		cpr_vreg->cpr_fuse_original_quot[corner] - adjust;
-	}
+	ro_sel = cpr_vreg->cpr_fuse_ro_sel[fuse_corner];
+	gcnt = cpr_vreg->gcnt | (cpr_vreg->cpr_fuse_target_quot[fuse_corner] -
+					cpr_vreg->quot_adjust[corner]);
 
-	ro_sel = cpr_vreg->cpr_fuse_ro_sel[corner];
-	gcnt = cpr_vreg->gcnt | cpr_vreg->cpr_fuse_target_quot[corner];
 	cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(ro_sel), gcnt);
 	ctl = cpr_vreg->save_ctl[corner];
 	cpr_write(cpr_vreg, REG_RBCPR_CTL, ctl);
@@ -462,8 +432,9 @@
 		goto _exit;
 	}
 
-	cpr_debug("%d -> %d [corner=%d]\n",
-		  old_cpr_enable, cpr_enable, the_cpr->corner);
+	cpr_debug("%d -> %d [corner=%d, fuse_corner=%d]\n",
+		  old_cpr_enable, cpr_enable, the_cpr->corner,
+		  the_cpr->corner_map[the_cpr->corner]);
 
 	if (the_cpr->cpr_fuse_disable) {
 		/* Already disabled */
@@ -509,17 +480,18 @@
 static int cpr_mx_get(struct cpr_regulator *cpr_vreg, int corner, int apc_volt)
 {
 	int vdd_mx;
+	int fuse_corner = cpr_vreg->corner_map[corner];
 
 	switch (cpr_vreg->vdd_mx_vmin_method) {
 	case VDD_MX_VMIN_APC:
 		vdd_mx = apc_volt;
 		break;
 	case VDD_MX_VMIN_APC_CORNER_CEILING:
-		vdd_mx = cpr_vreg->ceiling_volt[corner];
+		vdd_mx = cpr_vreg->ceiling_volt[fuse_corner];
 		break;
 	case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
 		vdd_mx = cpr_vreg->pvs_corner_v[APC_PVS_SLOW]
-						[CPR_CORNER_TURBO];
+						[CPR_FUSE_CORNER_TURBO];
 		break;
 	case VDD_MX_VMIN_MX_VMAX:
 		vdd_mx = cpr_vreg->vdd_mx_vmax;
@@ -536,15 +508,19 @@
 		      int vdd_mx_vmin)
 {
 	int rc;
+	int fuse_corner = cpr_vreg->corner_map[corner];
 
 	rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
 				   cpr_vreg->vdd_mx_vmax);
-	cpr_debug("[corner:%d] %d uV\n", corner, vdd_mx_vmin);
-	if (!rc)
+	cpr_debug("[corner:%d, fuse_corner:%d] %d uV\n", corner,
+			fuse_corner, vdd_mx_vmin);
+
+	if (!rc) {
 		cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
-	else
-		pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
-		       corner, vdd_mx_vmin, rc);
+	} else {
+		pr_err("set: vdd_mx [corner:%d, fuse_corner:%d] = %d uV failed: rc=%d\n",
+			corner, fuse_corner, vdd_mx_vmin, rc);
+	}
 	return rc;
 }
 
@@ -582,9 +558,11 @@
 		      enum voltage_change_dir dir)
 {
 	u32 reg_val, error_steps, reg_mask;
-	int last_volt, new_volt, corner;
+	int last_volt, new_volt, corner, fuse_corner;
+	u32 gcnt, quot;
 
 	corner = cpr_vreg->corner;
+	fuse_corner = cpr_vreg->corner_map[corner];
 
 	reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
 
@@ -592,18 +570,27 @@
 				& RBCPR_RESULT0_ERROR_STEPS_MASK;
 	last_volt = cpr_vreg->last_volt[corner];
 
-	cpr_debug_irq("last_volt[corner:%d] = %d uV\n", corner, last_volt);
+	cpr_debug_irq("last_volt[corner:%d, fuse_corner:%d] = %d uV\n", corner,
+			fuse_corner, last_volt);
+
+	gcnt = cpr_read(cpr_vreg, REG_RBCPR_GCNT_TARGET
+			(cpr_vreg->cpr_fuse_ro_sel[fuse_corner]));
+	quot = gcnt & ((1 << RBCPR_GCNT_TARGET_GCNT_SHIFT) - 1);
 
 	if (dir == UP) {
 		cpr_debug_irq("Up: cpr status = 0x%08x (error_steps=%d)\n",
 			      reg_val, error_steps);
 
-		if (last_volt >= cpr_vreg->ceiling_volt[corner]) {
-			cpr_debug_irq("[corn:%d] @ ceiling: %d >= %d: NACK\n",
-				      corner, last_volt,
-				      cpr_vreg->ceiling_volt[corner]);
+		if (last_volt >= cpr_vreg->ceiling_volt[fuse_corner]) {
+			cpr_debug_irq(
+			"[corn:%d, fuse_corn:%d] @ ceiling: %d >= %d: NACK\n",
+				corner, fuse_corner, last_volt,
+				cpr_vreg->ceiling_volt[fuse_corner]);
 			cpr_irq_clr_nack(cpr_vreg);
 
+			cpr_debug_irq("gcnt = 0x%08x (quot = %d)\n", gcnt,
+					quot);
+
 			/* Maximize the UP threshold */
 			reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
 					RBCPR_CTL_UP_THRESHOLD_SHIFT;
@@ -621,11 +608,12 @@
 
 		/* Calculate new voltage */
 		new_volt = last_volt + (error_steps * cpr_vreg->step_volt);
-		if (new_volt > cpr_vreg->ceiling_volt[corner]) {
+		if (new_volt > cpr_vreg->ceiling_volt[fuse_corner]) {
 			cpr_debug_irq("new_volt(%d) >= ceiling(%d): Clamp\n",
 				      new_volt,
-				      cpr_vreg->ceiling_volt[corner]);
-			new_volt = cpr_vreg->ceiling_volt[corner];
+				      cpr_vreg->ceiling_volt[fuse_corner]);
+
+			new_volt = cpr_vreg->ceiling_volt[fuse_corner];
 		}
 
 		if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
@@ -650,22 +638,26 @@
 		/* Ack */
 		cpr_irq_clr_ack(cpr_vreg);
 
-		cpr_debug_irq("UP: -> new_volt[corner:%d] = %d uV\n",
-			      corner, new_volt);
+		cpr_debug_irq(
+			"UP: -> new_volt[corner:%d, fuse_corner:%d] = %d uV\n",
+			corner, fuse_corner, new_volt);
 	} else if (dir == DOWN) {
 		cpr_debug_irq("Down: cpr status = 0x%08x (error_steps=%d)\n",
 			      reg_val, error_steps);
 
-		if (last_volt <= cpr_vreg->floor_volt[corner]) {
-			cpr_debug_irq("[corn:%d] @ floor: %d <= %d: NACK\n",
-				      corner, last_volt,
-				      cpr_vreg->floor_volt[corner]);
+		if (last_volt <= cpr_vreg->floor_volt[fuse_corner]) {
+			cpr_debug_irq(
+			"[corn:%d, fuse_corner:%d] @ floor: %d <= %d: NACK\n",
+				corner, fuse_corner, last_volt,
+				cpr_vreg->floor_volt[fuse_corner]);
 			cpr_irq_clr_nack(cpr_vreg);
 
 			/* Maximize the DOWN threshold */
 			reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
 					RBCPR_CTL_DN_THRESHOLD_SHIFT;
 			reg_val = reg_mask;
+			cpr_debug_irq("gcnt = 0x%08x (quot = %d)\n", gcnt,
+					quot);
 
 			/* Enable auto nack down */
 			reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
@@ -688,11 +680,11 @@
 
 		/* Calculte new voltage */
 		new_volt = last_volt - (error_steps * cpr_vreg->step_volt);
-		if (new_volt < cpr_vreg->floor_volt[corner]) {
+		if (new_volt < cpr_vreg->floor_volt[fuse_corner]) {
 			cpr_debug_irq("new_volt(%d) < floor(%d): Clamp\n",
 				      new_volt,
-				      cpr_vreg->floor_volt[corner]);
-			new_volt = cpr_vreg->floor_volt[corner];
+				      cpr_vreg->floor_volt[fuse_corner]);
+			new_volt = cpr_vreg->floor_volt[fuse_corner];
 		}
 
 		if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
@@ -711,8 +703,9 @@
 		/* Ack */
 		cpr_irq_clr_ack(cpr_vreg);
 
-		cpr_debug_irq("DOWN: -> new_volt[corner:%d] = %d uV\n",
-			      corner, new_volt);
+		cpr_debug_irq(
+		"DOWN: -> new_volt[corner:%d, fuse_corner:%d] = %d uV\n",
+			corner, fuse_corner, new_volt);
 	}
 }
 
@@ -724,6 +717,9 @@
 	mutex_lock(&cpr_vreg->cpr_mutex);
 
 	reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+	if (cpr_vreg->flags & FLAGS_IGNORE_1ST_IRQ_STATUS)
+		reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+
 	cpr_debug_irq("IRQ_STATUS = 0x%02X\n", reg_val);
 
 	if (!cpr_is_allowed(cpr_vreg)) {
@@ -831,6 +827,7 @@
 	int rc;
 	int new_volt;
 	enum voltage_change_dir change_dir = NO_CHANGE;
+	int fuse_corner = cpr_vreg->corner_map[corner];
 
 	mutex_lock(&cpr_vreg->cpr_mutex);
 
@@ -838,10 +835,12 @@
 		cpr_ctl_disable(cpr_vreg);
 		new_volt = cpr_vreg->last_volt[corner];
 	} else {
-		new_volt = cpr_vreg->pvs_corner_v[cpr_vreg->process][corner];
+		new_volt = cpr_vreg->pvs_corner_v
+				[cpr_vreg->process][fuse_corner];
 	}
 
-	cpr_debug("[corner:%d] = %d uV\n", corner, new_volt);
+	cpr_debug("[corner:%d, fuse_corner:%d] = %d uV\n", corner, fuse_corner,
+		new_volt);
 
 	if (corner > cpr_vreg->corner)
 		change_dir = UP;
@@ -934,11 +933,13 @@
 #define cpr_regulator_resume NULL
 #endif
 
-static int __devinit cpr_config(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_config(struct cpr_regulator *cpr_vreg,
+				struct device *dev)
 {
 	int i;
 	u32 val, gcnt, reg;
 	void __iomem *rbcpr_clk;
+	int size;
 
 	/* Use 19.2 MHz clock for CPR. */
 	rbcpr_clk = ioremap(cpr_vreg->rbcpr_clk_addr, 4);
@@ -1009,17 +1010,26 @@
 	cpr_vreg->save_regs[5] = REG_RBIF_IRQ_EN(cpr_vreg->irq_line);
 	cpr_vreg->save_regs[6] = REG_RBCPR_CTL;
 	cpr_vreg->save_regs[7] = REG_RBCPR_GCNT_TARGET
-		(cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS]);
+		(cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_SVS]);
 	cpr_vreg->save_regs[8] = REG_RBCPR_GCNT_TARGET
-		(cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL]);
+		(cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_NORMAL]);
 	cpr_vreg->save_regs[9] = REG_RBCPR_GCNT_TARGET
-		(cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO]);
+		(cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_TURBO]);
 
 	cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
 
-	cpr_corner_save(cpr_vreg, CPR_CORNER_SVS);
-	cpr_corner_save(cpr_vreg, CPR_CORNER_NORMAL);
-	cpr_corner_save(cpr_vreg, CPR_CORNER_TURBO);
+	val = cpr_read(cpr_vreg, REG_RBCPR_VERSION);
+	if (val <= RBCPR_VER_2)
+		cpr_vreg->flags |= FLAGS_IGNORE_1ST_IRQ_STATUS;
+
+	size = cpr_vreg->num_corners + 1;
+	cpr_vreg->save_ctl = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+	cpr_vreg->save_irq = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+	if (!cpr_vreg->save_ctl || !cpr_vreg->save_irq)
+		return -ENOMEM;
+
+	for (i = 1; i < size; i++)
+		cpr_corner_save(cpr_vreg, i);
 
 	return 0;
 }
@@ -1135,16 +1145,18 @@
 
 	init_v = cpr_vreg->pvs_init_v[cpr_vreg->pvs_bin];
 	for (process = NUM_APC_PVS - 1; process > APC_PVS_NO; process--) {
-		if (init_v <= cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO])
+		if (init_v <= cpr_vreg->pvs_corner_v
+			[process][CPR_FUSE_CORNER_TURBO])
 			break;
 	}
 
 	if (process == APC_PVS_NO) {
 		process = APC_PVS_SLOW;
-		cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO] = init_v;
+		cpr_vreg->pvs_corner_v[process][CPR_FUSE_CORNER_TURBO] = init_v;
 		cpr_vreg->ceiling_max = init_v;
 	} else if (process == APC_PVS_FAST &&
-		init_v < cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS]) {
+		init_v < cpr_vreg->pvs_corner_v
+			[APC_PVS_FAST][CPR_FUSE_CORNER_SVS]) {
 		process = APC_PVS_SLOW;
 	}
 
@@ -1152,7 +1164,7 @@
 		pvs_fuse[0], efuse_bits, pvs_fuse[2],
 		cpr_vreg->pvs_bin, process);
 	pr_info("pvs initial turbo voltage_= from %u to %u\n",
-		init_v, cpr_vreg->pvs_corner_v[process][CPR_CORNER_TURBO]);
+		init_v, cpr_vreg->pvs_corner_v[process][CPR_FUSE_CORNER_TURBO]);
 
 	cpr_vreg->process = process;
 
@@ -1245,22 +1257,68 @@
 		pr_err("cpr-uplift-quotient is missing: %d", rc);
 		return rc;
 	}
-	for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++)
+	for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
 		cpr_vreg->cpr_fuse_target_quot[i] += delta_quot[i-1];
 	return rc;
 }
 
-static int cpr_get_of_cprfreq_mappings(struct cpr_regulator *cpr_vreg,
+static int cpr_get_of_corner_mappings(struct cpr_regulator *cpr_vreg,
 					struct device *dev)
 {
 	int rc = 0;
-	int i, j, size, stripe_size, length;
+	int i, size, stripe_size;
 	struct property *prop;
 	u32 *tmp;
+	bool corners_mapped;
+
+	prop = of_find_property(dev->of_node, "qti,cpr-corner-map", NULL);
+
+	if (prop) {
+		size = prop->length / sizeof(u32);
+		corners_mapped = true;
+	} else {
+		size = CPR_FUSE_CORNER_MAX - 1;
+		corners_mapped = false;
+	}
+
+	cpr_vreg->corner_map = devm_kzalloc(dev, sizeof(int) * (size + 1),
+					GFP_KERNEL);
+	if (!cpr_vreg->corner_map) {
+		pr_err("Can't allocate cpr_vreg->corner_map memory\n");
+		return -ENOMEM;
+	}
+	cpr_vreg->num_corners = size;
+
+	if (!corners_mapped) {
+		for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
+			cpr_vreg->corner_map[i] = i;
+	} else {
+		rc = of_property_read_u32_array(dev->of_node,
+			"qti,cpr-corner-map", &cpr_vreg->corner_map[1], size);
+
+		if (rc) {
+			pr_err("qti,cpr-corner-map missing, rc = %d", rc);
+			return rc;
+		}
+	}
+
+	cpr_vreg->quot_adjust = devm_kzalloc(dev,
+			sizeof(int) * (cpr_vreg->num_corners + 1),
+			GFP_KERNEL);
+	if (!cpr_vreg->quot_adjust) {
+		pr_err("Can't allocate cpr_vreg->quot_adjust memory\n");
+		return -ENOMEM;
+	}
 
 	prop = of_find_property(dev->of_node, "qti,cpr-quot-adjust-table",
 				NULL);
+
 	if (prop) {
+		if (!corners_mapped) {
+			pr_err("qti,cpr-corner-map missing\n");
+			return -EINVAL;
+		}
+
 		size = prop->length / sizeof(u32);
 		tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
 		if (!tmp)
@@ -1275,51 +1333,33 @@
 			return rc;
 		}
 
-		length = 0;
-		stripe_size = 1 + sizeof(struct cpufreq_mapping_info) /
-				sizeof(int);
-		for (i = 0; i < size; i += stripe_size) {
-			if (tmp[i] == cpr_vreg->speed_bin)
-				length++;
-		}
-		if (i != size) {
-			pr_err("qti,cpr-quot-adjust-table data is not correct\n");
+		stripe_size = sizeof(struct quot_adjust_info) / sizeof(int);
+
+		if ((size % stripe_size) != 0) {
+			pr_err("qti,cpr-quot-adjust-table data is not correct");
 			kfree(tmp);
 			return -EINVAL;
 		}
 
-		cpr_vreg->cpufreq_mapping_size = length;
-		if (length) {
-			cpr_vreg->cpufreq_mapping = devm_kzalloc(dev,
-				sizeof(struct cpufreq_mapping_info) * length,
-				GFP_KERNEL);
-
-			if (!cpr_vreg->cpufreq_mapping) {
-				kfree(tmp);
-				return -ENOMEM;
-			}
-
-			cpr_vreg->flags |= FLAGS_QUOT_ADJUST_WITH_FREQ;
-
-			for (i = 0, j = 0; i < size; i += stripe_size) {
-				if (tmp[i] == cpr_vreg->speed_bin) {
-					cpr_vreg->cpufreq_mapping[j].freq =
-						tmp[i+1];
-					cpr_vreg->cpufreq_mapping[j].quot_adjust
-					= tmp[i+2];
-					cpr_vreg->cpufreq_mapping[j].corner =
-						tmp[i+3];
-					++j;
+		for (i = 0; i < size; i += stripe_size) {
+			if (tmp[i] == cpr_vreg->speed_bin) {
+				if (tmp[i + 1] >= 1 &&
+					tmp[i + 1] <=
+					cpr_vreg->num_corners) {
+					cpr_vreg->quot_adjust[tmp[i + 1]] =
+					tmp[i + 2];
+				} else {
+					pr_err("qti,cpr-quot-adjust-table data is not correct");
+					kfree(tmp);
+					return -EINVAL;
 				}
-
 			}
-
 		}
 
 		kfree(tmp);
 	}
 
-	return rc;
+	return 0;
 }
 
 static int __devinit cpr_init_cpr_efuse(struct platform_device *pdev,
@@ -1332,8 +1372,8 @@
 	char *targ_quot_str, *ro_sel_str;
 	u32 cpr_fuse_row[2];
 	u32 bp_cpr_disable, bp_scheme;
-	int bp_target_quot[CPR_CORNER_MAX];
-	int bp_ro_sel[CPR_CORNER_MAX];
+	int bp_target_quot[CPR_FUSE_CORNER_MAX];
+	int bp_ro_sel[CPR_FUSE_CORNER_MAX];
 	u32 ro_sel, val;
 	u64 fuse_bits, fuse_bits_2;
 
@@ -1364,8 +1404,8 @@
 
 	rc = of_property_read_u32_array(of_node,
 		targ_quot_str,
-		&bp_target_quot[CPR_CORNER_SVS],
-		CPR_CORNER_MAX - CPR_CORNER_SVS);
+		&bp_target_quot[CPR_FUSE_CORNER_SVS],
+		CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
 	if (rc < 0) {
 		pr_err("missing %s: rc=%d\n", targ_quot_str, rc);
 		return rc;
@@ -1373,8 +1413,8 @@
 
 	rc = of_property_read_u32_array(of_node,
 		ro_sel_str,
-		&bp_ro_sel[CPR_CORNER_SVS],
-		CPR_CORNER_MAX - CPR_CORNER_SVS);
+		&bp_ro_sel[CPR_FUSE_CORNER_SVS],
+		CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
 	if (rc < 0) {
 		pr_err("missing %s: rc=%d\n", ro_sel_str, rc);
 		return rc;
@@ -1432,7 +1472,7 @@
 	pr_info("disable = %d, local = %d\n",
 		cpr_vreg->cpr_fuse_disable, cpr_vreg->cpr_fuse_local);
 
-	for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+	for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
 		ro_sel = (fuse_bits >> bp_ro_sel[i])
 				& CPR_FUSE_RO_SEL_BITS_MASK;
 		val = (fuse_bits >> bp_target_quot[i])
@@ -1445,18 +1485,13 @@
 
 	if (cpr_vreg->flags & FLAGS_UPLIFT_QUOT_VOLT) {
 		cpr_voltage_uplift_wa_inc_quot(cpr_vreg, of_node);
-		for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+		for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
 			pr_info("Corner[%d]: uplifted target quot = %d\n",
 				i, cpr_vreg->cpr_fuse_target_quot[i]);
 		}
 	}
 
-	for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
-		cpr_vreg->cpr_fuse_original_quot[i] =
-		cpr_vreg->cpr_fuse_target_quot[i];
-	}
-
-	rc = cpr_get_of_cprfreq_mappings(cpr_vreg, &pdev->dev);
+	rc = cpr_get_of_corner_mappings(cpr_vreg, &pdev->dev);
 	if (rc)
 		return rc;
 
@@ -1469,10 +1504,12 @@
 		int *quot = cpr_vreg->cpr_fuse_target_quot;
 		bool valid_fuse = true;
 
-		if ((quot[CPR_CORNER_TURBO] > quot[CPR_CORNER_NORMAL]) &&
-		    (quot[CPR_CORNER_NORMAL] > quot[CPR_CORNER_SVS])) {
-			if ((quot[CPR_CORNER_TURBO] -
-			     quot[CPR_CORNER_NORMAL])
+		if ((quot[CPR_FUSE_CORNER_TURBO] >
+			quot[CPR_FUSE_CORNER_NORMAL]) &&
+		    (quot[CPR_FUSE_CORNER_NORMAL] >
+			quot[CPR_FUSE_CORNER_SVS])) {
+			if ((quot[CPR_FUSE_CORNER_TURBO] -
+			     quot[CPR_FUSE_CORNER_NORMAL])
 					<= CPR_FUSE_MIN_QUOT_DIFF)
 				valid_fuse = false;
 		} else {
@@ -1488,18 +1525,27 @@
 	return 0;
 }
 
-static int __devinit cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
+static int __devinit cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg,
+			struct device *dev)
 {
 	int i;
+	int size = cpr_vreg->num_corners + 1;
+
+	cpr_vreg->last_volt = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
+	if (!cpr_vreg->last_volt)
+		return -EINVAL;
 
 	/* Construct CPR voltage limits */
-	for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+	for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
 		cpr_vreg->floor_volt[i] =
 			cpr_vreg->pvs_corner_v[APC_PVS_FAST][i];
 		cpr_vreg->ceiling_volt[i] =
 			cpr_vreg->pvs_corner_v[APC_PVS_SLOW][i];
-		cpr_vreg->last_volt[i] =
-			cpr_vreg->pvs_corner_v[cpr_vreg->process][i];
+	}
+
+	for (i = 1; i < size; i++) {
+		cpr_vreg->last_volt[i] = cpr_vreg->pvs_corner_v
+				[cpr_vreg->process][cpr_vreg->corner_map[i]];
 	}
 
 	return 0;
@@ -1599,7 +1645,9 @@
 					    resource_size(res));
 
 	/* Init all voltage set points of APC regulator for CPR */
-	cpr_init_cpr_voltages(cpr_vreg);
+	rc = cpr_init_cpr_voltages(cpr_vreg, &pdev->dev);
+	if (rc)
+		return rc;
 
 	/* Init CPR configuration parameters */
 	rc = cpr_init_cpr_parameters(pdev, cpr_vreg);
@@ -1614,7 +1662,7 @@
 	}
 
 	/* Configure CPR HW but keep it disabled */
-	rc = cpr_config(cpr_vreg);
+	rc = cpr_config(cpr_vreg, &pdev->dev);
 	if (rc)
 		return rc;
 
@@ -1739,8 +1787,8 @@
 
 	rc = of_property_read_u32_array(of_node,
 		"qti,pvs-corner-ceiling-slow",
-		&cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_SVS],
-		CPR_CORNER_MAX - CPR_CORNER_SVS);
+		&cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_FUSE_CORNER_SVS],
+		CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
 	if (rc < 0) {
 		pr_err("pvs-corner-ceiling-slow missing: rc=%d\n", rc);
 		return rc;
@@ -1748,8 +1796,8 @@
 
 	rc = of_property_read_u32_array(of_node,
 		"qti,pvs-corner-ceiling-nom",
-		&cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_CORNER_SVS],
-		CPR_CORNER_MAX - CPR_CORNER_SVS);
+		&cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_FUSE_CORNER_SVS],
+		CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
 	if (rc < 0) {
 		pr_err("pvs-corner-ceiling-norm missing: rc=%d\n", rc);
 		return rc;
@@ -1757,8 +1805,8 @@
 
 	rc = of_property_read_u32_array(of_node,
 		"qti,pvs-corner-ceiling-fast",
-		&cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS],
-		CPR_CORNER_MAX - CPR_CORNER_SVS);
+		&cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_FUSE_CORNER_SVS],
+		CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
 	if (rc < 0) {
 		pr_err("pvs-corner-ceiling-fast missing: rc=%d\n", rc);
 		return rc;
@@ -1775,70 +1823,26 @@
 		of_property_read_u32(of_node, "qti,cpr-cond-min-voltage",
 					&min_uv);
 		for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++)
-			for (j = CPR_CORNER_SVS; j < CPR_CORNER_MAX; j++)
+			for (j = CPR_FUSE_CORNER_SVS; j < CPR_FUSE_CORNER_MAX;
+				j++)
 				if (cpr_vreg->pvs_corner_v[i][j] < min_uv)
 					cpr_vreg->pvs_corner_v[i][j] = min_uv;
 	}
 
 	/* Set ceiling max and use it for APC_PVS_NO */
 	cpr_vreg->ceiling_max =
-		cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_TURBO];
+		cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_FUSE_CORNER_TURBO];
 
 	for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++) {
 		pr_info("[%d] [%d %d %d] uV\n", i,
-			cpr_vreg->pvs_corner_v[i][CPR_CORNER_SVS],
-			cpr_vreg->pvs_corner_v[i][CPR_CORNER_NORMAL],
-			cpr_vreg->pvs_corner_v[i][CPR_CORNER_TURBO]);
+			cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_SVS],
+			cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_NORMAL],
+			cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_TURBO]);
 	}
 
 	return 0;
 }
 
-static int cpr_freq_transition(struct notifier_block *nb, unsigned long val,
-					void *data)
-{
-	int old_corner, new_corner;
-	struct cpr_regulator *cpr_vreg = container_of(nb, struct cpr_regulator,
-				freq_transition);
-	struct cpufreq_freqs *freqs = data;
-
-	mutex_lock(&cpr_vreg->cpr_mutex);
-	switch (val) {
-	case CPUFREQ_PRECHANGE:
-		cpr_vreg->freq = freqs->new;
-		if (freqs->new > freqs->old) {
-			old_corner = cpr_get_freq_corner(cpr_vreg, freqs->old);
-			new_corner = cpr_get_freq_corner(cpr_vreg, freqs->new);
-			if (new_corner > 0 && old_corner == new_corner &&
-				cpr_ctl_is_enabled(cpr_vreg)) {
-				cpr_ctl_disable(cpr_vreg);
-				cpr_irq_clr(cpr_vreg);
-				cpr_corner_restore(cpr_vreg, new_corner);
-				cpr_ctl_enable(cpr_vreg, new_corner);
-			}
-		}
-		break;
-	case CPUFREQ_POSTCHANGE:
-		if (freqs->new < freqs->old) {
-			old_corner = cpr_get_freq_corner(cpr_vreg, freqs->old);
-			new_corner = cpr_get_freq_corner(cpr_vreg, freqs->new);
-			if (new_corner > 0 && old_corner == new_corner &&
-				cpr_ctl_is_enabled(cpr_vreg)) {
-				cpr_ctl_disable(cpr_vreg);
-				cpr_irq_clr(cpr_vreg);
-				cpr_corner_restore(cpr_vreg, new_corner);
-				cpr_ctl_enable(cpr_vreg, new_corner);
-			}
-		}
-		break;
-	default:
-		break;
-	}
-	mutex_unlock(&cpr_vreg->cpr_mutex);
-
-	return NOTIFY_OK;
-}
-
 static int __devinit cpr_regulator_probe(struct platform_device *pdev)
 {
 	struct cpr_regulator *cpr_vreg;
@@ -1922,10 +1926,6 @@
 
 	platform_set_drvdata(pdev, cpr_vreg);
 	the_cpr = cpr_vreg;
-	cpr_vreg->freq_transition.notifier_call = cpr_freq_transition;
-	if (cpr_vreg->flags & FLAGS_QUOT_ADJUST_WITH_FREQ)
-		cpufreq_register_notifier(&cpr_vreg->freq_transition,
-						CPUFREQ_TRANSITION_NOTIFIER);
 
 	return 0;
 
@@ -1946,9 +1946,6 @@
 			cpr_irq_set(cpr_vreg, 0);
 		}
 
-		if (cpr_vreg->flags & FLAGS_QUOT_ADJUST_WITH_FREQ)
-			cpufreq_unregister_notifier(&cpr_vreg->freq_transition,
-						CPUFREQ_TRANSITION_NOTIFIER);
 		cpr_apc_exit(cpr_vreg);
 		regulator_unregister(cpr_vreg->rdev);
 	}
diff --git a/arch/arm/mach-msm/hsic_sysmon_test.c b/arch/arm/mach-msm/hsic_sysmon_test.c
index fac6575..a910cd26 100644
--- a/arch/arm/mach-msm/hsic_sysmon_test.c
+++ b/arch/arm/mach-msm/hsic_sysmon_test.c
@@ -63,9 +63,13 @@
 	if (!dev)
 		return -ENODEV;
 
+	/* Add check for user buf count greater than RD_BUF_SIZE */
+	if (count > RD_BUF_SIZE)
+		count = RD_BUF_SIZE;
+
 	if (copy_from_user(dev->buf, ubuf, count)) {
 		pr_err("error copying for writing");
-		return 0;
+		return -EFAULT;
 	}
 
 	ret = hsic_sysmon_write(id, dev->buf, count, 1000);
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
index 0a1cdd4..42cf6f9 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/rtac.h
@@ -45,7 +45,7 @@
 };
 
 void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id);
-void rtac_remove_adm_device(u32 port_id);
+void rtac_remove_adm_device(u32 port_id, u32 copp_id);
 void rtac_remove_popp_from_adm_devices(u32 popp_id);
 void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
 	u32 tx_afe_port, u32 session_id);
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index 2e15cae..9a27fd2 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -73,7 +73,8 @@
 #define USF_TSC_PTR_EVENT_IND  1
 #define USF_MOUSE_EVENT_IND    2
 #define USF_KEYBOARD_EVENT_IND 3
-#define USF_MAX_EVENT_IND      4
+#define USF_TSC_EXT_EVENT_IND  4
+#define USF_MAX_EVENT_IND      5
 
 /* Types of events, produced by the calculators */
 #define USF_NO_EVENT 0
@@ -81,10 +82,12 @@
 #define USF_TSC_PTR_EVENT  (1 << USF_TSC_PTR_EVENT_IND)
 #define USF_MOUSE_EVENT    (1 << USF_MOUSE_EVENT_IND)
 #define USF_KEYBOARD_EVENT (1 << USF_KEYBOARD_EVENT_IND)
+#define USF_TSC_EXT_EVENT  (1 << USF_TSC_EXT_EVENT_IND)
 #define USF_ALL_EVENTS         (USF_TSC_EVENT |\
 				USF_TSC_PTR_EVENT |\
 				USF_MOUSE_EVENT |\
-				USF_KEYBOARD_EVENT)
+				USF_KEYBOARD_EVENT |\
+				USF_TSC_EXT_EVENT)
 
 /* min, max array dimension */
 #define MIN_MAX_DIM 2
@@ -146,6 +149,8 @@
 	int tsc_y_tilt[MIN_MAX_DIM];
 	/* Touch screen pressure limits: min & max; for input module */
 	int tsc_pressure[MIN_MAX_DIM];
+	/* The requested side buttons bitmap */
+	uint16_t req_side_buttons_bitmap;
 	/* Bitmap of types of events (USF_X_EVENT), produced by calculator */
 	uint16_t event_types;
 	/* Input event source */
@@ -174,6 +179,8 @@
 	int inclinations[TILTS_DIM];
 /* [0-1023] (10bits); 0 - pen up */
 	uint32_t pressure;
+/* Bitmap for side button state. 1 - down, 0 - up */
+	uint16_t side_buttons_state_bitmap;
 };
 
 /* Mouse buttons, supported by USF */
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index ce66531..6bb4011 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -434,7 +434,7 @@
 				       unsigned int len)
 {
 	struct sk_buff *temp;
-	int offset = 0, buf_len = 0, copy_len;
+	unsigned int offset = 0, buf_len = 0, copy_len;
 	void *buf;
 
 	if (!skb_head) {
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index bdae10c..06160f7 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -290,7 +290,7 @@
 			system_level->num_cpu_votes != num_powered_cores)
 			continue;
 
-		if (latency_us < pwr_param->latency_us)
+		if (latency_us < pwr_param->latency_us && from_idle)
 			continue;
 
 		if (sleep_us < pwr_param->time_overhead_us)
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
index ac4ed25..c4e52be 100644
--- a/arch/arm/mach-msm/pm-stats.c
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -36,72 +36,132 @@
 	struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
 };
 
+static struct msm_pm_time_stats suspend_stats;
+
 static DEFINE_SPINLOCK(msm_pm_stats_lock);
 static DEFINE_PER_CPU_SHARED_ALIGNED(
 	struct msm_pm_cpu_time_stats, msm_pm_stats);
-
 /*
- * Add the given time data to the statistics collection.
+ *  Function to update stats
  */
-void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+static void update_stats(struct msm_pm_time_stats *stats, int64_t t)
 {
-	unsigned long flags;
-	struct msm_pm_time_stats *stats;
 	int64_t bt;
 	int i;
 
-	spin_lock_irqsave(&msm_pm_stats_lock, flags);
-	stats = __get_cpu_var(msm_pm_stats).stats;
+	if (!stats)
+		return;
 
-	if (!stats[id].enabled)
-		goto add_bail;
-
-	stats[id].total_time += t;
-	stats[id].count++;
+	stats->total_time += t;
+	stats->count++;
 
 	bt = t;
-	do_div(bt, stats[id].first_bucket_time);
+	do_div(bt, stats->first_bucket_time);
 
 	if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
-				(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+			(CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
 		i = DIV_ROUND_UP(fls((uint32_t)bt),
-					CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+			CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
 	else
 		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
 
 	if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
 		i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
 
-	stats[id].bucket[i]++;
+	stats->bucket[i]++;
 
-	if (t < stats[id].min_time[i] || !stats[id].max_time[i])
-		stats[id].min_time[i] = t;
-	if (t > stats[id].max_time[i])
-		stats[id].max_time[i] = t;
+	if (t < stats->min_time[i] || !stats->max_time[i])
+		stats->min_time[i] = t;
+	if (t > stats->max_time[i])
+		stats->max_time[i] = t;
+}
 
+/*
+ * Add the given time data to the statistics collection.
+ */
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+	struct msm_pm_time_stats *stats;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_pm_stats_lock, flags);
+	if (id == MSM_PM_STAT_SUSPEND) {
+		stats = &suspend_stats;
+	} else {
+		stats = __get_cpu_var(msm_pm_stats).stats;
+		if (!stats[id].enabled)
+			goto add_bail;
+		stats = &stats[id];
+	}
+	update_stats(stats, t);
 add_bail:
 	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
 }
 
-/*
- * Write out the power management statistics.
- */
-
-static int msm_pm_stats_show(struct seq_file *m, void *v)
+static void stats_show(struct seq_file *m,
+		struct msm_pm_time_stats *stats,
+		int cpu, int suspend)
 {
-	int cpu;
+	int64_t bucket_time;
+	int64_t s;
+	uint32_t ns;
+	int i;
 	int bucket_count = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
 	int bucket_shift = CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
 
-	for_each_possible_cpu(cpu) {
-		unsigned long flags;
-		struct msm_pm_time_stats *stats;
-		int i, id;
-		int64_t bucket_time;
-		int64_t s;
-		uint32_t ns;
+	if (!stats || !m)
+		return;
 
-		spin_lock_irqsave(&msm_pm_stats_lock, flags);
+	s = stats->total_time;
+	ns = do_div(s, NSEC_PER_SEC);
+	if (suspend)
+		seq_printf(m,
+			"%s:\n"
+			"  count: %7d\n"
+			"  total_time: %lld.%09u\n",
+			stats->name,
+			stats->count,
+			s, ns);
+	else
+		seq_printf(m,
+			"[cpu %u] %s:\n"
+			"  count: %7d\n"
+			"  total_time: %lld.%09u\n",
+			cpu, stats->name,
+			stats->count,
+			s, ns);
+
+	bucket_time = stats->first_bucket_time;
+	for (i = 0; i < bucket_count; i++) {
+		s = bucket_time;
+		ns = do_div(s, NSEC_PER_SEC);
+		seq_printf(m,
+			"   <%6lld.%09u: %7d (%lld-%lld)\n",
+			s, ns, stats->bucket[i],
+			stats->min_time[i],
+			stats->max_time[i]);
+			bucket_time <<= bucket_shift;
+	}
+
+	seq_printf(m, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
+		s, ns, stats->bucket[i],
+		stats->min_time[i],
+		stats->max_time[i]);
+}
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_stats_show(struct seq_file *m, void *v)
+{
+	int cpu;
+	int id;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_pm_stats_lock, flags);
+
+	for_each_possible_cpu(cpu) {
+		struct msm_pm_time_stats *stats;
+
 		stats = per_cpu(msm_pm_stats, cpu).stats;
 
 		for (id = 0; id < MSM_PM_STAT_COUNT; id++) {
@@ -109,38 +169,14 @@
 			if (!stats[id].enabled)
 				continue;
 
-			s = stats[id].total_time;
-			ns = do_div(s, NSEC_PER_SEC);
-			seq_printf(m,
-				"[cpu %u] %s:\n"
-				"  count: %7d\n"
-				"  total_time: %lld.%09u\n",
-				cpu, stats[id].name,
-				stats[id].count,
-				s, ns);
+			if (id == MSM_PM_STAT_SUSPEND)
+				continue;
 
-			bucket_time = stats[id].first_bucket_time;
-			for (i = 0; i < bucket_count; i++) {
-				s = bucket_time;
-				ns = do_div(s, NSEC_PER_SEC);
-				seq_printf(m,
-					"   <%6lld.%09u: %7d (%lld-%lld)\n",
-					s, ns, stats[id].bucket[i],
-					stats[id].min_time[i],
-					stats[id].max_time[i]);
-
-				bucket_time <<= bucket_shift;
-			}
-
-			seq_printf(m, "  >=%6lld.%09u: %7d (%lld-%lld)\n",
-				s, ns, stats[id].bucket[i],
-				stats[id].min_time[i],
-				stats[id].max_time[i]);
+			stats_show(m, &stats[id], cpu, false);
 		}
-
-		spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
 	}
-
+	stats_show(m, &suspend_stats, cpu, true);
+	spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
 	return 0;
 }
 
@@ -259,14 +295,6 @@
 			first_bucket_time =
 			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
 
-		stats[MSM_PM_STAT_SUSPEND].name = "suspend";
-		stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
-			CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
-		stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
 		stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
 		stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
 			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
@@ -275,6 +303,9 @@
 			stats[enable_stats[i]].enabled = true;
 
 	}
+	suspend_stats.name = "system_suspend";
+	suspend_stats.first_bucket_time =
+		CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
 
 	d_entry = proc_create_data("msm_pm_stats", S_IRUGO | S_IWUSR | S_IWGRP,
 			NULL, &msm_pm_stats_fops, NULL);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index bf47366..7ab4ec3 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -26,6 +26,8 @@
 #define FORMAT_USPS_EPOS	0x00000000
 #define FORMAT_USRAW		0x00000001
 #define FORMAT_USPROX		0x00000002
+#define FORMAT_USGES_SYNC	0x00000003
+#define FORMAT_USRAW_SYNC	0x00000004
 #define INVALID_FORMAT		0xffffffff
 
 #define IN			0x000
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 1ea213a..a18d0f3 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -27,8 +27,8 @@
 #include "usfcdev.h"
 
 /* The driver version*/
-#define DRV_VERSION "1.4.2"
-#define USF_VERSION_ID 0x0142
+#define DRV_VERSION "1.5.1"
+#define USF_VERSION_ID 0x0151
 
 /* Standard timeout in the asynchronous ops */
 #define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
@@ -51,12 +51,19 @@
 #define Y_IND 1
 #define Z_IND 2
 
+/* Shared memory limits */
+/* max_buf_size = (port_size(65535*2) * port_num(8) * group_size(3) */
+#define USF_MAX_BUF_SIZE 3145680
+#define USF_MAX_BUF_NUM  32
+
 /* Place for opreation result, received from QDSP6 */
 #define APR_RESULT_IND 1
 
 /* Place for US detection result, received from QDSP6 */
 #define APR_US_DETECT_RESULT_IND 0
 
+#define BITS_IN_BYTE 8
+
 /* The driver states */
 enum usf_state_type {
 	USF_IDLE_STATE,
@@ -117,6 +124,8 @@
 	uint16_t conflicting_event_types;
 	/* Bitmap of types of events from devs, conflicting with USF */
 	uint16_t conflicting_event_filters;
+	/* The requested side buttons bitmap */
+	uint16_t req_side_buttons_bitmap;
 };
 
 struct usf_input_dev_type {
@@ -146,6 +155,12 @@
 	0,            /* US_INPUT_SRC_UNDEF */
 };
 
+/* Supported buttons container */
+static const int s_button_map[] = {
+	BTN_STYLUS,
+	BTN_STYLUS2
+};
+
 /* The opened devices container */
 static int s_opened_devs[MAX_DEVS_NUMBER];
 
@@ -176,14 +191,35 @@
 				struct us_input_info_type *input_info,
 				const char *name)
 {
+	int i = 0;
+	int num_side_buttons = min(ARRAY_SIZE(s_button_map),
+		sizeof(input_info->req_side_buttons_bitmap) *
+		BITS_IN_BYTE);
+	uint16_t max_side_button_bitmap = ((1 << ARRAY_SIZE(s_button_map)) - 1);
 	struct input_dev *in_dev = allocate_dev(ind, name);
-
 	if (in_dev == NULL)
 		return -ENOMEM;
 
+	if (input_info->req_side_buttons_bitmap > max_side_button_bitmap) {
+		pr_err("%s: Requested side buttons[%d] exceeds max side buttons available[%d]\n",
+		__func__,
+		input_info->req_side_buttons_bitmap,
+		max_side_button_bitmap);
+		return -EINVAL;
+	}
+
 	usf_info->input_ifs[ind] = in_dev;
+	usf_info->req_side_buttons_bitmap =
+		input_info->req_side_buttons_bitmap;
 	in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 	in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+
+	for (i = 0; i < num_side_buttons; i++)
+		if (input_info->req_side_buttons_bitmap & (1 << i))
+			in_dev->keybit[BIT_WORD(s_button_map[i])] |=
+			BIT_MASK(s_button_map[i]);
+
 	input_set_abs_params(in_dev, ABS_X,
 			     input_info->tsc_x_dim[MIN_IND],
 			     input_info->tsc_x_dim[MAX_IND],
@@ -260,6 +296,11 @@
 			     struct usf_event_type *event)
 
 {
+	int i = 0;
+	int num_side_buttons = min(ARRAY_SIZE(s_button_map),
+		sizeof(usf_info->req_side_buttons_bitmap) *
+		BITS_IN_BYTE);
+
 	struct input_dev *input_if = usf_info->input_ifs[if_ind];
 	struct point_event_type *pe = &(event->event_data.point_event);
 
@@ -273,19 +314,27 @@
 	input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
 	input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
 
+	for (i = 0; i < num_side_buttons; i++) {
+		uint16_t mask = (1 << i),
+		btn_state = !!(pe->side_buttons_state_bitmap & mask);
+		if (usf_info->req_side_buttons_bitmap & mask)
+			input_report_key(input_if, s_button_map[i], btn_state);
+	}
+
 	if (usf_info->event_src)
 		input_report_key(input_if, usf_info->event_src, 1);
 
 	input_sync(input_if);
 
-	pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
+	pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d], side_buttons[%d]\n",
 		 __func__,
 		 pe->coordinates[X_IND],
 		 pe->coordinates[Y_IND],
 		 pe->coordinates[Z_IND],
 		 pe->inclinations[X_IND],
 		 pe->inclinations[Y_IND],
-		 pe->pressure);
+		 pe->pressure,
+		 pe->side_buttons_state_bitmap);
 }
 
 static void notify_mouse_event(struct usf_type *usf_info,
@@ -338,6 +387,8 @@
 		prepare_mouse_input_device, notify_mouse_event},
 	{USF_KEYBOARD_EVENT, "usf_kb",
 		prepare_keyboard_input_device, notify_key_event},
+	{USF_TSC_EXT_EVENT, "usf_tsc_ext",
+		prepare_tsc_input_device, notify_tsc_event},
 };
 
 static void usf_rx_cb(uint32_t opcode, uint32_t token,
@@ -436,6 +487,15 @@
 	    (config == NULL))
 		return -EINVAL;
 
+	if ((config->buf_size == 0) ||
+	    (config->buf_size > USF_MAX_BUF_SIZE) ||
+	    (config->buf_num == 0) ||
+	    (config->buf_num > USF_MAX_BUF_NUM)) {
+		pr_err("%s: wrong params: buf_size=%d; buf_num=%d\n",
+		       __func__, config->buf_size, config->buf_num);
+		return -EINVAL;
+	}
+
 	data_map_size = sizeof(usf_xx->encdec_cfg.cfg_common.data_map);
 	min_map_size = min(data_map_size, config->port_cnt);
 
@@ -748,6 +808,7 @@
 {
 	uint32_t timeout = 0;
 	struct us_detect_info_type detect_info;
+	struct usm_session_cmd_detect_info *p_allocated_memory = NULL;
 	struct usm_session_cmd_detect_info usm_detect_info;
 	struct usm_session_cmd_detect_info *p_usm_detect_info =
 						&usm_detect_info;
@@ -774,12 +835,13 @@
 		uint8_t *p_data = NULL;
 
 		detect_info_size += detect_info.params_data_size;
-		p_usm_detect_info = kzalloc(detect_info_size, GFP_KERNEL);
-		if (p_usm_detect_info == NULL) {
+		 p_allocated_memory = kzalloc(detect_info_size, GFP_KERNEL);
+		if (p_allocated_memory == NULL) {
 			pr_err("%s: detect_info[%d] allocation failed\n",
 			       __func__, detect_info_size);
 			return -ENOMEM;
 		}
+		p_usm_detect_info = p_allocated_memory;
 		p_data = (uint8_t *)p_usm_detect_info +
 			sizeof(struct usm_session_cmd_detect_info);
 
@@ -789,7 +851,7 @@
 		if (rc) {
 			pr_err("%s: copy params from user; rc=%d\n",
 				__func__, rc);
-			kfree(p_usm_detect_info);
+			kfree(p_allocated_memory);
 			return -EFAULT;
 		}
 		p_usm_detect_info->algorithm_cfg_size =
@@ -806,9 +868,7 @@
 				    p_usm_detect_info,
 				    detect_info_size);
 	if (rc || (detect_info.detect_timeout == USF_NO_WAIT_TIMEOUT)) {
-		if (detect_info_size >
-		    sizeof(struct usm_session_cmd_detect_info))
-			kfree(p_usm_detect_info);
+		kfree(p_allocated_memory);
 		return rc;
 	}
 
@@ -828,25 +888,24 @@
 					 USF_US_DETECT_UNDEF),
 					timeout);
 	/* In the case of timeout, "no US" is assumed */
-	if (rc < 0) {
+	if (rc < 0)
 		pr_err("%s: Getting US detection failed rc[%d]\n",
 		       __func__, rc);
-		return rc;
+	else {
+		usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
+		detect_info.is_us =
+			(usf_xx->us_detect_type == USF_US_DETECT_YES);
+		rc = copy_to_user((void __user *)arg,
+				  &detect_info,
+				  sizeof(detect_info));
+		if (rc) {
+			pr_err("%s: copy detect_info to user; rc=%d\n",
+				__func__, rc);
+			rc = -EFAULT;
+		}
 	}
 
-	usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
-	detect_info.is_us = (usf_xx->us_detect_type == USF_US_DETECT_YES);
-	rc = copy_to_user((void __user *)arg,
-			  &detect_info,
-			  sizeof(detect_info));
-	if (rc) {
-		pr_err("%s: copy detect_info to user; rc=%d\n",
-			__func__, rc);
-		rc = -EFAULT;
-	}
-
-	if (detect_info_size > sizeof(struct usm_session_cmd_detect_info))
-		kfree(p_usm_detect_info);
+	kfree(p_allocated_memory);
 
 	return rc;
 } /* usf_set_us_detection */
@@ -947,16 +1006,14 @@
 	if (rc)
 		return rc;
 
-	if (usf_xx->buffer_size && usf_xx->buffer_count) {
-		rc = q6usm_us_client_buf_alloc(
-					IN,
-					usf_xx->usc,
-					usf_xx->buffer_size,
-					usf_xx->buffer_count);
-		if (rc) {
-			(void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
-			return rc;
-		}
+	rc = q6usm_us_client_buf_alloc(
+				IN,
+				usf_xx->usc,
+				usf_xx->buffer_size,
+				usf_xx->buffer_count);
+	if (rc) {
+		(void)q6usm_cmd(usf_xx->usc, CMD_CLOSE);
+		return rc;
 	}
 
 	rc = q6usm_dec_cfg_blk(usf_xx->usc,
@@ -1175,10 +1232,15 @@
 		return -EFAULT;
 	}
 
-	/* version_info.buf is pointer to place for the version string */
+	if (version_info.buf_size < sizeof(DRV_VERSION)) {
+		pr_err("%s: buf_size (%d) < version string size (%d)\n",
+			__func__, version_info.buf_size, sizeof(DRV_VERSION));
+		return -EINVAL;
+	}
+
 	rc = copy_to_user(version_info.pbuf,
 			  DRV_VERSION,
-			  version_info.buf_size);
+			  sizeof(DRV_VERSION));
 	if (rc) {
 		pr_err("%s: copy to version_info.pbuf; rc=%d\n",
 			__func__, rc);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index fe7c8c2..51a51c5 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -628,6 +628,12 @@
 	case FORMAT_USPROX:
 		int_format = US_PROX_FORMAT_V2;
 		break;
+	case FORMAT_USGES_SYNC:
+		int_format = US_GES_SYNC_FORMAT;
+		break;
+	case FORMAT_USRAW_SYNC:
+		int_format = US_RAW_SYNC_FORMAT;
+		break;
 	default:
 		pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
 		break;
diff --git a/arch/arm/mach-msm/rpm_stats.c b/arch/arm/mach-msm/rpm_stats.c
index cb8ed19..1447854 100644
--- a/arch/arm/mach-msm/rpm_stats.c
+++ b/arch/arm/mach-msm/rpm_stats.c
@@ -54,7 +54,7 @@
 	u32 num_records;
 	u32 read_idx;
 	u32 len;
-	char buf[256];
+	char buf[320];
 	struct msm_rpmstats_platform_data *platform_data;
 };
 
@@ -64,7 +64,8 @@
 	u64 last_entered_at;
 	u64 last_exited_at;
 	u64 accumulated;
-	u32 reserved[4];
+	u32 client_votes;
+	u32 reserved[3];
 };
 
 static inline u64 get_time_in_sec(u64 counter)
@@ -98,10 +99,12 @@
 	actual_last_sleep = get_time_in_msec(data->accumulated);
 
 	return  snprintf(buf , buflength,
-		"RPM Mode:%s\n\t count:%d\n time in last mode(msec):%llu\n"
-		"time since last mode(sec):%llu\n actual last sleep(msec):%llu\n",
+		"RPM Mode:%s\n\t count:%d\ntime in last mode(msec):%llu\n"
+		"time since last mode(sec):%llu\nactual last sleep(msec):%llu\n"
+		"client votes: %#010x\n\n",
 		stat_type, data->count, time_in_last_mode,
-		time_since_last_mode, actual_last_sleep);
+		time_since_last_mode, actual_last_sleep,
+		data->client_votes);
 }
 
 static inline u32 msm_rpmstats_read_long_register_v2(void __iomem *regbase,
@@ -147,6 +150,9 @@
 		data.accumulated = msm_rpmstats_read_quad_register_v2(reg,
 				i, offsetof(struct msm_rpm_stats_data_v2,
 					accumulated));
+		data.client_votes = msm_rpmstats_read_long_register_v2(reg,
+				i, offsetof(struct msm_rpm_stats_data_v2,
+					client_votes));
 		length += msm_rpmstats_append_data_to_buf(prvdata->buf + length,
 				&data, sizeof(prvdata->buf) - length);
 		prvdata->read_idx++;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 97b1f39..a5748fb 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -658,13 +658,6 @@
 	  applications DSP processor. Say M if you want to enable this
 	  module.
 
-config MMC_GENERIC_CSDIO
-	tristate "Generic sdio driver"
-	default n
-	help
-	  SDIO function driver that extends SDIO card as character device
-	  in user space.
-
 config CSDIO_VENDOR_ID
 	hex "Card VendorId"
 	depends on MMC_GENERIC_CSDIO
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 7589946..292cc99 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -65,7 +65,6 @@
 
 obj-$(CONFIG_TILE_SROM)		+= tile-srom.o
 obj-$(CONFIG_MSM_ROTATOR)	+= msm_rotator.o
-obj-$(CONFIG_MMC_GENERIC_CSDIO)	+= csdio.o
 obj-$(CONFIG_DIAG_CHAR)		+= diag/
 obj-$(CONFIG_MSM_ADSPRPC)       += adsprpc.o
 obj-$(CONFIG_MSM_RDBG)       += rdbg.o
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index b6fbb3c2..cc8cf47 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -125,16 +125,38 @@
 	return n;
 }
 
+struct fastrpc_buf {
+	struct ion_handle *handle;
+	void *virt;
+	ion_phys_addr_t phys;
+	int size;
+	int used;
+};
+
+struct smq_context_list;
+
 struct smq_invoke_ctx {
+	struct hlist_node hn;
 	struct completion work;
 	int retval;
-	atomic_t free;
+	int pid;
+	remote_arg_t *pra;
+	remote_arg_t *rpra;
+	struct fastrpc_buf obuf;
+	struct fastrpc_buf *abufs;
+	struct fastrpc_device *dev;
+	struct fastrpc_apps *apps;
+	int *fds;
+	struct ion_handle **handles;
+	int nbufs;
+	bool smmu;
+	uint32_t sc;
 };
 
 struct smq_context_list {
-	struct smq_invoke_ctx *ls;
-	int size;
-	int last;
+	struct hlist_head pending;
+	struct hlist_head interrupted;
+	spinlock_t hlock;
 };
 
 struct fastrpc_smmu {
@@ -165,22 +187,16 @@
 	struct hlist_node hn;
 	struct ion_handle *handle;
 	void *virt;
+	ion_phys_addr_t phys;
 	uint32_t vaddrin;
 	uint32_t vaddrout;
 	int size;
 };
 
-struct fastrpc_buf {
-	struct ion_handle *handle;
-	void *virt;
-	ion_phys_addr_t phys;
-	int size;
-	int used;
-};
-
 struct file_data {
 	spinlock_t hlock;
 	struct hlist_head hlst;
+	uint32_t mode;
 };
 
 struct fastrpc_device {
@@ -214,6 +230,11 @@
 {
 	struct fastrpc_apps *me = &gfa;
 	if (!IS_ERR_OR_NULL(map->handle)) {
+		if (me->smmu.enabled && map->phys) {
+			ion_unmap_iommu(me->iclient, map->handle,
+					me->smmu.domain_id, 0);
+			map->phys = 0;
+		}
 		if (!IS_ERR_OR_NULL(map->virt)) {
 			ion_unmap_kernel(me->iclient, map->handle);
 			map->virt = 0;
@@ -263,65 +284,186 @@
 	return err;
 }
 
-static int context_list_ctor(struct smq_context_list *me, int size)
+static int context_restore_interrupted(struct fastrpc_apps *me,
+				struct fastrpc_ioctl_invoke_fd *invokefd,
+				struct smq_invoke_ctx **po)
 {
 	int err = 0;
-	VERIFY(err, 0 != (me->ls = kzalloc(size, GFP_KERNEL)));
-	if (err)
-		goto bail;
-	me->size = size / sizeof(*me->ls);
-	me->last = 0;
- bail:
+	struct smq_invoke_ctx *ctx = 0, *ictx = 0;
+	struct hlist_node *pos, *n;
+	struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
+	spin_lock(&me->clst.hlock);
+	hlist_for_each_entry_safe(ictx, pos, n, &me->clst.interrupted, hn) {
+		if (ictx->pid == current->pid) {
+			if (invoke->sc != ictx->sc)
+				err = -1;
+			else {
+				ctx = ictx;
+				hlist_del(&ctx->hn);
+				hlist_add_head(&ctx->hn, &me->clst.pending);
+			}
+			break;
+		}
+	}
+	spin_unlock(&me->clst.hlock);
+	if (ctx)
+		*po = ctx;
 	return err;
 }
 
-static void context_list_dtor(struct smq_context_list *me)
+static int context_alloc(struct fastrpc_apps *me, uint32_t kernel,
+				struct fastrpc_ioctl_invoke_fd *invokefd,
+				struct smq_invoke_ctx **po)
 {
-	kfree(me->ls);
-}
+	int err = 0, bufs, size = 0;
+	struct smq_invoke_ctx *ctx = 0;
+	struct smq_context_list *clst = &me->clst;
+	struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
 
-static void context_list_alloc_ctx(struct smq_context_list *me,
-					struct smq_invoke_ctx **po)
-{
-	int i = me->last;
-	struct smq_invoke_ctx *ctx;
-
-	for (;;) {
-		i = i % me->size;
-		ctx = &me->ls[i];
-		if (atomic_read(&ctx->free) == 0)
-			if (atomic_cmpxchg(&ctx->free, 0, 1) == 0)
-				break;
-		i++;
+	bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
+			REMOTE_SCALARS_OUTBUFS(invoke->sc);
+	if (bufs) {
+		size = bufs * sizeof(*ctx->pra);
+		if (invokefd->fds)
+			size = size + bufs * sizeof(*ctx->fds) +
+				bufs * sizeof(*ctx->handles);
 	}
-	me->last = i;
+
+	VERIFY(err, 0 != (ctx = kzalloc(sizeof(*ctx) + size, GFP_KERNEL)));
+	if (err)
+		goto bail;
+
+	INIT_HLIST_NODE(&ctx->hn);
+	ctx->pra = (remote_arg_t *)(&ctx[1]);
+	ctx->fds = invokefd->fds == 0 ? 0 : (int *)(&ctx->pra[bufs]);
+	ctx->handles = invokefd->fds == 0 ? 0 :
+					(struct ion_handle **)(&ctx->fds[bufs]);
+	if (!kernel) {
+		VERIFY(err, 0 == copy_from_user(ctx->pra, invoke->pra,
+					bufs * sizeof(*ctx->pra)));
+		if (err)
+			goto bail;
+	} else {
+		memmove(ctx->pra, invoke->pra, bufs * sizeof(*ctx->pra));
+	}
+
+	if (invokefd->fds) {
+		if (!kernel) {
+			VERIFY(err, 0 == copy_from_user(ctx->fds, invokefd->fds,
+						bufs * sizeof(*ctx->fds)));
+			if (err)
+				goto bail;
+		} else {
+			memmove(ctx->fds, invokefd->fds,
+						bufs * sizeof(*ctx->fds));
+		}
+	}
+	ctx->sc = invoke->sc;
 	ctx->retval = -1;
+	ctx->pid = current->pid;
+	ctx->apps = me;
 	init_completion(&ctx->work);
+	spin_lock(&clst->hlock);
+	hlist_add_head(&ctx->hn, &clst->pending);
+	spin_unlock(&clst->hlock);
+
 	*po = ctx;
+bail:
+	if (ctx && err)
+		kfree(ctx);
+	return err;
 }
 
-static void context_free(struct smq_invoke_ctx *me)
+static void context_save_interrupted(struct smq_invoke_ctx *ctx)
 {
-	if (me)
-		atomic_set(&me->free, 0);
+	struct smq_context_list *clst = &ctx->apps->clst;
+	spin_lock(&clst->hlock);
+	hlist_del(&ctx->hn);
+	hlist_add_head(&ctx->hn, &clst->interrupted);
+	spin_unlock(&clst->hlock);
 }
 
-static void context_notify_user(struct smq_invoke_ctx *me, int retval)
+static void add_dev(struct fastrpc_apps *me, struct fastrpc_device *dev);
+
+static void context_free(struct smq_invoke_ctx *ctx, bool lock)
 {
-	me->retval = retval;
-	complete(&me->work);
+	struct smq_context_list *clst = &ctx->apps->clst;
+	struct fastrpc_apps *apps = ctx->apps;
+	struct ion_client *clnt = apps->iclient;
+	struct fastrpc_smmu *smmu = &apps->smmu;
+	struct fastrpc_buf *b;
+	int i, bufs;
+	if (ctx->smmu) {
+		bufs = REMOTE_SCALARS_INBUFS(ctx->sc) +
+			REMOTE_SCALARS_OUTBUFS(ctx->sc);
+		if (ctx->fds) {
+			for (i = 0; i < bufs; i++)
+				if (!IS_ERR_OR_NULL(ctx->handles[i])) {
+					ion_unmap_iommu(clnt, ctx->handles[i],
+						smmu->domain_id, 0);
+					ion_free(clnt, ctx->handles[i]);
+				}
+		}
+		iommu_detach_group(smmu->domain, smmu->group);
+	}
+	for (i = 0, b = ctx->abufs; i < ctx->nbufs; ++i, ++b)
+		free_mem(b);
+
+	kfree(ctx->abufs);
+	if (ctx->dev) {
+		add_dev(apps, ctx->dev);
+		if (ctx->obuf.handle != ctx->dev->buf.handle)
+			free_mem(&ctx->obuf);
+	}
+	if (lock)
+		spin_lock(&clst->hlock);
+	hlist_del(&ctx->hn);
+	if (lock)
+		spin_unlock(&clst->hlock);
+	kfree(ctx);
+}
+
+static void context_notify_user(struct smq_invoke_ctx *ctx, int retval)
+{
+	ctx->retval = retval;
+	complete(&ctx->work);
 }
 
 static void context_notify_all_users(struct smq_context_list *me)
 {
-	int i;
-
-	if (!me->ls)
-		return;
-	for (i = 0; i < me->size; ++i) {
-		if (atomic_read(&me->ls[i].free) != 0)
-			complete(&me->ls[i].work);
+	struct smq_invoke_ctx *ictx = 0;
+	struct hlist_node *pos, *n;
+	spin_lock(&me->hlock);
+	hlist_for_each_entry_safe(ictx, pos, n, &me->pending, hn) {
+		complete(&ictx->work);
 	}
+	hlist_for_each_entry_safe(ictx, pos, n, &me->interrupted, hn) {
+		complete(&ictx->work);
+	}
+	spin_unlock(&me->hlock);
+
+}
+
+static void context_list_ctor(struct smq_context_list *me)
+{
+	INIT_HLIST_HEAD(&me->interrupted);
+	INIT_HLIST_HEAD(&me->pending);
+	spin_lock_init(&me->hlock);
+}
+
+static void context_list_dtor(struct fastrpc_apps *me,
+				struct smq_context_list *clst)
+{
+	struct smq_invoke_ctx *ictx = 0;
+	struct hlist_node *pos, *n;
+	spin_lock(&clst->hlock);
+	hlist_for_each_entry_safe(ictx, pos, n, &clst->interrupted, hn) {
+		context_free(ictx, 0);
+	}
+	hlist_for_each_entry_safe(ictx, pos, n, &clst->pending, hn) {
+		context_free(ictx, 0);
+	}
+	spin_unlock(&clst->hlock);
 }
 
 static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
@@ -400,13 +542,12 @@
 static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
 			remote_arg_t *rpra, remote_arg_t *upra,
 			struct fastrpc_buf *ibuf, struct fastrpc_buf **abufs,
-			int *nbufs, int *fds)
+			int *nbufs, int *fds, struct ion_handle **handles)
 {
 	struct fastrpc_apps *me = &gfa;
 	struct smq_invoke_buf *list;
 	struct fastrpc_buf *pbuf = ibuf, *obufs = 0;
 	struct smq_phy_page *pages;
-	struct ion_handle **handles = NULL;
 	void *args;
 	int i, rlen, size, used, inh, bufs = 0, err = 0;
 	int inbufs = REMOTE_SCALARS_INBUFS(sc);
@@ -418,8 +559,6 @@
 	used = ALIGN(pbuf->used, BALIGN);
 	args = (void *)((char *)pbuf->virt + used);
 	rlen = pbuf->size - used;
-	if (fds)
-		handles = (struct ion_handle **)(fds + inbufs + outbufs);
 	for (i = 0; i < inbufs + outbufs; ++i) {
 
 		rpra[i].buf.len = pra[i].buf.len;
@@ -614,7 +753,6 @@
 	struct fastrpc_apps *me = &gfa;
 
 	smd_close(me->chan);
-	context_list_dtor(&me->clst);
 	ion_client_destroy(me->iclient);
 	me->iclient = 0;
 	me->chan = 0;
@@ -667,16 +805,14 @@
 		spin_lock_init(&me->wrlock);
 		init_completion(&me->work);
 		mutex_init(&me->smd_mutex);
+		context_list_ctor(&me->clst);
 		for (i = 0; i < RPC_HASH_SZ; ++i)
 			INIT_HLIST_HEAD(&me->htbl[i]);
-		VERIFY(err, 0 == context_list_ctor(&me->clst, SZ_4K));
-		if (err)
-			goto context_list_bail;
 		me->iclient = msm_ion_client_create(ION_HEAP_CARVEOUT_MASK,
 							DEVICE_NAME);
 		VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
 		if (err)
-			goto ion_bail;
+			goto bail;
 		node = of_find_compatible_node(NULL, NULL,
 						"qcom,msm-audio-ion");
 		if (node)
@@ -697,9 +833,7 @@
 
 	return 0;
 
-ion_bail:
-	context_list_dtor(&me->clst);
-context_list_bail:
+bail:
 	return err;
 }
 
@@ -783,96 +917,88 @@
 
 static int fastrpc_release_current_dsp_process(void);
 
-static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t kernel,
-			struct fastrpc_ioctl_invoke *invoke, remote_arg_t *pra,
-			int *fds)
+static int fastrpc_internal_invoke(struct fastrpc_apps *me, uint32_t mode,
+			uint32_t kernel,
+			struct fastrpc_ioctl_invoke_fd *invokefd)
 {
-	remote_arg_t *rpra = 0;
-	struct fastrpc_device *dev = 0;
 	struct smq_invoke_ctx *ctx = 0;
-	struct fastrpc_buf obuf, *abufs = 0, *b;
-	struct ion_handle **handles = NULL;
+	struct fastrpc_ioctl_invoke *invoke = &invokefd->inv;
 	int interrupted = 0;
-	uint32_t sc;
-	int i, bufs, nbufs = 0, err = 0;
+	int err = 0;
 
-	sc = invoke->sc;
-	obuf.handle = 0;
+	if (!kernel) {
+		VERIFY(err, 0 == context_restore_interrupted(me, invokefd,
+								&ctx));
+		if (err)
+			goto bail;
+		if (ctx)
+			goto wait;
+	}
+
+	VERIFY(err, 0 == context_alloc(me, kernel, invokefd, &ctx));
+	if (err)
+		goto bail;
+
 	if (me->smmu.enabled) {
 		VERIFY(err, 0 == iommu_attach_group(me->smmu.domain,
 							me->smmu.group));
 		if (err)
-			return err;
+			goto bail;
+		ctx->smmu = 1;
 	}
-	if (REMOTE_SCALARS_LENGTH(sc)) {
-		VERIFY(err, 0 == get_dev(me, &dev));
+	if (REMOTE_SCALARS_LENGTH(ctx->sc)) {
+		VERIFY(err, 0 == get_dev(me, &ctx->dev));
 		if (err)
 			goto bail;
-		VERIFY(err, 0 == get_page_list(kernel, sc, pra, &dev->buf,
-						&obuf));
+		VERIFY(err, 0 == get_page_list(kernel, ctx->sc, ctx->pra,
+					&ctx->dev->buf, &ctx->obuf));
 		if (err)
 			goto bail;
-		rpra = (remote_arg_t *)obuf.virt;
-		VERIFY(err, 0 == get_args(kernel, sc, pra, rpra, invoke->pra,
-					&obuf, &abufs, &nbufs, fds));
+		ctx->rpra = (remote_arg_t *)ctx->obuf.virt;
+		VERIFY(err, 0 == get_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
+				invoke->pra, &ctx->obuf, &ctx->abufs,
+				&ctx->nbufs, ctx->fds, ctx->handles));
 		if (err)
 			goto bail;
 	}
 
-	context_list_alloc_ctx(&me->clst, &ctx);
-	inv_args_pre(sc, rpra);
-	VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle, sc,
-						ctx, &obuf));
+	inv_args_pre(ctx->sc, ctx->rpra);
+	if (FASTRPC_MODE_SERIAL == mode)
+		inv_args(ctx->sc, ctx->rpra, ctx->obuf.used);
+	VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle,
+						ctx->sc, ctx, &ctx->obuf));
 	if (err)
 		goto bail;
-	inv_args(sc, rpra, obuf.used);
-	VERIFY(err, 0 == (interrupted =
-			wait_for_completion_interruptible(&ctx->work)));
-	if (err)
-		goto bail;
+	if (FASTRPC_MODE_PARALLEL == mode)
+		inv_args(ctx->sc, ctx->rpra, ctx->obuf.used);
+ wait:
+	if (kernel)
+		wait_for_completion(&ctx->work);
+	else {
+		interrupted = wait_for_completion_interruptible(&ctx->work);
+		VERIFY(err, 0 == (err = interrupted));
+		if (err)
+			goto bail;
+	}
 	VERIFY(err, 0 == (err = ctx->retval));
 	if (err)
 		goto bail;
-	VERIFY(err, 0 == put_args(kernel, sc, pra, rpra, invoke->pra));
+	VERIFY(err, 0 == put_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
+					invoke->pra));
 	if (err)
 		goto bail;
  bail:
-	if (interrupted) {
-		if (!kernel)
-			(void)fastrpc_release_current_dsp_process();
-		wait_for_completion(&ctx->work);
-	}
-	context_free(ctx);
-
-	if (me->smmu.enabled) {
-		bufs = REMOTE_SCALARS_INBUFS(sc) + REMOTE_SCALARS_OUTBUFS(sc);
-		if (fds) {
-			handles = (struct ion_handle **)(fds + bufs);
-			for (i = 0; i < bufs; i++)
-				if (!IS_ERR_OR_NULL(handles[i])) {
-					ion_unmap_iommu(me->iclient, handles[i],
-							me->smmu.domain_id, 0);
-					ion_free(me->iclient, handles[i]);
-				}
-		}
-		iommu_detach_group(me->smmu.domain, me->smmu.group);
-	}
-	for (i = 0, b = abufs; i < nbufs; ++i, ++b)
-		free_mem(b);
-
-	kfree(abufs);
-	if (dev) {
-		add_dev(me, dev);
-		if (obuf.handle != dev->buf.handle)
-			free_mem(&obuf);
-	}
+	if (ctx && interrupted == -ERESTARTSYS)
+		context_save_interrupted(ctx);
+	else if (ctx)
+		context_free(ctx, 1);
 	return err;
 }
 
 static int fastrpc_create_current_dsp_process(void)
 {
 	int err = 0;
-	struct fastrpc_ioctl_invoke ioctl;
+	struct fastrpc_ioctl_invoke_fd ioctl;
 	struct fastrpc_apps *me = &gfa;
 	remote_arg_t ra[1];
 	int tgid = 0;
@@ -880,10 +1006,12 @@
 	tgid = current->tgid;
 	ra[0].buf.pv = &tgid;
 	ra[0].buf.len = sizeof(tgid);
-	ioctl.handle = 1;
-	ioctl.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
-	ioctl.pra = ra;
-	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+	ioctl.inv.handle = 1;
+	ioctl.inv.sc = REMOTE_SCALARS_MAKE(0, 1, 0);
+	ioctl.inv.pra = ra;
+	ioctl.fds = 0;
+	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+		FASTRPC_MODE_PARALLEL, 1, &ioctl)));
 	return err;
 }
 
@@ -891,17 +1019,19 @@
 {
 	int err = 0;
 	struct fastrpc_apps *me = &gfa;
-	struct fastrpc_ioctl_invoke ioctl;
+	struct fastrpc_ioctl_invoke_fd ioctl;
 	remote_arg_t ra[1];
 	int tgid = 0;
 
 	tgid = current->tgid;
 	ra[0].buf.pv = &tgid;
 	ra[0].buf.len = sizeof(tgid);
-	ioctl.handle = 1;
-	ioctl.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
-	ioctl.pra = ra;
-	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+	ioctl.inv.handle = 1;
+	ioctl.inv.sc = REMOTE_SCALARS_MAKE(1, 1, 0);
+	ioctl.inv.pra = ra;
+	ioctl.fds = 0;
+	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+		FASTRPC_MODE_PARALLEL, 1, &ioctl)));
 	return err;
 }
 
@@ -910,7 +1040,7 @@
 					 struct smq_phy_page *pages,
 					 int num)
 {
-	struct fastrpc_ioctl_invoke ioctl;
+	struct fastrpc_ioctl_invoke_fd ioctl;
 	remote_arg_t ra[3];
 	int err = 0;
 	struct {
@@ -936,10 +1066,12 @@
 	ra[2].buf.pv = &routargs;
 	ra[2].buf.len = sizeof(routargs);
 
-	ioctl.handle = 1;
-	ioctl.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
-	ioctl.pra = ra;
-	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+	ioctl.inv.handle = 1;
+	ioctl.inv.sc = REMOTE_SCALARS_MAKE(2, 2, 1);
+	ioctl.inv.pra = ra;
+	ioctl.fds = 0;
+	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+		FASTRPC_MODE_PARALLEL, 1, &ioctl)));
 	mmap->vaddrout = routargs.vaddrout;
 	if (err)
 		goto bail;
@@ -950,7 +1082,7 @@
 static int fastrpc_munmap_on_dsp(struct fastrpc_apps *me,
 				 struct fastrpc_ioctl_munmap *munmap)
 {
-	struct fastrpc_ioctl_invoke ioctl;
+	struct fastrpc_ioctl_invoke_fd ioctl;
 	remote_arg_t ra[1];
 	int err = 0;
 	struct {
@@ -965,10 +1097,12 @@
 	ra[0].buf.pv = &inargs;
 	ra[0].buf.len = sizeof(inargs);
 
-	ioctl.handle = 1;
-	ioctl.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
-	ioctl.pra = ra;
-	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 1, &ioctl, ra, 0)));
+	ioctl.inv.handle = 1;
+	ioctl.inv.sc = REMOTE_SCALARS_MAKE(3, 1, 0);
+	ioctl.inv.pra = ra;
+	ioctl.fds = 0;
+	VERIFY(err, 0 == (err = fastrpc_internal_invoke(me,
+		FASTRPC_MODE_PARALLEL, 1, &ioctl)));
 	return err;
 }
 
@@ -1010,7 +1144,7 @@
 	struct fastrpc_mmap *map = 0;
 	struct smq_phy_page *pages = 0;
 	void *buf;
-	int len;
+	unsigned long len;
 	int num;
 	int err = 0;
 
@@ -1031,9 +1165,22 @@
 	VERIFY(err, 0 != (pages = kzalloc(num * sizeof(*pages), GFP_KERNEL)));
 	if (err)
 		goto bail;
-	VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1, pages, num)));
-	if (err)
-		goto bail;
+
+	if (me->smmu.enabled) {
+		VERIFY(err, 0 == ion_map_iommu(clnt, map->handle,
+				me->smmu.domain_id, 0,
+				SZ_4K, 0, &map->phys, &len, 0, 0));
+		if (err)
+			goto bail;
+		pages->addr = map->phys;
+		pages->size = len;
+		num = 1;
+	} else {
+		VERIFY(err, 0 < (num = buf_get_pages(buf, len, num, 1,
+							pages, num)));
+		if (err)
+			goto bail;
+	}
 
 	VERIFY(err, 0 == fastrpc_mmap_on_dsp(me, mmap, pages, num));
 	if (err)
@@ -1100,7 +1247,7 @@
 	(void)fastrpc_release_current_dsp_process();
 	cleanup_current_dev();
 	if (fdata) {
-		struct fastrpc_mmap *map;
+		struct fastrpc_mmap *map = 0;
 		struct hlist_node *n, *pos;
 		file->private_data = 0;
 		hlist_for_each_entry_safe(map, pos, n, &fdata->hlst, hn) {
@@ -1179,48 +1326,23 @@
 {
 	struct fastrpc_apps *me = &gfa;
 	struct fastrpc_ioctl_invoke_fd invokefd;
-	struct fastrpc_ioctl_invoke *invoke = &invokefd.inv;
 	struct fastrpc_ioctl_mmap mmap;
 	struct fastrpc_ioctl_munmap munmap;
-	remote_arg_t *pra = 0;
 	void *param = (char *)ioctl_param;
 	struct file_data *fdata = (struct file_data *)file->private_data;
-	int *fds = 0;
-	int bufs, size = 0, err = 0;
+	int size = 0, err = 0;
 
 	switch (ioctl_num) {
 	case FASTRPC_IOCTL_INVOKE_FD:
 	case FASTRPC_IOCTL_INVOKE:
 		invokefd.fds = 0;
 		size = (ioctl_num == FASTRPC_IOCTL_INVOKE) ?
-				sizeof(*invoke) : sizeof(invokefd);
+				sizeof(invokefd.inv) : sizeof(invokefd);
 		VERIFY(err, 0 == copy_from_user(&invokefd, param, size));
 		if (err)
 			goto bail;
-		bufs = REMOTE_SCALARS_INBUFS(invoke->sc) +
-			REMOTE_SCALARS_OUTBUFS(invoke->sc);
-		if (bufs) {
-			size = bufs * sizeof(*pra);
-			if (invokefd.fds)
-				size = size + bufs * sizeof(*fds) +
-					bufs * sizeof(struct ion_handle *);
-			VERIFY(err, 0 != (pra = kzalloc(size, GFP_KERNEL)));
-			if (err)
-				goto bail;
-		}
-		VERIFY(err, 0 == copy_from_user(pra, invoke->pra,
-						bufs * sizeof(*pra)));
-		if (err)
-			goto bail;
-		if (invokefd.fds) {
-			fds = (int *)(pra + bufs);
-			VERIFY(err, 0 == copy_from_user(fds, invokefd.fds,
-							bufs * sizeof(*fds)));
-		if (err)
-			goto bail;
-		}
-		VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, 0, invoke,
-								pra, fds)));
+		VERIFY(err, 0 == (err = fastrpc_internal_invoke(me, fdata->mode,
+						0, &invokefd)));
 		if (err)
 			goto bail;
 		break;
@@ -1247,12 +1369,22 @@
 		if (err)
 			goto bail;
 		break;
+	case FASTRPC_IOCTL_SETMODE:
+		switch ((uint32_t)ioctl_param) {
+		case FASTRPC_MODE_PARALLEL:
+		case FASTRPC_MODE_SERIAL:
+			fdata->mode = (uint32_t)ioctl_param;
+			break;
+		default:
+			err = -ENOTTY;
+			break;
+		}
+		break;
 	default:
 		err = -ENOTTY;
 		break;
 	}
  bail:
-	kfree(pra);
 	return err;
 }
 
@@ -1307,7 +1439,9 @@
 {
 	struct fastrpc_apps *me = &gfa;
 
+	context_list_dtor(me, &me->clst);
 	fastrpc_deinit();
+	cleanup_current_dev();
 	device_destroy(me->class, MKDEV(MAJOR(me->dev_no), 0));
 	class_destroy(me->class);
 	cdev_del(&me->cdev);
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index da70eb5..f5d7450 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -20,9 +20,16 @@
 #define FASTRPC_IOCTL_MMAP    _IOWR('R', 2, struct fastrpc_ioctl_mmap)
 #define FASTRPC_IOCTL_MUNMAP  _IOWR('R', 3, struct fastrpc_ioctl_munmap)
 #define FASTRPC_IOCTL_INVOKE_FD  _IOWR('R', 4, struct fastrpc_ioctl_invoke_fd)
+#define FASTRPC_IOCTL_SETMODE    _IOWR('R', 5, uint32_t)
 #define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
 #define DEVICE_NAME      "adsprpc-smd"
 
+/* Driver should operate in parallel with the co-processor */
+#define FASTRPC_MODE_PARALLEL    0
+
+/* Driver should operate in serial mode with the co-processor */
+#define FASTRPC_MODE_SERIAL      1
+
 /* Retrives number of input buffers from the scalars parameter */
 #define REMOTE_SCALARS_INBUFS(sc)        (((sc) >> 16) & 0x0ff)
 
diff --git a/drivers/char/csdio.c b/drivers/char/csdio.c
deleted file mode 100644
index 85306d3..0000000
--- a/drivers/char/csdio.c
+++ /dev/null
@@ -1,1074 +0,0 @@
-/*
- * Copyright (c) 2010, 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/moduleparam.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/gfp.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-
-/* Char device */
-#include <linux/cdev.h>
-#include <linux/fs.h>
-
-/* Sdio device */
-#include <linux/mmc/core.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-
-#include <linux/csdio.h>
-
-#define FALSE   0
-#define TRUE    1
-
-#define VERSION                     "0.5"
-#define CSDIO_NUM_OF_SDIO_FUNCTIONS 7
-#define CSDIO_DEV_NAME              "csdio"
-#define TP_DEV_NAME                 CSDIO_DEV_NAME"f"
-#define CSDIO_DEV_PERMISSIONS       0666
-
-#define CSDIO_SDIO_BUFFER_SIZE      (64*512)
-
-int csdio_major;
-int csdio_minor;
-int csdio_transport_nr_devs = CSDIO_NUM_OF_SDIO_FUNCTIONS;
-static uint csdio_vendor_id;
-static uint csdio_device_id;
-static char *host_name;
-
-static struct csdio_func_t {
-	struct sdio_func   *m_func;
-	int                 m_enabled;
-	struct cdev         m_cdev;      /* char device structure */
-	struct device      *m_device;
-	u32                 m_block_size;
-} *g_csdio_func_table[CSDIO_NUM_OF_SDIO_FUNCTIONS] = {0};
-
-struct csdio_t {
-	struct cdev             m_cdev;
-	struct device          *m_device;
-	struct class           *m_driver_class;
-	struct fasync_struct   *m_async_queue;
-	unsigned char           m_current_irq_mask; /* currently enabled irqs */
-	struct mmc_host        *m_host;
-	unsigned int            m_num_of_func;
-} g_csdio;
-
-struct csdio_file_descriptor {
-	struct csdio_func_t    *m_port;
-	u32                     m_block_mode;/* data tran. byte(0)/block(1) */
-	u32                     m_op_code;   /* address auto increment flag */
-	u32                     m_address;
-};
-
-static void *g_sdio_buffer;
-
-/*
- * Open and release
- */
-static int csdio_transport_open(struct inode *inode, struct file *filp)
-{
-	int ret = 0;
-	struct csdio_func_t *port = NULL; /*  device information */
-	struct sdio_func *func = NULL;
-	struct csdio_file_descriptor *descriptor = NULL;
-
-	port = container_of(inode->i_cdev, struct csdio_func_t, m_cdev);
-	func = port->m_func;
-	descriptor = kzalloc(sizeof(struct csdio_file_descriptor), GFP_KERNEL);
-	if (!descriptor) {
-		ret = -ENOMEM;
-		goto exit;
-	}
-
-	pr_info(TP_DEV_NAME"%d: open: func=%p, port=%p\n",
-			func->num, func, port);
-	sdio_claim_host(func);
-	ret = sdio_enable_func(func);
-	if (ret) {
-		pr_err(TP_DEV_NAME"%d:Enable func failed (%d)\n",
-				func->num, ret);
-		ret = -EIO;
-		goto free_descriptor;
-	}
-	descriptor->m_port = port;
-	filp->private_data = descriptor;
-	goto release_host;
-
-free_descriptor:
-	kfree(descriptor);
-release_host:
-	sdio_release_host(func);
-exit:
-	return ret;
-}
-
-static int csdio_transport_release(struct inode *inode, struct file *filp)
-{
-	int ret = 0;
-	struct csdio_file_descriptor *descriptor = filp->private_data;
-	struct csdio_func_t *port = descriptor->m_port;
-	struct sdio_func *func = port->m_func;
-
-	pr_info(TP_DEV_NAME"%d: release\n", func->num);
-	sdio_claim_host(func);
-	ret = sdio_disable_func(func);
-	if (ret) {
-		pr_err(TP_DEV_NAME"%d:Disable func failed(%d)\n",
-				func->num, ret);
-		ret = -EIO;
-	}
-	sdio_release_host(func);
-	kfree(descriptor);
-	return ret;
-}
-
-/*
- * Data management: read and write
- */
-static ssize_t csdio_transport_read(struct file *filp,
-		char __user *buf,
-		size_t count,
-		loff_t *f_pos)
-{
-	ssize_t ret = 0;
-	struct csdio_file_descriptor *descriptor = filp->private_data;
-	struct csdio_func_t *port = descriptor->m_port;
-	struct sdio_func *func = port->m_func;
-	size_t t_count = count;
-
-	if (descriptor->m_block_mode) {
-		pr_info(TP_DEV_NAME "%d: CMD53 read, Md:%d, Addr:0x%04X,"
-				" Un:%d (Bl:%d, BlSz:%d)\n", func->num,
-				descriptor->m_block_mode,
-				descriptor->m_address,
-				count*port->m_block_size,
-				count, port->m_block_size);
-		/* recalculate size */
-		count *= port->m_block_size;
-	}
-	sdio_claim_host(func);
-	if (descriptor->m_op_code) {
-		/* auto increment */
-		ret = sdio_memcpy_fromio(func, g_sdio_buffer,
-				descriptor->m_address, count);
-	} else { /* FIFO */
-		ret = sdio_readsb(func, g_sdio_buffer,
-				descriptor->m_address, count);
-	}
-	sdio_release_host(func);
-	if (!ret) {
-		if (copy_to_user(buf, g_sdio_buffer, count))
-			ret = -EFAULT;
-		else
-			ret = t_count;
-	}
-	if (ret < 0) {
-		pr_err(TP_DEV_NAME "%d: CMD53 read failed (%d)"
-				"(Md:%d, Addr:0x%04X, Sz:%d)\n",
-				func->num, ret,
-				descriptor->m_block_mode,
-				descriptor->m_address, count);
-	}
-	return ret;
-}
-
-static ssize_t csdio_transport_write(struct file *filp,
-		const char __user *buf,
-		size_t count,
-		loff_t *f_pos)
-{
-	ssize_t ret = 0;
-	struct csdio_file_descriptor *descriptor = filp->private_data;
-	struct csdio_func_t *port = descriptor->m_port;
-	struct sdio_func *func = port->m_func;
-	size_t t_count = count;
-
-	if (descriptor->m_block_mode)
-		count *= port->m_block_size;
-
-	if (copy_from_user(g_sdio_buffer, buf, count)) {
-		pr_err(TP_DEV_NAME"%d:copy_from_user failed\n", func->num);
-		ret = -EFAULT;
-	} else {
-		sdio_claim_host(func);
-		if (descriptor->m_op_code) {
-			/* auto increment */
-			ret = sdio_memcpy_toio(func, descriptor->m_address,
-					g_sdio_buffer, count);
-		} else {
-			/* FIFO */
-			ret = sdio_writesb(func, descriptor->m_address,
-					g_sdio_buffer, count);
-		}
-		sdio_release_host(func);
-		if (!ret) {
-			ret = t_count;
-		} else {
-			pr_err(TP_DEV_NAME "%d: CMD53 write failed (%d)"
-				"(Md:%d, Addr:0x%04X, Sz:%d)\n",
-				func->num, ret, descriptor->m_block_mode,
-				descriptor->m_address, count);
-		}
-	}
-	return ret;
-}
-
-/* disable interrupt for sdio client */
-static int disable_sdio_client_isr(struct sdio_func *func)
-{
-	int ret;
-
-	/* disable for all functions, to restore interrupts
-	 * use g_csdio.m_current_irq_mask */
-	sdio_f0_writeb(func, 0, SDIO_CCCR_IENx, &ret);
-	if (ret)
-		pr_err(CSDIO_DEV_NAME" Can't sdio_f0_writeb (%d)\n", ret);
-
-	return ret;
-}
-
-/*
- * This handles the interrupt from SDIO.
- */
-static void csdio_sdio_irq(struct sdio_func *func)
-{
-	int ret;
-
-	pr_info(CSDIO_DEV_NAME" csdio_sdio_irq: func=%d\n", func->num);
-	ret = disable_sdio_client_isr(func);
-	if (ret) {
-		pr_err(CSDIO_DEV_NAME" Can't disable client isr(%d)\n", ret);
-		return;
-	}
-	/*  signal asynchronous readers */
-	if (g_csdio.m_async_queue)
-		kill_fasync(&g_csdio.m_async_queue, SIGIO, POLL_IN);
-}
-
-/*
- * The ioctl() implementation
- */
-static int csdio_transport_ioctl(struct inode *inode,
-		struct file *filp,
-		unsigned int cmd,
-		unsigned long arg)
-{
-	int err = 0;
-	int ret = 0;
-	struct csdio_file_descriptor *descriptor = filp->private_data;
-	struct csdio_func_t *port = descriptor->m_port;
-	struct sdio_func *func = port->m_func;
-
-	/*  extract the type and number bitfields
-	    sanity check: return ENOTTY (inappropriate ioctl) before
-	    access_ok()
-	*/
-	if ((_IOC_TYPE(cmd) != CSDIO_IOC_MAGIC) ||
-			(_IOC_NR(cmd) > CSDIO_IOC_MAXNR)) {
-		pr_err(TP_DEV_NAME "Wrong ioctl command parameters\n");
-		ret = -ENOTTY;
-		goto exit;
-	}
-
-	/*  the direction is a bitmask, and VERIFY_WRITE catches R/W
-	 *  transfers. `Type' is user-oriented, while access_ok is
-	    kernel-oriented, so the concept of "read" and "write" is reversed
-	*/
-	if (_IOC_DIR(cmd) & _IOC_READ) {
-		err = !access_ok(VERIFY_WRITE, (void __user *)arg,
-				_IOC_SIZE(cmd));
-	} else {
-		if (_IOC_DIR(cmd) & _IOC_WRITE) {
-			err =  !access_ok(VERIFY_READ, (void __user *)arg,
-					_IOC_SIZE(cmd));
-		}
-	}
-	if (err) {
-		pr_err(TP_DEV_NAME "Wrong ioctl access direction\n");
-		ret = -EFAULT;
-		goto exit;
-	}
-
-	switch (cmd) {
-	case CSDIO_IOC_SET_OP_CODE:
-		{
-			pr_info(TP_DEV_NAME"%d:SET_OP_CODE=%d\n",
-					func->num, descriptor->m_op_code);
-			ret = get_user(descriptor->m_op_code,
-					(unsigned char __user *)arg);
-			if (ret) {
-				pr_err(TP_DEV_NAME"%d:SET_OP_CODE get data"
-						" from user space failed(%d)\n",
-						func->num, ret);
-				ret = -ENOTTY;
-				break;
-			}
-		}
-		break;
-	case CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE:
-		{
-			unsigned block_size;
-
-			ret = get_user(block_size, (unsigned __user *)arg);
-			if (ret) {
-				pr_err(TP_DEV_NAME"%d:SET_BLOCK_SIZE get data"
-						" from user space failed(%d)\n",
-						func->num, ret);
-				ret = -ENOTTY;
-				break;
-			}
-			pr_info(TP_DEV_NAME"%d:SET_BLOCK_SIZE=%d\n",
-					func->num, block_size);
-			sdio_claim_host(func);
-			ret = sdio_set_block_size(func, block_size);
-			if (!ret) {
-				port->m_block_size = block_size;
-			} else {
-				pr_err(TP_DEV_NAME"%d:SET_BLOCK_SIZE set block"
-						" size to %d failed (%d)\n",
-						func->num, block_size, ret);
-				ret = -ENOTTY;
-				break;
-			}
-			sdio_release_host(func);
-		}
-		break;
-	case CSDIO_IOC_SET_BLOCK_MODE:
-		{
-			pr_info(TP_DEV_NAME"%d:SET_BLOCK_MODE=%d\n",
-					func->num, descriptor->m_block_mode);
-			ret = get_user(descriptor->m_block_mode,
-					(unsigned char __user *)arg);
-			if (ret) {
-				pr_err(TP_DEV_NAME"%d:SET_BLOCK_MODE get data"
-						" from user space failed\n",
-						func->num);
-				ret = -ENOTTY;
-				break;
-			}
-		}
-		break;
-	case CSDIO_IOC_CMD52:
-		{
-			struct csdio_cmd52_ctrl_t cmd52ctrl;
-			int cmd52ret;
-
-			if (copy_from_user(&cmd52ctrl,
-					(const unsigned char __user *)arg,
-					sizeof(cmd52ctrl))) {
-				pr_err(TP_DEV_NAME"%d:IOC_CMD52 get data"
-						" from user space failed\n",
-						func->num);
-				ret = -ENOTTY;
-				break;
-			}
-			sdio_claim_host(func);
-			if (cmd52ctrl.m_write)
-				sdio_writeb(func, cmd52ctrl.m_data,
-						cmd52ctrl.m_address, &cmd52ret);
-			else
-				cmd52ctrl.m_data = sdio_readb(func,
-						cmd52ctrl.m_address, &cmd52ret);
-
-			cmd52ctrl.m_ret = cmd52ret;
-			sdio_release_host(func);
-			if (cmd52ctrl.m_ret)
-				pr_err(TP_DEV_NAME"%d:IOC_CMD52 failed (%d)\n",
-						func->num, cmd52ctrl.m_ret);
-
-			if (copy_to_user((unsigned char __user *)arg,
-						&cmd52ctrl,
-						sizeof(cmd52ctrl))) {
-				pr_err(TP_DEV_NAME"%d:IOC_CMD52 put data"
-						" to user space failed\n",
-						func->num);
-				ret = -ENOTTY;
-				break;
-			}
-		}
-		break;
-	case CSDIO_IOC_CMD53:
-		{
-			struct csdio_cmd53_ctrl_t csdio_cmd53_ctrl;
-
-			if (copy_from_user(&csdio_cmd53_ctrl,
-						(const char __user *)arg,
-						sizeof(csdio_cmd53_ctrl))) {
-				ret = -EPERM;
-				pr_err(TP_DEV_NAME"%d:"
-					"Get data from user space failed\n",
-					func->num);
-				break;
-			}
-			descriptor->m_block_mode =
-				csdio_cmd53_ctrl.m_block_mode;
-			descriptor->m_op_code = csdio_cmd53_ctrl.m_op_code;
-			descriptor->m_address = csdio_cmd53_ctrl.m_address;
-		}
-		break;
-	case CSDIO_IOC_CONNECT_ISR:
-		{
-			pr_info(CSDIO_DEV_NAME" SDIO_CONNECT_ISR"
-				" func=%d, csdio_sdio_irq=%x\n",
-				func->num, (unsigned int)csdio_sdio_irq);
-			sdio_claim_host(func);
-			ret = sdio_claim_irq(func, csdio_sdio_irq);
-			sdio_release_host(func);
-			if (ret) {
-				pr_err(CSDIO_DEV_NAME" SDIO_CONNECT_ISR"
-						" claim irq failed(%d)\n", ret);
-			} else {
-				/* update current irq mask for disable/enable */
-				g_csdio.m_current_irq_mask |= (1 << func->num);
-			}
-		}
-		break;
-	case CSDIO_IOC_DISCONNECT_ISR:
-		{
-			pr_info(CSDIO_DEV_NAME " SDIO_DISCONNECT_ISR func=%d\n",
-					func->num);
-			sdio_claim_host(func);
-			sdio_release_irq(func);
-			sdio_release_host(func);
-			/* update current irq mask for disable/enable */
-			g_csdio.m_current_irq_mask &= ~(1 << func->num);
-		}
-		break;
-	default:  /*  redundant, as cmd was checked against MAXNR */
-		pr_warning(TP_DEV_NAME"%d: Redundant IOCTL\n",
-				func->num);
-		ret = -ENOTTY;
-	}
-exit:
-	return ret;
-}
-
-static const struct file_operations csdio_transport_fops = {
-	.owner =    THIS_MODULE,
-	.read =     csdio_transport_read,
-	.write =    csdio_transport_write,
-	.ioctl =    csdio_transport_ioctl,
-	.open =     csdio_transport_open,
-	.release =  csdio_transport_release,
-};
-
-static void csdio_transport_cleanup(struct csdio_func_t *port)
-{
-	int devno = MKDEV(csdio_major, csdio_minor + port->m_func->num);
-	device_destroy(g_csdio.m_driver_class, devno);
-	port->m_device = NULL;
-	cdev_del(&port->m_cdev);
-}
-
-#if defined(CONFIG_DEVTMPFS)
-static inline int csdio_cdev_update_permissions(
-    const char *devname, int dev_minor)
-{
-	return 0;
-}
-#else
-static int csdio_cdev_update_permissions(
-    const char *devname, int dev_minor)
-{
-	int ret = 0;
-	mm_segment_t fs;
-	struct file *file;
-	struct inode *inode;
-	struct iattr newattrs;
-	int mode = CSDIO_DEV_PERMISSIONS;
-	char dev_file[64];
-
-	fs = get_fs();
-	set_fs(get_ds());
-
-	snprintf(dev_file, sizeof(dev_file), "/dev/%s%d",
-		devname, dev_minor);
-	file = filp_open(dev_file, O_RDWR, 0);
-	if (IS_ERR(file)) {
-		ret = -EFAULT;
-		goto exit;
-	}
-
-	inode = file->f_path.dentry->d_inode;
-
-	mutex_lock(&inode->i_mutex);
-	newattrs.ia_mode =
-		(mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
-	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-	ret = notify_change(file->f_path.dentry, &newattrs);
-	mutex_unlock(&inode->i_mutex);
-
-	filp_close(file, NULL);
-
-exit:
-	set_fs(fs);
-	return ret;
-}
-#endif
-
-static struct device *csdio_cdev_init(struct cdev *char_dev,
-		const struct file_operations *file_op, int dev_minor,
-		const char *devname, struct device *parent)
-{
-	int ret = 0;
-	struct device *new_device = NULL;
-	dev_t devno = MKDEV(csdio_major, dev_minor);
-
-	/*  Initialize transport device */
-	cdev_init(char_dev, file_op);
-	char_dev->owner = THIS_MODULE;
-	char_dev->ops = file_op;
-	ret = cdev_add(char_dev, devno, 1);
-
-	/*  Fail gracefully if need be */
-	if (ret) {
-		pr_warning("Error %d adding CSDIO char device '%s%d'",
-				ret, devname, dev_minor);
-		goto exit;
-	}
-	pr_info("'%s%d' char driver registered\n", devname, dev_minor);
-
-	/*  create a /dev entry for transport drivers */
-	new_device = device_create(g_csdio.m_driver_class, parent, devno, NULL,
-			"%s%d", devname, dev_minor);
-	if (!new_device) {
-		pr_err("Can't create device node '/dev/%s%d'\n",
-				devname, dev_minor);
-		goto cleanup;
-	}
-	/* no irq attached */
-	g_csdio.m_current_irq_mask = 0;
-
-	if (csdio_cdev_update_permissions(devname, dev_minor)) {
-		pr_warning("%s%d: Unable to update access permissions of the"
-			" '/dev/%s%d'\n",
-			devname, dev_minor, devname, dev_minor);
-	}
-
-	pr_info("%s%d: Device node '/dev/%s%d' created successfully\n",
-			devname, dev_minor, devname, dev_minor);
-	goto exit;
-cleanup:
-	cdev_del(char_dev);
-exit:
-	return new_device;
-}
-
-/* Looks for first non empty function, returns NULL otherwise */
-static struct sdio_func *get_active_func(void)
-{
-	int i;
-
-	for (i = 0; i < CSDIO_NUM_OF_SDIO_FUNCTIONS; i++) {
-		if (g_csdio_func_table[i])
-			return g_csdio_func_table[i]->m_func;
-	}
-	return NULL;
-}
-
-static ssize_t
-show_vdd(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	if (NULL == g_csdio.m_host)
-		return snprintf(buf, PAGE_SIZE, "N/A\n");
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-		g_csdio.m_host->ios.vdd);
-}
-
-static int
-set_vdd_helper(int value)
-{
-	struct mmc_ios *ios = NULL;
-
-	if (NULL == g_csdio.m_host) {
-		pr_err("%s0: Set VDD, no MMC host assigned\n", CSDIO_DEV_NAME);
-		return -ENXIO;
-	}
-
-	mmc_claim_host(g_csdio.m_host);
-	ios = &g_csdio.m_host->ios;
-	ios->vdd = value;
-	g_csdio.m_host->ops->set_ios(g_csdio.m_host, ios);
-	mmc_release_host(g_csdio.m_host);
-	return 0;
-}
-
-static ssize_t
-set_vdd(struct device *dev, struct device_attribute *att,
-	const char *buf, size_t count)
-{
-	int value = 0;
-
-	sscanf(buf, "%d", &value);
-	if (set_vdd_helper(value))
-		return -ENXIO;
-	return count;
-}
-
-static DEVICE_ATTR(vdd, S_IRUGO | S_IWUSR,
-	show_vdd, set_vdd);
-
-static struct attribute *dev_attrs[] = {
-	&dev_attr_vdd.attr,
-	NULL,
-};
-
-static struct attribute_group dev_attr_grp = {
-	.attrs = dev_attrs,
-};
-
-/*
- * The ioctl() implementation for control device
- */
-static int csdio_ctrl_ioctl(struct inode *inode, struct file *filp,
-		unsigned int cmd, unsigned long arg)
-{
-	int err = 0;
-	int ret = 0;
-
-	pr_info("CSDIO ctrl ioctl.\n");
-
-	/*  extract the type and number bitfields
-	    sanity check: return ENOTTY (inappropriate ioctl) before
-	    access_ok()
-	*/
-	if ((_IOC_TYPE(cmd) != CSDIO_IOC_MAGIC) ||
-			(_IOC_NR(cmd) > CSDIO_IOC_MAXNR)) {
-		pr_err(CSDIO_DEV_NAME "Wrong ioctl command parameters\n");
-		ret = -ENOTTY;
-		goto exit;
-	}
-
-	/*  the direction is a bitmask, and VERIFY_WRITE catches R/W
-	  transfers. `Type' is user-oriented, while access_ok is
-	  kernel-oriented, so the concept of "read" and "write" is reversed
-	  */
-	if (_IOC_DIR(cmd) & _IOC_READ) {
-		err = !access_ok(VERIFY_WRITE, (void __user *)arg,
-				_IOC_SIZE(cmd));
-	} else {
-		if (_IOC_DIR(cmd) & _IOC_WRITE)
-			err =  !access_ok(VERIFY_READ, (void __user *)arg,
-					_IOC_SIZE(cmd));
-	}
-	if (err) {
-		pr_err(CSDIO_DEV_NAME "Wrong ioctl access direction\n");
-		ret = -EFAULT;
-		goto exit;
-	}
-
-	switch (cmd) {
-	case CSDIO_IOC_ENABLE_HIGHSPEED_MODE:
-		pr_info(CSDIO_DEV_NAME" ENABLE_HIGHSPEED_MODE\n");
-		break;
-	case CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS:
-		{
-			struct mmc_host *host = g_csdio.m_host;
-			struct mmc_ios *ios = NULL;
-
-			if (NULL == host) {
-				pr_err("%s0: "
-					"CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS,"
-					" no MMC host assigned\n",
-					CSDIO_DEV_NAME);
-				ret = -EFAULT;
-				goto exit;
-			}
-			ios = &host->ios;
-
-			mmc_claim_host(host);
-			ret = get_user(host->ios.clock,
-					(unsigned int __user *)arg);
-			if (ret) {
-				pr_err(CSDIO_DEV_NAME
-					" get data from user space failed\n");
-			} else {
-				pr_err(CSDIO_DEV_NAME
-					"SET_DATA_TRANSFER_CLOCKS(%d-%d)(%d)\n",
-					host->f_min, host->f_max,
-					host->ios.clock);
-				host->ops->set_ios(host, ios);
-			}
-			mmc_release_host(host);
-		}
-		break;
-	case CSDIO_IOC_ENABLE_ISR:
-		{
-			int ret;
-			unsigned char reg;
-			struct sdio_func *func = get_active_func();
-
-			if (!func) {
-				pr_err(CSDIO_DEV_NAME " CSDIO_IOC_ENABLE_ISR"
-						" no active sdio function\n");
-				ret = -EFAULT;
-				goto exit;
-			}
-			pr_info(CSDIO_DEV_NAME
-					" CSDIO_IOC_ENABLE_ISR func=%d\n",
-					func->num);
-			reg = g_csdio.m_current_irq_mask | 1;
-
-			sdio_claim_host(func);
-			sdio_f0_writeb(func, reg, SDIO_CCCR_IENx, &ret);
-			sdio_release_host(func);
-			if (ret) {
-				pr_err(CSDIO_DEV_NAME
-						" Can't sdio_f0_writeb (%d)\n",
-						ret);
-				goto exit;
-			}
-		}
-		break;
-	case CSDIO_IOC_DISABLE_ISR:
-		{
-			int ret;
-			struct sdio_func *func = get_active_func();
-			if (!func) {
-				pr_err(CSDIO_DEV_NAME " CSDIO_IOC_ENABLE_ISR"
-						" no active sdio function\n");
-				ret = -EFAULT;
-				goto exit;
-			}
-			pr_info(CSDIO_DEV_NAME
-					" CSDIO_IOC_DISABLE_ISR func=%p\n",
-					func);
-
-			sdio_claim_host(func);
-			ret = disable_sdio_client_isr(func);
-			sdio_release_host(func);
-			if (ret) {
-				pr_err("%s0: Can't disable client isr (%d)\n",
-					CSDIO_DEV_NAME, ret);
-				goto exit;
-			}
-		}
-	break;
-	case CSDIO_IOC_SET_VDD:
-		{
-			unsigned int vdd = 0;
-
-			ret = get_user(vdd, (unsigned int __user *)arg);
-			if (ret) {
-				pr_err("%s0: CSDIO_IOC_SET_VDD,"
-					" get data from user space failed\n",
-					CSDIO_DEV_NAME);
-				goto exit;
-			}
-			pr_info(CSDIO_DEV_NAME" CSDIO_IOC_SET_VDD - %d\n", vdd);
-
-			ret = set_vdd_helper(vdd);
-			if (ret)
-				goto exit;
-		}
-	break;
-	case CSDIO_IOC_GET_VDD:
-		{
-			if (NULL == g_csdio.m_host) {
-				pr_err("%s0: CSDIO_IOC_GET_VDD,"
-					" no MMC host assigned\n",
-					CSDIO_DEV_NAME);
-				ret = -EFAULT;
-				goto exit;
-			}
-			ret = put_user(g_csdio.m_host->ios.vdd,
-				(unsigned short __user *)arg);
-			if (ret) {
-				pr_err("%s0: CSDIO_IOC_GET_VDD, put data"
-					" to user space failed\n",
-					CSDIO_DEV_NAME);
-				goto exit;
-			}
-		}
-	break;
-	default:  /*  redundant, as cmd was checked against MAXNR */
-		pr_warning(CSDIO_DEV_NAME" Redundant IOCTL\n");
-		ret = -ENOTTY;
-	}
-exit:
-	return ret;
-}
-
-static int csdio_ctrl_fasync(int fd, struct file *filp, int mode)
-{
-	pr_info(CSDIO_DEV_NAME
-			" csdio_ctrl_fasync: fd=%d, filp=%p, mode=%d\n",
-			fd, filp, mode);
-	return fasync_helper(fd, filp, mode, &g_csdio.m_async_queue);
-}
-
-/*
- * Open and close
- */
-static int csdio_ctrl_open(struct inode *inode, struct file *filp)
-{
-	int ret = 0;
-	struct csdio_t *csdio_ctrl_drv = NULL; /*  device information */
-
-	pr_info("CSDIO ctrl open.\n");
-	csdio_ctrl_drv = container_of(inode->i_cdev, struct csdio_t, m_cdev);
-	filp->private_data = csdio_ctrl_drv; /*  for other methods */
-	return ret;
-}
-
-static int csdio_ctrl_release(struct inode *inode, struct file *filp)
-{
-	pr_info("CSDIO ctrl release.\n");
-	/*  remove this filp from the asynchronously notified filp's */
-	csdio_ctrl_fasync(-1, filp, 0);
-	return 0;
-}
-
-static const struct file_operations csdio_ctrl_fops = {
-	.owner =	THIS_MODULE,
-	.ioctl =	csdio_ctrl_ioctl,
-	.open  =	csdio_ctrl_open,
-	.release =	csdio_ctrl_release,
-	.fasync =	csdio_ctrl_fasync,
-};
-
-static int csdio_probe(struct sdio_func *func,
-		const struct sdio_device_id *id)
-{
-	struct csdio_func_t *port;
-	int ret = 0;
-	struct mmc_host *host = func->card->host;
-
-	if (NULL != g_csdio.m_host && g_csdio.m_host != host) {
-		pr_info("%s: Device is on unexpected host\n",
-			CSDIO_DEV_NAME);
-		ret = -ENODEV;
-		goto exit;
-	}
-
-	/* enforce single instance policy */
-	if (g_csdio_func_table[func->num-1]) {
-		pr_err("%s - only single SDIO device supported",
-				sdio_func_id(func));
-		ret = -EEXIST;
-		goto exit;
-	}
-
-	port = kzalloc(sizeof(struct csdio_func_t), GFP_KERNEL);
-	if (!port) {
-		pr_err("Can't allocate memory\n");
-		ret = -ENOMEM;
-		goto exit;
-	}
-
-	/* initialize SDIO side */
-	port->m_func = func;
-	sdio_set_drvdata(func, port);
-
-	pr_info("%s - SDIO device found. Function %d\n",
-			sdio_func_id(func), func->num);
-
-	port->m_device = csdio_cdev_init(&port->m_cdev, &csdio_transport_fops,
-			csdio_minor + port->m_func->num,
-			TP_DEV_NAME, &port->m_func->dev);
-
-	/* create appropriate char device */
-	if (!port->m_device)
-		goto free;
-
-	if (0 == g_csdio.m_num_of_func && NULL == host_name)
-		g_csdio.m_host = host;
-	g_csdio.m_num_of_func++;
-	g_csdio_func_table[func->num-1] = port;
-	port->m_enabled = TRUE;
-	goto exit;
-free:
-	kfree(port);
-exit:
-	return ret;
-}
-
-static void csdio_remove(struct sdio_func *func)
-{
-	struct csdio_func_t *port = sdio_get_drvdata(func);
-
-	csdio_transport_cleanup(port);
-	sdio_claim_host(func);
-	sdio_release_irq(func);
-	sdio_disable_func(func);
-	sdio_release_host(func);
-	kfree(port);
-	g_csdio_func_table[func->num-1] = NULL;
-	g_csdio.m_num_of_func--;
-	if (0 == g_csdio.m_num_of_func && NULL == host_name)
-		g_csdio.m_host = NULL;
-	pr_info("%s%d: Device removed (%s). Function %d\n",
-		CSDIO_DEV_NAME, func->num, sdio_func_id(func), func->num);
-}
-
-/* CONFIG_CSDIO_VENDOR_ID and CONFIG_CSDIO_DEVICE_ID are defined in Kconfig.
- * Use kernel configuration to change the values or overwrite them through
- * module parameters */
-static struct sdio_device_id csdio_ids[] = {
-	{ SDIO_DEVICE(CONFIG_CSDIO_VENDOR_ID, CONFIG_CSDIO_DEVICE_ID) },
-	{ /* end: all zeroes */},
-};
-
-MODULE_DEVICE_TABLE(sdio, csdio_ids);
-
-static struct sdio_driver csdio_driver = {
-	.probe      = csdio_probe,
-	.remove     = csdio_remove,
-	.name       = "csdio",
-	.id_table   = csdio_ids,
-};
-
-static void __exit csdio_exit(void)
-{
-	dev_t devno = MKDEV(csdio_major, csdio_minor);
-
-	sdio_unregister_driver(&csdio_driver);
-	sysfs_remove_group(&g_csdio.m_device->kobj, &dev_attr_grp);
-	kfree(g_sdio_buffer);
-	device_destroy(g_csdio.m_driver_class, devno);
-	cdev_del(&g_csdio.m_cdev);
-	class_destroy(g_csdio.m_driver_class);
-	unregister_chrdev_region(devno, csdio_transport_nr_devs);
-	pr_info("%s: Exit driver module\n", CSDIO_DEV_NAME);
-}
-
-static char *csdio_devnode(struct device *dev, mode_t *mode)
-{
-	*mode = CSDIO_DEV_PERMISSIONS;
-	return NULL;
-}
-
-static int __init csdio_init(void)
-{
-	int ret = 0;
-	dev_t devno = 0;
-
-	pr_info("Init CSDIO driver module.\n");
-
-	/*  Get a range of minor numbers to work with, asking for a dynamic */
-	/*  major unless directed otherwise at load time. */
-	if (csdio_major) {
-		devno = MKDEV(csdio_major, csdio_minor);
-		ret = register_chrdev_region(devno, csdio_transport_nr_devs,
-				CSDIO_DEV_NAME);
-	} else {
-		ret = alloc_chrdev_region(&devno, csdio_minor,
-				csdio_transport_nr_devs, CSDIO_DEV_NAME);
-		csdio_major = MAJOR(devno);
-	}
-	if (ret < 0) {
-		pr_err("CSDIO: can't get major %d\n", csdio_major);
-		goto exit;
-	}
-	pr_info("CSDIO char driver major number is %d\n", csdio_major);
-
-	/* kernel module got parameters: overwrite vendor and device id's */
-	if ((csdio_vendor_id != 0) && (csdio_device_id != 0)) {
-		csdio_ids[0].vendor = (u16)csdio_vendor_id;
-		csdio_ids[0].device = (u16)csdio_device_id;
-	}
-
-	/*  prepare create /dev/... instance */
-	g_csdio.m_driver_class = class_create(THIS_MODULE, CSDIO_DEV_NAME);
-	if (IS_ERR(g_csdio.m_driver_class)) {
-		ret = -ENOMEM;
-		pr_err(CSDIO_DEV_NAME " class_create failed\n");
-		goto unregister_region;
-	}
-	g_csdio.m_driver_class->devnode = csdio_devnode;
-
-	/*  create CSDIO ctrl driver */
-	g_csdio.m_device = csdio_cdev_init(&g_csdio.m_cdev,
-		&csdio_ctrl_fops, csdio_minor, CSDIO_DEV_NAME, NULL);
-	if (!g_csdio.m_device) {
-		pr_err("%s: Unable to create ctrl driver\n",
-			CSDIO_DEV_NAME);
-		goto destroy_class;
-	}
-
-	g_sdio_buffer = kmalloc(CSDIO_SDIO_BUFFER_SIZE, GFP_KERNEL);
-	if (!g_sdio_buffer) {
-		pr_err("Unable to allocate %d bytes\n", CSDIO_SDIO_BUFFER_SIZE);
-		ret = -ENOMEM;
-		goto destroy_cdev;
-	}
-
-	ret = sysfs_create_group(&g_csdio.m_device->kobj, &dev_attr_grp);
-	if (ret) {
-		pr_err("%s: Unable to create device attribute\n",
-			CSDIO_DEV_NAME);
-		goto free_sdio_buff;
-	}
-
-	g_csdio.m_num_of_func = 0;
-	g_csdio.m_host = NULL;
-
-	if (NULL != host_name) {
-		struct device *dev = bus_find_device_by_name(&platform_bus_type,
-			NULL, host_name);
-		if (NULL != dev) {
-			g_csdio.m_host = dev_get_drvdata(dev);
-		} else {
-			pr_err("%s: Host '%s' doesn't exist!\n", CSDIO_DEV_NAME,
-				host_name);
-		}
-	}
-
-	pr_info("%s: Match with VendorId=0x%X, DeviceId=0x%X, Host = %s\n",
-		CSDIO_DEV_NAME, csdio_device_id, csdio_vendor_id,
-		(NULL == host_name) ? "Any" : host_name);
-
-	/* register sdio driver */
-	ret = sdio_register_driver(&csdio_driver);
-	if (ret) {
-		pr_err("%s: Unable to register as SDIO driver\n",
-			CSDIO_DEV_NAME);
-		goto remove_group;
-	}
-
-	goto exit;
-
-remove_group:
-	sysfs_remove_group(&g_csdio.m_device->kobj, &dev_attr_grp);
-free_sdio_buff:
-	kfree(g_sdio_buffer);
-destroy_cdev:
-	cdev_del(&g_csdio.m_cdev);
-destroy_class:
-	class_destroy(g_csdio.m_driver_class);
-unregister_region:
-	unregister_chrdev_region(devno, csdio_transport_nr_devs);
-exit:
-	return ret;
-}
-module_param(csdio_vendor_id, uint, S_IRUGO);
-module_param(csdio_device_id, uint, S_IRUGO);
-module_param(host_name, charp, S_IRUGO);
-
-module_init(csdio_init);
-module_exit(csdio_exit);
-
-MODULE_AUTHOR("The Linux Foundation");
-MODULE_DESCRIPTION("CSDIO device driver version " VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 03304dc..c9be39a 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -24,7 +24,7 @@
 #define DISABLE_LOG_MASK	0
 #define MAX_EVENT_SIZE		512
 #define DCI_CLIENT_INDEX_INVALID -1
-#define DCI_PKT_REQ_MIN_LEN		8
+#define DCI_PKT_REQ_MIN_LEN		5
 #define DCI_LOG_CON_MIN_LEN		14
 #define DCI_EVENT_CON_MIN_LEN		16
 
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 4f5893c..8f7d39c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -318,6 +318,7 @@
 show_one(down_differential, down_differential);
 show_one(sampling_down_factor, sampling_down_factor);
 show_one(ignore_nice_load, ignore_nice);
+show_one(down_differential_multi_core, down_differential_multi_core);
 show_one(optimal_freq, optimal_freq);
 show_one(up_threshold_any_cpu_load, up_threshold_any_cpu_load);
 show_one(sync_freq, sync_freq);
@@ -437,6 +438,20 @@
 	return count;
 }
 
+static ssize_t store_down_differential_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)
+		return -EINVAL;
+	dbs_tuners_ins.down_differential_multi_core = input;
+	return count;
+}
+
+
 static ssize_t store_optimal_freq(struct kobject *a, struct attribute *b,
 				   const char *buf, size_t count)
 {
@@ -695,6 +710,7 @@
 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(down_differential_multi_core);
 define_one_global_rw(optimal_freq);
 define_one_global_rw(up_threshold_any_cpu_load);
 define_one_global_rw(sync_freq);
@@ -710,6 +726,7 @@
 	&powersave_bias.attr,
 	&io_is_busy.attr,
 	&up_threshold_multi_core.attr,
+	&down_differential_multi_core.attr,
 	&optimal_freq.attr,
 	&up_threshold_any_cpu_load.attr,
 	&sync_freq.attr,
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 0809308..514385c 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -36,6 +36,7 @@
 #include <linux/uaccess.h>
 #include <linux/debugfs.h>
 #include <linux/dma-buf.h>
+#include <linux/idr.h>
 #include <linux/msm_ion.h>
 #include <trace/events/kmem.h>
 
@@ -70,6 +71,7 @@
  * @node:		node in the tree of all clients
  * @dev:		backpointer to ion device
  * @handles:		an rb tree of all the handles in this client
+ * @idr:		an idr space for allocating handle ids
  * @lock:		lock protecting the tree of handles
  * @name:		used for debugging
  * @task:		used for debugging
@@ -82,6 +84,7 @@
 	struct rb_node node;
 	struct ion_device *dev;
 	struct rb_root handles;
+	struct idr idr;
 	struct mutex lock;
 	char *name;
 	struct task_struct *task;
@@ -96,7 +99,7 @@
  * @buffer:		pointer to the buffer
  * @node:		node in the client's handle rbtree
  * @kmap_cnt:		count of times this client has mapped to kernel
- * @dmap_cnt:		count of times this client has mapped for dma
+ * @id:			client-unique id allocated by client->idr
  *
  * Modifications to node, map_cnt or mapping should be protected by the
  * lock in the client.  Other fields are never changed after initialization.
@@ -107,6 +110,7 @@
 	struct ion_buffer *buffer;
 	struct rb_node node;
 	unsigned int kmap_cnt;
+	int id;
 };
 
 bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
@@ -343,6 +347,7 @@
 		ion_handle_kmap_put(handle);
 	mutex_unlock(&buffer->lock);
 
+	idr_remove(&client->idr, handle->id);
 	if (!RB_EMPTY_NODE(&handle->node))
 		rb_erase(&handle->node, &client->handles);
 
@@ -362,9 +367,16 @@
 	kref_get(&handle->ref);
 }
 
-static int ion_handle_put(struct ion_handle *handle)
+int ion_handle_put(struct ion_handle *handle)
 {
-	return kref_put(&handle->ref, ion_handle_destroy);
+	struct ion_client *client = handle->client;
+	int ret;
+
+	mutex_lock(&client->lock);
+	ret = kref_put(&handle->ref, ion_handle_destroy);
+	mutex_unlock(&client->lock);
+
+	return ret;
 }
 
 static struct ion_handle *ion_handle_lookup(struct ion_client *client,
@@ -374,36 +386,52 @@
 
 	for (n = rb_first(&client->handles); n; n = rb_next(n)) {
 		struct ion_handle *handle = rb_entry(n, struct ion_handle,
-						     node);
+						   node);
 		if (handle->buffer == buffer)
 			return handle;
 	}
 	return NULL;
 }
 
-static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+						int id)
 {
-	struct rb_node *n = client->handles.rb_node;
+	struct ion_handle *handle;
 
-	while (n) {
-		struct ion_handle *handle_node = rb_entry(n, struct ion_handle,
-							  node);
-		if (handle < handle_node)
-			n = n->rb_left;
-		else if (handle > handle_node)
-			n = n->rb_right;
-		else
-			return true;
-	}
-	return false;
+	mutex_lock(&client->lock);
+	handle = idr_find(&client->idr, id);
+	if (handle)
+		ion_handle_get(handle);
+	mutex_unlock(&client->lock);
+
+	return handle ? handle : ERR_PTR(-EINVAL);
 }
 
-static void ion_handle_add(struct ion_client *client, struct ion_handle *handle)
+static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle)
 {
+	WARN_ON(!mutex_is_locked(&client->lock));
+	return (idr_find(&client->idr, handle->id) == handle);
+}
+
+static int ion_handle_add(struct ion_client *client, struct ion_handle *handle)
+{
+	int rc;
 	struct rb_node **p = &client->handles.rb_node;
 	struct rb_node *parent = NULL;
 	struct ion_handle *entry;
 
+	do {
+		int id;
+		rc = idr_pre_get(&client->idr, GFP_KERNEL);
+		if (!rc)
+			return -ENOMEM;
+		rc = idr_get_new_above(&client->idr, handle, 1, &id);
+		handle->id = id;
+	} while (rc == -EAGAIN);
+
+	if (rc < 0)
+		return rc;
+
 	while (*p) {
 		parent = *p;
 		entry = rb_entry(parent, struct ion_handle, node);
@@ -418,6 +446,8 @@
 
 	rb_link_node(&handle->node, parent, p);
 	rb_insert_color(&handle->node, &client->handles);
+
+	return 0;
 }
 
 struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
@@ -428,6 +458,7 @@
 	struct ion_device *dev = client->dev;
 	struct ion_buffer *buffer = NULL;
 	struct ion_heap *heap;
+	int ret;
 	unsigned long secure_allocation = flags & ION_FLAG_SECURE;
 	const unsigned int MAX_DBG_STR_LEN = 64;
 	char dbg_str[MAX_DBG_STR_LEN];
@@ -518,12 +549,16 @@
 	 */
 	ion_buffer_put(buffer);
 
-	if (!IS_ERR(handle)) {
-		mutex_lock(&client->lock);
-		ion_handle_add(client, handle);
-		mutex_unlock(&client->lock);
-	}
+	if (IS_ERR(handle))
+		return handle;
 
+	mutex_lock(&client->lock);
+	ret = ion_handle_add(client, handle);
+	mutex_unlock(&client->lock);
+	if (ret) {
+		ion_handle_put(handle);
+		handle = ERR_PTR(ret);
+	}
 
 	return handle;
 }
@@ -542,8 +577,8 @@
 		mutex_unlock(&client->lock);
 		return;
 	}
-	ion_handle_put(handle);
 	mutex_unlock(&client->lock);
+	ion_handle_put(handle);
 }
 EXPORT_SYMBOL(ion_free);
 
@@ -775,6 +810,7 @@
 
 	client->dev = dev;
 	client->handles = RB_ROOT;
+	idr_init(&client->idr);
 	mutex_init(&client->lock);
 
 	client->name = kzalloc(name_len+1, GFP_KERNEL);
@@ -831,6 +867,10 @@
 						     node);
 		ion_handle_destroy(&handle->ref);
 	}
+
+	idr_remove_all(&client->idr);
+	idr_destroy(&client->idr);
+
 	down_write(&dev->lock);
 	if (client->task)
 		put_task_struct(client->task);
@@ -1175,14 +1215,15 @@
 
 	mutex_lock(&client->lock);
 	valid_handle = ion_handle_validate(client, handle);
-	mutex_unlock(&client->lock);
 	if (!valid_handle) {
 		WARN(1, "%s: invalid handle passed to share.\n", __func__);
+		mutex_unlock(&client->lock);
 		return ERR_PTR(-EINVAL);
 	}
-
 	buffer = handle->buffer;
 	ion_buffer_get(buffer);
+	mutex_unlock(&client->lock);
+
 	dmabuf = dma_buf_export(buffer, &dma_buf_ops, buffer->size, O_RDWR);
 	if (IS_ERR(dmabuf)) {
 		ion_buffer_put(buffer);
@@ -1215,6 +1256,7 @@
 	struct dma_buf *dmabuf;
 	struct ion_buffer *buffer;
 	struct ion_handle *handle;
+	int ret;
 
 	dmabuf = dma_buf_get(fd);
 	if (IS_ERR_OR_NULL(dmabuf))
@@ -1234,14 +1276,24 @@
 	handle = ion_handle_lookup(client, buffer);
 	if (!IS_ERR_OR_NULL(handle)) {
 		ion_handle_get(handle);
+		mutex_unlock(&client->lock);
 		goto end;
 	}
+	mutex_unlock(&client->lock);
+
 	handle = ion_handle_create(client, buffer);
 	if (IS_ERR_OR_NULL(handle))
 		goto end;
-	ion_handle_add(client, handle);
-end:
+
+	mutex_lock(&client->lock);
+	ret = ion_handle_add(client, handle);
 	mutex_unlock(&client->lock);
+	if (ret) {
+		ion_handle_put(handle);
+		handle = ERR_PTR(ret);
+	}
+
+end:
 	dma_buf_put(dmabuf);
 	return handle;
 }
@@ -1279,17 +1331,20 @@
 	case ION_IOC_ALLOC:
 	{
 		struct ion_allocation_data data;
+		struct ion_handle *handle;
 
 		if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
 			return -EFAULT;
-		data.handle = ion_alloc(client, data.len, data.align,
+		handle = ion_alloc(client, data.len, data.align,
 					     data.heap_mask, data.flags);
 
-		if (IS_ERR(data.handle))
-			return PTR_ERR(data.handle);
+		if (IS_ERR(handle))
+			return PTR_ERR(handle);
+
+		data.handle = (ion_user_handle_t)handle->id;
 
 		if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
-			ion_free(client, data.handle);
+			ion_free(client, handle);
 			return -EFAULT;
 		}
 		break;
@@ -1297,28 +1352,31 @@
 	case ION_IOC_FREE:
 	{
 		struct ion_handle_data data;
-		bool valid;
+		struct ion_handle *handle;
 
 		if (copy_from_user(&data, (void __user *)arg,
 				   sizeof(struct ion_handle_data)))
 			return -EFAULT;
-		mutex_lock(&client->lock);
-		valid = ion_handle_validate(client, data.handle);
-		mutex_unlock(&client->lock);
-		if (!valid)
-			return -EINVAL;
-		ion_free(client, data.handle);
+		handle = ion_handle_get_by_id(client, (int)data.handle);
+		if (IS_ERR(handle))
+			return PTR_ERR(handle);
+		ion_free(client, handle);
+		ion_handle_put(handle);
 		break;
 	}
 	case ION_IOC_SHARE:
 	case ION_IOC_MAP:
 	{
 		struct ion_fd_data data;
+		struct ion_handle *handle;
 		if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
 			return -EFAULT;
 
-		data.fd = ion_share_dma_buf_fd(client, data.handle);
-
+		handle = ion_handle_get_by_id(client, (int)data.handle);
+		if (IS_ERR(handle))
+			return PTR_ERR(handle);
+		data.fd = ion_share_dma_buf_fd(client, handle);
+		ion_handle_put(handle);
 		if (copy_to_user((void __user *)arg, &data, sizeof(data)))
 			return -EFAULT;
 		if (data.fd < 0)
@@ -1328,15 +1386,17 @@
 	case ION_IOC_IMPORT:
 	{
 		struct ion_fd_data data;
+		struct ion_handle *handle;
 		int ret = 0;
 		if (copy_from_user(&data, (void __user *)arg,
 				   sizeof(struct ion_fd_data)))
 			return -EFAULT;
-		data.handle = ion_import_dma_buf(client, data.fd);
-		if (IS_ERR(data.handle)) {
-			ret = PTR_ERR(data.handle);
-			data.handle = NULL;
-		}
+		handle = ion_import_dma_buf(client, data.fd);
+		if (IS_ERR(handle))
+			ret = PTR_ERR(handle);
+		else
+			data.handle = (ion_user_handle_t)handle->id;
+
 		if (copy_to_user((void __user *)arg, &data,
 				 sizeof(struct ion_fd_data)))
 			return -EFAULT;
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index f5d0287..aa0a9e2 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -396,4 +396,9 @@
 int ion_walk_heaps(struct ion_client *client, int heap_id, void *data,
 			int (*f)(struct ion_heap *heap, void *data));
 
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+					int id);
+
+int ion_handle_put(struct ion_handle *handle);
+
 #endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 213bcb1..cdd31e1 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -973,11 +973,18 @@
 					sizeof(struct ion_flush_data)))
 			return -EFAULT;
 
-		if (!data.handle) {
+		if (data.handle >= 0) {
+			handle = ion_handle_get_by_id(client, (int)data.handle);
+			if (IS_ERR(handle)) {
+				pr_info("%s: Could not find handle: %d\n",
+					__func__, (int)data.handle);
+				return PTR_ERR(handle);
+			}
+		} else {
 			handle = ion_import_dma_buf(client, data.fd);
 			if (IS_ERR(handle)) {
-				pr_info("%s: Could not import handle: %d\n",
-					__func__, (int)handle);
+				pr_info("%s: Could not import handle: %p\n",
+					__func__, handle);
 				return -EINVAL;
 			}
 		}
@@ -988,28 +995,20 @@
 		end = (unsigned long) data.vaddr + data.length;
 
 		if (start && check_vaddr_bounds(start, end)) {
-			up_read(&mm->mmap_sem);
 			pr_err("%s: virtual address %p is out of bounds\n",
 				__func__, data.vaddr);
-			if (!data.handle)
-				ion_free(client, handle);
-			return -EINVAL;
+			ret = -EINVAL;
+		} else {
+			ret = ion_do_cache_op(client, handle, data.vaddr,
+					data.offset, data.length, cmd);
 		}
-
-		ret = ion_do_cache_op(client,
-				data.handle ? data.handle : handle,
-				data.vaddr, data.offset, data.length,
-				cmd);
-
 		up_read(&mm->mmap_sem);
 
-		if (!data.handle)
-			ion_free(client, handle);
+		ion_free(client, handle);
 
 		if (ret < 0)
 			return ret;
 		break;
-
 	}
 	case ION_IOC_PREFETCH:
 	{
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 070b5ac..eba60ea 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2051,6 +2051,8 @@
 
 	device->reset_counter++;
 
+	set_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv);
+
 	return 0;
 
 error_rb_stop:
@@ -2088,7 +2090,25 @@
 	set_user_nice(current, _wake_nice);
 
 	mutex_lock(&device->mutex);
-	_status = _adreno_start(adreno_dev);
+	/*
+	 *  If adreno start is already called, no need to call it again
+	 *  it can lead to unpredictable behavior if we try to start
+	 *  the device that is already started.
+	 *  Below is the sequence of events that can go bad without the check
+	 *  1) thread 1 calls adreno_start to be scheduled on high priority wq
+	 *  2) thread 2 calls adreno_start with normal priority
+	 *  3) thread 1 after checking the device to be in slumber state gives
+	 *     up mutex to be scheduled on high priority wq
+	 *  4) thread 2 after checking the device to be in slumber state gets
+	 *     the mutex and finishes adreno_start before thread 1 is scheduled
+	 *     on high priority wq.
+	 *  5) thread 1 gets scheduled on high priority wq and executes
+	 *     adreno_start again. This leads to unpredictable behavior.
+	 */
+	if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv))
+		_status = _adreno_start(adreno_dev);
+	else
+		_status = 0;
 	mutex_unlock(&device->mutex);
 }
 
@@ -2149,6 +2169,8 @@
 
 	kgsl_cffdump_close(device);
 
+	clear_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 1b538a7..800caf1 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -216,6 +216,7 @@
 	ADRENO_DEVICE_PWRON = 0,
 	ADRENO_DEVICE_PWRON_FIXUP = 1,
 	ADRENO_DEVICE_INITIALIZED = 2,
+	ADRENO_DEVICE_STARTED = 3,
 };
 
 #define PERFCOUNTER_FLAG_NONE 0x0
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index e5f5ad7..3d4c66a 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -4077,6 +4077,7 @@
 static int a3xx_perfcounter_init(struct adreno_device *adreno_dev)
 {
 	int ret;
+	struct kgsl_device *device = &adreno_dev->dev;
 	/* SP[3] counter is broken on a330 so disable it if a330 device */
 	if (adreno_is_a330(adreno_dev))
 		a3xx_perfcounters_sp[3].countable = KGSL_PERFCOUNTER_BROKEN;
@@ -4088,15 +4089,18 @@
 	ret = adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_PWR, 1,
 			NULL, PERFCOUNTER_FLAG_KERNEL);
 
-	/* VBIF waiting for RAM */
-	ret |= adreno_perfcounter_get(adreno_dev,
+	if (device->pwrctrl.bus_control) {
+		/* VBIF waiting for RAM */
+		ret |= adreno_perfcounter_get(adreno_dev,
 				KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0,
 				NULL, PERFCOUNTER_FLAG_KERNEL);
-	/* VBIF DDR cycles */
-	ret |= adreno_perfcounter_get(adreno_dev, KGSL_PERFCOUNTER_GROUP_VBIF,
+		/* VBIF DDR cycles */
+		ret |= adreno_perfcounter_get(adreno_dev,
+				KGSL_PERFCOUNTER_GROUP_VBIF,
 				VBIF_AXI_TOTAL_BEATS,
 				&adreno_dev->ram_cycles_lo,
 				PERFCOUNTER_FLAG_KERNEL);
+	}
 
 	/* Default performance counter profiling to false */
 	adreno_dev->profile.enabled = false;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index fe99a4b..9aefda6 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2878,7 +2878,7 @@
 	bool full_flush = false;
 
 	if (param->id_list == NULL || param->count == 0
-			|| param->count > (UINT_MAX/sizeof(unsigned int)))
+			|| param->count > (PAGE_SIZE / sizeof(unsigned int)))
 		return -EINVAL;
 
 	id_list = kzalloc(param->count * sizeof(unsigned int), GFP_KERNEL);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 505be69..f0114ad 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -141,7 +141,7 @@
 
 static inline void *kgsl_sg_alloc(unsigned int sglen)
 {
-	if (sglen >= ULONG_MAX / sizeof(struct scatterlist))
+	if ((sglen == 0) || (sglen >= ULONG_MAX / sizeof(struct scatterlist)))
 		return NULL;
 
 	if ((sglen * sizeof(struct scatterlist)) <  PAGE_SIZE)
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
index ceeb67b..5c89c0c 100644
--- a/drivers/input/misc/cm36283.c
+++ b/drivers/input/misc/cm36283.c
@@ -17,7 +17,6 @@
  */
 
 #include <linux/delay.h>
-#include <linux/earlysuspend.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/sensors.h>
@@ -118,7 +117,6 @@
 	struct input_dev *ls_input_dev;
 	struct input_dev *ps_input_dev;
 
-	struct early_suspend early_suspend;
 	struct i2c_client *i2c_client;
 	struct workqueue_struct *lp_wq;
 
@@ -1426,29 +1424,6 @@
 	return ret;
 }
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static void cm36283_early_suspend(struct early_suspend *h)
-{
-	struct cm36283_info *lpi = lp_info;
-
-	D("[LS][CM36283] %s\n", __func__);
-
-	if (lpi->als_enable)
-		lightsensor_disable(lpi);
-
-}
-
-static void cm36283_late_resume(struct early_suspend *h)
-{
-	struct cm36283_info *lpi = lp_info;
-
-	D("[LS][CM36283] %s\n", __func__);
-
-	if (!lpi->als_enable)
-		lightsensor_enable(lpi);
-}
-#endif
-
 static int cm36283_parse_dt(struct device *dev,
 				struct cm36283_platform_data *pdata)
 {
@@ -1744,13 +1719,6 @@
 	if (ret)
 		goto err_create_ps_device_file;
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
-	lpi->early_suspend.level =
-			EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
-	lpi->early_suspend.suspend = cm36283_early_suspend;
-	lpi->early_suspend.resume = cm36283_late_resume;
-	register_early_suspend(&lpi->early_suspend);
-#endif
 	ret = sensors_classdev_register(&client->dev, &sensors_light_cdev);
 	if (ret)
 		goto err_create_ps_device_file;
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 3b7bf5a..fab209e 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -325,32 +325,32 @@
 {
 	struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
 	unsigned long val;
+	u32 enable;
 
 	if (kstrtoul(buf, 10, &val))
 		return -EINVAL;
-	sensor->enable = (u32)val == 0 ? 0 : 1;
-	if (sensor->enable) {
+	enable = (u32)val == 0 ? 0 : 1;
+	if (enable && (!sensor->enable)) {
+		sensor->enable = enable;
 		pm_runtime_get_sync(sensor->dev);
-		gpio_set_value(sensor->enable_gpio, 1);
 		if (sensor->use_poll)
 			schedule_delayed_work(&sensor->input_work,
 				msecs_to_jiffies(sensor->poll_interval));
-		else {
-			i2c_smbus_write_byte_data(sensor->client,
-					MPU3050_INT_CFG,
-					MPU3050_ACTIVE_LOW |
-					MPU3050_OPEN_DRAIN |
-					MPU3050_RAW_RDY_EN);
+		else
 			enable_irq(sensor->client->irq);
-		}
-	} else {
+	} else if (!enable && sensor->enable) {
 		if (sensor->use_poll)
 			cancel_delayed_work_sync(&sensor->input_work);
 		else
 			disable_irq(sensor->client->irq);
-		gpio_set_value(sensor->enable_gpio, 0);
-		pm_runtime_put(sensor->dev);
+		pm_runtime_put_sync(sensor->dev);
+		sensor->enable = enable;
+	} else {
+		dev_warn(&sensor->client->dev,
+				"ignore enable state change from %d to %d\n",
+				sensor->enable, enable);
 	}
+
 	return count;
 }
 
@@ -485,54 +485,6 @@
 }
 
 /**
- *	mpu3050_input_open	-	called on input event open
- *	@input: input dev of opened device
- *
- *	The input layer calls this function when input event is opened. The
- *	function will push the device to resume. Then, the device is ready
- *	to provide data.
- */
-static int mpu3050_input_open(struct input_dev *input)
-{
-	struct mpu3050_sensor *sensor = input_get_drvdata(input);
-	int error;
-
-	pm_runtime_get_sync(sensor->dev);
-
-	/* Enable interrupts */
-	error = i2c_smbus_write_byte_data(sensor->client, MPU3050_INT_CFG,
-					MPU3050_ACTIVE_LOW |
-					MPU3050_OPEN_DRAIN |
-					MPU3050_RAW_RDY_EN);
-	if (error < 0) {
-		pm_runtime_put(sensor->dev);
-		return error;
-	}
-	if (sensor->use_poll)
-		schedule_delayed_work(&sensor->input_work,
-			msecs_to_jiffies(sensor->poll_interval));
-
-	return 0;
-}
-
-/**
- *	mpu3050_input_close	-	called on input event close
- *	@input: input dev of closed device
- *
- *	The input layer calls this function when input event is closed. The
- *	function will push the device to suspend.
- */
-static void mpu3050_input_close(struct input_dev *input)
-{
-	struct mpu3050_sensor *sensor = input_get_drvdata(input);
-
-	if (sensor->use_poll)
-		cancel_delayed_work_sync(&sensor->input_work);
-
-	pm_runtime_put(sensor->dev);
-}
-
-/**
  *	mpu3050_interrupt_thread	-	handle an IRQ
  *	@irq: interrupt numner
  *	@data: the sensor
@@ -588,18 +540,12 @@
  *
  *	Called during device probe; configures the sampling method.
  */
-static int __devinit mpu3050_hw_init(struct mpu3050_sensor *sensor)
+static int mpu3050_hw_init(struct mpu3050_sensor *sensor)
 {
 	struct i2c_client *client = sensor->client;
 	int ret;
 	u8 reg;
 
-	/* Reset */
-	ret = i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM,
-					MPU3050_PWR_MGM_RESET);
-	if (ret < 0)
-		return ret;
-
 	ret = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
 	if (ret < 0)
 		return ret;
@@ -624,6 +570,16 @@
 	if (ret < 0)
 		return ret;
 
+	/* Enable interrupts */
+	if (!sensor->use_poll) {
+		reg = MPU3050_ACTIVE_LOW;
+		reg |= MPU3050_OPEN_DRAIN;
+		reg |= MPU3050_RAW_RDY_EN;
+		ret = i2c_smbus_write_byte_data(client, MPU3050_INT_CFG, reg);
+		if (ret < 0)
+			return ret;
+	}
+
 	return 0;
 }
 #ifdef CONFIG_OF
@@ -750,9 +706,6 @@
 	idev->name = "MPU3050";
 	idev->id.bustype = BUS_I2C;
 
-	idev->open = mpu3050_input_open;
-	idev->close = mpu3050_input_close;
-
 	input_set_capability(idev, EV_ABS, ABS_MISC);
 	input_set_abs_params(idev, ABS_X,
 			     MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
@@ -813,6 +766,9 @@
 		disable_irq(client->irq);
 	}
 
+	sensor->enable = 0;
+	mpu3050_set_power_mode(client, 0);
+
 	error = input_register_device(idev);
 	if (error) {
 		dev_err(&client->dev, "failed to register input device\n");
@@ -893,10 +849,11 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
 
-	if (!sensor->use_poll)
-		disable_irq(client->irq);
-
-	mpu3050_set_power_mode(client, 0);
+	if (sensor->enable) {
+		if (!sensor->use_poll)
+			disable_irq(client->irq);
+		mpu3050_set_power_mode(client, 0);
+	}
 
 	return 0;
 }
@@ -912,16 +869,64 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
 
-	mpu3050_set_power_mode(client, 1);
+	if (sensor->enable) {
+		mpu3050_set_power_mode(client, 1);
+		mpu3050_hw_init(sensor);
+		if (!sensor->use_poll)
+			enable_irq(client->irq);
+	}
 
-	if (!sensor->use_poll)
-		enable_irq(client->irq);
+	return 0;
+}
+
+/**
+ *	mpu3050_runtime_suspend		-	called on device enters runtime suspend
+ *	@dev: device being suspended
+ *
+ *	Put the device into sleep mode.
+ */
+static int mpu3050_runtime_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+	if (sensor->enable)
+		mpu3050_set_power_mode(client, 0);
+
+	return 0;
+}
+
+/**
+ *	mpu3050_runtime_resume		-	called on device enters runtime resume
+ *	@dev: device being resumed
+ *
+ *	Put the device into powered mode.
+ */
+static int mpu3050_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+	if (sensor->enable) {
+		mpu3050_set_power_mode(client, 1);
+		mpu3050_hw_init(sensor);
+	}
 
 	return 0;
 }
 #endif
 
-static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL);
+static const struct dev_pm_ops mpu3050_pm = {
+	.runtime_suspend = mpu3050_runtime_suspend,
+	.runtime_resume = mpu3050_runtime_resume,
+	.runtime_idle = NULL,
+	.suspend = mpu3050_suspend,
+	.resume = mpu3050_resume,
+	.freeze = mpu3050_suspend,
+	.thaw = mpu3050_resume,
+	.poweroff = mpu3050_suspend,
+	.restore = mpu3050_resume,
+};
 
 static const struct i2c_device_id mpu3050_ids[] = {
 	{ "mpu3050", 0 },
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 755084c..7152ec8 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -2424,6 +2424,8 @@
 		}
 	}
 
+	INIT_LIST_HEAD(&rmi->support_fn_list);
+
 	retval = synaptics_rmi4_query_device(rmi4_data);
 	if (retval < 0) {
 		dev_err(&rmi4_data->i2c_client->dev,
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 7954296..e776dbb 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -713,7 +713,7 @@
 			duty_us = (led->mpp_cfg->pwm_cfg->pwm_period_us *
 					led->cdev.brightness) / LED_FULL;
 			/*config pwm for brightness scaling*/
-			rc = pwm_config(led->mpp_cfg->pwm_cfg->pwm_dev,
+			rc = pwm_config_us(led->mpp_cfg->pwm_cfg->pwm_dev,
 					duty_us,
 					led->mpp_cfg->pwm_cfg->pwm_period_us);
 			if (rc < 0) {
@@ -1239,7 +1239,7 @@
 		if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) {
 			duty_us = (led->kpdbl_cfg->pwm_cfg->pwm_period_us *
 				led->cdev.brightness) / KPDBL_MAX_LEVEL;
-			rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev,
+			rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev,
 					duty_us,
 					led->kpdbl_cfg->pwm_cfg->pwm_period_us);
 			if (rc < 0) {
@@ -1261,7 +1261,7 @@
 			led->kpdbl_cfg->pwm_cfg->default_mode;
 
 		if (led->kpdbl_cfg->always_on) {
-			rc = pwm_config(led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
+			rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
 					led->kpdbl_cfg->pwm_cfg->pwm_period_us);
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev,
@@ -1310,7 +1310,8 @@
 		if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
 			duty_us = (led->rgb_cfg->pwm_cfg->pwm_period_us *
 				led->cdev.brightness) / LED_FULL;
-			rc = pwm_config(led->rgb_cfg->pwm_cfg->pwm_dev, duty_us,
+			rc = pwm_config_us(led->rgb_cfg->pwm_cfg->pwm_dev,
+					duty_us,
 					led->rgb_cfg->pwm_cfg->pwm_period_us);
 			if (rc < 0) {
 				dev_err(&led->spmi_dev->dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 2be1f01..59b648d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -122,6 +122,8 @@
 {
 	int i, rc = -1;
 	struct msm_isp_buffer_mapped_info *mapped_info;
+	struct buffer_cmd *buf_pending = NULL;
+
 	for (i = 0; i < v4l2_buf->length; i++) {
 		mapped_info = &buf_info->mapped_info[i];
 		mapped_info->handle =
@@ -144,6 +146,15 @@
 		mapped_info->paddr += v4l2_buf->m.planes[i].data_offset;
 		CDBG("%s: plane: %d addr:%lu\n",
 			__func__, i, mapped_info->paddr);
+
+		buf_pending = kzalloc(sizeof(struct buffer_cmd), GFP_ATOMIC);
+		if (!buf_pending) {
+			pr_err("No free memory for buf_pending\n");
+			return rc;
+		}
+
+		buf_pending->mapped_info = mapped_info;
+		list_add_tail(&buf_pending->list, &buf_mgr->buffer_q);
 	}
 	buf_info->num_planes = v4l2_buf->length;
 	return 0;
@@ -163,11 +174,26 @@
 {
 	int i;
 	struct msm_isp_buffer_mapped_info *mapped_info;
+	struct buffer_cmd *buf_pending = NULL;
+
 	for (i = 0; i < buf_info->num_planes; i++) {
 		mapped_info = &buf_info->mapped_info[i];
-		ion_unmap_iommu(buf_mgr->client, mapped_info->handle,
-			buf_mgr->iommu_domain_num, 0);
-		ion_free(buf_mgr->client, mapped_info->handle);
+
+		list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) {
+			if (!buf_pending)
+				break;
+
+			if (buf_pending->mapped_info == mapped_info) {
+				ion_unmap_iommu(buf_mgr->client,
+					mapped_info->handle,
+					buf_mgr->iommu_domain_num, 0);
+				ion_free(buf_mgr->client, mapped_info->handle);
+
+				list_del_init(&buf_pending->list);
+				kfree(buf_pending);
+				break;
+			}
+		}
 	}
 	return;
 }
@@ -586,7 +612,7 @@
 		}
 	} else {
 		bufq = msm_isp_get_bufq(buf_mgr, info->handle);
-		if (BUF_SRC(bufq->stream_id)) {
+		if (bufq && BUF_SRC(bufq->stream_id)) {
 			rc = msm_isp_put_buf(buf_mgr,
 					info->handle, info->buf_idx);
 			if (rc < 0) {
@@ -691,6 +717,7 @@
 		if (!bufq->bufq_handle)
 			continue;
 		msm_isp_buf_unprepare(buf_mgr, bufq->bufq_handle);
+
 		kfree(bufq->bufs);
 		msm_isp_free_buf_handle(buf_mgr, bufq->bufq_handle);
 	}
@@ -739,9 +766,10 @@
 		pr_err("Invalid buffer queue number\n");
 		return rc;
 	}
-
 	CDBG("%s: E\n", __func__);
+
 	msm_isp_attach_ctx(buf_mgr);
+	INIT_LIST_HEAD(&buf_mgr->buffer_q);
 	buf_mgr->num_buf_q = num_buf_q;
 	buf_mgr->bufq =
 		kzalloc(sizeof(struct msm_isp_bufq) * num_buf_q,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
index 6d6ff9d..d8d3ba2 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
@@ -44,6 +44,11 @@
 	struct ion_handle *handle;
 };
 
+struct buffer_cmd {
+	struct list_head list;
+	struct msm_isp_buffer_mapped_info *mapped_info;
+};
+
 struct msm_isp_buffer {
 	/*Common Data structure*/
 	int num_planes;
@@ -138,6 +143,7 @@
 
 	int num_iommu_ctx;
 	struct device *iommu_ctx[2];
+	struct list_head buffer_q;
 };
 
 int msm_isp_create_isp_buf_mgr(struct msm_isp_buf_mgr *buf_mgr,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index 2c5e136..80a0073 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -140,6 +140,7 @@
 		&vfe_vb2_ops, &vfe_layout);
 	if (rc < 0) {
 		pr_err("%s: Unable to create buffer manager\n", __func__);
+		msm_sd_unregister(&vfe_dev->subdev);
 		kfree(vfe_dev);
 		return -EINVAL;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 87bffde..9dd0085 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -106,7 +106,7 @@
 		uint32_t reload_mask);
 	void (*enable_wm) (struct vfe_device *vfe_dev,
 		uint8_t wm_idx, uint8_t enable);
-	void (*cfg_io_format) (struct vfe_device *vfe_dev,
+	int32_t (*cfg_io_format) (struct vfe_device *vfe_dev,
 		enum msm_vfe_axi_stream_src stream_src,
 		uint32_t io_format);
 	void (*cfg_framedrop) (struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index f5529cd..410fe8f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -74,6 +74,8 @@
 			goto fs_failed;
 		}
 	}
+	else
+		goto fs_failed;
 
 	rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info,
 		 vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1);
@@ -495,12 +497,17 @@
 	}
 }
 
-static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
+static int32_t msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
 	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
 {
 	int bpp, bpp_reg = 0, pack_fmt = 0, pack_reg = 0;
 	uint32_t io_format_reg;
 	bpp = msm_isp_get_bit_per_pixel(io_format);
+	if (bpp < 0) {
+		pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+			io_format, bpp);
+		return -EINVAL;
+	}
 
 	switch (bpp) {
 	case 8:
@@ -512,6 +519,9 @@
 	case 12:
 		bpp_reg = 1 << 1;
 		break;
+	default:
+		pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+		return -EINVAL;
 	}
 
 	if (stream_src == IDEAL_RAW) {
@@ -537,7 +547,7 @@
 			break;
 		default:
 			pr_err("%s: invalid pack fmt!\n", __func__);
-			return;
+			return -EINVAL;
 		}
 	}
 
@@ -558,9 +568,10 @@
 	case RDI_INTF_2:
 	default:
 		pr_err("%s: Invalid stream source\n", __func__);
-		return;
+		return -EINVAL;
 	}
 	msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x6F8);
+	return 0;
 }
 
 static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 50a25bd..ad4b75f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -268,6 +268,8 @@
 			goto fs_failed;
 		}
 	}
+	else
+		goto fs_failed;
 
 	rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe40_clk_info,
 		vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe40_clk_info), 1);
@@ -724,13 +726,18 @@
 			VFE40_WM_BASE(stream_info->wm[i]) + 0x1C);
 }
 
-static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
+static int32_t msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
 	enum msm_vfe_axi_stream_src stream_src, uint32_t io_format)
 {
 	int bpp, bpp_reg = 0, pack_reg = 0;
 	enum msm_isp_pack_fmt pack_fmt = 0;
 	uint32_t io_format_reg; /*io format register bit*/
 	bpp = msm_isp_get_bit_per_pixel(io_format);
+	if (bpp < 0) {
+		pr_err("%s:%d invalid io_format %d bpp %d", __func__, __LINE__,
+			io_format, bpp);
+		return -EINVAL;
+	}
 
 	switch (bpp) {
 	case 8:
@@ -742,6 +749,9 @@
 	case 12:
 		bpp_reg = 1 << 1;
 		break;
+	default:
+		pr_err("%s:%d invalid bpp %d", __func__, __LINE__, bpp);
+		return -EINVAL;
 	}
 
 	if (stream_src == IDEAL_RAW) {
@@ -768,7 +778,7 @@
 			break;
 		default:
 			pr_err("%s: invalid pack fmt!\n", __func__);
-			return;
+			return -EINVAL;
 		}
 	}
 
@@ -789,9 +799,10 @@
 	case RDI_INTF_2:
 	default:
 		pr_err("%s: Invalid stream source\n", __func__);
-		return;
+		return -EINVAL;
 	}
 	msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x54);
+	return 0;
 }
 
 static void msm_vfe40_cfg_camif(struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 3202cdb..97b6347 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -68,9 +68,17 @@
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
 {
 	int rc = -1, i;
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-			HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
+	struct msm_vfe_axi_stream *stream_info = NULL;
+	uint32_t idx = 0;
+
+	if (NULL == stream_cfg_cmd || NULL == axi_data)
+		return rc;
+
+	idx = HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle);
+	if (idx < MAX_NUM_STREAM)
+		stream_info = &axi_data->stream_info[idx];
+	else
+		return rc;
 
 	switch (stream_cfg_cmd->output_format) {
 	case V4L2_PIX_FMT_SBGGR8:
@@ -428,11 +436,22 @@
 	struct msm_vfe_axi_shared_data *axi_data,
 	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
 {
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-		HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
-	uint32_t framedrop_period = msm_isp_get_framedrop_period(
-	   stream_cfg_cmd->frame_skip_pattern);
+	struct msm_vfe_axi_stream *stream_info = NULL;
+	uint32_t framedrop_period = 0;
+	uint8_t idx = 0;
+
+	if (NULL == axi_data || NULL == stream_cfg_cmd)
+		return;
+
+	idx = HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle);
+
+	if (idx < MAX_NUM_STREAM)
+		stream_info = &axi_data->stream_info[idx];
+	else
+		return;
+
+	framedrop_period = msm_isp_get_framedrop_period(
+			stream_cfg_cmd->frame_skip_pattern);
 
 	if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
 		stream_info->framedrop_pattern = 0x0;
@@ -520,8 +539,17 @@
 
 			io_format = stream_info->output_format;
 		}
-		vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
+		rc = vfe_dev->hw_info->vfe_ops.axi_ops.cfg_io_format(
 			vfe_dev, stream_info->stream_src, io_format);
+		if (rc) {
+			pr_err("%s: cfg io format failed\n", __func__);
+			msm_isp_axi_free_wm(&vfe_dev->axi_data,
+				stream_info);
+			msm_isp_axi_destroy_stream(&vfe_dev->axi_data,
+				HANDLE_TO_IDX(
+				stream_cfg_cmd->axi_stream_handle));
+			return rc;
+		}
 	}
 
 	msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
@@ -763,8 +791,9 @@
 	rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
 			vfe_dev->pdev->id, bufq_handle, &buf);
 	if (rc < 0) {
-		vfe_dev->error_info.
-			stream_framedrop_count[stream_idx]++;
+		if(stream_idx < MAX_NUM_STREAM)
+			vfe_dev->error_info.
+				stream_framedrop_count[stream_idx]++;
 		return rc;
 	}
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index b479857..8b83144 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -39,8 +39,9 @@
 	rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
 			vfe_dev->pdev->id, bufq_handle, &buf);
 	if (rc < 0) {
-		vfe_dev->error_info.stats_framedrop_count[
-			STATS_IDX(stream_info->stream_handle)]++;
+		uint8_t idx = STATS_IDX(stream_info->stream_handle);
+		if (idx < MSM_ISP_STATS_MAX)
+			vfe_dev->error_info.stats_framedrop_count[idx]++;
 		return rc;
 	}
 
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index ea0195d..3cb48d1 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -77,6 +77,25 @@
 	.name = "msm_camera_isp",
 };
 
+static void msm_isp_print_fourcc_error(const char *origin,
+	uint32_t fourcc_format)
+{
+	int i;
+	char text[5];
+	text[4] = '\0';
+	for (i = 0; i < 4; i++) {
+		text[i] = (char)(((fourcc_format) >> (i * 8)) & 0xFF);
+		if ((text[i] < '0') || (text[i] > 'z')) {
+			pr_err("%s: Invalid output format %d (unprintable)\n",
+				origin, fourcc_format);
+			return;
+		}
+	}
+	pr_err("%s: Invalid output format %s\n",
+		origin, text);
+	return;
+}
+
 int msm_isp_init_bandwidth_mgr(enum msm_isp_hw_client client)
 {
 	int rc = 0;
@@ -735,7 +754,7 @@
 		break;
 		/*TD: Add more image format*/
 	default:
-		pr_err("%s: Invalid output format\n", __func__);
+		msm_isp_print_fourcc_error(__func__, output_format);
 		break;
 	}
 	return val;
@@ -771,7 +790,7 @@
 	case V4L2_PIX_FMT_QRGGB12:
 		return QCOM;
 	default:
-		pr_err("%s: Invalid output format\n", __func__);
+		msm_isp_print_fourcc_error(__func__, output_format);
 		break;
 	}
 	return -EINVAL;
@@ -780,6 +799,10 @@
 int msm_isp_get_bit_per_pixel(uint32_t output_format)
 {
 	switch (output_format) {
+	case V4L2_PIX_FMT_Y4:
+		return 4;
+	case V4L2_PIX_FMT_Y6:
+		return 6;
 	case V4L2_PIX_FMT_SBGGR8:
 	case V4L2_PIX_FMT_SGBRG8:
 	case V4L2_PIX_FMT_SGRBG8:
@@ -790,6 +813,29 @@
 	case V4L2_PIX_FMT_QRGGB8:
 	case V4L2_PIX_FMT_JPEG:
 	case V4L2_PIX_FMT_META:
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV14:
+	case V4L2_PIX_FMT_NV41:
+	case V4L2_PIX_FMT_YVU410:
+	case V4L2_PIX_FMT_YVU420:
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YYUV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
+	case V4L2_PIX_FMT_YUV422P:
+	case V4L2_PIX_FMT_YUV411P:
+	case V4L2_PIX_FMT_Y41P:
+	case V4L2_PIX_FMT_YUV444:
+	case V4L2_PIX_FMT_YUV555:
+	case V4L2_PIX_FMT_YUV565:
+	case V4L2_PIX_FMT_YUV32:
+	case V4L2_PIX_FMT_YUV410:
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_GREY:
+	case V4L2_PIX_FMT_PAL8:
+	case MSM_V4L2_PIX_FMT_META:
 		return 8;
 	case V4L2_PIX_FMT_SBGGR10:
 	case V4L2_PIX_FMT_SGBRG10:
@@ -799,6 +845,8 @@
 	case V4L2_PIX_FMT_QGBRG10:
 	case V4L2_PIX_FMT_QGRBG10:
 	case V4L2_PIX_FMT_QRGGB10:
+	case V4L2_PIX_FMT_Y10:
+	case V4L2_PIX_FMT_Y10BPACK:
 		return 10;
 	case V4L2_PIX_FMT_SBGGR12:
 	case V4L2_PIX_FMT_SGBRG12:
@@ -808,21 +856,17 @@
 	case V4L2_PIX_FMT_QGBRG12:
 	case V4L2_PIX_FMT_QGRBG12:
 	case V4L2_PIX_FMT_QRGGB12:
+	case V4L2_PIX_FMT_Y12:
 		return 12;
-	case V4L2_PIX_FMT_NV12:
-	case V4L2_PIX_FMT_NV21:
-	case V4L2_PIX_FMT_NV14:
-	case V4L2_PIX_FMT_NV41:
-		return 8;
 	case V4L2_PIX_FMT_NV16:
 	case V4L2_PIX_FMT_NV61:
+	case V4L2_PIX_FMT_Y16:
 		return 16;
 		/*TD: Add more image format*/
 	default:
-		pr_err("%s: Invalid output format\n", __func__);
-		break;
+		msm_isp_print_fourcc_error(__func__, output_format);
+		return -EINVAL;
 	}
-	return -EINVAL;
 }
 
 void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev)
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 8f080ce..407b81f 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -31,14 +31,19 @@
 int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
 		long clk_rate)
 {
-	struct msm_cam_clk_info jpeg_core_clk_info[] = {
-		{"core_clk", JPEG_CLK_RATE, 0}
-	};
+	int rc = 0;
+	struct clk *jpeg_clk;
 
-	jpeg_core_clk_info[0].clk_rate = clk_rate;
+	jpeg_clk = clk_get(&pgmn_dev->pdev->dev, "core_clk");
+	if (IS_ERR(jpeg_clk)) {
+		JPEG_PR_ERR("%s get failed\n", "core_clk");
+		rc = PTR_ERR(jpeg_clk);
+		return rc;
+	}
 
-	return msm_cam_clk_enable(&pgmn_dev->pdev->dev, jpeg_core_clk_info,
-			pgmn_dev->jpeg_clk, ARRAY_SIZE(jpeg_core_clk_info), 1);
+	rc = clk_set_rate(jpeg_clk, clk_rate);
+
+	return rc;
 }
 
 void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file  *file,
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index c79b3a3..8a2c8e5 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -1001,8 +1001,10 @@
 	video_set_drvdata(pvdev->vdev, pvdev);
 
 	msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL);
-	if (WARN_ON(!msm_session_q))
-		goto v4l2_fail;
+	if (WARN_ON(!msm_session_q)) {
+		rc = -ENOMEM;
+		goto session_fail;
+	}
 
 	msm_init_queue(msm_session_q);
 	spin_lock_init(&msm_eventq_lock);
@@ -1010,6 +1012,8 @@
 	INIT_LIST_HEAD(&ordered_sd_list);
 	goto probe_end;
 
+session_fail:
+	video_unregister_device(pvdev->vdev);
 v4l2_fail:
 	v4l2_device_unregister(pvdev->vdev->v4l2_dev);
 register_fail:
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 69f0a3d..532bebc 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1845,6 +1845,11 @@
 	cpp_dev->timer_wq = create_workqueue("msm_cpp_workqueue");
 	cpp_dev->work = kmalloc(sizeof(struct msm_cpp_work_t),
 		GFP_KERNEL);
+	if (!cpp_dev->work) {
+		pr_err("cpp_dev->work is NULL\n");
+		rc = -ENOMEM;
+		goto ERROR3;
+	}
 	INIT_WORK((struct work_struct *)cpp_dev->work, msm_cpp_do_timeout_work);
 	cpp_dev->cpp_open_cnt = 0;
 	cpp_dev->is_firmware_loaded = 0;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
index dc29199..8d14363 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -691,43 +691,47 @@
 
 	if (queue->len > 0) {
 		frame_qcmd = msm_dequeue(queue, list_frame);
-		processed_frame = frame_qcmd->command;
-		do_gettimeofday(&(processed_frame->out_time));
-		kfree(frame_qcmd);
-		event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
-		if (!event_qcmd) {
-			pr_err("%s: Insufficient memory\n", __func__);
-			return -ENOMEM;
-		}
-		atomic_set(&event_qcmd->on_heap, 1);
-		event_qcmd->command = processed_frame;
-		VPE_DBG("fid %d\n", processed_frame->frame_id);
-		msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
+		if(frame_qcmd) {
+			processed_frame = frame_qcmd->command;
+			do_gettimeofday(&(processed_frame->out_time));
+			kfree(frame_qcmd);
+			event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+			if (!event_qcmd) {
+				pr_err("%s: Insufficient memory\n", __func__);
+				return -ENOMEM;
+			}
+			atomic_set(&event_qcmd->on_heap, 1);
+			event_qcmd->command = processed_frame;
+			VPE_DBG("fid %d\n", processed_frame->frame_id);
+			msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
 
-		if (!processed_frame->output_buffer_info.processed_divert) {
-			memset(&buff_mgr_info, 0 ,
-				sizeof(buff_mgr_info));
-			buff_mgr_info.session_id =
-				((processed_frame->identity >> 16) & 0xFFFF);
-			buff_mgr_info.stream_id =
-				(processed_frame->identity & 0xFFFF);
-			buff_mgr_info.frame_id = processed_frame->frame_id;
-			buff_mgr_info.timestamp = processed_frame->timestamp;
-			buff_mgr_info.index =
-				processed_frame->output_buffer_info.index;
-			rc = msm_vpe_buffer_ops(vpe_dev,
+			if (!processed_frame->output_buffer_info.processed_divert) {
+				memset(&buff_mgr_info, 0 ,
+					sizeof(buff_mgr_info));
+				buff_mgr_info.session_id =
+					((processed_frame->identity >> 16) & 0xFFFF);
+				buff_mgr_info.stream_id =
+					(processed_frame->identity & 0xFFFF);
+				buff_mgr_info.frame_id = processed_frame->frame_id;
+				buff_mgr_info.timestamp = processed_frame->timestamp;
+				buff_mgr_info.index =
+					processed_frame->output_buffer_info.index;
+				rc = msm_vpe_buffer_ops(vpe_dev,
 						VIDIOC_MSM_BUF_MNGR_BUF_DONE,
 						&buff_mgr_info);
-			if (rc < 0) {
-				pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
-					__func__);
-				rc = -EINVAL;
+				if (rc < 0) {
+					pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
+						__func__);
+					rc = -EINVAL;
+				}
 			}
-		}
 
-		v4l2_evt.id = processed_frame->inst_id;
-		v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
-		v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+			v4l2_evt.id = processed_frame->inst_id;
+			v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
+			v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+		}
+		else
+			rc = -EFAULT;
 	}
 	return rc;
 }
@@ -1368,6 +1372,8 @@
 		struct msm_vpe_frame_info_t *process_frame;
 		VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n");
 		event_qcmd = msm_dequeue(queue, list_eventdata);
+		if (NULL == event_qcmd)
+			break;
 		process_frame = event_qcmd->command;
 		VPE_DBG("fid %d\n", process_frame->frame_id);
 		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 45db19c..69c1faa 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -809,6 +809,7 @@
 	e_ctrl->is_supported = 0;
 	if (!of_node) {
 		pr_err("%s dev.of_node NULL\n", __func__);
+		kfree(e_ctrl);
 		return -EINVAL;
 	}
 
@@ -817,6 +818,7 @@
 	CDBG("cell-index %d, rc %d\n", pdev->id, rc);
 	if (rc < 0) {
 		pr_err("failed rc %d\n", rc);
+		kfree(e_ctrl);
 		return rc;
 	}
 	e_ctrl->subdev_id = pdev->id;
@@ -826,12 +828,14 @@
 	CDBG("qcom,cci-master %d, rc %d\n", e_ctrl->cci_master, rc);
 	if (rc < 0) {
 		pr_err("%s failed rc %d\n", __func__, rc);
+		kfree(e_ctrl);
 		return rc;
 	}
 	rc = of_property_read_u32(of_node, "qcom,slave-addr",
 		&temp);
 	if (rc < 0) {
 		pr_err("%s failed rc %d\n", __func__, rc);
+		kfree(e_ctrl);
 		return rc;
 	}
 
@@ -844,6 +848,7 @@
 		struct msm_camera_cci_client), GFP_KERNEL);
 	if (!e_ctrl->i2c_client.cci_client) {
 		pr_err("%s failed no memory\n", __func__);
+		kfree(e_ctrl);
 		return -ENOMEM;
 	}
 
@@ -936,6 +941,7 @@
 	kfree(e_ctrl->eboard_info);
 cciclient_free:
 	kfree(e_ctrl->i2c_client.cci_client);
+	kfree(e_ctrl);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 699142a..b88ac00 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -71,9 +71,9 @@
 	case MSM_CAMERA_LED_LOW:
 		if (fctrl->torch_trigger) {
 			max_curr_l = fctrl->torch_max_current;
-			if (cfg->led_current > 0 &&
-					cfg->led_current < max_curr_l) {
-				curr_l = cfg->led_current;
+			if (cfg->torch_current > 0 &&
+					cfg->torch_current < max_curr_l) {
+				curr_l = cfg->torch_current;
 			} else {
 				curr_l = fctrl->torch_op_current;
 				pr_err("LED current clamped to %d\n",
@@ -90,9 +90,9 @@
 		for (i = 0; i < fctrl->num_sources; i++)
 			if (fctrl->flash_trigger[i]) {
 				max_curr_l = fctrl->flash_max_current[i];
-				if (cfg->led_current > 0 &&
-						cfg->led_current < max_curr_l) {
-					curr_l = cfg->led_current;
+				if (cfg->flash_current[i] > 0 &&
+						cfg->flash_current[i] < max_curr_l) {
+					curr_l = cfg->flash_current[i];
 				} else {
 					curr_l = fctrl->flash_op_current[i];
 					pr_err("LED current clamped to %d\n",
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 19a378f..5694658 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -3964,6 +3964,58 @@
 }
 EXPORT_SYMBOL(mpq_dmx_set_cipher_ops);
 
+static int mpq_sdmx_invalidate_buffer(struct mpq_feed *mpq_feed)
+{
+	struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+	struct mpq_video_feed_info *feed_data;
+	struct dvb_ringbuffer *buffer;
+	struct ion_handle *ion_handle;
+	int ret = 0;
+	int i;
+
+	if (!dvb_dmx_is_video_feed(feed)) {
+		if (dvb_dmx_is_sec_feed(feed) ||
+			dvb_dmx_is_pcr_feed(feed)) {
+			buffer = (struct dvb_ringbuffer *)
+				&mpq_feed->sdmx_buf;
+			ion_handle = mpq_feed->sdmx_buf_handle;
+		} else {
+			buffer = (struct dvb_ringbuffer *)
+				feed->feed.ts.buffer.ringbuff;
+			ion_handle = feed->feed.ts.buffer.priv_handle;
+		}
+
+		ret = msm_ion_do_cache_op(mpq_feed->mpq_demux->ion_client,
+			ion_handle, buffer->data,
+			buffer->size, ION_IOC_INV_CACHES);
+		if (ret)
+			MPQ_DVB_ERR_PRINT(
+				"%s: msm_ion_do_cache_op failed, ret = %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	/* Video buffers */
+	feed_data = &mpq_feed->video_info;
+	for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+		if (feed_data->buffer_desc.desc[i].base) {
+			/* Non-secured buffer */
+			ret = msm_ion_do_cache_op(
+				mpq_feed->mpq_demux->ion_client,
+				feed_data->buffer_desc.ion_handle[i],
+				feed_data->buffer_desc.desc[i].base,
+				feed_data->buffer_desc.desc[i].size,
+				ION_IOC_INV_CACHES);
+			if (ret)
+				MPQ_DVB_ERR_PRINT(
+					"%s: msm_ion_do_cache_op failed, ret = %d\n",
+					__func__, ret);
+		}
+	}
+
+	return ret;
+}
+
 static void mpq_sdmx_prepare_filter_status(struct mpq_demux *mpq_demux,
 	struct sdmx_filter_status *filter_sts,
 	struct mpq_feed *mpq_feed)
@@ -4757,6 +4809,9 @@
 			 mpq_feed->session_id))
 			continue;
 
+		/* Invalidate output buffer before processing the results */
+		mpq_sdmx_invalidate_buffer(mpq_feed);
+
 		if (sts->error_indicators & SDMX_FILTER_ERR_MD_BUF_FULL)
 			MPQ_DVB_ERR_PRINT(
 				"%s: meta-data buff for pid %d overflowed!\n",
@@ -4831,7 +4886,6 @@
 	for (i = 0; i < MPQ_MAX_DMX_FILES; i++) {
 		mpq_feed = &mpq_demux->feeds[i];
 		if ((mpq_feed->sdmx_filter_handle != SDMX_INVALID_FILTER_HANDLE)
-			&& (mpq_feed->dvb_demux_feed->state == DMX_STATE_GO)
 			&& (!mpq_feed->secondary_feed)) {
 			sts = mpq_demux->sdmx_filters_state.status +
 				filter_index;
@@ -4950,6 +5004,10 @@
 	const char *buf,
 	size_t count)
 {
+	struct ion_handle *ion_handle =
+		mpq_demux->demux.dmx.dvr_input.priv_handle;
+	struct dvb_ringbuffer *rbuf = (struct dvb_ringbuffer *)
+		mpq_demux->demux.dmx.dvr_input.ringbuff;
 	struct sdmx_buff_descr buf_desc;
 	u32 read_offset;
 	int ret;
@@ -4968,6 +5026,19 @@
 	}
 	read_offset = mpq_demux->demux.dmx.dvr_input.ringbuff->pread;
 
+
+	/*
+	 * We must flush the buffer before SDMX starts reading from it
+	 * so that it gets a valid data in memory.
+	 */
+	ret = msm_ion_do_cache_op(mpq_demux->ion_client,
+		ion_handle, rbuf->data,
+		rbuf->size, ION_IOC_CLEAN_CACHES);
+	if (ret)
+		MPQ_DVB_ERR_PRINT(
+			"%s: msm_ion_do_cache_op failed, ret = %d\n",
+			__func__, ret);
+
 	return mpq_sdmx_process(mpq_demux, &buf_desc, count,
 				read_offset, mpq_demux->demux.ts_packet_size);
 }
diff --git a/drivers/media/radio/radio-iris-transport.c b/drivers/media/radio/radio-iris-transport.c
index 9a9b385..d3fe11c 100644
--- a/drivers/media/radio/radio-iris-transport.c
+++ b/drivers/media/radio/radio-iris-transport.c
@@ -105,6 +105,7 @@
 	skb = alloc_skb(len, GFP_ATOMIC);
 	if (!skb) {
 		FMDERR("Memory not allocated for the socket");
+		kfree(worker);
 		return;
 	}
 
@@ -153,7 +154,13 @@
 	struct radio_hci_dev *hdev;
 	int rc;
 
+	if (hsmd == NULL)
+		return -ENODEV;
+
 	hdev = kmalloc(sizeof(struct radio_hci_dev), GFP_KERNEL);
+	if (hdev == NULL)
+		return -ENODEV;
+
 	hsmd->hdev = hdev;
 	tasklet_init(&hsmd->rx_task, radio_hci_smd_recv_event,
 		(unsigned long) hsmd);
@@ -166,6 +173,8 @@
 
 	if (rc < 0) {
 		FMDERR("Cannot open the command channel");
+		hsmd->hdev = NULL;
+		kfree(hdev);
 		return -ENODEV;
 	}
 
@@ -173,6 +182,9 @@
 
 	if (radio_hci_register_dev(hdev) < 0) {
 		FMDERR("Can't register HCI device");
+		smd_close(hsmd->fm_channel);
+		hsmd->hdev = NULL;
+		kfree(hdev);
 		return -ENODEV;
 	}
 
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index a554749..5dde469 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -88,7 +88,7 @@
 
 	struct radio_hci_dev *fm_hdev;
 
-	struct v4l2_capability *g_cap;
+	struct v4l2_capability g_cap;
 	struct v4l2_control *g_ctl;
 
 	struct hci_fm_mute_mode_req mute_mode;
@@ -1825,7 +1825,7 @@
 		return;
 	}
 
-	v4l_cap = radio->g_cap;
+	v4l_cap = &radio->g_cap;
 
 	if (rsp->status)
 		return;
@@ -3159,7 +3159,7 @@
 			struct v4l2_ext_controls *ctrl)
 {
 	int retval = 0;
-	int bytes_to_copy;
+	size_t bytes_to_copy;
 	struct hci_fm_tx_ps tx_ps;
 	struct hci_fm_tx_rt tx_rt;
 	struct hci_fm_def_data_wr_req default_data;
@@ -3168,18 +3168,20 @@
 	struct iris_device *radio = video_get_drvdata(video_devdata(file));
 	char *data = NULL;
 
-	if (radio == NULL) {
-		FMDERR(":radio is null");
-		return -EINVAL;
+	if ((ctrl == NULL) || (ctrl->controls == NULL)
+		|| (ctrl->count == 0)) {
+		retval = -EINVAL;
+		return retval;
 	}
+
 	switch ((ctrl->controls[0]).id) {
 	case V4L2_CID_RDS_TX_PS_NAME:
 		FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
 		/*Pass a sample PS string */
 
 		memset(tx_ps.ps_data, 0, MAX_PS_LENGTH);
-		bytes_to_copy = min((int)(ctrl->controls[0]).size,
-			MAX_PS_LENGTH);
+		bytes_to_copy = min(ctrl->controls[0].size,
+			(size_t)MAX_PS_LENGTH);
 		data = (ctrl->controls[0]).string;
 
 		if (copy_from_user(tx_ps.ps_data,
@@ -3196,7 +3198,7 @@
 		break;
 	case V4L2_CID_RDS_TX_RADIO_TEXT:
 		bytes_to_copy =
-		    min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
+		    min((ctrl->controls[0]).size, (size_t)MAX_RT_LENGTH);
 		data = (ctrl->controls[0]).string;
 
 		memset(tx_rt.rt_data, 0, MAX_RT_LENGTH);
@@ -4298,8 +4300,12 @@
 	}
 	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
-	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-	radio->g_cap = capability;
+
+	strlcpy(radio->g_cap.driver, DRIVER_NAME, sizeof(radio->g_cap.driver));
+	strlcpy(radio->g_cap.card, DRIVER_CARD, sizeof(radio->g_cap.card));
+
+	radio->g_cap.capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	capability->capabilities = radio->g_cap.capabilities;
 	return 0;
 }
 
@@ -4470,11 +4476,11 @@
 		if (kfifo_alloc_rc != 0) {
 			FMDERR("failed allocating buffers %d\n",
 				   kfifo_alloc_rc);
-			for (; i > -1; i--) {
+			for (; i > -1; i--)
 				kfifo_free(&radio->data_buf[i]);
-				kfree(radio);
-				return -ENOMEM;
-			}
+			video_device_release(radio->videodev);
+			kfree(radio);
+			return -ENOMEM;
 		}
 	}
 
@@ -4502,8 +4508,17 @@
 	} else {
 		priv_videodev = kzalloc(sizeof(struct video_device),
 			GFP_KERNEL);
-		memcpy(priv_videodev, radio->videodev,
-			sizeof(struct video_device));
+		if (priv_videodev != NULL) {
+			memcpy(priv_videodev, radio->videodev,
+				sizeof(struct video_device));
+		} else {
+			video_unregister_device(radio->videodev);
+			video_device_release(radio->videodev);
+			for (; i > -1; i--)
+				kfifo_free(&radio->data_buf[i]);
+			kfree(radio);
+			return -ENOMEM;
+		}
 	}
 	return 0;
 }
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 6b9f2b3..c44e2a5 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -185,6 +185,10 @@
 	if (bahama_present == -ENODEV)
 		return -ENODEV;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
 	if (bahama_present)
 		radio->marimba->mod_id = SLAVE_ID_BAHAMA_FM;
 	else
@@ -216,6 +220,11 @@
    * (otherwise, it may have already been there and will not be added a second
    * time).
    */
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
 	queue_delayed_work(radio->wqueue, &radio->work,
 				msecs_to_jiffies(TAVARUA_DELAY));
 	return IRQ_HANDLED;
@@ -243,6 +252,12 @@
 				unsigned char offset, int len)
 {
 	int retval = 0, i = 0;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	retval = set_fm_slave_id(radio);
 
 	if (retval == -ENODEV)
@@ -282,6 +297,12 @@
 			unsigned char offset, unsigned char value)
 {
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	retval = set_fm_slave_id(radio);
 
 	if (retval == -ENODEV)
@@ -322,6 +343,12 @@
 
 	int i;
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	retval = set_fm_slave_id(radio);
 
 	if (retval == -ENODEV)
@@ -358,6 +385,11 @@
 */
 static int read_data_blocks(struct tavarua_device *radio, unsigned char offset)
 {
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	/* read all 3 RDS blocks */
 	return tavarua_read_registers(radio, offset, RDS_BLOCK*4);
 }
@@ -376,10 +408,17 @@
 */
 static void tavarua_rds_read(struct tavarua_device *radio)
 {
-	struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+	struct kfifo *rds_buf;
 	unsigned char blocknum;
 	unsigned char tmp[3];
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
+	rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+
 	if (read_data_blocks(radio, RAW_RDS) < 0)
 		return;
 	 /* copy all four RDS blocks to internal buffer */
@@ -430,6 +469,12 @@
 static int request_read_xfr(struct tavarua_device *radio,
 				enum tavarua_xfr_ctrl_t mode){
 
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	tavarua_write_register(radio, XFRCTRL, mode);
 	msleep(TAVARUA_DELAY);
 	return 0;
@@ -457,8 +502,17 @@
 static int copy_from_xfr(struct tavarua_device *radio,
 		enum tavarua_buf_t buf_type, unsigned int n){
 
-	struct kfifo *data_fifo = &radio->data_buf[buf_type];
-	unsigned char *xfr_regs = &radio->registers[XFRCTRL+1];
+	struct kfifo *data_fifo;
+	unsigned char *xfr_regs;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	data_fifo = &radio->data_buf[buf_type];
+	xfr_regs = &radio->registers[XFRCTRL+1];
+
 	kfifo_in_locked(data_fifo, xfr_regs, n, &radio->buf_lock[buf_type]);
 	return 0;
 }
@@ -496,6 +550,12 @@
 			char *buf, int len)
 {
 	char buffer[len+1];
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	memcpy(buffer+1, buf, len);
 	/* buffer[0] corresponds to XFRCTRL register
 	   set the CTRL bit to 1 for write mode
@@ -520,6 +580,11 @@
 static int xfr_intf_own(struct tavarua_device *radio)
 {
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	mutex_lock(&radio->lock);
 	if (radio->xfr_in_progress) {
 		radio->pending_xfrs[TAVARUA_XFR_SYNC] = 1;
@@ -552,6 +617,12 @@
 			enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
 {
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	retval = xfr_intf_own(radio);
 	if (retval < 0)
 		return retval;
@@ -590,6 +661,17 @@
 		enum tavarua_xfr_ctrl_t xfr_type, unsigned char *buf)
 {
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(buf == NULL)) {
+		FMDERR("%s:buf is null", __func__);
+		return -EINVAL;
+	}
+
 	retval = xfr_intf_own(radio);
 	if (retval < 0)
 		return retval;
@@ -627,6 +709,12 @@
 {
 	int i;
 	enum tavarua_xfr_t xfr;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
 	for (i = 0; i < TAVARUA_XFR_MAX; i++) {
 		if (radio->pending_xfrs[i]) {
 			radio->xfr_in_progress = 1;
@@ -681,8 +769,16 @@
 				enum tavarua_evt_t event)
 {
 
-	struct kfifo *data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+	struct kfifo *data_b;
 	unsigned char evt = event;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
+	data_b = &radio->data_buf[TAVARUA_BUF_EVENTS];
+
 	FMDBG("updating event_q with event %x\n", event);
 	if (kfifo_in_locked(data_b, &evt, 1, &radio->buf_lock[TAVARUA_BUF_EVENTS]))
 		wake_up_interruptible(&radio->event_queue);
@@ -707,12 +803,18 @@
 static void tavarua_start_xfr(struct tavarua_device *radio,
 		enum tavarua_xfr_t pending_id, enum tavarua_xfr_ctrl_t xfr_id)
 {
-		if (radio->xfr_in_progress)
-			radio->pending_xfrs[pending_id] = 1;
-		else {
-			radio->xfr_in_progress = 1;
-			request_read_xfr(radio, xfr_id);
-		}
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
+	if (radio->xfr_in_progress)
+		radio->pending_xfrs[pending_id] = 1;
+	else {
+		radio->xfr_in_progress = 1;
+		request_read_xfr(radio, xfr_id);
+	}
 }
 
 /*=============================================================================
@@ -739,6 +841,12 @@
 	int i;
 	int retval, adj_channel_tune_req = 0;
 	unsigned char xfr_status;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
 	if (!radio->handle_irq) {
 		FMDBG("IRQ happend, but I wont handle it\n");
 		return;
@@ -1143,15 +1251,34 @@
 */
 static void read_int_stat(struct work_struct *work)
 {
-	struct tavarua_device *radio = container_of(work,
-					struct tavarua_device, work.work);
+	struct tavarua_device *radio;
+
+	if (unlikely(work == NULL)) {
+		FMDERR("%s:work is null", __func__);
+		return;
+	}
+
+	radio = container_of(work, struct tavarua_device, work.work);
+
 	tavarua_handle_interrupts(radio);
 }
 
 static void fm_shutdown(struct work_struct *work)
 {
-	struct tavarua_device *radio = container_of(work,
-					struct tavarua_device, work.work);
+	struct tavarua_device *radio;
+
+	if (unlikely(work == NULL)) {
+		FMDERR("%s:work is null", __func__);
+		return;
+	}
+
+	radio = container_of(work, struct tavarua_device, work.work);
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return;
+	}
+
 	FMDERR("%s: Releasing the FM I2S GPIO\n", __func__);
 	if (radio->pdata->config_i2s_gpio != NULL)
 		radio->pdata->config_i2s_gpio(FM_I2S_OFF);
@@ -1178,9 +1305,14 @@
 static int tavarua_request_irq(struct tavarua_device *radio)
 {
 	int retval;
-	int irq = radio->pdata->irq;
-	if (radio == NULL)
+	int irq;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
 		return -EINVAL;
+	}
+
+	irq = radio->pdata->irq;
 
   /* A workqueue created with create_workqueue() will have one worker thread
    * for each CPU on the system; create_singlethread_workqueue(), instead,
@@ -1237,8 +1369,12 @@
 static int tavarua_disable_irq(struct tavarua_device *radio)
 {
 	int irq;
-	if (!radio)
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
 		return -EINVAL;
+	}
+
 	irq = radio->pdata->irq;
 	disable_irq_wake(irq);
 	free_irq(irq, radio);
@@ -1255,6 +1391,11 @@
 	unsigned int rdsMask = 0;
 	unsigned char value = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	adie_type_bahma = is_bahama();
 
 	switch (region) {
@@ -1435,9 +1576,17 @@
 */
 static int tavarua_search(struct tavarua_device *radio, int on, int dir)
 {
-	enum search_t srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+	enum search_t srch;
 
 	FMDBG("In tavarua_search\n");
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	srch = radio->registers[SRCHCTRL] & SRCH_MODE;
+
 	if (on) {
 		radio->registers[SRCHRDS1] = 0x00;
 		radio->registers[SRCHRDS2] = 0x00;
@@ -1503,6 +1652,11 @@
 	enum tavarua_region_t region = req_region;
 	unsigned char adie_type_bahma;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	adie_type_bahma = is_bahama();
 
 	/* Set freq band */
@@ -1671,6 +1825,17 @@
 	unsigned short chan;
 	unsigned int band_bottom;
 	unsigned int spacing;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(freq == NULL)) {
+		FMDERR("%s:freq is null", __func__);
+		return -EINVAL;
+	}
+
 	band_bottom = radio->region_params.band_low;
 	spacing  = 0.100 * FREQ_MUL;
 	/* read channel */
@@ -1716,6 +1881,12 @@
 	unsigned char cmd[] = {0x00, 0x00};
 	unsigned int spacing;
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	band_bottom = radio->region_params.band_low;
 	spacing  = 0.100 * FREQ_MUL;
 	if ((freq % 1600) == 800) {
@@ -1760,8 +1931,19 @@
 				size_t count, loff_t *ppos)
 {
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
-	struct kfifo *rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
+	struct kfifo *rds_buf;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(buf == NULL)) {
+		FMDERR("%s:buf is null", __func__);
+		return -EINVAL;
+	}
+
+	rds_buf = &radio->data_buf[TAVARUA_BUF_RAW_RDS];
 	/* block if no new data available */
 	while (!kfifo_len(rds_buf)) {
 		if (file->f_flags & O_NONBLOCK)
@@ -1810,6 +1992,17 @@
 	int bytes_left;
 	int chunk_index = 0;
 	unsigned char tx_data[XFR_REG_NUM];
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(data == NULL)) {
+		FMDERR("%s:data is null", __func__);
+		return -EINVAL;
+	}
+
 	/* Disable TX of this type first */
 	switch (radio->tx_mode) {
 	case TAVARUA_TX_RT:
@@ -1897,6 +2090,11 @@
 	char buffer[] = {0x00, 0x48, 0x8A, 0x8E, 0x97, 0xB7};
 	int bahama_present = -ENODEV;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	INIT_DELAYED_WORK(&radio->work, read_int_stat);
 	if (!atomic_dec_and_test(&radio->users)) {
 		pr_err("%s: Device already in use."
@@ -2518,6 +2716,16 @@
 {
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(capability == NULL)) {
+		FMDERR("%s:capability is null", __func__);
+		return -EINVAL;
+	}
+
 	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
 	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
 	sprintf(capability->bus_info, "I2C");
@@ -2553,6 +2761,12 @@
 	unsigned char i;
 	int retval = -EINVAL;
 
+	if (unlikely(qc == NULL)) {
+		FMDERR("%s:qc is null", __func__);
+		return -EINVAL;
+	}
+
+
 	for (i = 0; i < ARRAY_SIZE(tavarua_v4l2_queryctrl); i++) {
 		if (qc->id && qc->id == tavarua_v4l2_queryctrl[i].id) {
 			memcpy(qc, &(tavarua_v4l2_queryctrl[i]), sizeof(*qc));
@@ -2574,6 +2788,11 @@
 	int index = 0, offset = 0, addr = 0x0, val = 0;
 	int retval = 0, temp = 0, cnt = 0, j = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	memset(xfr_buf, 0x0, XFR_REG_NUM);
 
 	/* Read the SPUR Table Size */
@@ -2651,6 +2870,15 @@
 	unsigned char xfr_buf[XFR_REG_NUM + 1];
 	int retval = 0, temp = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(buf == NULL)) {
+		FMDERR("%s:buf is null", __func__);
+		return -EINVAL;
+	}
 	/* zero initialize the buffer */
 	memset(xfr_buf, 0x0, XFR_REG_NUM);
 
@@ -2725,6 +2953,11 @@
 	int ct = 0;
 	unsigned char size = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	/*
 	Poking the MPX_DCC_BYPASS register to freeze the
 	value of MPX_DCC from changing while we access it
@@ -2844,6 +3077,16 @@
 	signed char ioc;
 	unsigned char size = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(ctrl == NULL)) {
+		FMDERR("%s:ctrl is null", __func__);
+		return -EINVAL;
+	}
+
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
 		break;
@@ -3059,6 +3302,18 @@
 	int extra_name_byte = 0;
 	int name_bytes = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(ctrl == NULL) ||
+		unlikely(ctrl->controls == NULL) ||
+		unlikely(ctrl->count <= 0)) {
+		FMDERR("%s:ctrl is null", __func__);
+		return -EINVAL;
+	}
+
 	switch ((ctrl->controls[0]).id)	{
 	case V4L2_CID_RDS_TX_PS_NAME: {
 		FMDBG("In V4L2_CID_RDS_TX_PS_NAME\n");
@@ -3191,6 +3446,16 @@
 	unsigned int freq = 0, mpx_dcc = 0;
 	unsigned long curr = 0, prev = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(ctrl == NULL)) {
+		FMDERR("%s:ctrl is null", __func__);
+		return -EINVAL;
+	}
+
 	memset(xfr_buf, 0x0, XFR_REG_NUM);
 
 	switch (ctrl->id) {
@@ -3797,6 +4062,16 @@
 	char rmssi = 0;
 	unsigned char size = 0;
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(tuner == NULL)) {
+		FMDERR("%s:tuner is null", __func__);
+		return -EINVAL;
+	}
+
 	if (tuner->index > 0)
 		return -EINVAL;
 
@@ -3863,6 +4138,17 @@
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
 	int retval;
 	int audmode;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(tuner == NULL)) {
+		FMDERR("%s:tuner is null", __func__);
+		return -EINVAL;
+	}
+
 	if (tuner->index > 0)
 		return -EINVAL;
 
@@ -3910,6 +4196,17 @@
 		struct v4l2_frequency *freq)
 {
 	struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(freq == NULL)) {
+		FMDERR("%s:freq is null", __func__);
+		return -EINVAL;
+	}
+
 	freq->type = V4L2_TUNER_RADIO;
 	return tavarua_get_freq(radio, freq);
 
@@ -3945,6 +4242,16 @@
 
 	FMDBG("%s\n", __func__);
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(freq == NULL)) {
+		FMDERR("%s:freq is null", __func__);
+		return -EINVAL;
+	}
+
 	if (freq->type != V4L2_TUNER_RADIO)
 		return -EINVAL;
 
@@ -4108,6 +4415,17 @@
 {
 	struct tavarua_device  *radio = video_get_drvdata(video_devdata(file));
 	int dir;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(seek == NULL)) {
+		FMDERR("%s:seek is null", __func__);
+		return -EINVAL;
+	}
+
 	if (seek->seek_upward)
 		dir = SRCH_DIR_UP;
 	else
@@ -4159,6 +4477,11 @@
 	int retval;
 	unsigned char int_ctrl[XFR_REG_NUM];
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	if (!radio->lp_mode)
 		return 0;
 
@@ -4222,6 +4545,12 @@
 {
 	unsigned char lpm_buf[XFR_REG_NUM];
 	int retval;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	if (radio->lp_mode)
 		return 0;
 	FMDBG("%s\n", __func__);
@@ -4270,6 +4599,12 @@
 
 	int retval;
 	FMDBG("%s <%d>\n", __func__, state);
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	/* set geographic region */
 	radio->region_params.region = TAVARUA_REGION_US;
 
@@ -4305,6 +4640,12 @@
 	int retval;
 	int users = 0;
 	printk(KERN_INFO DRIVER_NAME "%s: radio suspend\n\n", __func__);
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	if (radio) {
 		users = atomic_read(&radio->users);
 		if (!users) {
@@ -4336,6 +4677,12 @@
 	int retval;
 	int users = 0;
 	printk(KERN_INFO DRIVER_NAME "%s: radio resume\n\n", __func__);
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	if (radio) {
 		users = atomic_read(&radio->users);
 
@@ -4380,8 +4727,12 @@
 	struct tavarua_device *radio = private_data;
 	int rx_on = radio->registers[RDCTRL] & FM_RECV;
 	int retval = 0;
-	if (!radio)
-		return -ENOMEM;
+
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	/* RX */
 	FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
 	if ((radio->pdata != NULL) && (radio->pdata->config_i2s_gpio != NULL)) {
@@ -4469,6 +4820,12 @@
 	int retval = 0;
 	int i = 0, j = 0;
 	FMDBG("%s: probe called\n", __func__);
+
+	if (unlikely(pdev == NULL)) {
+		FMDERR("%s:pdev is null", __func__);
+		return -EINVAL;
+	}
+
 	/* private data allocation */
 	radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
 	if (!radio) {
@@ -4593,6 +4950,11 @@
 	int i;
 	struct tavarua_device *radio = platform_get_drvdata(pdev);
 
+	if (unlikely(radio == NULL)) {
+		FMDERR("%s:radio is null", __func__);
+		return -EINVAL;
+	}
+
 	/* disable irq */
 	tavarua_disable_irq(radio);
 
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 9dd06ee..127a231 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -310,6 +310,7 @@
 		"Scalable High",
 		"Scalable High Intra",
 		"Multiview High",
+		"Constrained High",
 		NULL,
 	};
 	static const char * const vui_sar_idc[] = {
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 3d69473..19f26f2 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1706,6 +1706,8 @@
 	dma_free_coherent(NULL, config->desc.size, config->desc.base,
 		config->desc.phys_base);
 
+	sps_free_endpoint(channel->pipe);
+
 	tspp_destroy_buffers(channel_id, channel);
 	if (channel->dma_pool) {
 		dma_pool_destroy(channel->dma_pool);
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 421774f..b36faff 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -467,6 +467,7 @@
 	}
 
 	kfree(card->wr_pack_stats.packing_events);
+	kfree(card->cached_ext_csd);
 
 	put_device(&card->dev);
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 997e14b..b295bb8 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1189,9 +1189,9 @@
 		mmc_set_timing(card->host, MMC_TIMING_LEGACY);
 		mmc_set_clock(card->host, MMC_HIGH_26_MAX_DTR);
 
-		err = mmc_select_hs(card, &card->cached_ext_csd);
+		err = mmc_select_hs(card, card->cached_ext_csd);
 	} else {
-		err = mmc_select_hs400(card, &card->cached_ext_csd);
+		err = mmc_select_hs400(card, card->cached_ext_csd);
 	}
 
 	return err;
@@ -1439,7 +1439,7 @@
 		err = mmc_get_ext_csd(card, &ext_csd);
 		if (err)
 			goto free_card;
-		memcpy(&card->cached_ext_csd, ext_csd, sizeof(card->ext_csd));
+		card->cached_ext_csd = ext_csd;
 		err = mmc_read_ext_csd(card, ext_csd);
 		if (err)
 			goto free_card;
@@ -1637,15 +1637,12 @@
 	if (!oldcard)
 		host->card = card;
 
-	mmc_free_ext_csd(ext_csd);
 	return 0;
 
 free_card:
 	if (!oldcard)
 		mmc_remove_card(card);
 err:
-	mmc_free_ext_csd(ext_csd);
-
 	return err;
 }
 
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 95f0a04..c335be1 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -6962,7 +6962,7 @@
 
 static const struct of_device_id msmsdcc_dt_match[] = {
 	{.compatible = "qcom,msm-sdcc"},
-
+	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, msmsdcc_dt_match);
 
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index e391a06..4d3a560 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -3113,6 +3113,7 @@
 #endif
 static const struct of_device_id sdhci_msm_dt_match[] = {
 	{.compatible = "qcom,sdhci-msm"},
+	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
 
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 76eb15b..12c5704 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -50,6 +50,7 @@
 
 /* module params */
 #define WCNSS_CONFIG_UNSPECIFIED (-1)
+#define UINT32_MAX (0xFFFFFFFFU)
 
 static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED;
 module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
@@ -355,7 +356,7 @@
 	int	fw_cal_available;
 	int	user_cal_read;
 	int	user_cal_available;
-	int	user_cal_rcvd;
+	u32	user_cal_rcvd;
 	int	user_cal_exp_size;
 	int	device_opened;
 	int	iris_xo_mode_set;
@@ -2134,7 +2135,7 @@
 			*user_buffer, size_t count, loff_t *position)
 {
 	int rc = 0;
-	int size = 0;
+	size_t size = 0;
 
 	if (!penv || !penv->device_opened || penv->user_cal_available)
 		return -EFAULT;
@@ -2142,7 +2143,7 @@
 	if (penv->user_cal_rcvd == 0 && count >= 4
 			&& !penv->user_cal_data) {
 		rc = copy_from_user((void *)&size, user_buffer, 4);
-		if (size > MAX_CALIBRATED_DATA_SIZE) {
+		if (!size || size > MAX_CALIBRATED_DATA_SIZE) {
 			pr_err(DEVICE " invalid size to write %d\n", size);
 			return -EFAULT;
 		}
@@ -2161,7 +2162,8 @@
 	} else if (penv->user_cal_rcvd == 0 && count < 4)
 		return -EFAULT;
 
-	if (MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
+	if ((UINT32_MAX - count < penv->user_cal_rcvd) ||
+	     MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
 		pr_err(DEVICE " invalid size to write %d\n", count +
 				penv->user_cal_rcvd);
 		rc = -ENOMEM;
diff --git a/drivers/platform/msm/qpnp-clkdiv.c b/drivers/platform/msm/qpnp-clkdiv.c
index c55ed09..696c84f 100644
--- a/drivers/platform/msm/qpnp-clkdiv.c
+++ b/drivers/platform/msm/qpnp-clkdiv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -202,6 +202,7 @@
 	if (!res) {
 		dev_err(&spmi->dev, "%s: unable to get device reg resource\n",
 					__func__);
+		return -EINVAL;
 	}
 
 	q_clkdiv->slave = spmi->sid;
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 7d26bef..588afc6 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -208,6 +208,12 @@
 #define QPNP_PWM_SIZE_8_BIT		8
 #define QPNP_PWM_SIZE_9_BIT		9
 
+/* Supported time levels */
+enum time_level {
+	LVL_NSEC,
+	LVL_USEC,
+};
+
 /* LPG revisions */
 enum qpnp_lpg_revision {
 	QPNP_LPG_REVISION_0 = 0x0,
@@ -305,8 +311,8 @@
 	bool				in_use;
 	const char			*lable;
 	int				pwm_value;
-	int				pwm_period;
-	int				pwm_duty;
+	int				pwm_period;	/* in microseconds */
+	int				pwm_duty;	/* in microseconds */
 	struct pwm_period_config	period;
 	int				force_pwm_size;
 };
@@ -425,8 +431,9 @@
  * This is the formula to figure out m for the best pre-divide and clock:
  * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
  */
-static void qpnp_lpg_calc_period(unsigned int period_us,
-				   struct pwm_device *pwm)
+static void qpnp_lpg_calc_period(enum time_level tm_lvl,
+				unsigned int period_value,
+				struct pwm_device *pwm)
 {
 	int		n, m, clk, div;
 	int		best_m, best_div, best_clk;
@@ -443,14 +450,18 @@
 	else
 		n = 6;
 
-	if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
-		period_n = (period_us * NSEC_PER_USEC) >> n;
+	if (tm_lvl == LVL_USEC) {
+		if (period_value < ((unsigned)(-1) / NSEC_PER_USEC)) {
+			period_n = (period_value * NSEC_PER_USEC) >> n;
+		} else {
+			if (qpnp_check_gpled_lpg_channel(id))
+				n = 8;
+			else
+				n = 9;
+			period_n = (period_value >> n) * NSEC_PER_USEC;
+		}
 	} else {
-		if (qpnp_check_gpled_lpg_channel(id))
-			n = 8;
-		else
-			n = 9;
-		period_n = (period_us >> n) * NSEC_PER_USEC;
+		period_n = period_value >> n;
 	}
 
 	if (force_pwm_size != 0) {
@@ -520,20 +531,20 @@
 }
 
 static void qpnp_lpg_calc_pwm_value(struct pwm_device *pwm,
-				      unsigned int period_us,
-				      unsigned int duty_us)
+				      unsigned int period_value,
+				      unsigned int duty_value)
 {
 	unsigned int		max_pwm_value, tmp;
 	struct qpnp_pwm_config	*pwm_config = &pwm->pwm_config;
 
 	/* Figure out pwm_value with overflow handling */
 	tmp = 1 << (sizeof(tmp) * 8 - pwm_config->period.pwm_size);
-	if (duty_us < tmp) {
-		tmp = duty_us << pwm_config->period.pwm_size;
-		pwm_config->pwm_value = tmp / period_us;
+	if (duty_value < tmp) {
+		tmp = duty_value << pwm_config->period.pwm_size;
+		pwm_config->pwm_value = tmp / period_value;
 	} else {
-		tmp = period_us >> pwm_config->period.pwm_size;
-		pwm_config->pwm_value = duty_us / tmp;
+		tmp = period_value >> pwm_config->period.pwm_size;
+		pwm_config->pwm_value = duty_value / tmp;
 	}
 	max_pwm_value = (1 << pwm_config->period.pwm_size) - 1;
 	if (pwm_config->pwm_value > max_pwm_value)
@@ -1083,25 +1094,36 @@
 	return rc;
 }
 
-static int _pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+static int _pwm_config(struct pwm_device *pwm,
+				enum time_level tm_lvl,
+				int duty_value, int period_value)
 {
 	struct qpnp_pwm_config		*pwm_config;
 	struct qpnp_lpg_chip		*chip;
 	struct pwm_period_config	*period;
-	int				rc;
+	int period_us, duty_us;
+	int	rc;
 
 	chip = pwm->chip;
 	pwm_config = &pwm->pwm_config;
 	period = &pwm_config->period;
 
+	if (tm_lvl == LVL_USEC) {
+		period_us = period_value;
+		duty_us = duty_value;
+	} else {
+		period_us = period_value / NSEC_PER_USEC;
+		duty_us = duty_value / NSEC_PER_USEC;
+	}
+
 	if (pwm_config->pwm_period != period_us) {
-		qpnp_lpg_calc_period(period_us, pwm);
+		qpnp_lpg_calc_period(tm_lvl, period_value, pwm);
 		qpnp_lpg_save_period(pwm);
 		pwm_config->pwm_period = period_us;
 	}
 
 	pwm_config->pwm_duty = duty_us;
-	qpnp_lpg_calc_pwm_value(pwm, period_us, duty_us);
+	qpnp_lpg_calc_pwm_value(pwm, period_value, duty_value);
 	rc = qpnp_lpg_save_pwm_value(pwm);
 
 	if (rc) {
@@ -1124,8 +1146,9 @@
 		return rc;
 	}
 
-	pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
+	pr_debug("duty/period=%u/%u %s: pwm_value=%d (of %d)\n",
 		 (unsigned)duty_us, (unsigned)period_us,
+		 (tm_lvl == LVL_USEC) ? "usec" : "nsec",
 		 pwm_config->pwm_value, 1 << period->pwm_size);
 
 	return 0;
@@ -1151,7 +1174,7 @@
 	period = &pwm_config->period;
 
 	if (pwm_config->pwm_period != period_us) {
-		qpnp_lpg_calc_period(period_us, pwm);
+		qpnp_lpg_calc_period(LVL_USEC, period_us, pwm);
 		qpnp_lpg_save_period(pwm);
 		pwm_config->pwm_period = period_us;
 	}
@@ -1302,10 +1325,41 @@
 /**
  * pwm_config - change a PWM device configuration
  * @pwm: the PWM device
+ * @period_ns: period in nanoseconds
+ * @duty_ns: duty cycle in nanoseconds
+ */
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+	int rc;
+	unsigned long flags;
+
+	if (pwm == NULL || IS_ERR(pwm) || duty_ns > period_ns ||
+		(unsigned)period_ns < PM_PWM_PERIOD_MIN * NSEC_PER_USEC) {
+		pr_err("Invalid pwm handle or parameters\n");
+		return -EINVAL;
+	}
+
+	if (!pwm->pwm_config.in_use)
+		return -EINVAL;
+
+	spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
+	rc = _pwm_config(pwm, LVL_NSEC, duty_ns, period_ns);
+	spin_unlock_irqrestore(&pwm->chip->lpg_lock, flags);
+
+	if (rc)
+		pr_err("Failed to configure PWM mode\n");
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_config);
+
+/**
+ * pwm_config_us - change a PWM device configuration
+ * @pwm: the PWM device
  * @period_us: period in microseconds
  * @duty_us: duty cycle in microseconds
  */
-int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+int pwm_config_us(struct pwm_device *pwm, int duty_us, int period_us)
 {
 	int rc;
 	unsigned long flags;
@@ -1322,7 +1376,7 @@
 		return -EINVAL;
 
 	spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
-	rc = _pwm_config(pwm, duty_us, period_us);
+	rc = _pwm_config(pwm, LVL_USEC, duty_us, period_us);
 	spin_unlock_irqrestore(&pwm->chip->lpg_lock, flags);
 
 	if (rc)
@@ -1330,7 +1384,7 @@
 
 	return rc;
 }
-EXPORT_SYMBOL_GPL(pwm_config);
+EXPORT_SYMBOL_GPL(pwm_config_us);
 
 /**
  * pwm_enable - start a PWM output toggling
@@ -1627,7 +1681,8 @@
 		return rc;
 	}
 
-	rc = _pwm_config(pwm_dev, pwm_dev->pwm_config.pwm_duty, period);
+	rc = _pwm_config(pwm_dev, LVL_USEC,
+					pwm_dev->pwm_config.pwm_duty, period);
 
 	return rc;
 }
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 8572616..6ea4ea6 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1285,6 +1285,21 @@
 	return 0;
 }
 
+static int
+qpnp_chg_vddmax_get(struct qpnp_chg_chip *chip)
+{
+	int rc;
+	u8 vddmax = 0;
+
+	rc = qpnp_chg_read(chip, &vddmax, chip->chgr_base + CHGR_VDD_MAX, 1);
+	if (rc) {
+		pr_err("Failed to write vddmax: %d\n", rc);
+		return rc;
+	}
+
+	return QPNP_CHG_V_MIN_MV + (int)vddmax * QPNP_CHG_V_STEP_MV;
+}
+
 /* JEITA compliance logic */
 static void
 qpnp_chg_set_appropriate_vddmax(struct qpnp_chg_chip *chip)
@@ -2077,6 +2092,8 @@
 		if (battery_status != POWER_SUPPLY_STATUS_CHARGING
 				&& bms_status != POWER_SUPPLY_STATUS_CHARGING
 				&& charger_in
+				&& !chip->bat_is_cool
+				&& !chip->bat_is_warm
 				&& !chip->resuming_charging
 				&& !chip->charging_disabled
 				&& chip->soc_resume_limit
@@ -3118,10 +3135,17 @@
 			count = 0;
 		} else {
 			if (count == CONSECUTIVE_COUNT) {
-				pr_info("End of Charging\n");
+				if (!chip->bat_is_cool && !chip->bat_is_warm) {
+					pr_info("End of Charging\n");
+					chip->chg_done = true;
+				} else {
+					pr_info("stop charging: battery is %s, vddmax = %d reached\n",
+						chip->bat_is_cool
+							? "cool" : "warm",
+						qpnp_chg_vddmax_get(chip));
+				}
 				chip->delta_vddmax_mv = 0;
 				qpnp_chg_set_appropriate_vddmax(chip);
-				chip->chg_done = true;
 				qpnp_chg_charge_en(chip, 0);
 				/* sleep for a second before enabling */
 				msleep(2000);
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index cf1801b..efb87a9 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1339,7 +1339,7 @@
 {
 	u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
 	u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
-	u8 sensor_mask = 0;
+	u8 sensor_mask = 0, adc_tm_low_thr_set = 0, adc_tm_high_thr_set = 0;
 	int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
 	uint32_t btm_chan_num = 0;
 	struct qpnp_adc_thr_client_info *client_info = NULL;
@@ -1368,6 +1368,20 @@
 		goto fail;
 	}
 
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+						&adc_tm_low_thr_set);
+	if (rc) {
+		pr_err("adc-tm-tm read low thr failed with %d\n", rc);
+		goto fail;
+	}
+
+	rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+						&adc_tm_high_thr_set);
+	if (rc) {
+		pr_err("adc-tm-tm read high thr 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(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
@@ -1378,7 +1392,9 @@
 	}
 
 	adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
+	adc_tm_low_enable &= adc_tm_low_thr_set;
 	adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
+	adc_tm_high_enable &= adc_tm_high_thr_set;
 
 	if (adc_tm_high_enable) {
 		sensor_notify_num = adc_tm_high_enable;
@@ -1886,7 +1902,7 @@
 			pr_debug("thermal node%x\n", btm_channel_num);
 			chip->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
 			chip->sensor[sen_idx].thermal_node = true;
-			snprintf(name, sizeof(name),
+			snprintf(name, sizeof(name), "%s",
 				chip->adc->adc_channels[sen_idx].name);
 			chip->sensor[sen_idx].meas_interval =
 				QPNP_ADC_TM_MEAS_INTERVAL;
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index dd04f49..7ae0a54 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -1063,7 +1063,7 @@
 
 	memset(kbuf, 0, 10);
 
-	if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+	if (copy_from_user(kbuf, buf, min_t(size_t, sizeof(kbuf) - 1, count)))
 		return -EFAULT;
 
 	if (sscanf(kbuf, "%x", &data) != 1)
@@ -1088,7 +1088,7 @@
 
 	memset(kbuf, 0, 10);
 
-	if (copy_from_user(kbuf, buf, count > 10 ? 10 : count))
+	if (copy_from_user(kbuf, buf, min_t(size_t, sizeof(kbuf) - 1, count)))
 		return -EFAULT;
 
 	if (sscanf(kbuf, "%x", &temp) != 1)
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 52c4a20..25ee3e4 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -78,6 +78,9 @@
 
 	if (status) {
 		MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, status);
+
+		/* Writing of an extra 0 needed to clear error bits */
+		MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, 0);
 		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
@@ -932,17 +935,18 @@
 	if (req->cb)
 		req->cb(len);
 }
-void msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+int msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
 {
 	struct dcs_cmd_req *req;
 	int dsi_on;
+	int ret = -EINVAL;
 
 	mutex_lock(&ctrl->mutex);
 	dsi_on = dsi_host_private->dsi_on;
 	mutex_unlock(&ctrl->mutex);
 	if (!dsi_on) {
 		pr_err("try to send DSI commands while dsi is off\n");
-		return;
+		return ret;
 	}
 
 	mutex_lock(&ctrl->cmd_mutex);
@@ -950,21 +954,20 @@
 
 	if (!req) {
 		mutex_unlock(&ctrl->cmd_mutex);
-		return;
+		return ret;
 	}
 
 	msm_dsi_clk_ctrl(&ctrl->panel_data, 1);
-	dsi_set_tx_power_mode(0);
 
 	if (req->flags & CMD_REQ_RX)
 		msm_dsi_cmdlist_rx(ctrl, req);
 	else
 		msm_dsi_cmdlist_tx(ctrl, req);
 
-	dsi_set_tx_power_mode(1);
 	msm_dsi_clk_ctrl(&ctrl->panel_data, 0);
 
 	mutex_unlock(&ctrl->cmd_mutex);
+	return 0;
 }
 
 static int msm_dsi_cal_clk_rate(struct mdss_panel_data *pdata,
@@ -1302,6 +1305,21 @@
 	return rc;
 }
 
+static struct device_node *dsi_pref_prim_panel(
+		struct platform_device *pdev)
+{
+	struct device_node *dsi_pan_node = NULL;
+
+	pr_debug("%s:%d: Select primary panel from dt\n",
+					__func__, __LINE__);
+	dsi_pan_node = of_parse_phandle(pdev->dev.of_node,
+					"qcom,dsi-pref-prim-pan", 0);
+	if (!dsi_pan_node)
+		pr_err("%s:can't find panel phandle\n", __func__);
+
+	return dsi_pan_node;
+}
+
 /**
  * dsi_find_panel_of_node(): find device node of dsi panel
  * @pdev: platform_device of the dsi ctrl node
@@ -1331,14 +1349,7 @@
 		/* no panel cfg chg, parse dt */
 		pr_debug("%s:%d: no cmd line cfg present\n",
 			 __func__, __LINE__);
-		dsi_pan_node = of_parse_phandle(
-			pdev->dev.of_node,
-			"qcom,dsi-pref-prim-pan", 0);
-		if (!dsi_pan_node) {
-			pr_err("%s:can't find panel phandle\n",
-			       __func__);
-			return NULL;
-		}
+		dsi_pan_node = dsi_pref_prim_panel(pdev);
 	} else {
 		if (panel_cfg[0] != '0') {
 			pr_err("%s:%d:ctrl id=[%d] not supported\n",
@@ -1366,7 +1377,7 @@
 		if (!dsi_pan_node) {
 			pr_err("%s: invalid pan node\n",
 			       __func__);
-			return NULL;
+			dsi_pan_node = dsi_pref_prim_panel(pdev);
 		}
 	}
 	return dsi_pan_node;
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 3999db9..02bd7e9 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -186,6 +186,7 @@
 	int i = 0;
 	struct mdp3_hw_resource *mdata = (struct mdp3_hw_resource *)ptr;
 	u32 mdp_interrupt = 0;
+	u32 mdp_status = 0;
 
 	spin_lock(&mdata->irq_lock);
 	if (!mdata->irq_mask)
@@ -194,8 +195,8 @@
 	clk_enable(mdp3_res->clocks[MDP3_CLK_AHB]);
 	clk_enable(mdp3_res->clocks[MDP3_CLK_CORE]);
 
-	mdp_interrupt = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
-	MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_interrupt);
+	mdp_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
+	mdp_interrupt = mdp_status;
 	pr_debug("mdp3_irq_handler irq=%d\n", mdp_interrupt);
 
 	mdp_interrupt &= mdata->irq_mask;
@@ -206,6 +207,7 @@
 		mdp_interrupt = mdp_interrupt >> 1;
 		i++;
 	}
+	MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_status);
 
 	clk_disable(mdp3_res->clocks[MDP3_CLK_AHB]);
 	clk_disable(mdp3_res->clocks[MDP3_CLK_CORE]);
@@ -949,7 +951,7 @@
 {
 	char *t = NULL;
 	char pan_intf_str[MDSS_MAX_PANEL_LEN];
-	int rc, i;
+	int rc, i, panel_len;
 	char pan_name[MDSS_MAX_PANEL_LEN];
 
 	if (!pan_cfg)
@@ -986,6 +988,14 @@
 	strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg));
 	pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__,
 		t, pan_cfg->arg_cfg);
+
+	panel_len = strlen(pan_cfg->arg_cfg);
+	if (!panel_len) {
+		pr_err("%s: Panel name is invalid\n", __func__);
+		pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+		return -EINVAL;
+	}
+
 	rc = mdp3_get_pan_intf(pan_intf_str);
 	pan_cfg->pan_intf = (rc < 0) ?  MDSS_PANEL_INTF_INVALID : rc;
 	return 0;
@@ -1069,10 +1079,10 @@
 	of_node_put(chosen_node);
 
 	rc = mdp3_get_pan_cfg(pan_cfg);
-	if (!rc)
+	if (!rc) {
 		pan_cfg->init_done = true;
-
-	return rc;
+		return rc;
+	}
 
 get_dt_pan:
 	rc = mdp3_parse_dt_pan_intf(pdev);
@@ -1443,7 +1453,9 @@
 			ret = 0;
 		} else {
 			ret = PTR_ERR(iommu_meta);
-			goto out_unlock;
+			mutex_unlock(&mdp3_res->iommu_lock);
+			pr_err("%s: meta_create failed err=%d", __func__, ret);
+			return ret;
 		}
 	} else {
 		if (iommu_meta->flags != iommu_flags) {
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 28997ec..f1f0455 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -26,6 +26,7 @@
 #include "mdss_fb.h"
 
 #define MDP_VSYNC_CLK_RATE	19200000
+#define KOFF_TIMEOUT msecs_to_jiffies(84)
 
 enum  {
 	MDP3_CLK_AHB,
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 6219737..6fc6195 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -91,6 +91,36 @@
 	return bufq->count;
 }
 
+void mdp3_ctrl_notifier_register(struct mdp3_session_data *ses,
+	struct notifier_block *notifier)
+{
+	blocking_notifier_chain_register(&ses->notifier_head, notifier);
+}
+
+void mdp3_ctrl_notifier_unregister(struct mdp3_session_data *ses,
+	struct notifier_block *notifier)
+{
+	blocking_notifier_chain_unregister(&ses->notifier_head, notifier);
+}
+
+int mdp3_ctrl_notify(struct mdp3_session_data *ses, int event)
+{
+	return blocking_notifier_call_chain(&ses->notifier_head, event, ses);
+}
+
+static void mdp3_dispatch_dma_done(struct work_struct *work)
+{
+	struct mdp3_session_data *session;
+
+	pr_debug("%s\n", __func__);
+	session = container_of(work, struct mdp3_session_data,
+				dma_done_work);
+	if (!session)
+		return;
+
+	mdp3_ctrl_notify(session, MDP_NOTIFY_FRAME_DONE);
+}
+
 static void mdp3_dispatch_clk_off(struct work_struct *work)
 {
 	struct mdp3_session_data *session;
@@ -121,6 +151,12 @@
 	sysfs_notify_dirent(session->vsync_event_sd);
 }
 
+void dma_done_notify_handler(void *arg)
+{
+	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+	schedule_work(&session->dma_done_work);
+}
+
 void vsync_count_down(void *arg)
 {
 	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
@@ -140,8 +176,8 @@
 static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
 {
 	struct mdp3_session_data *mdp3_session;
-	struct mdp3_vsync_notification vsync_client;
-	struct mdp3_vsync_notification *arg = NULL;
+	struct mdp3_notification vsync_client;
+	struct mdp3_notification *arg = NULL;
 
 	pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable);
 	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -464,6 +500,7 @@
 	int frame_rate = mfd->panel_info->mipi.frame_rate;
 	int vbp, vfp, vspw;
 	int vtotal, vporch;
+	struct mdp3_notification dma_done_callback;
 
 	vbp = panel_info->lcdc.v_back_porch;
 	vfp = panel_info->lcdc.v_front_porch;
@@ -499,6 +536,13 @@
 		rc = dma->dma_config(dma, &sourceConfig, &outputConfig);
 	else
 		rc = -EINVAL;
+
+	if (outputConfig.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		dma_done_callback.handler = dma_done_notify_handler;
+		dma_done_callback.arg = mfd->mdp.private1;
+		dma->dma_done_notifier(dma, &dma_done_callback);
+	}
+
 	return rc;
 }
 
@@ -527,6 +571,8 @@
 	}
 
 	mdp3_batfet_ctrl(true);
+	mdp3_ctrl_notifier_register(mdp3_session,
+		&mdp3_session->mfd->mdp_sync_pt_data.notifier);
 
 	rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
 	if (rc) {
@@ -613,9 +659,6 @@
 	panel = mdp3_session->panel;
 	mutex_lock(&mdp3_session->lock);
 
-	if (panel && panel->set_backlight)
-		panel->set_backlight(panel, 0);
-
 	if (!mdp3_session->status) {
 		pr_debug("fb%d is off already", mfd->index);
 		goto off_error;
@@ -661,6 +704,8 @@
 	if (rc)
 		pr_err("fail to dettach MDP DMA SMMU\n");
 
+	mdp3_ctrl_notifier_unregister(mdp3_session,
+		&mdp3_session->mfd->mdp_sync_pt_data.notifier);
 	mdp3_batfet_ctrl(false);
 	mdp3_session->vsync_enabled = 0;
 	atomic_set(&mdp3_session->vsync_countdown, 0);
@@ -680,7 +725,7 @@
 	struct mdp3_session_data *mdp3_session;
 	struct mdp3_dma *mdp3_dma;
 	struct mdss_panel_data *panel;
-	struct mdp3_vsync_notification vsync_client;
+	struct mdp3_notification vsync_client;
 
 	pr_debug("mdp3_ctrl_reset_cmd\n");
 	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -730,7 +775,7 @@
 	struct mdp3_session_data *mdp3_session;
 	struct mdp3_dma *mdp3_dma;
 	struct mdss_panel_data *panel;
-	struct mdp3_vsync_notification vsync_client;
+	struct mdp3_notification vsync_client;
 
 	pr_debug("mdp3_ctrl_reset\n");
 	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -838,6 +883,14 @@
 {
 	int rc = 0;
 	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+	struct fb_var_screeninfo *var;
+	struct fb_fix_screeninfo *fix;
+	struct fb_info *fbi = mfd->fbi;
+	int stride;
+
+	fix = &fbi->fix;
+	var = &fbi->var;
+	stride = req->src.width * var->bits_per_pixel/8;
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -846,6 +899,9 @@
 
 	mdp3_session->overlay = *req;
 	if (req->id == MSMFB_NEW_REQUEST) {
+		if (fix->line_length != stride)
+			mdp3_session->dma->config_stride(
+						mdp3_session->dma, stride);
 		mdp3_session->overlay.id = 1;
 		req->id = 1;
 	}
@@ -859,10 +915,15 @@
 {
 	int rc = 0;
 	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+	struct fb_info *fbi = mfd->fbi;
+	struct fb_fix_screeninfo *fix;
 
+	fix = &fbi->fix;
 	mutex_lock(&mdp3_session->lock);
 
 	if (mdp3_session->overlay.id == ndx && ndx == 1) {
+		mdp3_session->dma->config_stride(mdp3_session->dma,
+							fix->line_length);
 		mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
 		mdp3_bufq_deinit(&mdp3_session->bufq_in);
 	} else {
@@ -956,17 +1017,31 @@
 		return -EPERM;
 	}
 
+	mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
 	data = mdp3_bufq_pop(&mdp3_session->bufq_in);
 	if (data) {
 		mdp3_ctrl_reset_countdown(mdp3_session, mfd);
 		mdp3_ctrl_clk_enable(mfd, 1);
-		mdp3_session->dma->update(mdp3_session->dma,
+		rc = mdp3_session->dma->update(mdp3_session->dma,
 			(void *)data->addr,
 			mdp3_session->intf);
+		/* This is for the previous frame */
+		if (rc < 0) {
+			mdp3_ctrl_notify(mdp3_session,
+				MDP_NOTIFY_FRAME_TIMEOUT);
+		} else {
+			if (mdp3_ctrl_get_intf_type(mfd) ==
+						MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+				mdp3_ctrl_notify(mdp3_session,
+					MDP_NOTIFY_FRAME_DONE);
+			}
+		}
+
+		mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
 		mdp3_bufq_push(&mdp3_session->bufq_out, data);
 	}
 
-	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) {
+	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
 		data = mdp3_bufq_pop(&mdp3_session->bufq_out);
 		mdp3_put_img(data, MDP3_CLIENT_DMA_P);
 	}
@@ -985,7 +1060,7 @@
 
 	mdss_fb_update_notify_update(mfd);
 
-	return rc;
+	return 0;
 }
 
 static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
@@ -995,6 +1070,7 @@
 	u32 offset;
 	int bpp;
 	struct mdss_panel_info *panel_info = mfd->panel_info;
+	int rc;
 
 	pr_debug("mdp3_ctrl_pan_display\n");
 	if (!mfd || !mfd->mdp.private1)
@@ -1031,10 +1107,23 @@
 
 	if (mfd->fbi->screen_base) {
 		mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+		mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
 		mdp3_ctrl_clk_enable(mfd, 1);
-		mdp3_session->dma->update(mdp3_session->dma,
-				(void *)mfd->iova + offset,
+		rc = mdp3_session->dma->update(mdp3_session->dma,
+				(void *)(mfd->iova + offset),
 				mdp3_session->intf);
+		/* This is for the previous frame */
+		if (rc < 0) {
+			mdp3_ctrl_notify(mdp3_session,
+				MDP_NOTIFY_FRAME_TIMEOUT);
+		} else {
+			if (mdp3_ctrl_get_intf_type(mfd) ==
+						MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+				mdp3_ctrl_notify(mdp3_session,
+					MDP_NOTIFY_FRAME_DONE);
+			}
+		}
+		mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
 	} else {
 		pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
 		mdp3_clk_enable(1, 0);
@@ -1645,6 +1734,7 @@
 	memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
 	mutex_init(&mdp3_session->lock);
 	INIT_WORK(&mdp3_session->clk_off_work, mdp3_dispatch_clk_off);
+	INIT_WORK(&mdp3_session->dma_done_work, mdp3_dispatch_dma_done);
 	atomic_set(&mdp3_session->vsync_countdown, 0);
 	mutex_init(&mdp3_session->histo_lock);
 	mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
@@ -1680,6 +1770,7 @@
 	mdp3_bufq_init(&mdp3_session->bufq_out);
 	mdp3_session->histo_status = 0;
 	mdp3_session->lut_sel = 0;
+	BLOCKING_INIT_NOTIFIER_HEAD(&mdp3_session->notifier_head);
 
 	init_timer(&mdp3_session->vsync_timer);
 	mdp3_session->vsync_timer.function = mdp3_vsync_timer_func;
@@ -1708,14 +1799,17 @@
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
 
+	if (mdp3_get_cont_spash_en()) {
+		mdp3_session->clk_on = 1;
+		mdp3_ctrl_notifier_register(mdp3_session,
+			&mdp3_session->mfd->mdp_sync_pt_data.notifier);
+	}
+
 	if (splash_mismatch) {
 		pr_err("splash memory mismatch, stop splash\n");
 		mdp3_ctrl_off(mfd);
 	}
 
-	if (mdp3_get_cont_spash_en())
-		mdp3_session->clk_on = 1;
-
 	mdp3_session->vsync_before_commit = true;
 init_done:
 	if (IS_ERR_VALUE(rc))
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index f2484ef..cfad1d3 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -49,6 +49,7 @@
 	struct mdp3_buffer_queue bufq_in;
 	struct mdp3_buffer_queue bufq_out;
 	struct work_struct clk_off_work;
+	struct work_struct dma_done_work;
 	int histo_status;
 	struct mutex histo_lock;
 	int lut_sel;
@@ -56,6 +57,7 @@
 	bool vsync_before_commit;
 	bool first_commit;
 	int clk_on;
+	struct blocking_notifier_head notifier_head;
 
 	int vsync_enabled;
 	atomic_t vsync_countdown; /* Used to count down  */
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 3a2c94b..5cae2de 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -27,26 +27,38 @@
 static void mdp3_vsync_intr_handler(int type, void *arg)
 {
 	struct mdp3_dma *dma = (struct mdp3_dma *)arg;
-	struct mdp3_vsync_notification vsync_client;
+	struct mdp3_notification vsync_client;
+	unsigned int wait_for_next_vs;
 
 	pr_debug("mdp3_vsync_intr_handler\n");
 	spin_lock(&dma->dma_lock);
 	vsync_client = dma->vsync_client;
-	complete(&dma->vsync_comp);
+	wait_for_next_vs = !dma->vsync_status;
+	dma->vsync_status = 0;
+	if (wait_for_next_vs)
+		complete(&dma->vsync_comp);
 	spin_unlock(&dma->dma_lock);
-	if (vsync_client.handler)
+	if (vsync_client.handler) {
 		vsync_client.handler(vsync_client.arg);
-	else
-		mdp3_irq_disable_nosync(type);
+	} else {
+		if (wait_for_next_vs)
+			mdp3_irq_disable_nosync(type);
+	}
 }
 
 static void mdp3_dma_done_intr_handler(int type, void *arg)
 {
 	struct mdp3_dma *dma = (struct mdp3_dma *)arg;
+	struct mdp3_notification dma_client;
 
 	pr_debug("mdp3_dma_done_intr_handler\n");
+	spin_lock(&dma->dma_lock);
+	dma_client = dma->dma_notifier_client;
 	complete(&dma->dma_comp);
+	spin_unlock(&dma->dma_lock);
 	mdp3_irq_disable_nosync(type);
+	if (dma_client.handler)
+		dma_client.handler(dma_client.arg);
 }
 
 static void mdp3_hist_done_intr_handler(int type, void *arg)
@@ -189,7 +201,7 @@
 }
 
 static void mdp3_dma_vsync_enable(struct mdp3_dma *dma,
-				struct mdp3_vsync_notification *vsync_client)
+				struct mdp3_notification *vsync_client)
 {
 	unsigned long flag;
 	int updated = 0;
@@ -220,6 +232,21 @@
 	}
 }
 
+static void mdp3_dma_done_notifier(struct mdp3_dma *dma,
+				struct mdp3_notification *dma_client)
+{
+	unsigned long flag;
+
+	spin_lock_irqsave(&dma->dma_lock, flag);
+	if (dma_client) {
+		dma->dma_notifier_client = *dma_client;
+	} else {
+		dma->dma_notifier_client.handler = NULL;
+		dma->dma_notifier_client.arg = NULL;
+	}
+	spin_unlock_irqrestore(&dma->dma_lock, flag);
+}
+
 static void mdp3_dma_clk_auto_gating(struct mdp3_dma *dma, int enable)
 {
 	u32 cgc;
@@ -268,6 +295,23 @@
 	return 0;
 }
 
+static void mdp3_dma_stride_config(struct mdp3_dma *dma, int stride)
+{
+	struct mdp3_dma_source *source_config;
+	u32 dma_stride_offset;
+
+	if (dma->dma_sel == MDP3_DMA_P)
+		dma_stride_offset = MDP3_REG_DMA_P_IBUF_Y_STRIDE;
+	else
+		dma_stride_offset = MDP3_REG_DMA_S_IBUF_Y_STRIDE;
+
+	source_config = &dma->source_config;
+	source_config->stride = stride;
+	pr_debug("%s: Update the fb stride for DMA to %d", __func__,
+						(u32)source_config->stride);
+	MDP3_REG_WRITE(dma_stride_offset, source_config->stride);
+}
+
 static int mdp3_dmap_config(struct mdp3_dma *dma,
 			struct mdp3_dma_source *source_config,
 			struct mdp3_dma_output_config *output_config)
@@ -529,13 +573,20 @@
 {
 	unsigned long flag;
 	int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
+	int rc = 0;
 
 	pr_debug("mdp3_dmap_update\n");
 
 	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
 		cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
-		if (intf->active)
-			wait_for_completion_killable(&dma->dma_comp);
+		if (intf->active) {
+			rc = wait_for_completion_timeout(&dma->dma_comp,
+				KOFF_TIMEOUT);
+			if (rc <= 0) {
+				WARN(1, "cmd kickoff timed out (%d)\n", rc);
+				rc = -1;
+			}
+		}
 	}
 	spin_lock_irqsave(&dma->dma_lock, flag);
 	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf);
@@ -550,16 +601,22 @@
 		intf->start(intf);
 	}
 
-	wmb();
+	mb();
+	dma->vsync_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS) &
+		(1 << MDP3_INTR_LCDC_START_OF_FRAME);
 	init_completion(&dma->vsync_comp);
 	spin_unlock_irqrestore(&dma->dma_lock, flag);
 
 	mdp3_dma_callback_enable(dma, cb_type);
 	pr_debug("mdp3_dmap_update wait for vsync_comp in\n");
-	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
-		wait_for_completion_killable(&dma->vsync_comp);
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
+		rc = wait_for_completion_timeout(&dma->vsync_comp,
+			KOFF_TIMEOUT);
+		if (rc <= 0)
+			rc = -1;
+	}
 	pr_debug("mdp3_dmap_update wait for vsync_comp out\n");
-	return 0;
+	return rc;
 }
 
 static int mdp3_dmas_update(struct mdp3_dma *dma, void *buf,
@@ -853,8 +910,10 @@
 		dma->get_histo = mdp3_dmap_histo_get;
 		dma->histo_op = mdp3_dmap_histo_op;
 		dma->vsync_enable = mdp3_dma_vsync_enable;
+		dma->dma_done_notifier = mdp3_dma_done_notifier;
 		dma->start = mdp3_dma_start;
 		dma->stop = mdp3_dma_stop;
+		dma->config_stride = mdp3_dma_stride_config;
 		break;
 	case MDP3_DMA_S:
 		dma->dma_config = mdp3_dmas_config;
@@ -869,6 +928,7 @@
 		dma->vsync_enable = mdp3_dma_vsync_enable;
 		dma->start = mdp3_dma_start;
 		dma->stop = mdp3_dma_stop;
+		dma->config_stride = mdp3_dma_stride_config;
 		break;
 	case MDP3_DMA_E:
 	default:
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 6983e55..04955d4 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -14,6 +14,7 @@
 #ifndef MDP3_DMA_H
 #define MDP3_DMA_H
 
+#include <linux/notifier.h>
 #include <linux/sched.h>
 
 #define MDP_HISTOGRAM_BL_SCALE_MAX 1024
@@ -227,7 +228,7 @@
 	u32 extra[2];
 };
 
-struct mdp3_vsync_notification {
+struct mdp3_notification {
 	void (*handler)(void *arg);
 	void *arg;
 };
@@ -245,7 +246,8 @@
 	struct completion vsync_comp;
 	struct completion dma_comp;
 	struct completion histo_comp;
-	struct mdp3_vsync_notification vsync_client;
+	struct mdp3_notification vsync_client;
+	struct mdp3_notification dma_notifier_client;
 
 	struct mdp3_dma_output_config output_config;
 	struct mdp3_dma_source source_config;
@@ -256,6 +258,7 @@
 	struct mdp3_dma_histogram_config histogram_config;
 	int histo_state;
 	struct mdp3_dma_histogram_data histo_data;
+	unsigned int vsync_status;
 
 	int (*dma_config)(struct mdp3_dma *dma,
 			struct mdp3_dma_source *source_config,
@@ -287,8 +290,13 @@
 
 	int (*histo_op)(struct mdp3_dma *dma, u32 op);
 
+	void (*config_stride)(struct mdp3_dma *dma, int stride);
+
 	void (*vsync_enable)(struct mdp3_dma *dma,
-			struct mdp3_vsync_notification *vsync_client);
+			struct mdp3_notification *vsync_client);
+
+	void (*dma_done_notifier)(struct mdp3_dma *dma,
+			struct mdp3_notification *dma_client);
 };
 
 struct mdp3_video_intf_cfg {
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index a64a6b4..d778af8 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -412,12 +412,47 @@
 	mdp3_ppp_kickoff();
 }
 
-static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
+static int solid_fill_workaround(struct mdp_blit_req *req,
+						struct ppp_blit_op *blit_op)
+{
+	/* Make width 2 when there is a solid fill of width 1, and make
+	sure width does not become zero while trying to avoid odd width */
+	if (blit_op->dst.roi.width == 1) {
+		if (req->dst_rect.x + 2 > req->dst.width) {
+			pr_err("%s: Unable to handle solid fill of width 1",
+								__func__);
+			return -EINVAL;
+		}
+		blit_op->dst.roi.width = 2;
+	}
+	if (blit_op->src.roi.width == 1) {
+		if (req->src_rect.x + 2 > req->src.width) {
+			pr_err("%s: Unable to handle solid fill of width 1",
+								__func__);
+			return -EINVAL;
+		}
+		blit_op->src.roi.width = 2;
+	}
+
+	/* Avoid odd width, as it could hang ppp during solid fill */
+	blit_op->dst.roi.width = (blit_op->dst.roi.width / 2) * 2;
+	blit_op->src.roi.width = (blit_op->src.roi.width / 2) * 2;
+
+	/* Avoid RGBA format, as it could hang ppp during solid fill */
+	if (blit_op->src.color_fmt == MDP_RGBA_8888)
+		blit_op->src.color_fmt = MDP_RGBX_8888;
+	if (blit_op->dst.color_fmt == MDP_RGBA_8888)
+		blit_op->dst.color_fmt = MDP_RGBX_8888;
+	return 0;
+}
+
+static int mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
 	struct mdp_blit_req *req, struct mdp3_img_data *src_data,
 	struct mdp3_img_data *dst_data)
 {
 	unsigned long srcp0_start, srcp0_len, dst_start, dst_len;
 	uint32_t dst_width, dst_height;
+	int ret = 0;
 
 	srcp0_start = (unsigned long) src_data->addr;
 	srcp0_len = (unsigned long) src_data->len;
@@ -510,24 +545,19 @@
 		blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR;
 
 	if (req->flags & MDP_SOLID_FILL) {
-		blit_op->solid_fill = true;
+		ret = solid_fill_workaround(req, blit_op);
+		if (ret)
+			return ret;
 
-		/* Avoid odd width, as it could hang ppp during solid fill */
-		blit_op->dst.roi.width = (blit_op->dst.roi.width / 2) * 2;
-		blit_op->src.roi.width = (blit_op->src.roi.width / 2) * 2;
-
-		/* Avoid RGBA format, as it could hang ppp during solid fill */
-		if (blit_op->src.color_fmt == MDP_RGBA_8888)
-			blit_op->src.color_fmt = MDP_RGBX_8888;
-		if (blit_op->dst.color_fmt == MDP_RGBA_8888)
-			blit_op->dst.color_fmt = MDP_RGBX_8888;
 		blit_op->solid_fill_color = (req->const_color.g & 0xFF)|
 				(req->const_color.r & 0xFF) << 8 |
 				(req->const_color.b & 0xFF)  << 16 |
 				(req->const_color.alpha & 0xFF) << 24;
+		blit_op->solid_fill = true;
 	} else {
 		blit_op->solid_fill = false;
 	}
+	return ret;
 }
 
 static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op,
@@ -626,6 +656,7 @@
 	struct mdp3_img_data *dst_data)
 {
 	struct ppp_blit_op blit_op;
+	int ret = 0;
 
 	memset(&blit_op, 0, sizeof(blit_op));
 
@@ -639,7 +670,11 @@
 		return -EINVAL;
 	}
 
-	mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+	ret = mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+	if (ret) {
+		pr_err("%s: Failed to process the blit request", __func__);
+		return ret;
+	}
 
 	if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
 	     (req->src.format == MDP_ARGB_8888) ||
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index d33aefa..54c8a06 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -793,6 +793,21 @@
 	return rc;
 }
 
+static struct device_node *mdss_dsi_pref_prim_panel(
+		struct platform_device *pdev)
+{
+	struct device_node *dsi_pan_node = NULL;
+
+	pr_debug("%s:%d: Select primary panel from dt\n",
+					__func__, __LINE__);
+	dsi_pan_node = of_parse_phandle(pdev->dev.of_node,
+					"qcom,dsi-pref-prim-pan", 0);
+	if (!dsi_pan_node)
+		pr_err("%s:can't find panel phandle\n", __func__);
+
+	return dsi_pan_node;
+}
+
 /**
  * mdss_dsi_find_panel_of_node(): find device node of dsi panel
  * @pdev: platform_device of the dsi ctrl node
@@ -820,14 +835,7 @@
 		/* no panel cfg chg, parse dt */
 		pr_debug("%s:%d: no cmd line cfg present\n",
 			 __func__, __LINE__);
-		dsi_pan_node = of_parse_phandle(
-			pdev->dev.of_node,
-			"qcom,dsi-pref-prim-pan", 0);
-		if (!dsi_pan_node) {
-			pr_err("%s:can't find panel phandle\n",
-			       __func__);
-			return NULL;
-		}
+		dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
 	} else {
 		if (panel_cfg[0] == '0') {
 			pr_debug("%s:%d: DSI ctrl 1\n", __func__, __LINE__);
@@ -860,11 +868,12 @@
 		dsi_pan_node = of_find_node_by_name(mdss_node,
 						    panel_name);
 		if (!dsi_pan_node) {
-			pr_err("%s: invalid pan node\n",
+			pr_err("%s: invalid pan node, selecting prim panel\n",
 			       __func__);
-			return NULL;
+			dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
 		}
 	}
+
 	return dsi_pan_node;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index d743c42..855ec6c 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -233,7 +233,7 @@
 	int (*off) (struct mdss_panel_data *pdata);
 	int (*partial_update_fnc) (struct mdss_panel_data *pdata);
 	int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
-	void (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+	int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
 	struct mdss_panel_data panel_data;
 	unsigned char *ctrl_base;
 	int reg_size;
@@ -336,7 +336,7 @@
 void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
 void mdss_dsi_cmdlist_kickoff(int intf);
 int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
 
diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.c b/drivers/video/msm/mdss/mdss_dsi_cmd.c
index 9a3e638..8fc1115c0 100644
--- a/drivers/video/msm/mdss/mdss_dsi_cmd.c
+++ b/drivers/video/msm/mdss/mdss_dsi_cmd.c
@@ -655,7 +655,7 @@
 {
 	struct dcs_cmd_req *req;
 	struct dcs_cmd_list *clist;
-	int ret = 0;
+	int ret = -EINVAL;
 
 	mutex_lock(&ctrl->cmd_mutex);
 	clist = &ctrl->cmdlist;
@@ -674,7 +674,6 @@
 	}
 	mutex_unlock(&ctrl->cmd_mutex);
 
-	ret++;
 	pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
 		clist->tot, clist->put, clist->get);
 
@@ -682,7 +681,7 @@
 		if (!ctrl->cmdlist_commit)
 			pr_err("cmdlist_commit not implemented!\n");
 		else
-			ctrl->cmdlist_commit(ctrl, 0);
+			ret = ctrl->cmdlist_commit(ctrl, 0);
 	}
 	return ret;
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 37ccd4f..65e6214 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1155,38 +1155,55 @@
 				__func__, current->pid);
 }
 
-void mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+int mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
 				struct dcs_cmd_req *req)
 {
-	int ret;
+	int ret, ret_val = -EINVAL;
 
 	ret = mdss_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt);
 
+	if (!IS_ERR_VALUE(ret))
+		ret_val = 0;
+
 	if (req->cb)
 		req->cb(ret);
+
+	return ret_val;
 }
 
-void mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+int mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
 				struct dcs_cmd_req *req)
 {
 	struct dsi_buf *rp;
-	int len = 0;
+	int len = 0, ret = -EINVAL;
 
 	if (req->rbuf) {
 		rp = &ctrl->rx_buf;
 		len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen);
 		memcpy(req->rbuf, rp->data, rp->len);
+		/*
+		 * For dual DSI cases, early return of controller - 0
+		 * is valid. Hence, for those cases the return value
+		 * is zero even though we don't send any commands.
+		 *
+		 */
+		if ((ctrl->shared_pdata.broadcast_enable &&
+			ctrl->ndx == DSI_CTRL_0) || (len != 0))
+			ret = 0;
 	} else {
 		pr_err("%s: No rx buffer provided\n", __func__);
 	}
 
 	if (req->cb)
 		req->cb(len);
+
+	return ret;
 }
 
-void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
 {
 	struct dcs_cmd_req *req;
+	int ret = -EINVAL;
 
 	mutex_lock(&ctrl->cmd_mutex);
 	req = mdss_dsi_cmdlist_get(ctrl);
@@ -1211,9 +1228,9 @@
 	mdss_dsi_clk_ctrl(ctrl, 1);
 
 	if (req->flags & CMD_REQ_RX)
-		mdss_dsi_cmdlist_rx(ctrl, req);
+		ret = mdss_dsi_cmdlist_rx(ctrl, req);
 	else
-		mdss_dsi_cmdlist_tx(ctrl, req);
+		ret = mdss_dsi_cmdlist_tx(ctrl, req);
 
 	mdss_dsi_clk_ctrl(ctrl, 0);
 	mdss_bus_bandwidth_ctrl(0);
@@ -1224,6 +1241,7 @@
 		mdss_dsi_cmd_mdp_start(ctrl);
 
 	mutex_unlock(&ctrl->cmd_mutex);
+	return ret;
 }
 
 static void dsi_send_events(struct mdss_dsi_ctrl_pdata *ctrl, u32 events)
@@ -1313,6 +1331,8 @@
 
 	if (status) {
 		MIPI_OUTP(base + 0x0068, status);
+		/* Writing of an extra 0 needed to clear error bits */
+		MIPI_OUTP(base + 0x0068, 0);
 		pr_err("%s: status=%x\n", __func__, status);
 	}
 }
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 06f6959..3c7d17c 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -19,7 +19,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/leds.h>
-#include <linux/pwm.h>
+#include <linux/qpnp/pwm.h>
 #include <linux/err.h>
 
 #include "mdss_dsi.h"
@@ -69,9 +69,9 @@
 		ctrl->pwm_enabled = 0;
 	}
 
-	ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period);
+	ret = pwm_config_us(ctrl->pwm_bl, duty, ctrl->pwm_period);
 	if (ret) {
-		pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret);
+		pr_err("%s: pwm_config_us() failed err=%d.\n", __func__, ret);
 		return;
 	}
 
@@ -459,7 +459,7 @@
 	}
 
 	data = of_get_property(np, link_key, NULL);
-	if (!strncmp(data, "dsi_hs_mode", 11))
+	if (data && !strcmp(data, "dsi_hs_mode"))
 		pcmds->link_state = DSI_HS_MODE;
 	else
 		pcmds->link_state = DSI_LP_MODE;
@@ -695,19 +695,24 @@
 	pdest = of_get_property(np,
 		"qcom,mdss-dsi-panel-destination", NULL);
 
-	if (strlen(pdest) != 9) {
-		pr_err("%s: Unknown pdest specified\n", __func__);
+	if (pdest) {
+		if (strlen(pdest) != 9) {
+			pr_err("%s: Unknown pdest specified\n", __func__);
+			return -EINVAL;
+		}
+		if (!strcmp(pdest, "display_1"))
+			pinfo->pdest = DISPLAY_1;
+		else if (!strcmp(pdest, "display_2"))
+			pinfo->pdest = DISPLAY_2;
+		else {
+			pr_debug("%s: pdest not specified. Set Default\n",
+								__func__);
+			pinfo->pdest = DISPLAY_1;
+		}
+	} else {
+		pr_err("%s: pdest not specified\n", __func__);
 		return -EINVAL;
 	}
-	if (!strncmp(pdest, "display_1", 9))
-		pinfo->pdest = DISPLAY_1;
-	else if (!strncmp(pdest, "display_2", 9))
-		pinfo->pdest = DISPLAY_2;
-	else {
-		pr_debug("%s: pdest not specified. Set Default\n",
-							__func__);
-		pinfo->pdest = DISPLAY_1;
-	}
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-front-porch", &tmp);
 	pinfo->lcdc.h_front_porch = (!rc ? tmp : 6);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-h-back-porch", &tmp);
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index bb27e6b..6dbca10 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -23,7 +23,7 @@
 #include <linux/gpio.h>
 #include <linux/err.h>
 #include <linux/regulator/consumer.h>
-#include <linux/pwm.h>
+#include <linux/qpnp/pwm.h>
 #include <linux/clk.h>
 #include <linux/spinlock_types.h>
 #include <linux/kthread.h>
@@ -210,11 +210,11 @@
 		if (bl_level > bl_max)
 			bl_level = bl_max;
 
-		ret = pwm_config(edp_drv->bl_pwm,
+		ret = pwm_config_us(edp_drv->bl_pwm,
 				bl_level * edp_drv->pwm_period / bl_max,
 				edp_drv->pwm_period);
 		if (ret) {
-			pr_err("%s: pwm_config() failed err=%d.\n", __func__,
+			pr_err("%s: pwm_config_us() failed err=%d.\n", __func__,
 					ret);
 			return;
 		}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index c15c02b..54e3bc8 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1836,11 +1836,11 @@
 
 int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state)
 {
-	int ret = -EINVAL;
+	int ret = 0;
 
 	if (req_state == mfd->dcm_state) {
-		pr_warn("Already in correct DCM state");
-		ret = 0;
+		pr_warn("Already in correct DCM/DTM state");
+		return ret;
 	}
 
 	switch (req_state) {
@@ -1856,11 +1856,12 @@
 		break;
 	case DCM_ENTER:
 		if (mfd->dcm_state == DCM_UNBLANK) {
-			/* Keep unblank path available for only
-			DCM operation */
+			/*
+			 * Keep unblank path available for only
+			 * DCM operation
+			 */
 			mfd->panel_power_on = false;
 			mfd->dcm_state = DCM_ENTER;
-			ret = 0;
 		}
 		break;
 	case DCM_EXIT:
@@ -1868,7 +1869,6 @@
 			/* Release the unblank path for exit */
 			mfd->panel_power_on = true;
 			mfd->dcm_state = DCM_EXIT;
-			ret = 0;
 		}
 		break;
 	case DCM_BLANK:
@@ -1882,7 +1882,16 @@
 			}
 		}
 		break;
+	case DTM_ENTER:
+		if (mfd->dcm_state == DCM_UNINIT)
+			mfd->dcm_state = DTM_ENTER;
+		break;
+	case DTM_EXIT:
+		if (mfd->dcm_state == DTM_ENTER)
+			mfd->dcm_state = DCM_UNINIT;
+		break;
 	}
+
 	return ret;
 }
 
@@ -2187,6 +2196,7 @@
 	struct platform_device *fb_pdev, *mdss_pdev;
 	struct device_node *node;
 	int rc = 0;
+	bool master_panel = true;
 
 	if (!pdev || !pdev->dev.of_node) {
 		pr_err("Invalid device node\n");
@@ -2214,6 +2224,8 @@
 	fb_pdev = of_find_device_by_node(node);
 	if (fb_pdev) {
 		rc = mdss_fb_register_extra_panel(fb_pdev, pdata);
+		if (rc == 0)
+			master_panel = false;
 	} else {
 		pr_info("adding framebuffer device %s\n", dev_name(&pdev->dev));
 		fb_pdev = of_platform_device_create(node, NULL,
@@ -2221,7 +2233,7 @@
 		fb_pdev->dev.platform_data = pdata;
 	}
 
-	if (mdp_instance->panel_register_done)
+	if (master_panel && mdp_instance->panel_register_done)
 		mdp_instance->panel_register_done(pdata);
 
 mdss_notfound:
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index b218b1e..3269eec 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1316,7 +1316,7 @@
 {
 	char *t = NULL;
 	char pan_intf_str[MDSS_MAX_PANEL_LEN];
-	int rc, i;
+	int rc, i, panel_len;
 	char pan_name[MDSS_MAX_PANEL_LEN];
 
 	if (!pan_cfg)
@@ -1353,6 +1353,14 @@
 	strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg));
 	pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__,
 		t, pan_cfg->arg_cfg);
+
+	panel_len = strlen(pan_cfg->arg_cfg);
+	if (!panel_len) {
+		pr_err("%s: Panel name is invalid\n", __func__);
+		pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID;
+		return -EINVAL;
+	}
+
 	rc = mdss_mdp_get_pan_intf(pan_intf_str);
 	pan_cfg->pan_intf = (rc < 0) ?  MDSS_PANEL_INTF_INVALID : rc;
 	return 0;
@@ -1457,10 +1465,10 @@
 	of_node_put(chosen_node);
 
 	rc = mdss_mdp_get_pan_cfg(pan_cfg);
-	if (!rc)
+	if (!rc) {
 		pan_cfg->init_done = true;
-
-	return rc;
+		return rc;
+	}
 
 get_dt_pan:
 	rc = mdss_mdp_parse_dt_pan_intf(pdev);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 769f9b2..fad6b0c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -289,6 +289,7 @@
 struct mdss_ad_info {
 	u8 num;
 	u8 calc_hw_num;
+	u32 ops;
 	u32 sts;
 	u32 reg_sts;
 	u32 state;
@@ -516,7 +517,7 @@
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
 		struct mdss_panel_data *pdata);
 int mdss_mdp_ctl_destroy(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff);
 int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
 int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index bad4d06..d57e4fb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1062,26 +1062,34 @@
 	return rc;
 }
 
-static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl)
+static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
 {
 	struct mdss_mdp_mixer *mixer;
 	u32 outsize, temp;
 	int ret = 0;
 	int i, nmixers;
 
-	if (ctl->start_fnc)
-		ret = ctl->start_fnc(ctl);
-	else
-		pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
-				ctl->panel_data->panel_info.type);
-
-	if (ret) {
-		pr_err("unable to start intf\n");
-		return ret;
-	}
-
 	pr_debug("ctl_num=%d\n", ctl->num);
 
+	/*
+	 * Need start_fnc in 2 cases:
+	 * (1) handoff
+	 * (2) continuous splash finished.
+	 */
+	if (handoff || !ctl->panel_data->panel_info.cont_splash_enabled) {
+		if (ctl->start_fnc)
+			ret = ctl->start_fnc(ctl);
+		else
+			pr_warn("no start function for ctl=%d type=%d\n",
+					ctl->num,
+					ctl->panel_data->panel_info.type);
+
+		if (ret) {
+			pr_err("unable to start intf\n");
+			return ret;
+		}
+	}
+
 	if (!ctl->panel_data->panel_info.cont_splash_enabled) {
 		nmixers = MDSS_MDP_INTF_MAX_LAYERMIXER +
 			MDSS_MDP_WB_MAX_LAYERMIXER;
@@ -1108,7 +1116,7 @@
 	return ret;
 }
 
-int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl)
+int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
 {
 	struct mdss_mdp_ctl *sctl;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -1123,12 +1131,17 @@
 	if (ret)
 		return ret;
 
-
 	sctl = mdss_mdp_get_split_ctl(ctl);
 
 	mutex_lock(&ctl->lock);
 
-	ctl->power_on = true;
+	/*
+	 * keep power_on false during handoff to avoid unexpected
+	 * operations to overlay.
+	 */
+	if (!handoff)
+		ctl->power_on = true;
+
 	ctl->bus_ab_quota = 0;
 	ctl->bus_ib_quota = 0;
 	ctl->clk_rate = 0;
@@ -1141,10 +1154,10 @@
 		goto error;
 	}
 
-	ret = mdss_mdp_ctl_start_sub(ctl);
+	ret = mdss_mdp_ctl_start_sub(ctl, handoff);
 	if (ret == 0) {
 		if (sctl) { /* split display is available */
-			ret = mdss_mdp_ctl_start_sub(sctl);
+			ret = mdss_mdp_ctl_start_sub(sctl, handoff);
 			if (!ret)
 				mdss_mdp_ctl_split_display_enable(1, ctl, sctl);
 		} else if (ctl->mixer_right) {
@@ -1900,8 +1913,10 @@
 	if (ctl->wait_pingpong)
 		ctl->wait_pingpong(ctl, NULL);
 
-	/* postprocessing setup, including dspp */
-	mdss_mdp_pp_setup_locked(ctl);
+	if (ctl->mfd && ctl->mfd->dcm_state != DTM_ENTER)
+		/* postprocessing setup, including dspp */
+		mdss_mdp_pp_setup_locked(ctl);
+
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
 	if (sctl) {
 		mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index b6f94d0..bcd3cf4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -108,7 +108,9 @@
 	MDSS_MDP_MAX_CTL
 };
 
-#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * 0x100))
+#define MDSS_MDP_CTL_ADDRESS_OFFSET			0x100
+#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * \
+					 MDSS_MDP_CTL_ADDRESS_OFFSET))
 
 #define MDSS_MDP_REG_CTL_LAYER(lm)			((lm) * 0x004)
 #define MDSS_MDP_REG_CTL_TOP				0x014
@@ -159,7 +161,10 @@
 	MDSS_MDP_CHROMA_420
 };
 
-#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * 0x400))
+
+#define MDSS_MDP_SSPP_ADDRESS_OFFSET			0x400
+#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * \
+					MDSS_MDP_SSPP_ADDRESS_OFFSET))
 
 #define MDSS_MDP_REG_SSPP_SRC_SIZE			0x000
 #define MDSS_MDP_REG_SSPP_SRC_IMG_SIZE			0x004
@@ -175,6 +180,7 @@
 #define MDSS_MDP_REG_SSPP_STILE_FRAME_SIZE		0x02C
 #define MDSS_MDP_REG_SSPP_SRC_FORMAT			0x030
 #define MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN		0x034
+#define MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR		0x03C
 #define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_0		0x050
 #define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_1		0x054
 #define MDSS_MDP_REG_SSPP_REQPRIO_FIFO_WM_2		0x058
@@ -280,8 +286,9 @@
 	MDSS_MDP_MAX_STAGE
 };
 
-#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * 0x400))
-
+#define MDSS_MDP_LM_ADDRESS_OFFSET			0x400
+#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * \
+					MDSS_MDP_LM_ADDRESS_OFFSET))
 #define MDSS_MDP_REG_LM_OP_MODE				0x000
 #define MDSS_MDP_REG_LM_OUT_SIZE			0x004
 #define MDSS_MDP_REG_LM_BORDER_COLOR_0			0x008
@@ -423,7 +430,9 @@
 	MDSS_MDP_MAX_DSPP
 };
 
-#define MDSS_MDP_REG_DSPP_OFFSET(pipe)	(0x4600 + ((pipe) * 0x400))
+#define MDSS_MDP_DSPP_ADDRESS_OFFSET			0x400
+#define MDSS_MDP_REG_DSPP_OFFSET(pipe)	(0x4600 + ((pipe) * \
+					MDSS_MDP_DSPP_ADDRESS_OFFSET))
 #define MDSS_MDP_REG_DSPP_OP_MODE			0x000
 #define MDSS_MDP_REG_DSPP_PCC_BASE			0x030
 #define MDSS_MDP_REG_DSPP_DITHER_DEPTH			0x150
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 14b486a..4c89064 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -859,7 +859,7 @@
 		mdss_hw_init(mdss_res);
 	}
 
-	rc = mdss_mdp_ctl_start(ctl);
+	rc = mdss_mdp_ctl_start(ctl, false);
 	if (rc == 0) {
 		atomic_inc(&ov_active_panels);
 
@@ -1580,8 +1580,8 @@
 		return -ENODEV;
 	if (!ctl->add_vsync_handler || !ctl->remove_vsync_handler)
 		return -EOPNOTSUPP;
-
-	if (!ctl->power_on) {
+	if (!ctl->panel_data->panel_info.cont_splash_enabled
+			&& !ctl->power_on) {
 		pr_debug("fb%d vsync pending first update en=%d\n",
 				mfd->index, en);
 		return -EPERM;
@@ -1698,7 +1698,9 @@
 	u64 vsync_ticks;
 	int ret;
 
-	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+	if (!mdp5_data->ctl ||
+		(!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled
+			&& !mdp5_data->ctl->power_on))
 		return -EAGAIN;
 
 	vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
@@ -2535,9 +2537,15 @@
 		mdp5_data->ctl = ctl;
 	}
 
-	rc = mdss_mdp_ctl_setup(ctl);
-	if (rc)
+	/*
+	 * vsync interrupt needs on during continuous splash, this is
+	 * to initialize necessary ctl members here.
+	 */
+	rc = mdss_mdp_ctl_start(ctl, true);
+	if (rc) {
+		pr_err("Failed to initialize ctl\n");
 		goto error;
+	}
 
 	ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC);
 	pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 0dc61d0..555974b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -173,6 +173,13 @@
 	GAMUT_T2_SIZE + GAMUT_T3_SIZE + GAMUT_T4_SIZE + \
 	GAMUT_T5_SIZE + GAMUT_T6_SIZE + GAMUT_T7_SIZE)
 
+#define MDSS_MDP_PA_SIZE		0xC
+#define MDSS_MDP_GC_SIZE		0x28
+#define MDSS_MDP_PCC_SIZE		0xB8
+#define MDSS_MDP_GAMUT_SIZE		0x5C
+#define MDSS_MDP_IGC_DSPP_COLORS	0x3
+#define TOTAL_BLEND_STAGES		0x4
+
 #define PP_FLAGS_DIRTY_PA	0x1
 #define PP_FLAGS_DIRTY_PCC	0x2
 #define PP_FLAGS_DIRTY_IGC	0x4
@@ -205,6 +212,10 @@
 
 #define PP_AD_BAD_HW_NUM 255
 
+#define MDSS_SIDE_NONE	0
+#define MDSS_SIDE_LEFT	1
+#define MDSS_SIDE_RIGHT	2
+
 #define PP_AD_STATE_INIT	0x2
 #define PP_AD_STATE_CFG		0x4
 #define PP_AD_STATE_DATA	0x8
@@ -293,15 +304,15 @@
 	struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE];
 	u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE];
-	/* physical info */
 	struct pp_sts_type pp_disp_sts[MDSS_BLOCK_DISP_NUM];
+	/* physical info */
 	struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP];
 };
 
 static DEFINE_MUTEX(mdss_pp_mutex);
 static struct mdss_pp_res_type *mdss_pp_res;
 
-static void pp_hist_read(char __iomem *v_addr,
+static u32 pp_hist_read(char __iomem *v_addr,
 				struct pp_hist_col_info *hist_info);
 static int pp_histogram_setup(u32 *op, u32 block, struct mdss_mdp_mixer *mix);
 static int pp_histogram_disable(struct pp_hist_col_info *hist_info,
@@ -340,8 +351,9 @@
 static void pp_dither_config(char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_dither_cfg_data *dither_cfg);
-static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode,
-				int mdp_rev);
+static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
+					struct pp_sts_type *pp_sts, int mdp_rev,
+					u32 *opmode);
 static void pp_sharp_config(char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_sharp_cfg *sharp_config);
@@ -375,11 +387,15 @@
 			struct mdss_ad_info *ad, struct mdss_mdp_ctl *ctl);
 static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw,
 						struct mdss_ad_info *ad);
-static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode);
 static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
 						struct mdss_ad_info *ad);
+static void pp_ad_bypass_config(struct mdss_ad_info *ad,
+				struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode);
 static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
 static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
+static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num);
+static inline bool pp_sts_is_enabled(u32 sts, int side);
+static inline void pp_sts_set_split_bits(u32 *sts, u32 bits);
 
 static u32 last_sts, last_state;
 
@@ -511,6 +527,7 @@
 		pp_sts->gamut_sts &= ~PP_STS_ENABLE;
 	else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
 		pp_sts->gamut_sts |= PP_STS_ENABLE;
+	pp_sts_set_split_bits(&pp_sts->gamut_sts, gamut_cfg->flags);
 }
 
 static void pp_pa_config(unsigned long flags, char __iomem *addr,
@@ -679,6 +696,7 @@
 	if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_VAL_MASK)
 		pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_VAL_MASK;
 
+	pp_sts_set_split_bits(&pp_sts->pa_sts, pa_v2_config->flags);
 }
 
 static void pp_pcc_config(unsigned long flags, char __iomem *addr,
@@ -693,6 +711,7 @@
 			pp_sts->pcc_sts &= ~PP_STS_ENABLE;
 		else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
 			pp_sts->pcc_sts |= PP_STS_ENABLE;
+		pp_sts_set_split_bits(&pp_sts->pcc_sts, pcc_config->ops);
 	}
 }
 
@@ -720,6 +739,7 @@
 			pp_sts->igc_sts &= ~PP_STS_ENABLE;
 		else if (igc_config->ops & MDP_PP_OPS_ENABLE)
 			pp_sts->igc_sts |= PP_STS_ENABLE;
+		pp_sts_set_split_bits(&pp_sts->igc_sts, igc_config->ops);
 	}
 }
 
@@ -1324,12 +1344,20 @@
 		pp_sts->dither_sts &= ~PP_STS_ENABLE;
 	else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
 		pp_sts->dither_sts |= PP_STS_ENABLE;
+	pp_sts_set_split_bits(&pp_sts->dither_sts, dither_cfg->flags);
 }
 
-static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode,
-			int mdp_rev)
+static void pp_dspp_opmode_config(struct mdss_mdp_ctl *ctl, u32 num,
+					struct pp_sts_type *pp_sts, int mdp_rev,
+					u32 *opmode)
 {
-	if (pp_sts->pa_sts & PP_STS_ENABLE)
+	int side;
+	side = pp_num_to_side(ctl, num);
+
+	if (side < 0)
+		return;
+
+	if (pp_sts_is_enabled(pp_sts->pa_sts, side))
 		*opmode |= MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
 	if (mdp_rev >= MDSS_MDP_HW_REV_103) {
 		if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK)
@@ -1357,10 +1385,10 @@
 		if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_VAL_MASK)
 			*opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK;
 	}
-	if (pp_sts->pcc_sts & PP_STS_ENABLE)
+	if (pp_sts_is_enabled(pp_sts->pcc_sts, side))
 		*opmode |= MDSS_MDP_DSPP_OP_PCC_EN; /* PCC_EN */
 
-	if (pp_sts->igc_sts & PP_STS_ENABLE) {
+	if (pp_sts_is_enabled(pp_sts->igc_sts, side)) {
 		*opmode |= MDSS_MDP_DSPP_OP_IGC_LUT_EN | /* IGC_LUT_EN */
 			      (pp_sts->igc_tbl_idx << 1);
 	}
@@ -1368,14 +1396,14 @@
 		*opmode |= MDSS_MDP_DSPP_OP_HIST_LUTV_EN | /* HIST_LUT_EN */
 				  MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
 	}
-	if (pp_sts->dither_sts & PP_STS_ENABLE)
+	if (pp_sts_is_enabled(pp_sts->dither_sts, side))
 		*opmode |= MDSS_MDP_DSPP_OP_DST_DITHER_EN; /* DITHER_EN */
-	if (pp_sts->gamut_sts & PP_STS_ENABLE) {
+	if (pp_sts_is_enabled(pp_sts->gamut_sts, side)) {
 		*opmode |= MDSS_MDP_DSPP_OP_GAMUT_EN; /* GAMUT_EN */
 		if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
 			*opmode |= MDSS_MDP_DSPP_OP_GAMUT_PCC_ORDER;
 	}
-	if (pp_sts->pgc_sts & PP_STS_ENABLE)
+	if (pp_sts_is_enabled(pp_sts->pgc_sts, side))
 		*opmode |= MDSS_MDP_DSPP_OP_ARGC_LUT_EN;
 }
 
@@ -1481,6 +1509,7 @@
 			pp_sts->pgc_sts &= ~PP_STS_ENABLE;
 		else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
 			pp_sts->pgc_sts |= PP_STS_ENABLE;
+		pp_sts_set_split_bits(&pp_sts->pgc_sts, pgc_config->flags);
 	}
 
 	if (ad_hw) {
@@ -1492,12 +1521,12 @@
 			pp_ad_init_write(ad_hw, ad, ctl);
 		if (ad_flags & PP_AD_STS_DIRTY_CFG)
 			pp_ad_cfg_write(ad_hw, ad);
-		pp_ad_bypass_config(ad, &ad_bypass);
+		pp_ad_bypass_config(ad, ctl, ad_hw->num, &ad_bypass);
 		writel_relaxed(ad_bypass, ad_hw->base);
 		mutex_unlock(&ad->lock);
 	}
 
-	pp_dspp_opmode_config(pp_sts, &opmode, mdata->mdp_rev);
+	pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode);
 flush_exit:
 	writel_relaxed(opmode, base + MDSS_MDP_REG_DSPP_OP_MODE);
 	ctl->flush_bits |= BIT(13 + dspp_num);
@@ -1705,11 +1734,13 @@
 		if (mdss_pp_res == NULL) {
 			pr_err("%s mdss_pp_res allocation failed!", __func__);
 			ret = -ENOMEM;
-		}
-
-		for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) {
-			mutex_init(&mdss_pp_res->dspp_hist[i].hist_mutex);
-			spin_lock_init(&mdss_pp_res->dspp_hist[i].hist_lock);
+		} else {
+			for (i = 0; i < MDSS_MDP_MAX_DSPP; i++) {
+				mutex_init(
+					&mdss_pp_res->dspp_hist[i].hist_mutex);
+				spin_lock_init(
+					&mdss_pp_res->dspp_hist[i].hist_lock);
+			}
 		}
 	}
 	if (mdata) {
@@ -1836,6 +1867,12 @@
 		(config->block >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
+	if ((config->pa_v2_data.flags & MDSS_PP_SPLIT_MASK) ==
+							MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
@@ -2119,6 +2156,11 @@
 		(config->block >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
+	if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
@@ -2238,6 +2280,11 @@
 	if (config->len != IGC_LUT_ENTRIES)
 		return -EINVAL;
 
+	if ((config->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
@@ -2437,6 +2484,11 @@
 		(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
+	if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 
 	disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2608,6 +2660,11 @@
 	if (config->flags & MDP_PP_OPS_READ)
 		return -ENOTSUPP;
 
+	if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 	mdss_pp_res->dither_disp_cfg[disp_num] = *config;
@@ -2657,6 +2714,11 @@
 	if (pp_gm_has_invalid_lut_size(config))
 		return -EINVAL;
 
+	if ((config->flags & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
@@ -2773,19 +2835,27 @@
 	mutex_unlock(&mdss_pp_mutex);
 	return ret;
 }
-static void pp_hist_read(char __iomem *v_addr,
+
+static u32 pp_hist_read(char __iomem *v_addr,
 				struct pp_hist_col_info *hist_info)
 {
 	int i, i_start;
+	u32 sum = 0;
 	u32 data;
 	data = readl_relaxed(v_addr);
 	i_start = data >> 24;
 	hist_info->data[i_start] = data & 0xFFFFFF;
-	for (i = i_start + 1; i < HIST_V_SIZE; i++)
+	sum += hist_info->data[i_start];
+	for (i = i_start + 1; i < HIST_V_SIZE; i++) {
 		hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
-	for (i = 0; i < i_start - 1; i++)
+		sum += hist_info->data[i];
+	}
+	for (i = 0; i < i_start; i++) {
 		hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
+		sum += hist_info->data[i];
+	}
 	hist_info->hist_cnt_read++;
+	return sum;
 }
 
 /* Assumes that relevant clocks are enabled */
@@ -3168,10 +3238,10 @@
 
 static int pp_hist_collect(struct mdp_histogram_data *hist,
 				struct pp_hist_col_info *hist_info,
-				char __iomem *ctl_base)
+				char __iomem *ctl_base, u32 expect_sum)
 {
 	int wait_ret, ret = 0;
-	u32 timeout;
+	u32 timeout, sum;
 	char __iomem *v_base;
 	unsigned long flag;
 	struct mdss_pipe_pp_res *res;
@@ -3238,10 +3308,13 @@
 		spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 		v_base = ctl_base + 0x1C;
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-		pp_hist_read(v_base, hist_info);
+		sum = pp_hist_read(v_base, hist_info);
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 		spin_lock_irqsave(&hist_info->hist_lock, flag);
-		hist_info->read_request = false;
+		if (!expect_sum || sum == expect_sum)
+			hist_info->read_request = false;
+		else
+			ret = -ENODATA;
 		hist_info->col_state = HIST_IDLE;
 	}
 	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
@@ -3261,6 +3334,7 @@
 	u32 *hist_data_addr;
 	u32 pipe_cnt = 0;
 	u32 pipe_num = MDSS_MDP_SSPP_VIG0;
+	u32 exp_sum = 0;
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
@@ -3290,7 +3364,10 @@
 			hist_info = &mdss_pp_res->dspp_hist[dspp_num];
 			ctl_base = mdss_mdp_get_dspp_addr_off(dspp_num) +
 				MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
-			ret = pp_hist_collect(hist, hist_info, ctl_base);
+			exp_sum = (mdata->mixer_intf[dspp_num].width *
+					mdata->mixer_intf[dspp_num].height);
+			ret = pp_hist_collect(hist, hist_info, ctl_base,
+								exp_sum);
 			if (ret)
 				goto hist_collect_exit;
 		}
@@ -3359,7 +3436,8 @@
 			hist_info = &pipe->pp_res.hist;
 			ctl_base = pipe->base +
 				MDSS_MDP_REG_VIG_HIST_CTL_BASE;
-			ret = pp_hist_collect(hist, hist_info, ctl_base);
+			ret = pp_hist_collect(hist, hist_info, ctl_base,
+								exp_sum);
 			mdss_mdp_pipe_unmap(pipe);
 			if (ret)
 				goto hist_collect_exit;
@@ -3490,6 +3568,53 @@
 	return out;
 }
 
+static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num)
+{
+	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+	u32 mixer_num;
+
+	if (!ctl || !ctl->mfd)
+		return -EINVAL;
+	mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
+	if (mixer_num < 2)
+		return MDSS_SIDE_NONE;
+	else if (mixer_id[1] == num)
+		return MDSS_SIDE_RIGHT;
+	else if (mixer_id[0] == num)
+		return MDSS_SIDE_LEFT;
+	else
+		pr_err("invalid, not on any side");
+	return -EINVAL;
+}
+
+static inline void pp_sts_set_split_bits(u32 *sts, u32 bits)
+{
+	u32 tmp = *sts;
+	tmp &= ~MDSS_PP_SPLIT_MASK;
+	tmp |= bits & MDSS_PP_SPLIT_MASK;
+	*sts = tmp;
+}
+
+static inline bool pp_sts_is_enabled(u32 sts, int side)
+{
+	bool ret = false;
+	/*
+	 * If there are no sides, or if there are no split mode bits set, the
+	 * side can't be disabled via split mode.
+	 *
+	 * Otherwise, if the side being checked opposes the split mode
+	 * configuration, the side is disabled.
+	 */
+	if ((side == MDSS_SIDE_NONE) || !(sts & MDSS_PP_SPLIT_MASK))
+		ret = true;
+	else if ((sts & MDSS_PP_SPLIT_RIGHT_ONLY) && (side == MDSS_SIDE_RIGHT))
+		ret = true;
+	else if ((sts & MDSS_PP_SPLIT_LEFT_ONLY) && (side == MDSS_SIDE_LEFT))
+		ret = true;
+
+	return ret && (sts & PP_STS_ENABLE);
+}
+
 static int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
 {
 	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
@@ -3586,7 +3711,7 @@
 	struct mdss_mdp_ctl *ctl;
 	struct msm_fb_data_type *bl_mfd;
 	int lin_ret = -1, inv_ret = -1, ret = 0;
-	u32 ratio_temp, shift = 0;
+	u32 ratio_temp, shift = 0, last_ops;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
 	if (ret)
@@ -3599,6 +3724,11 @@
 		bl_mfd = mfd;
 	}
 
+	if ((init_cfg->ops & MDSS_PP_SPLIT_MASK) == MDSS_PP_SPLIT_MASK) {
+		pr_warn("Can't set both split bits\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&ad->lock);
 	if (init_cfg->ops & MDP_PP_AD_INIT) {
 		memcpy(&ad->init, &init_cfg->params.init,
@@ -3638,6 +3768,22 @@
 		ad->sts |= PP_AD_STS_DIRTY_CFG;
 	}
 
+	last_ops = ad->ops & MDSS_PP_SPLIT_MASK;
+	ad->ops = init_cfg->ops & MDSS_PP_SPLIT_MASK;
+	/*
+	 *  if there is a change in the split mode config, the init values
+	 *  need to be re-written to hardware (if they have already been
+	 *  written or if there is data pending to be written). Check for
+	 *  pending data (DIRTY_INIT) is not checked here since it will not
+	 *  affect the outcome of this conditional (i.e. if init hasn't
+	 *  already been written (*_STATE_INIT is set), this conditional will
+	 *  only evaluate to true (and set the DIRTY bit) if the DIRTY bit has
+	 *  already been set).
+	 */
+	if ((last_ops ^ ad->ops) && (ad->state & PP_AD_STATE_INIT))
+		ad->sts |= PP_AD_STS_DIRTY_INIT;
+
+
 	if (!ret && (init_cfg->ops & MDP_PP_OPS_DISABLE)) {
 		ad->sts &= ~PP_STS_ENABLE;
 		mutex_unlock(&ad->lock);
@@ -3792,8 +3938,9 @@
 	u32 temp;
 	u32 frame_start, frame_end, procs_start, procs_end, tile_ctrl;
 	u32 num;
+	int side;
 	char __iomem *base;
-	bool is_calc, is_dual_pipe;
+	bool is_calc, is_dual_pipe, split_mode;
 	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
 	u32 mixer_num;
 	mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
@@ -3804,6 +3951,7 @@
 
 	base = ad_hw->base;
 	is_calc = ad->calc_hw_num == ad_hw->num;
+	split_mode = !!(ad->ops & MDSS_PP_SPLIT_MASK);
 
 	writel_relaxed(ad->init.i_control[0] & 0x1F,
 				base + MDSS_MDP_REG_AD_CON_CTRL_0);
@@ -3829,7 +3977,10 @@
 	writel_relaxed(ad->init.format, base + MDSS_MDP_REG_AD_CTRL_0);
 	writel_relaxed(ad->init.auto_size, base + MDSS_MDP_REG_AD_CTRL_1);
 
-	temp = ad->init.frame_w << 16;
+	if (split_mode)
+		temp = mdata->mixer_intf[ad_hw->num].width << 16;
+	else
+		temp = ad->init.frame_w << 16;
 	temp |= ad->init.frame_h & 0xFFFF;
 	writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
 
@@ -3841,17 +3992,26 @@
 	pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_CC, ad->init.color_corr_lut);
 
 	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
-		if (is_dual_pipe) {
+		if (is_dual_pipe && !split_mode) {
 			num = ad_hw->num;
+			side = pp_num_to_side(ctl, num);
 			tile_ctrl = 0x5;
-			if (is_calc) {
+			if ((ad->calc_hw_num + 1) == num)
+				tile_ctrl |= 0x10;
+
+			if (side <= MDSS_SIDE_NONE) {
+				WARN(1, "error finding sides, %d", side);
+				frame_start = 0;
+				procs_start = frame_start;
+				frame_end = 0;
+				procs_end = frame_end;
+			} else if (side == MDSS_SIDE_LEFT) {
 				frame_start = 0;
 				procs_start = 0;
 				frame_end = mdata->mixer_intf[num].width +
 							MDSS_AD_MERGED_WIDTH;
 				procs_end = mdata->mixer_intf[num].width;
 			} else {
-				tile_ctrl |= 0x10;
 				procs_start = ad->init.frame_w -
 					(mdata->mixer_intf[num].width);
 				procs_end = ad->init.frame_w;
@@ -3866,8 +4026,13 @@
 			frame_end = 0xFFFF;
 			procs_start = 0x0;
 			procs_end = 0xFFFF;
-			tile_ctrl = 0x1;
+			if (split_mode)
+				tile_ctrl = 0x0;
+			else
+				tile_ctrl = 0x1;
 		}
+
+
 		writel_relaxed(frame_start, base + MDSS_MDP_REG_AD_FRAME_START);
 		writel_relaxed(frame_end, base + MDSS_MDP_REG_AD_FRAME_END);
 		writel_relaxed(procs_start, base + MDSS_MDP_REG_AD_PROCS_START);
@@ -3931,12 +4096,17 @@
 }
 
 #define MDSS_PP_AD_BYPASS_DEF 0x101
-static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode)
+static void pp_ad_bypass_config(struct mdss_ad_info *ad,
+				struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode)
 {
-	if (ad->reg_sts & PP_STS_ENABLE)
+	int side = pp_num_to_side(ctl, num);
+
+	if (pp_sts_is_enabled(ad->reg_sts | (ad->ops & MDSS_PP_SPLIT_MASK),
+								side)) {
 		*opmode = 0;
-	else
+	} else {
 		*opmode = MDSS_PP_AD_BYPASS_DEF;
+	}
 }
 
 static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
@@ -3951,6 +4121,8 @@
 
 	/* default to left mixer */
 	ad->calc_hw_num = mixer_id[0];
+	if ((mixer_num > 1) && (ad->ops & MDSS_PP_SPLIT_RIGHT_ONLY))
+		ad->calc_hw_num = mixer_id[1];
 	return 0;
 }
 
@@ -4258,6 +4430,7 @@
 		mdata->ad_off[i].base = mdata->mdp_base + ad_offsets[i];
 		mdata->ad_off[i].num = i;
 		mdata->ad_cfgs[i].num = i;
+		mdata->ad_cfgs[i].ops = 0;
 		mdata->ad_cfgs[i].reg_sts = 0;
 		mdata->ad_cfgs[i].calc_itr = 0;
 		mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
@@ -4270,71 +4443,271 @@
 	return rc;
 }
 
-static int is_valid_calib_addr(void *addr)
+static int is_valid_calib_ctrl_addr(char __iomem *ptr)
+{
+	char __iomem *base;
+	int ret = 0, counter = 0;
+	int stage = 0;
+	struct mdss_mdp_ctl *ctl;
+
+	/* Controller */
+	for (counter = 0; counter < mdss_res->nctl; counter++) {
+		ctl = mdss_res->ctl_off + counter;
+		base = ctl->base;
+
+		if (ptr == base + MDSS_MDP_REG_CTL_TOP) {
+			ret = MDP_PP_OPS_READ;
+			break;
+		} else if (ptr == base + MDSS_MDP_REG_CTL_FLUSH) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		}
+
+		for (stage = 0; stage < mdss_res->nmixers_intf; stage++)
+			if (ptr == base + MDSS_MDP_REG_CTL_LAYER(stage)) {
+				ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+				goto End;
+			}
+	}
+
+End:
+	return ret;
+}
+
+static int is_valid_calib_dspp_addr(char __iomem *ptr)
+{
+	char __iomem *base;
+	int ret = 0, counter = 0;
+	struct mdss_mdp_mixer *mixer;
+
+	for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
+		mixer = mdss_res->mixer_intf + counter;
+		base = mixer->dspp_base;
+
+		if (ptr == base) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* PA range */
+		} else if ((ptr >= base + MDSS_MDP_REG_DSPP_PA_BASE) &&
+				(ptr <= base + MDSS_MDP_REG_DSPP_PA_BASE +
+						MDSS_MDP_PA_SIZE)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* PCC range */
+		} else if ((ptr >= base + MDSS_MDP_REG_DSPP_PCC_BASE) &&
+				(ptr <= base + MDSS_MDP_REG_DSPP_PCC_BASE +
+						MDSS_MDP_PCC_SIZE)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* Gamut range */
+		} else if ((ptr >= base + MDSS_MDP_REG_DSPP_GAMUT_BASE) &&
+				(ptr <= base + MDSS_MDP_REG_DSPP_GAMUT_BASE +
+						MDSS_MDP_GAMUT_SIZE)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* GC range */
+		} else if ((ptr >= base + MDSS_MDP_REG_DSPP_GC_BASE) &&
+				(ptr <= base + MDSS_MDP_REG_DSPP_GC_BASE +
+						MDSS_MDP_GC_SIZE)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* Dither enable/disable */
+		} else if ((ptr == base + MDSS_MDP_REG_DSPP_DITHER_DEPTH)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int is_valid_calib_vig_addr(char __iomem *ptr)
+{
+	char __iomem *base;
+	int ret = 0, counter = 0;
+	struct mdss_mdp_pipe *pipe;
+
+	for (counter = 0; counter < mdss_res->nvig_pipes; counter++) {
+		pipe = mdss_res->vig_pipes + counter;
+		base = pipe->base;
+
+		if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		} else if ((ptr == base + MDSS_MDP_REG_VIG_QSEED2_SHARP)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* PA range */
+		} else if ((ptr >= base + MDSS_MDP_REG_VIG_PA_BASE) &&
+				(ptr <= base + MDSS_MDP_REG_VIG_PA_BASE +
+						MDSS_MDP_PA_SIZE)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* IGC range */
+		} else if ((ptr >= base + MDSS_MDP_REG_IGC_VIG_BASE) &&
+				(ptr <= base + MDSS_MDP_REG_IGC_VIG_BASE +
+						MDSS_MDP_GC_SIZE)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int is_valid_calib_rgb_addr(char __iomem *ptr)
+{
+	char __iomem *base;
+	int ret = 0, counter = 0;
+	struct mdss_mdp_pipe *pipe;
+
+	for (counter = 0; counter < mdss_res->nrgb_pipes; counter++) {
+		pipe = mdss_res->rgb_pipes + counter;
+		base = pipe->base;
+
+		if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* IGC range */
+		} else if ((ptr >= base + MDSS_MDP_REG_IGC_RGB_BASE) &&
+				(ptr <= base + MDSS_MDP_REG_IGC_RGB_BASE +
+						MDSS_MDP_GC_SIZE)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int is_valid_calib_dma_addr(char __iomem *ptr)
+{
+	char __iomem *base;
+	int ret = 0, counter = 0;
+	struct mdss_mdp_pipe *pipe;
+
+	for (counter = 0; counter < mdss_res->ndma_pipes; counter++) {
+		pipe = mdss_res->dma_pipes + counter;
+		base = pipe->base;
+
+		if (ptr == base + MDSS_MDP_REG_SSPP_SRC_FORMAT) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		} else if (ptr == base + MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* IGC range */
+		} else if ((ptr >= base + MDSS_MDP_REG_IGC_DMA_BASE) &&
+				(ptr <= base + MDSS_MDP_REG_IGC_DMA_BASE +
+						MDSS_MDP_GC_SIZE)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int is_valid_calib_mixer_addr(char __iomem *ptr)
+{
+	char __iomem *base;
+	int ret = 0, counter = 0;
+	int stage = 0;
+	struct mdss_mdp_mixer *mixer;
+
+	for (counter = 0; counter < mdss_res->nmixers_intf; counter++) {
+		mixer = mdss_res->mixer_intf + counter;
+		base = mixer->base;
+
+		if (ptr == base + MDSS_MDP_REG_LM_OP_MODE) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		/* GC range */
+		} else if ((ptr >= base + MDSS_MDP_REG_LM_GC_LUT_BASE) &&
+			(ptr <= base + MDSS_MDP_REG_LM_GC_LUT_BASE +
+						MDSS_MDP_GC_SIZE)) {
+			ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+			break;
+		}
+
+		for (stage = 0; stage < TOTAL_BLEND_STAGES; stage++)
+			if (ptr == base + MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+						 MDSS_MDP_REG_LM_BLEND_OP) {
+				ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+				goto End;
+			} else if (ptr == base +
+					MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+					MDSS_MDP_REG_LM_BLEND_FG_ALPHA) {
+				ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+				goto End;
+			} else if (ptr == base +
+					 MDSS_MDP_REG_LM_BLEND_OFFSET(stage) +
+					 MDSS_MDP_REG_LM_BLEND_BG_ALPHA) {
+				ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+				goto End;
+			}
+	}
+
+End:
+	return ret;
+}
+
+static int is_valid_calib_addr(void *addr, u32 operation)
 {
 	int ret = 0;
-	unsigned int ptr;
-	ptr = (unsigned int) addr;
-	/* if request is outside the MDP reg-map or is not aligned 4 */
-	if (ptr > 0x5138 || ptr % 0x4)
-		goto end;
-	if (ptr >= 0x100 && ptr <= 0x5138) {
-		/* if ptr is in dspp range */
-		if (ptr >= 0x4600 && ptr <= 0x5138) {
-			/* if ptr is in dspp0 range*/
-			if (ptr >= 0x4600 && ptr <= 0x4938)
-				ptr -= 0x4600;
-			/* if ptr is in dspp1 range */
-			else if (ptr >= 0x4a00 && ptr <= 0x4d38)
-				ptr -= 0x4a00;
-			/* if ptr is in dspp2 range */
-			else if (ptr >= 0x4e00 && ptr <= 0x5138)
-				ptr -= 0x4e00;
-			/* if ptr is in pcc plane rgb coeff.range */
-			if (ptr >= 0x30 && ptr <= 0xe8)
-				ret = 1;
-			/* if ptr is in ARLUT red range */
-			else if (ptr >= 0x2b0 && ptr <= 0x2b8)
-				ret = 1;
-			/* if ptr is in PA range */
-			else if (ptr >= 0x238 && ptr <= 0x244)
-				ret = 1;
-			 /* if ptr is in ARLUT green range */
-			else if (ptr >= 0x2c0 && ptr <= 0x2c8)
-				ret = 1;
-			/* if ptr is in ARLUT blue range or
-			    gamut map table range */
-			else if (ptr >= 0x2d0 && ptr <= 0x338)
-				ret = 1;
-			/* if ptr is dspp0,dspp1,dspp2 op mode
-						register */
-			else if (ptr == 0)
-				ret = 1;
-		} else if (ptr >= 0x600 && ptr <= 0x608)
-				ret = 1;
-		else if (ptr >= 0x400 && ptr <= 0x408)
-				ret = 1;
-		else if ((ptr == 0x1830) || (ptr == 0x1c30) ||
-				(ptr == 0x1430) || (ptr == 0x1e38))
-				ret = 1;
-		else if ((ptr == 0x1e3c) || (ptr == 0x1e30))
-				ret = 1;
-		else if (ptr >= 0x3220 && ptr <= 0x3228)
-				ret = 1;
-		else if (ptr == 0x3200 || ptr == 0x100)
-				ret = 1;
-		else if (ptr == 0x104 || ptr == 0x614 || ptr == 0x714 ||
-			ptr == 0x814 || ptr == 0x914 || ptr == 0xa14)
-				ret = 1;
-		else if (ptr == 0x618 || ptr == 0x718 || ptr == 0x818 ||
-				 ptr == 0x918 || ptr == 0xa18)
-				ret = 1;
-		else if (ptr == 0x2234 || ptr == 0x1e34 || ptr == 0x2634)
-				ret = 1;
-	} else if (ptr == 0x0)
-		ret = 1;
-end:
-	return ret;
+	char __iomem *ptr = addr;
+	char __iomem *mixer_base = mdss_res->mixer_intf->base;
+	char __iomem *rgb_base   = mdss_res->rgb_pipes->base;
+	char __iomem *dma_base   = mdss_res->dma_pipes->base;
+	char __iomem *vig_base   = mdss_res->vig_pipes->base;
+	char __iomem *ctl_base   = mdss_res->ctl_off->base;
+	char __iomem *dspp_base  = mdss_res->mixer_intf->dspp_base;
+
+	if ((unsigned int)addr % 4) {
+		ret = 0;
+	} else if (ptr == (mdss_res->mdp_base + MDSS_MDP_REG_HW_VERSION) ||
+	    ptr == (mdss_res->mdp_base + MDSS_MDP_REG_DISP_INTF_SEL)) {
+		ret = MDP_PP_OPS_READ;
+	} else if (ptr >= (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE) &&
+		    ptr < (mdss_res->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE +
+						MDSS_MDP_IGC_DSPP_COLORS)) {
+		ret = MDP_PP_OPS_READ | MDP_PP_OPS_WRITE;
+	} else if (ptr >= dspp_base && ptr < (dspp_base +
+		(mdss_res->nmixers_intf * MDSS_MDP_DSPP_ADDRESS_OFFSET))) {
+		ret = is_valid_calib_dspp_addr(ptr);
+	} else if (ptr >= ctl_base && ptr < (ctl_base + (mdss_res->nctl
+					* MDSS_MDP_CTL_ADDRESS_OFFSET))) {
+		ret = is_valid_calib_ctrl_addr(ptr);
+	} else if (ptr >= vig_base && ptr < (vig_base + (mdss_res->nvig_pipes
+					* MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+		ret = is_valid_calib_vig_addr(ptr);
+	} else if (ptr >= rgb_base && ptr < (rgb_base + (mdss_res->nrgb_pipes
+					* MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+		ret = is_valid_calib_rgb_addr(ptr);
+	} else if (ptr >= dma_base && ptr < (dma_base + (mdss_res->ndma_pipes
+					* MDSS_MDP_SSPP_ADDRESS_OFFSET))) {
+		ret = is_valid_calib_dma_addr(ptr);
+	} else if (ptr >= mixer_base && ptr < (mixer_base +
+		(mdss_res->nmixers_intf * MDSS_MDP_LM_ADDRESS_OFFSET))) {
+		ret = is_valid_calib_mixer_addr(ptr);
+	}
+
+	return ret & operation;
 }
 
 int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback)
@@ -4342,11 +4715,12 @@
 	int ret = -1;
 	void *ptr = (void *) cfg->addr;
 
-	if (is_valid_calib_addr(ptr))
+	ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+	if (is_valid_calib_addr(ptr, cfg->ops))
 		ret = 0;
 	else
 		return ret;
-	ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
 	if (cfg->ops & MDP_PP_OPS_READ) {
@@ -4381,65 +4755,50 @@
 	int i = 0;
 
 	if (!cfg) {
-		pr_err("Invalid buffer pointer");
+		pr_err("Invalid buffer pointer\n");
 		return ret;
 	}
 
-	if (cfg->size == 0 || cfg->size > PAGE_SIZE) {
-		pr_err("Invalid buffer size %d", cfg->size);
+	if (cfg->size == 0) {
+		pr_err("Invalid buffer size\n");
 		return ret;
 	}
 
 	counter = cfg->size / (sizeof(uint32_t) * 2);
 	buff_org = buff = kzalloc(cfg->size, GFP_KERNEL);
 	if (buff == NULL) {
-		pr_err("Allocation failed");
+		pr_err("Config buffer allocation failed\n");
 		return ret;
 	}
 
 	if (copy_from_user(buff, cfg->buffer, cfg->size)) {
 		kfree(buff);
-		pr_err("Copy failed");
+		pr_err("config buffer copy failed\n");
 		return ret;
 	}
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
-	if (cfg->ops & MDP_PP_OPS_READ) {
-		for (i = 0 ; i < counter ; i++) {
-			if (is_valid_calib_addr((void *) *buff)) {
-				ret = 0;
-			} else {
-				ret = -1;
-				pr_err("Address validation failed");
-				break;
-			}
+	for (i = 0; i < counter; i++) {
+		ptr = (void *) (((unsigned int) *buff) + mdss_res->mdp_base);
 
-			ptr = (void *)(((unsigned int) *buff) +
-					 (mdss_res->mdp_base));
-			buff++;
+		if (!is_valid_calib_addr(ptr, cfg->ops)) {
+			ret = -1;
+			pr_err("Address validation failed or access not permitted\n");
+			break;
+		}
+
+		buff++;
+		if (cfg->ops & MDP_PP_OPS_READ)
 			*buff = readl_relaxed(ptr);
-			buff++;
-		}
-		if (!ret)
-			ret = copy_to_user(cfg->buffer, buff_org, cfg->size);
-		*copyback = 1;
-	} else if (cfg->ops & MDP_PP_OPS_WRITE) {
-		for (i = 0 ; i < counter ; i++) {
-			if (is_valid_calib_addr((void *) *buff)) {
-				ret = 0;
-			} else {
-				ret = -1;
-				pr_err("Address validation failed");
-				break;
-			}
-
-			ptr = (void *)(((unsigned int) *buff) +
-					 (mdss_res->mdp_base));
-			buff++;
+		else if (cfg->ops & MDP_PP_OPS_WRITE)
 			writel_relaxed(*buff, ptr);
-			buff++;
-		}
+		buff++;
+	}
+
+	if (ret & MDP_PP_OPS_READ) {
+		ret = copy_to_user(cfg->buffer, buff_org, cfg->size);
+		*copyback = 1;
 	}
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 329b58e..4640d3b 100755
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -99,7 +99,6 @@
 header-y += connector.h
 header-y += const.h
 header-y += cramfs_fs.h
-header-y += csdio.h
 header-y += cuda.h
 header-y += cyclades.h
 header-y += cycx_cfm.h
diff --git a/include/linux/csdio.h b/include/linux/csdio.h
deleted file mode 100644
index 260c49d..0000000
--- a/include/linux/csdio.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef CSDIO_H
-#define CSDIO_H
-
-#include <linux/ioctl.h>
-
-#define CSDIO_IOC_MAGIC  'm'
-
-#define CSDIO_IOC_ENABLE_HIGHSPEED_MODE      _IO(CSDIO_IOC_MAGIC, 0)
-#define CSDIO_IOC_SET_DATA_TRANSFER_CLOCKS   _IO(CSDIO_IOC_MAGIC, 1)
-#define CSDIO_IOC_SET_OP_CODE                _IO(CSDIO_IOC_MAGIC, 2)
-#define CSDIO_IOC_FUNCTION_SET_BLOCK_SIZE    _IO(CSDIO_IOC_MAGIC, 3)
-#define CSDIO_IOC_SET_BLOCK_MODE             _IO(CSDIO_IOC_MAGIC, 4)
-#define CSDIO_IOC_CONNECT_ISR                _IO(CSDIO_IOC_MAGIC, 5)
-#define CSDIO_IOC_DISCONNECT_ISR             _IO(CSDIO_IOC_MAGIC, 6)
-#define CSDIO_IOC_CMD52                      _IO(CSDIO_IOC_MAGIC, 7)
-#define CSDIO_IOC_CMD53                      _IO(CSDIO_IOC_MAGIC, 8)
-#define CSDIO_IOC_ENABLE_ISR                 _IO(CSDIO_IOC_MAGIC, 9)
-#define CSDIO_IOC_DISABLE_ISR                _IO(CSDIO_IOC_MAGIC, 10)
-#define CSDIO_IOC_SET_VDD                    _IO(CSDIO_IOC_MAGIC, 11)
-#define CSDIO_IOC_GET_VDD                    _IO(CSDIO_IOC_MAGIC, 12)
-
-#define CSDIO_IOC_MAXNR   12
-
-struct csdio_cmd53_ctrl_t {
-	uint32_t    m_block_mode;   /* data tran. byte(0)/block(1) mode */
-	uint32_t    m_op_code;      /* address auto increment flag */
-	uint32_t    m_address;
-} __attribute__ ((packed));
-
-struct csdio_cmd52_ctrl_t {
-	uint32_t    m_write;
-	uint32_t    m_address;
-	uint32_t    m_data;
-	uint32_t    m_ret;
-} __attribute__ ((packed));
-
-#endif
diff --git a/include/linux/ion.h b/include/linux/ion.h
index f36298b..7131da3 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -22,6 +22,8 @@
 #include <linux/types.h>
 
 struct ion_handle;
+typedef struct ion_handle *ion_user_handle_t;
+
 /**
  * enum ion_heap_types - list of all possible types of heaps
  * @ION_HEAP_TYPE_SYSTEM:	 memory allocated via vmalloc
@@ -350,7 +352,7 @@
 	size_t align;
 	unsigned int heap_mask;
 	unsigned int flags;
-	struct ion_handle *handle;
+	ion_user_handle_t handle;
 };
 
 /**
@@ -364,7 +366,7 @@
  * provides the file descriptor and the kernel returns the handle.
  */
 struct ion_fd_data {
-	struct ion_handle *handle;
+	ion_user_handle_t handle;
 	int fd;
 };
 
@@ -373,7 +375,7 @@
  * @handle:	a handle
  */
 struct ion_handle_data {
-	struct ion_handle *handle;
+	ion_user_handle_t handle;
 };
 
 /**
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 1bcfd28..43aebb5 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -392,7 +392,7 @@
 	unsigned int		idle_timeout;
 	struct notifier_block        reboot_notify;
 	bool issue_long_pon;
-	u8 cached_ext_csd;
+	u8 *cached_ext_csd;
 };
 
 /*
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 724e573..0791545 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -800,8 +800,14 @@
 	DCM_ENTER,
 	DCM_EXIT,
 	DCM_BLANK,
+	DTM_ENTER,
+	DTM_EXIT,
 };
 
+#define MDSS_PP_SPLIT_LEFT_ONLY		0x10000000
+#define MDSS_PP_SPLIT_RIGHT_ONLY	0x20000000
+#define MDSS_PP_SPLIT_MASK		0x30000000
+
 #define MDSS_MAX_BL_BRIGHTNESS 255
 #define AD_BL_LIN_LEN 256
 
diff --git a/include/linux/qpnp/pwm.h b/include/linux/qpnp/pwm.h
index bf7908b..50fb2e5 100644
--- a/include/linux/qpnp/pwm.h
+++ b/include/linux/qpnp/pwm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -146,6 +146,12 @@
 int pwm_lut_config(struct pwm_device *pwm, int period_us,
 		int duty_pct[], struct lut_params lut_params);
 
+/*
+ * support microsecond level configuration
+ */
+int pwm_config_us(struct pwm_device *pwm,
+		int duty_us, int period_us);
+
 /* Standard APIs supported */
 /*
  * pwm_request - request a PWM device
@@ -161,8 +167,8 @@
 /*
  * pwm_config - change a PWM device configuration
  * @pwm: the PWM device
- * @period_us: period in microsecond
- * @duty_us: duty cycle in microsecond
+ * @period_ns: period in nanosecond
+ * @duty_ns: duty cycle in nanosecond
  */
 
 /*
diff --git a/include/linux/regulator/cpr-regulator.h b/include/linux/regulator/cpr-regulator.h
index 624860e..2e2d931 100644
--- a/include/linux/regulator/cpr-regulator.h
+++ b/include/linux/regulator/cpr-regulator.h
@@ -22,20 +22,51 @@
 #define CPR_PVS_EFUSE_BINS_MAX		(1 << CPR_PVS_EFUSE_BITS_MAX)
 
 /**
+ * enum cpr_fuse_corner_enum - CPR fuse corner enum values
+ * %CPR_FUSE_CORNER_SVS:		Lowest voltage for APC
+ * %CPR_FUSE_CORNER_NORMAL:		Normal mode voltage
+ * %CPR_FUSE_CORNER_TURBO:		Turbo mode voltage
+ * %CPR_FUSE_CORNER_SUPER_TURBO:	Super Turbo mode voltage
+ *
+ */
+enum cpr_fuse_corner_enum {
+	CPR_FUSE_CORNER_SVS = 1,
+	CPR_FUSE_CORNER_NORMAL,
+	CPR_FUSE_CORNER_TURBO,
+	CPR_FUSE_CORNER_MAX,
+};
+
+/**
  * enum cpr_corner_enum - CPR corner enum values
- * %CPR_CORNER_SVS:		Lowest voltage for APC
- * %CPR_CORNER_NORMAL:		Normal mode voltage
- * %CPR_CORNER_TURBO:		Turbo mode voltage
- * %CPR_CORNER_SUPER_TURBO:	Super Turbo mode voltage
+ * %CPR_CORNER_1:		Lowest voltage for APC
+ * %CPR_CORNER_2:		Second lowest voltage for APC
+ * %CPR_CORNER_3:		Third lowest voltage for APC
+ * %CPR_CORNER_4:		Forth lowest voltage for APC
+ * %CPR_CORNER_5:		Fifth lowest voltage for APC
+ * %CPR_CORNER_6:		Sixth lowest voltage for APC
+ * %CPR_CORNER_7:		Seventh lowest voltage for APC
+ * %CPR_CORNER_8:		Eighth lowest voltage for APC
+ * %CPR_CORNER_9:		Ninth lowest voltage for APC
+ * %CPR_CORNER_10:		Tenth lowest voltage for APC
+ * %CPR_CORNER_11:		Eleventh lowest voltage for APC
+ * %CPR_CORNER_12:		Twelfth lowest voltage for APC
  *
  * These should be used in regulator_set_voltage() for CPR
  * regulator as if they had units of uV.
  */
 enum cpr_corner_enum {
-	CPR_CORNER_SVS = 1,
-	CPR_CORNER_NORMAL,
-	CPR_CORNER_TURBO,
-	CPR_CORNER_MAX,
+	CPR_CORNER_1 = 1,
+	CPR_CORNER_2,
+	CPR_CORNER_3,
+	CPR_CORNER_4,
+	CPR_CORNER_5,
+	CPR_CORNER_6,
+	CPR_CORNER_7,
+	CPR_CORNER_8,
+	CPR_CORNER_9,
+	CPR_CORNER_10,
+	CPR_CORNER_11,
+	CPR_CORNER_12,
 };
 
 /**
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 560accb..bfafe00 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1904,6 +1904,9 @@
 	V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 1,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 36)
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 37)
+
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index c48586e..a01dd9a 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -571,7 +571,8 @@
 
 struct msm_camera_led_cfg_t {
 	enum msm_camera_led_config_t cfgtype;
-	uint32_t led_current;
+	uint32_t torch_current;
+	uint32_t flash_current[2];
 };
 
 #define VIDIOC_MSM_SENSOR_CFG \
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 75fe3a2..2c969cd 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -7172,5 +7172,7 @@
 #define US_POINT_EPOS_FORMAT_V2 0x0001272D
 #define US_RAW_FORMAT_V2        0x0001272C
 #define US_PROX_FORMAT_V2       0x0001272E
+#define US_RAW_SYNC_FORMAT      0x0001272F
+#define US_GES_SYNC_FORMAT      0x00012730
 
 #endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 6f121b3..5941f71 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -31,7 +31,7 @@
 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,
-				bool perf_mode, uint16_t bits_per_sample);
+				int perf_mode, uint16_t bits_per_sample);
 
 int adm_get_params(int port_id, uint32_t module_id, uint32_t param_id,
 			uint32_t params_length, char *params);
@@ -40,7 +40,7 @@
 				 uint32_t params_length);
 
 int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
-			int topology, bool perf_mode, uint16_t bits_per_sample);
+			int topology, int perf_mode, uint16_t bits_per_sample);
 
 int adm_unmap_cal_blocks(void);
 
@@ -53,10 +53,10 @@
 
 int adm_memory_unmap_regions(int port_id);
 
-int adm_close(int port, bool perf_mode);
+int adm_close(int port, int perf_mode);
 
 int adm_matrix_map(int session_id, int path, int num_copps,
-		unsigned int *port_id, int copp_id, bool perf_mode);
+		unsigned int *port_id, int copp_id, int perf_mode);
 
 int adm_connect_afe_port(int mode, int session_id, int port_id);
 
@@ -64,6 +64,8 @@
 
 int adm_get_copp_id(int port_id);
 
+int adm_get_lowlatency_copp_id(int port_id);
+
 void adm_set_multi_ch_map(char *channel_map);
 
 void adm_get_multi_ch_map(char *channel_map);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 9a459b8..a78c333 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -67,6 +67,8 @@
 /* Enable Sample_Rate/Channel_Mode notification event from Decoder */
 #define SR_CM_NOTIFY_ENABLE	0x0004
 
+#define TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
+#define TUN_READ_IO_MODE  0x0004 /* tunnel read write mode */
 #define SYNC_IO_MODE	0x0001
 #define ASYNC_IO_MODE	0x0002
 #define COMPRESSED_IO	0x0040
@@ -173,7 +175,7 @@
 	struct audio_port_data port[2];
 	wait_queue_head_t      cmd_wait;
 	wait_queue_head_t      time_wait;
-	bool                   perf_mode;
+	int                    perf_mode;
 	int					   stream_id;
 	/* audio cache operations fptr*/
 	int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
@@ -218,6 +220,9 @@
 			uint32_t rd_format,
 			uint32_t wr_format);
 
+int q6asm_open_loopback_v2(struct audio_client *ac,
+			   uint16_t bits_per_sample);
+
 int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
 				uint32_t lsw_ts, uint32_t flags);
 int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/include/sound/q6audio-v2.h b/include/sound/q6audio-v2.h
index fd6a490..8ac835c 100644
--- a/include/sound/q6audio-v2.h
+++ b/include/sound/q6audio-v2.h
@@ -15,6 +15,13 @@
 
 #include <mach/qdsp6v2/apr.h>
 
+enum {
+	LEGACY_PCM_MODE = 0,
+	LOW_LATENCY_PCM_MODE,
+	ULTRA_LOW_LATENCY_PCM_MODE,
+};
+
+
 int q6audio_get_port_index(u16 port_id);
 
 int q6audio_convert_virtual_to_portid(u16 port_id);
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index 6d22836..955a47b 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -108,7 +108,7 @@
 static void __spin_lock_debug(raw_spinlock_t *lock)
 {
 	u64 i;
-	u64 loops = (loops_per_jiffy * HZ) >> 1;
+	u64 loops = (loops_per_jiffy * HZ);
 
 	for (i = 0; i < loops; i++) {
 		if (arch_spin_trylock(&lock->raw_lock))
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9962c88..6c78c0c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1457,7 +1457,7 @@
 		head = p; id++;
 	}
 
-	sprintf(hdev->name, "hci%d", id);
+	snprintf(hdev->name, sizeof(hdev->name), "hci%d", id);
 	hdev->id = id;
 	list_add(&hdev->list, head);
 
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 2628937..b2b0e99 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3443,10 +3443,7 @@
 			tcp_done(sk);
 			bh_unlock_sock(sk);
 			local_bh_enable();
-			if (!sock_flag(sk, SOCK_DEAD)) {
-				sock_orphan(sk);
-				sock_put(sk);
-			}
+			sock_put(sk);
 
 			goto restart;
 		}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index bddb720..b094741 100755
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1510,8 +1510,8 @@
 	if (wiphy_idx_valid(reg_request->wiphy_idx))
 		wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
 
-	if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER &&
-	    !wiphy) {
+	if ((reg_initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+	     reg_initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) && !wiphy) {
 		kfree(reg_request);
 		return;
 	}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 487ac6f..9a11f9f 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -55,6 +55,7 @@
 static unsigned int table_size, table_cnt;
 static int all_symbols = 0;
 static char symbol_prefix_char = '\0';
+static unsigned long long kernel_start_addr = 0;
 
 int token_profit[0x10000];
 
@@ -65,7 +66,10 @@
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
+	fprintf(stderr, "Usage: kallsyms [--all-symbols] "
+			"[--symbol-prefix=<prefix char>] "
+			"[--page-offset=<CONFIG_PAGE_OFFSET>] "
+			"< in.map > out.S\n");
 	exit(1);
 }
 
@@ -194,6 +198,9 @@
 	int i;
 	int offset = 1;
 
+	if (s->addr < kernel_start_addr)
+		return 0;
+
 	/* skip prefix char */
 	if (symbol_prefix_char && *(s->sym + 1) == symbol_prefix_char)
 		offset++;
@@ -646,6 +653,9 @@
 				if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
 					p++;
 				symbol_prefix_char = *p;
+			} else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
+				const char *p = &argv[i][14];
+				kernel_start_addr = strtoull(p, NULL, 16);
 			} else
 				usage();
 		}
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 55fec32..1962ff0 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1396,7 +1396,10 @@
 	switch (decimator) {
 	case 1:
 	case 2:
-			adc_dmic_sel = 0x0;
+			if ((dec_mux == 3) || (dec_mux == 4))
+				adc_dmic_sel = 0x1;
+			else
+				adc_dmic_sel = 0x0;
 		break;
 	default:
 		dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index c62f875..f874c43 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -3404,6 +3404,7 @@
 					TAIKO_A_TX_7_MBHC_EN, 0x80, 00);
 			ret |= taiko_codec_enable_anc(w, kcontrol, event);
 		}
+		break;
 	case SND_SOC_DAPM_POST_PMD:
 		ret = taiko_hph_pa_event(w, kcontrol, event);
 		break;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 28d4c84..14218d8 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -213,7 +213,6 @@
 /* called under codec_resource_lock acquisition */
 static void wcd9xxx_start_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
-	s16 v_brh, v_b1_hu;
 	struct snd_soc_codec *codec = mbhc->codec;
 	int mbhc_state = mbhc->mbhc_state;
 
@@ -254,17 +253,6 @@
 		/* set to max */
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL, 0x7F);
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, 0xFF);
-
-		v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-			      (v_brh >> 8) & 0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
-			      v_brh & 0xFF);
-		v_b1_hu = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
-			      v_b1_hu & 0xFF);
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-			      (v_b1_hu >> 8) & 0xFF);
 	}
 
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
@@ -325,22 +313,32 @@
 			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
 				      (d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
 				      0xFF);
-			/* Threshods for button press */
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
-				      d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-				      (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
-				      0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
-				      d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
-				      (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
-				      0xFF);
-			/* Threshods for button release */
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
-				      d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-				      (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) & 0xFF);
+
+			if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+				/* Threshods for button press */
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+					d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+					(d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
+					0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+					d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+					(d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
+					0xFF);
+				/* Threshods for button release */
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+					d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+					(d->v_brh[MBHC_V_IDX_VDDIO] >> 8) &
+					0xFF);
+			}
 			pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
 				 __func__);
 		}
@@ -376,22 +374,31 @@
 			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
 					(d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
 					0xFF);
-			/* Revert threshods for button press */
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
-				      d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-				      (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
-				      0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
-				      d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
-				      (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
-				      0xFF);
-			/* Revert threshods for button release */
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
-				      d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
-			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-				      (d->v_brh[MBHC_V_IDX_CFILT] >> 8) & 0xFF);
+			if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+				/* Revert threshods for button press */
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+					d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+					(d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
+					0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+					d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+					(d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
+					0xFF);
+				/* Revert threshods for button release */
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+					d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
+				snd_soc_write(codec,
+					WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+					(d->v_brh[MBHC_V_IDX_CFILT] >> 8) &
+					0xFF);
+			}
 			pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
 					__func__);
 		}
@@ -489,19 +496,25 @@
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
 		      (v_ins_hu >> 8) & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-		      (v_b1_hu >> 8) & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
-		      (v_b1_h >> 8) & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-		      (v_brh >> 8) & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
-		      mbhc->mbhc_data.v_brl & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
-		      (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
+
+	if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
+				0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+				(v_b1_hu >> 8) & 0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h &
+				0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+				(v_b1_h >> 8) & 0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
+				0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+				(v_brh >> 8) & 0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
+				mbhc->mbhc_data.v_brl & 0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
+				(mbhc->mbhc_data.v_brl >> 8) & 0xFF);
+	}
 }
 
 static void wcd9xxx_codec_switch_cfilt_mode(struct wcd9xxx_mbhc *mbhc,
@@ -3148,15 +3161,22 @@
 	mv = ceilmv + btn_det->v_btn_press_delta_cic;
 	pr_debug("%s: reprogram vb1hu/vbrh to %dmv\n", __func__, mv);
 
-	/* update LSB first so mbhc hardware block doesn't see too low value */
-	v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-		      (v_b1_hu >> 8) & 0xFF);
-	v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-		      (v_brh >> 8) & 0xFF);
+	if (mbhc->mbhc_state != MBHC_STATE_POTENTIAL_RECOVERY) {
+		/*
+		 * update LSB first so mbhc hardware block
+		 * doesn't see too low value.
+		 */
+		v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu &
+				0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+				(v_b1_hu >> 8) & 0xFF);
+		v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh &
+				0xFF);
+		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+				(v_brh >> 8) & 0xFF);
+	}
 	return 0;
 }
 
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 39cb470..6f94d99 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -422,6 +422,30 @@
 	},
 	{
 		.playback = {
+			.stream_name = "INT_HFP_BT Hostless Playback",
+			.aif_name = "INTHFP_DL_HL",
+			.rates = 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 =     16000,
+		},
+		.capture = {
+			.stream_name = "INT_HFP_BT Hostless Capture",
+			.aif_name = "INTHFP_UL_HL",
+			.rates = 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 =     16000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "INT_HFP_BT_HOSTLESS",
+	},
+	{
+		.playback = {
 			.stream_name = "AFE-PROXY Playback",
 			.aif_name = "PCM_RX",
 			.rates = (SNDRV_PCM_RATE_8000 |
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index c120e0c..4c3a72e 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2203,6 +2203,53 @@
 		.codec_name = "snd-soc-dummy",
 	},
 	{
+		.name = "Voice2",
+		.stream_name = "Voice2",
+		.cpu_dai_name   = "Voice2",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOICE2,
+	},
+	{
+		.name = "INT_HFP_BT Hostless",
+		.stream_name = "INT_HFP_BT Hostless",
+		.cpu_dai_name   = "INT_HFP_BT_HOSTLESS",
+		.platform_name  = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dai link has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
+	{
+		.name = "MSM8974 HFP TX",
+		.stream_name = "MultiMedia6",
+		.cpu_dai_name = "MultiMedia6",
+		.platform_name  = "msm-pcm-loopback",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+	},
+	{
 		.name = LPASS_BE_SLIMBUS_4_TX,
 		.stream_name = "Slimbus4 Capture",
 		.cpu_dai_name = "msm-dai-q6-dev.16393",
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 408ec03..c1ba26a 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -163,6 +163,8 @@
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
 	SND_SOC_DAPM_MIC("Secondary Mic", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
 };
 static int msm8x10_ext_spk_power_amp_init(void)
 {
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index ea16f47..f0f5db6 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -3,7 +3,8 @@
 			msm-multi-ch-pcm-q6-v2.o msm-pcm-lpa-v2.o \
 			msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
 			msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
-			msm-lsm-client.o msm-audio-effects-q6-v2.o
+			msm-lsm-client.o msm-audio-effects-q6-v2.o \
+			msm-pcm-loopback-v2.o
 obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
 				 msm-dai-stub-v2.o
 obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 58c3cdf..4e04bef 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -405,9 +405,9 @@
 
 done:
 	mutex_unlock(&acdb_data.acdb_mutex);
-ret:
 	pr_debug("ACDB=> %s: Path = %d samplerate = %u usec = %u status %d\n",
 		 __func__, path, entry->sample_rate, entry->delay_usec, result);
+ret:
 	return result;
 }
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
new file mode 100644
index 0000000..57fc268
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -0,0 +1,441 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <asm/dma.h>
+
+#include "msm-pcm-routing-v2.h"
+
+#define LOOPBACK_VOL_MAX_STEPS 0x2000
+
+static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0,
+				LOOPBACK_VOL_MAX_STEPS);
+
+struct msm_pcm_loopback {
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	int instance;
+
+	struct mutex lock;
+
+	uint32_t samp_rate;
+	uint32_t channel_mode;
+
+	int playback_start;
+	int capture_start;
+	int session_id;
+	struct audio_client *audio_client;
+	int volume;
+};
+
+static void stop_pcm(struct msm_pcm_loopback *pcm);
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+	.formats                = 0xffffffff,
+	.channels_min           = 1,
+	.channels_max           = UINT_MAX,
+
+	/* Random values to keep userspace happy when checking constraints */
+	.info                   = SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.buffer_bytes_max       = 128*1024,
+	.period_bytes_min       = 1024,
+	.period_bytes_max       = 1024*2,
+	.periods_min            = 2,
+	.periods_max            = 128,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+					void *priv_data)
+{
+	struct msm_pcm_loopback *pcm = priv_data;
+
+	BUG_ON(!pcm);
+
+	pr_debug("%s: event %x\n", __func__, event);
+
+	switch (event) {
+	case MSM_PCM_RT_EVT_DEVSWITCH:
+		q6asm_cmd(pcm->audio_client, CMD_PAUSE);
+		q6asm_cmd(pcm->audio_client, CMD_FLUSH);
+		q6asm_run(pcm->audio_client, 0, 0, 0);
+	default:
+		break;
+	}
+}
+
+static void msm_pcm_loopback_event_handler(uint32_t opcode, uint32_t token,
+					   uint32_t *payload, void *priv)
+{
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+			break;
+		default:
+			break;
+		}
+	}
+		break;
+	default:
+		pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume)
+{
+	int rc = -EINVAL;
+
+	pr_debug("%s Setting volume 0x%x\n", __func__, volume);
+
+	if (prtd && prtd->audio_client) {
+		rc = q6asm_set_volume(prtd->audio_client, volume);
+		if (rc < 0) {
+			pr_err("%s: Send Volume command failed rc = %d\n",
+				__func__, rc);
+			return rc;
+		}
+		prtd->volume = volume;
+	}
+	return rc;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct msm_pcm_loopback *pcm;
+	int ret = 0;
+	uint16_t bits_per_sample = 16;
+	struct msm_pcm_routing_evt event;
+
+	pcm = dev_get_drvdata(rtd->platform->dev);
+	mutex_lock(&pcm->lock);
+
+	snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+	pcm->volume = 0x2000;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm->playback_substream = substream;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm->capture_substream = substream;
+
+	pcm->instance++;
+	dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
+			pcm->instance, substream->stream);
+	if (pcm->instance == 2) {
+		struct snd_soc_pcm_runtime *soc_pcm_rx =
+				pcm->playback_substream->private_data;
+		struct snd_soc_pcm_runtime *soc_pcm_tx =
+				pcm->capture_substream->private_data;
+		if (pcm->audio_client != NULL)
+			stop_pcm(pcm);
+
+		pcm->audio_client = q6asm_audio_client_alloc(
+				(app_cb)msm_pcm_loopback_event_handler, pcm);
+		if (!pcm->audio_client) {
+			dev_err(rtd->platform->dev,
+				"%s: Could not allocate memory\n", __func__);
+			mutex_unlock(&pcm->lock);
+			return -ENOMEM;
+		}
+		pcm->session_id = pcm->audio_client->session;
+		pcm->audio_client->perf_mode = false;
+		ret = q6asm_open_loopback_v2(pcm->audio_client,
+					     bits_per_sample);
+		if (ret < 0) {
+			dev_err(rtd->platform->dev,
+				"%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(pcm->audio_client);
+			mutex_unlock(&pcm->lock);
+			return -ENOMEM;
+		}
+		event.event_func = msm_pcm_route_event_handler;
+		event.priv_data = (void *) pcm;
+		msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->capture_substream->stream);
+		msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
+			pcm->audio_client->perf_mode,
+			pcm->session_id, pcm->playback_substream->stream,
+			event);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			pcm->playback_substream = substream;
+			ret = pcm_loopback_set_volume(pcm, pcm->volume);
+			if (ret < 0)
+				dev_err(rtd->platform->dev,
+					"Error %d setting volume", ret);
+		}
+	}
+	dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
+			__func__ , pcm->instance, substream->pcm->id);
+	runtime->private_data = pcm;
+
+	mutex_unlock(&pcm->lock);
+
+	return 0;
+}
+
+static void stop_pcm(struct msm_pcm_loopback *pcm)
+{
+	struct snd_soc_pcm_runtime *soc_pcm_rx =
+		pcm->playback_substream->private_data;
+	struct snd_soc_pcm_runtime *soc_pcm_tx =
+		pcm->capture_substream->private_data;
+
+	if (pcm->audio_client == NULL)
+		return;
+	q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+	msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+			SNDRV_PCM_STREAM_PLAYBACK);
+	msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+			SNDRV_PCM_STREAM_CAPTURE);
+	q6asm_audio_client_free(pcm->audio_client);
+	pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	int ret = 0;
+
+	mutex_lock(&pcm->lock);
+
+	dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
+		__func__, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		pcm->playback_start = 0;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		pcm->capture_start = 0;
+
+	pcm->instance--;
+	if (!pcm->playback_start || !pcm->capture_start) {
+		dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
+		stop_pcm(pcm);
+	}
+
+	mutex_unlock(&pcm->lock);
+	return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	mutex_lock(&pcm->lock);
+
+	dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
+		__func__, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!pcm->playback_start)
+			pcm->playback_start = 1;
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (!pcm->capture_start)
+			pcm->capture_start = 1;
+	}
+	mutex_unlock(&pcm->lock);
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_pcm_loopback *pcm = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		dev_dbg(rtd->platform->dev,
+			"%s: playback_start:%d,capture_start:%d\n", __func__,
+			pcm->playback_start, pcm->capture_start);
+		if (pcm->playback_start && pcm->capture_start)
+			q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+		dev_dbg(rtd->platform->dev,
+			"%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+			__func__, pcm->playback_start, pcm->capture_start);
+		if (pcm->playback_start && pcm->capture_start)
+			q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
+
+	return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+		params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.hw_params      = msm_pcm_hw_params,
+	.hw_free        = msm_pcm_hw_free,
+	.close          = msm_pcm_close,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+};
+
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	int rc = 0;
+	struct snd_pcm_volume *vol = kcontrol->private_data;
+	struct snd_pcm_substream *substream = vol->pcm->streams[0].substream;
+	struct msm_pcm_loopback *prtd = substream->runtime->private_data;
+	int volume = ucontrol->value.integer.value[0];
+
+	rc = pcm_loopback_set_volume(prtd, volume);
+	return rc;
+}
+
+static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+	struct snd_pcm_volume *volume_info;
+	struct snd_kcontrol *kctl;
+	int ret = 0;
+
+	dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
+	ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+				      NULL, 1,
+				      rtd->dai_link->be_id,
+				      &volume_info);
+	if (ret < 0)
+		return ret;
+	kctl = volume_info->kctl;
+	kctl->put = msm_pcm_volume_ctl_put;
+	kctl->tlv.p = loopback_rx_vol_gain;
+	return 0;
+}
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	ret = msm_pcm_add_controls(rtd);
+	if (ret)
+		dev_err(rtd->dev, "%s, kctl add failed\n", __func__);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops            = &msm_pcm_ops,
+	.pcm_new        = msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	struct msm_pcm_loopback *pcm;
+
+	dev_set_name(&pdev->dev, "%s", "msm-pcm-loopback");
+	dev_dbg(&pdev->dev, "%s: dev name %s\n",
+		__func__, dev_name(&pdev->dev));
+
+	pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL);
+	if (!pcm) {
+		dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n",
+			__func__);
+		return -ENOMEM;
+	} else {
+		mutex_init(&pcm->lock);
+		dev_set_drvdata(&pdev->dev, pcm);
+	}
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	struct msm_pcm_loopback *pcm;
+
+	pcm = dev_get_drvdata(&pdev->dev);
+	mutex_destroy(&pcm->lock);
+	kfree(pcm);
+
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id msm_pcm_loopback_dt_match[] = {
+	{.compatible = "qti,msm-pcm-loopback"},
+	{}
+};
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-pcm-loopback",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_pcm_loopback_dt_match,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index dc41948..3ddc3e0 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -25,6 +25,7 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/control.h>
+#include <sound/q6audio-v2.h>
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/msm_audio_ion.h>
@@ -109,6 +110,25 @@
 	.mask = 0,
 };
 
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+					void *priv_data)
+{
+	struct msm_audio *prtd = priv_data;
+
+	BUG_ON(!prtd);
+
+	pr_debug("%s: event %x\n", __func__, event);
+
+	switch (event) {
+	case MSM_PCM_RT_EVT_BUF_RECFG:
+		q6asm_cmd(prtd->audio_client, CMD_PAUSE);
+		q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+		q6asm_run(prtd->audio_client, 0, 0, 0);
+	default:
+		break;
+	}
+}
+
 static void event_handler(uint32_t opcode,
 		uint32_t token, uint32_t *payload, void *priv)
 {
@@ -151,18 +171,31 @@
 		pr_debug("token = 0x%08x\n", token);
 		in_frame_info[token][0] = payload[4];
 		in_frame_info[token][1] = payload[5];
-		prtd->pcm_irq_pos += in_frame_info[token][0];
-		pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
-		if (atomic_read(&prtd->start))
-			snd_pcm_period_elapsed(substream);
-		if (atomic_read(&prtd->in_count) <= prtd->periods)
-			atomic_inc(&prtd->in_count);
-		wake_up(&the_locks.read_wait);
-		if (prtd->mmap_flag
-			&& q6asm_is_cpu_buf_avail_nolock(OUT,
+		/* assume data size = 0 during flushing */
+		if (in_frame_info[token][0]) {
+			prtd->pcm_irq_pos += in_frame_info[token][0];
+			pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+			if (atomic_read(&prtd->start))
+				snd_pcm_period_elapsed(substream);
+			if (atomic_read(&prtd->in_count) <= prtd->periods)
+				atomic_inc(&prtd->in_count);
+			wake_up(&the_locks.read_wait);
+			if (prtd->mmap_flag &&
+			    q6asm_is_cpu_buf_avail_nolock(OUT,
 				prtd->audio_client,
 				&size, &idx))
-			q6asm_read_nolock(prtd->audio_client);
+				q6asm_read_nolock(prtd->audio_client);
+		} else {
+			pr_debug("%s: reclaim flushed buf in_count %x\n",
+				__func__, atomic_read(&prtd->in_count));
+			atomic_inc(&prtd->in_count);
+			if (atomic_read(&prtd->in_count) == prtd->periods) {
+				pr_info("%s: reclaimed all bufs\n", __func__);
+				if (atomic_read(&prtd->start))
+					snd_pcm_period_elapsed(substream);
+				wake_up(&the_locks.read_wait);
+			}
+		}
 		break;
 	}
 	case APR_BASIC_RSP_RESULT: {
@@ -681,6 +714,7 @@
 	int dir, ret;
 	struct msm_plat_data *pdata;
 	uint16_t bits_per_sample = 16;
+	struct msm_pcm_routing_evt event;
 
 	pdata = (struct msm_plat_data *)
 				dev_get_drvdata(soc_prtd->platform->dev);
@@ -737,9 +771,12 @@
 		pr_debug("%s: session ID %d\n",
 				__func__, prtd->audio_client->session);
 		prtd->session_id = prtd->audio_client->session;
-		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+		event.event_func = msm_pcm_route_event_handler;
+		event.priv_data = (void *) prtd;
+		msm_pcm_routing_reg_phy_stream_v2(soc_prtd->dai_link->be_id,
 				prtd->audio_client->perf_mode,
-				prtd->session_id, substream->stream);
+				prtd->session_id, substream->stream,
+				event);
 	}
 
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
@@ -880,11 +917,12 @@
 	int rc;
 	int id;
 	struct msm_plat_data *pdata;
+	const char *latency_level;
 
 	rc = of_property_read_u32(pdev->dev.of_node,
-				"qcom,msm-pcm-dsp-id", &id);
+				"qti,msm-pcm-dsp-id", &id);
 	if (rc) {
-		dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
+		dev_err(&pdev->dev, "%s: qti,msm-pcm-dsp-id missing in DT node\n",
 					__func__);
 		return rc;
 	}
@@ -896,10 +934,17 @@
 	}
 
 	if (of_property_read_bool(pdev->dev.of_node,
-				"qcom,msm-pcm-low-latency"))
-		pdata->perf_mode = 1;
-	else
-		pdata->perf_mode = 0;
+				"qti,msm-pcm-low-latency")) {
+
+		pdata->perf_mode = LOW_LATENCY_PCM_MODE;
+		rc = of_property_read_string(pdev->dev.of_node,
+			"qti,latency-level", &latency_level);
+		if (!rc) {
+			if (!strcmp(latency_level, "ultra"))
+				pdata->perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+		}
+	} else
+		pdata->perf_mode = LEGACY_PCM_MODE;
 
 	dev_set_drvdata(&pdev->dev, pdata);
 
@@ -921,7 +966,7 @@
 	return 0;
 }
 static const struct of_device_id msm_pcm_dt_match[] = {
-	{.compatible = "qcom,msm-pcm-dsp"},
+	{.compatible = "qti,msm-pcm-dsp"},
 	{}
 };
 MODULE_DEVICE_TABLE(of, msm_pcm_dt_match);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 537719f..91c0744 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -50,6 +50,12 @@
 	unsigned int  format;
 };
 
+struct msm_pcm_routing_fdai_data {
+	u16 be_srate; /* track prior backend sample rate for flushing purpose */
+	int strm_id; /* ASM stream ID */
+	struct msm_pcm_routing_evt event_info;
+};
+
 #define INVALID_SESSION -1
 #define SESSION_TYPE_RX 0
 #define SESSION_TYPE_TX 1
@@ -250,31 +256,41 @@
 
 
 /* Track ASM playback & capture sessions of DAI */
-static int fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+static struct msm_pcm_routing_fdai_data
+	fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
 	/* MULTIMEDIA1 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA2 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA3 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA4 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION,  {NULL, NULL} } },
 	/* MULTIMEDIA5 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA6 */
-	{INVALID_SESSION, INVALID_SESSION},
-	/* MULTIMEDIA7 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
+	/* MULTIMEDIA7*/
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA8 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 	/* MULTIMEDIA9 */
-	{INVALID_SESSION, INVALID_SESSION},
+	{{0, INVALID_SESSION, {NULL, NULL} },
+	{0, INVALID_SESSION, {NULL, NULL} } },
 };
 
 /* Track performance mode of all front-end multimedia sessions.
  * Performance mode is only valid when session is valid.
  */
-static bool fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
+static int fe_dai_perf_mode[MSM_FRONTEND_DAI_MM_SIZE][2];
 
 static uint8_t is_be_dai_extproc(int be_dai)
 {
@@ -287,7 +303,7 @@
 }
 
 static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
-	int path_type, bool perf_mode)
+	int path_type, int perf_mode)
 {
 	int i, port_type;
 	struct route_payload payload;
@@ -334,7 +350,7 @@
 
 	mutex_lock(&routing_lock);
 
-	fe_dai_map[fedai_id][session_type] = dspst_id;
+	fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
 		if (!is_be_dai_extproc(i) &&
 		    (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
@@ -349,7 +365,7 @@
 	mutex_unlock(&routing_lock);
 }
 
-void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
 					int dspst_id, int stream_type)
 {
 	int i, session_type, path_type, port_type, port_id, topology;
@@ -376,7 +392,7 @@
 	mutex_lock(&routing_lock);
 
 	payload.num_copps = 0; /* only RX needs to use payload */
-	fe_dai_map[fedai_id][session_type] = dspst_id;
+	fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
 	fe_dai_perf_mode[fedai_id][session_type] = perf_mode;
 
 	/* re-enable EQ if active */
@@ -421,7 +437,7 @@
 			port_id = srs_port_id = msm_bedais[i].port_id;
 			srs_send_params(srs_port_id, 1, 0);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (!perf_mode))
+			    (perf_mode == LEGACY_PCM_MODE))
 				if (dolby_dap_init(port_id,
 						msm_bedais[i].channel) < 0)
 					pr_err("%s: Err init dolby dap\n",
@@ -435,6 +451,19 @@
 	mutex_unlock(&routing_lock);
 }
 
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+				       int dspst_id, int stream_type,
+				       struct msm_pcm_routing_evt event_info)
+{
+	msm_pcm_routing_reg_phy_stream(fedai_id, perf_mode, dspst_id,
+				       stream_type);
+
+	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+		fe_dai_map[fedai_id][SESSION_TYPE_RX].event_info = event_info;
+	else
+		fe_dai_map[fedai_id][SESSION_TYPE_TX].event_info = event_info;
+}
+
 void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
 {
 	int i, port_type, session_type, path_type, topology;
@@ -465,13 +494,14 @@
 			adm_close(msm_bedais[i].port_id,
 				  fe_dai_perf_mode[fedai_id][session_type]);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (fe_dai_perf_mode[fedai_id][session_type] == false))
+			    (fe_dai_perf_mode[fedai_id][session_type] ==
+							LEGACY_PCM_MODE))
 				dolby_dap_deinit(msm_bedais[i].port_id);
 		}
 	}
 
-	fe_dai_map[fedai_id][session_type] = INVALID_SESSION;
-
+	fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
+	fe_dai_map[fedai_id][session_type].be_srate = 0;
 	mutex_unlock(&routing_lock);
 }
 
@@ -497,6 +527,7 @@
 	int session_type, path_type, port_id, topology;
 	u32 channels;
 	uint16_t bits_per_sample = 16;
+	struct msm_pcm_routing_fdai_data *fdai;
 
 	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
 
@@ -523,10 +554,23 @@
 			(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
 			voc_start_playback(set, msm_bedais[reg].port_id);
 		set_bit(val, &msm_bedais[reg].fe_sessions);
-		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+		fdai = &fe_dai_map[val][session_type];
+		if (msm_bedais[reg].active && fdai->strm_id !=
 			INVALID_SESSION) {
 
 			channels = msm_bedais[reg].channel;
+			if (session_type == SESSION_TYPE_TX &&
+			    fdai->be_srate &&
+			    (fdai->be_srate != msm_bedais[reg].sample_rate)) {
+				pr_debug("%s: flush strm %d diff BE rates\n",
+					__func__, fdai->strm_id);
+
+				if (fdai->event_info.event_func)
+					fdai->event_info.event_func(
+						MSM_PCM_RT_EVT_BUF_RECFG,
+						fdai->event_info.priv_data);
+				fdai->be_srate = 0; /* might not need it */
+			}
 			if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
 				bits_per_sample = 24;
 
@@ -549,13 +593,20 @@
 				msm_bedais[reg].sample_rate, channels,
 				topology, false, bits_per_sample);
 
+			if (session_type == SESSION_TYPE_RX &&
+			    fdai->event_info.event_func)
+				fdai->event_info.event_func(
+					MSM_PCM_RT_EVT_DEVSWITCH,
+					fdai->event_info.priv_data);
+
 			msm_pcm_routing_build_matrix(val,
-				fe_dai_map[val][session_type], path_type,
+				fdai->strm_id, path_type,
 				fe_dai_perf_mode[val][session_type]);
 			port_id = srs_port_id = msm_bedais[reg].port_id;
 			srs_send_params(srs_port_id, 1, 0);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (fe_dai_perf_mode[val][session_type] == false))
+			    (fe_dai_perf_mode[val][session_type] ==
+							LEGACY_PCM_MODE))
 				if (dolby_dap_init(port_id, channels) < 0)
 					pr_err("%s: Err init dolby dap\n",
 						__func__);
@@ -566,15 +617,17 @@
 			(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
 			voc_start_playback(set, msm_bedais[reg].port_id);
 		clear_bit(val, &msm_bedais[reg].fe_sessions);
-		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+		fdai = &fe_dai_map[val][session_type];
+		if (msm_bedais[reg].active && fdai->strm_id !=
 			INVALID_SESSION) {
 			adm_close(msm_bedais[reg].port_id,
 				  fe_dai_perf_mode[val][session_type]);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (fe_dai_perf_mode[val][session_type] == false))
+			    (fe_dai_perf_mode[val][session_type] ==
+							LEGACY_PCM_MODE))
 				dolby_dap_deinit(msm_bedais[reg].port_id);
 			msm_pcm_routing_build_matrix(val,
-				fe_dai_map[val][session_type], path_type,
+				fdai->strm_id, path_type,
 				fe_dai_perf_mode[val][session_type]);
 		}
 	}
@@ -1203,12 +1256,12 @@
 static void msm_send_eq_values(int eq_idx)
 {
 	int result;
-	struct audio_client *ac =
-		q6asm_get_audio_client(fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+	struct audio_client *ac = q6asm_get_audio_client(
+				  fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
 
 	if (ac == NULL) {
 		pr_err("%s: Could not get audio client for session: %d\n",
-		      __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+		      __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
 		goto done;
 	}
 
@@ -2034,6 +2087,15 @@
 };
 
 
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA6, 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_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
 	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -3040,6 +3102,7 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
@@ -3068,6 +3131,10 @@
 		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture",
 		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("INTHFP_DL_HL", "INT_HFP_BT_HOSTLESS Playback",
+		0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("INTHFP_UL_HL", "INT_HFP_BT_HOSTLESS Capture",
+		0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
 		0, 0, 0, 0),
@@ -3218,6 +3285,8 @@
 	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3474,6 +3543,7 @@
 	{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
 	{"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+	{"MultiMedia6 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3484,6 +3554,7 @@
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
 	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
+	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_UL6"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
 
 	{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3516,6 +3587,7 @@
 	{"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+	{"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 
 	{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
 	{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -3527,6 +3599,7 @@
 	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
 	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
 	{"MM_UL8", NULL, "MultiMedia8 Mixer"},
+	{"MM_UL6", NULL, "MultiMedia6 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -3716,6 +3789,8 @@
 
 	{"INT_FM_RX", NULL, "INTFM_DL_HL"},
 	{"INTFM_UL_HL", NULL, "INT_FM_TX"},
+	{"INTHFP_UL_HL", NULL, "INT_BT_SCO_TX"},
+	{"INT_BT_SCO_RX", NULL, "MM_DL6"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
 	{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
 	{"MI2S_RX", NULL, "MI2S_DL_HL"},
@@ -3881,12 +3956,15 @@
 	mutex_lock(&routing_lock);
 	topology = get_topology(path_type);
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
-		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+		if (fe_dai_map[i][session_type].strm_id != INVALID_SESSION) {
+			fe_dai_map[i][session_type].be_srate =
+				bedai->sample_rate;
 			adm_close(bedai->port_id,
 				  fe_dai_perf_mode[i][session_type]);
 			srs_port_id = -1;
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (fe_dai_perf_mode[i][session_type] == false))
+			    (fe_dai_perf_mode[i][session_type] ==
+							LEGACY_PCM_MODE))
 				dolby_dap_deinit(bedai->port_id);
 		}
 	}
@@ -3908,6 +3986,7 @@
 	u32 channels;
 	bool playback, capture;
 	uint16_t bits_per_sample = 16;
+	struct msm_pcm_routing_fdai_data *fdai;
 
 	if (be_id >= MSM_BACKEND_DAI_MAX) {
 		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -3939,8 +4018,21 @@
 	capture = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
 
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
-		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+		fdai = &fe_dai_map[i][session_type];
+		if (fdai->strm_id != INVALID_SESSION) {
+			if (session_type == SESSION_TYPE_TX &&
+			    fdai->be_srate &&
+			    (fdai->be_srate != bedai->sample_rate)) {
+				pr_debug("%s: flush strm %d diff BE rates\n",
+					__func__,
+					fdai->strm_id);
 
+				if (fdai->event_info.event_func)
+					fdai->event_info.event_func(
+						MSM_PCM_RT_EVT_BUF_RECFG,
+						fdai->event_info.priv_data);
+				fdai->be_srate = 0; /* might not need it */
+			}
 			channels = bedai->channel;
 			if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
 				bits_per_sample = 24;
@@ -3967,12 +4059,13 @@
 			}
 
 			msm_pcm_routing_build_matrix(i,
-				fe_dai_map[i][session_type], path_type,
+				fdai->strm_id, path_type,
 				fe_dai_perf_mode[i][session_type]);
 			port_id = srs_port_id = bedai->port_id;
 			srs_send_params(srs_port_id, 1, 0);
 			if ((DOLBY_ADM_COPP_TOPOLOGY_ID == topology) &&
-			    (fe_dai_perf_mode[i][session_type] == false))
+			    (fe_dai_perf_mode[i][session_type] ==
+							LEGACY_PCM_MODE))
 				if (dolby_dap_init(port_id, channels) < 0)
 					pr_err("%s: Err init dolby dap\n",
 						__func__);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 10be150..54f5e4a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -133,15 +133,30 @@
 	MSM_BACKEND_DAI_MAX,
 };
 
+enum msm_pcm_routing_event {
+	MSM_PCM_RT_EVT_BUF_RECFG,
+	MSM_PCM_RT_EVT_DEVSWITCH,
+	MSM_PCM_RT_EVT_MAX,
+};
+
 /* dai_id: front-end ID,
  * dspst_id:  DSP audio stream ID
  * stream_type: playback or capture
  */
-void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, int dspst_id,
 	int stream_type);
 void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
 		int stream_type);
 
+struct msm_pcm_routing_evt {
+	void (*event_func)(enum msm_pcm_routing_event, void *);
+	void *priv_data;
+};
+
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+				       int dspst_id, int stream_type,
+				       struct msm_pcm_routing_evt event_info);
+
 void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
 
 int msm_routing_check_backend_enabled(int fedai_id);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 6cb7ce1..54b1263 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -702,7 +702,8 @@
 	return;
 }
 
-static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
+static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal,
+			      int perf_mode)
 {
 	s32				result = 0;
 	struct adm_cmd_set_pp_params_v5	adm_params;
@@ -731,7 +732,14 @@
 	adm_params.hdr.src_port = port_id;
 	adm_params.hdr.dest_svc = APR_SVC_ADM;
 	adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
-	adm_params.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+
+	if (perf_mode == LEGACY_PCM_MODE)
+		adm_params.hdr.dest_port =
+			atomic_read(&this_adm.copp_id[index]);
+	else
+		adm_params.hdr.dest_port =
+			atomic_read(&this_adm.copp_low_latency_id[index]);
+
 	adm_params.hdr.token = port_id;
 	adm_params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
 	adm_params.payload_addr_lsw = aud_cal->cal_paddr;
@@ -767,7 +775,7 @@
 	return result;
 }
 
-static void send_adm_cal(int port_id, int path)
+static void send_adm_cal(int port_id, int path, int perf_mode)
 {
 	int			result = 0;
 	s32			acdb_path;
@@ -808,7 +816,7 @@
 		}
 	}
 
-	if (!send_adm_cal_block(port_id, &aud_cal))
+	if (!send_adm_cal_block(port_id, &aud_cal, perf_mode))
 		pr_debug("%s: Audproc cal sent for port id: %#x, path %d\n",
 			__func__, port_id, acdb_path);
 	else
@@ -842,7 +850,7 @@
 		}
 	}
 
-	if (!send_adm_cal_block(port_id, &aud_cal))
+	if (!send_adm_cal_block(port_id, &aud_cal, perf_mode))
 		pr_debug("%s: Audvol cal sent for port id: %#x, path %d\n",
 			__func__, port_id, acdb_path);
 	else
@@ -1048,7 +1056,7 @@
 }
 
 int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
-			bool perf_mode, uint16_t bits_per_sample)
+			int perf_mode, uint16_t bits_per_sample)
 {
 	struct adm_cmd_device_open_v5	open;
 	int ret = 0;
@@ -1079,7 +1087,7 @@
 		rtac_set_adm_handle(this_adm.apr);
 	}
 
-	if (!perf_mode) {
+	if (perf_mode == LEGACY_PCM_MODE) {
 		atomic_set(&this_adm.copp_perf_mode[index], 0);
 		send_adm_custom_topology(port_id);
 	} else {
@@ -1087,8 +1095,9 @@
 	}
 
 	/* Create a COPP if port id are not enabled */
-	if ((!perf_mode && (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
-		(perf_mode &&
+	if ((perf_mode == LEGACY_PCM_MODE &&
+		(atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
+		(perf_mode != LEGACY_PCM_MODE &&
 		(atomic_read(&this_adm.copp_low_latency_cnt[index]) == 0))) {
 		pr_debug("%s:opening ADM: perf_mode: %d\n", __func__,
 			perf_mode);
@@ -1103,12 +1112,12 @@
 		open.hdr.dest_port = tmp_port;
 		open.hdr.token = port_id;
 		open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
-		open.flags = 0x00;
-		if (perf_mode) {
-			open.flags |= ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
-		} else {
-			open.flags |= ADM_LEGACY_DEVICE_SESSION;
-		}
+		if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
+			open.flags = ADM_ULTRA_LOW_LATENCY_DEVICE_SESSION;
+		else if (perf_mode == LOW_LATENCY_PCM_MODE)
+			open.flags = ADM_LOW_LATENCY_DEVICE_SESSION;
+		else
+			open.flags = ADM_LEGACY_DEVICE_SESSION;
 
 		open.mode_of_operation = path;
 		open.endpoint_id_1 = tmp_port;
@@ -1125,7 +1134,7 @@
 			(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
 				rate = 16000;
 
-		if (perf_mode) {
+		if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) {
 			open.topology_id = NULL_COPP_TOPOLOGY;
 			rate = ULL_SUPPORTED_SAMPLE_RATE;
 			if(channel_mode > ULL_MAX_SUPPORTED_CHANNEL)
@@ -1133,7 +1142,8 @@
 		}
 		open.dev_num_channel = channel_mode & 0x00FF;
 		open.bit_width = bits_per_sample;
-		WARN_ON(perf_mode && (rate != 48000));
+		WARN_ON(perf_mode == ULTRA_LOW_LATENCY_PCM_MODE &&
+							(rate != 48000));
 		open.sample_rate  = rate;
 		memset(open.dev_channel_mapping, 0, 8);
 
@@ -1208,7 +1218,8 @@
 			goto fail_cmd;
 		}
 	}
-	if (perf_mode) {
+	if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+			perf_mode == LOW_LATENCY_PCM_MODE) {
 		atomic_inc(&this_adm.copp_low_latency_cnt[index]);
 		pr_debug("%s: index: %d coppid: %d", __func__, index,
 			atomic_read(&this_adm.copp_low_latency_id[index]));
@@ -1225,7 +1236,7 @@
 }
 
 int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
-			int topology, bool perf_mode, uint16_t bits_per_sample)
+			int topology, int perf_mode, uint16_t bits_per_sample)
 {
 	int ret = 0;
 
@@ -1236,7 +1247,7 @@
 }
 
 int adm_matrix_map(int session_id, int path, int num_copps,
-			unsigned int *port_id, int copp_id, bool perf_mode)
+			unsigned int *port_id, int copp_id, int perf_mode)
 {
 	struct adm_cmd_matrix_map_routings_v5	*route;
 	struct adm_session_map_node_v5 *node;
@@ -1275,7 +1286,8 @@
 	route->hdr.src_port = copp_id;
 	route->hdr.dest_svc = APR_SVC_ADM;
 	route->hdr.dest_domain = APR_DOMAIN_ADSP;
-	if (perf_mode) {
+	if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+			perf_mode == LOW_LATENCY_PCM_MODE) {
 		route->hdr.dest_port =
 			atomic_read(&this_adm.copp_low_latency_id[index]);
 	} else {
@@ -1313,7 +1325,8 @@
 
 
 		if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
-			if (perf_mode)
+			if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+					perf_mode == LOW_LATENCY_PCM_MODE)
 				copps_list[i] =
 				atomic_read(&this_adm.copp_low_latency_id[tmp]);
 			else
@@ -1323,8 +1336,7 @@
 		else
 			continue;
 		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]));
+			__func__, i, port_id[i], tmp, copps_list[i]);
 	}
 	atomic_set(&this_adm.copp_stat[index], 0);
 
@@ -1344,25 +1356,31 @@
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
-	if (!perf_mode) {
+
+	if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
 		for (i = 0; i < num_copps; i++)
-			send_adm_cal(port_id[i], path);
+			send_adm_cal(port_id[i], path, perf_mode);
 
 		for (i = 0; i < num_copps; i++) {
-			int tmp;
+			int tmp, copp_id;
 			tmp = afe_get_port_index(port_id[i]);
 			if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+				if (perf_mode == LEGACY_PCM_MODE)
+					copp_id = atomic_read(
+					&this_adm.copp_id[tmp]);
+				else
+					copp_id = atomic_read(
+					&this_adm.copp_low_latency_id[tmp]);
 				rtac_add_adm_device(port_id[i],
-					atomic_read(&this_adm.copp_id[tmp]),
-					path, session_id);
-				pr_debug("%s, copp_id: %d\n", __func__,
-					atomic_read(&this_adm.copp_id[tmp]));
-			} else {
+						copp_id, path, session_id);
+				pr_debug("%s, copp_id: %d\n",
+							__func__, copp_id);
+			} else
 				pr_debug("%s: Invalid port index %d",
-					__func__, tmp);
-			}
+							__func__, tmp);
 		}
 	}
+
 fail_cmd:
 	kfree(matrix_map);
 	return ret;
@@ -1514,8 +1532,26 @@
 	return ret;
 }
 
+#ifdef CONFIG_RTAC
 int adm_get_copp_id(int port_index)
 {
+	int copp_id;
+	pr_debug("%s\n", __func__);
+
+	if (port_index < 0) {
+		pr_err("%s: invalid port_id = %d\n", __func__, port_index);
+		return -EINVAL;
+	}
+
+	copp_id = atomic_read(&this_adm.copp_id[port_index]);
+	if (copp_id == RESET_COPP_ID)
+		copp_id = atomic_read(
+			&this_adm.copp_low_latency_id[port_index]);
+	return copp_id;
+}
+
+int adm_get_lowlatency_copp_id(int port_index)
+{
 	pr_debug("%s\n", __func__);
 
 	if (port_index < 0) {
@@ -1523,8 +1559,19 @@
 		return -EINVAL;
 	}
 
-	return atomic_read(&this_adm.copp_id[port_index]);
+	return atomic_read(&this_adm.copp_low_latency_id[port_index]);
 }
+#else
+int adm_get_copp_id(int port_index)
+{
+	return -EINVAL;
+}
+
+int adm_get_lowlatency_copp_id(int port_index)
+{
+	return -EINVAL;
+}
+#endif /* #ifdef CONFIG_RTAC */
 
 void adm_ec_ref_rx_id(int port_id)
 {
@@ -1532,12 +1579,13 @@
 	pr_debug("%s ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
 }
 
-int adm_close(int port_id, bool perf_mode)
+int adm_close(int port_id, int perf_mode)
 {
 	struct apr_hdr close;
 
 	int ret = 0;
 	int index = 0;
+	int copp_id = RESET_COPP_ID;
 
 	port_id = q6audio_convert_virtual_to_portid(port_id);
 
@@ -1548,7 +1596,8 @@
 	pr_debug("%s port_id=%#x index %d perf_mode: %d\n", __func__, port_id,
 		index, perf_mode);
 
-	if (perf_mode) {
+	if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+				perf_mode == LOW_LATENCY_PCM_MODE) {
 		if (!(atomic_read(&this_adm.copp_low_latency_cnt[index]))) {
 			pr_err("%s: copp count for port[%#x]is 0\n", __func__,
 				port_id);
@@ -1563,8 +1612,9 @@
 		}
 		atomic_dec(&this_adm.copp_cnt[index]);
 	}
-	if ((!perf_mode && !(atomic_read(&this_adm.copp_cnt[index]))) ||
-		(perf_mode &&
+	if ((perf_mode == LEGACY_PCM_MODE &&
+		!(atomic_read(&this_adm.copp_cnt[index]))) ||
+		((perf_mode != LEGACY_PCM_MODE) &&
 		!(atomic_read(&this_adm.copp_low_latency_cnt[index])))) {
 
 		pr_debug("%s:Closing ADM: perf_mode: %d\n", __func__,
@@ -1577,7 +1627,8 @@
 		close.src_port = port_id;
 		close.dest_svc = APR_SVC_ADM;
 		close.dest_domain = APR_DOMAIN_ADSP;
-		if (perf_mode)
+		if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+				perf_mode == LOW_LATENCY_PCM_MODE)
 			close.dest_port =
 			     atomic_read(&this_adm.copp_low_latency_id[index]);
 		else
@@ -1587,18 +1638,23 @@
 
 		atomic_set(&this_adm.copp_stat[index], 0);
 
-		if (perf_mode) {
+		if (perf_mode == ULTRA_LOW_LATENCY_PCM_MODE ||
+				perf_mode == LOW_LATENCY_PCM_MODE) {
+			copp_id = atomic_read(
+				&this_adm.copp_low_latency_id[index]);
 			pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
-			    __func__,
-			    atomic_read(&this_adm.copp_low_latency_id[index]),
-			    port_id, index,
-			    atomic_read(&this_adm.copp_low_latency_cnt[index]));
+				__func__,
+				copp_id,
+				port_id, index,
+				atomic_read(
+					&this_adm.copp_low_latency_cnt[index]));
 			atomic_set(&this_adm.copp_low_latency_id[index],
 				RESET_COPP_ID);
 		} else {
+			copp_id = atomic_read(&this_adm.copp_id[index]);
 			pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
 				__func__,
-				atomic_read(&this_adm.copp_id[index]),
+				copp_id,
 				port_id, index,
 				atomic_read(&this_adm.copp_cnt[index]));
 			atomic_set(&this_adm.copp_id[index],
@@ -1623,9 +1679,9 @@
 		}
 	}
 
-	if (!perf_mode) {
+	if (perf_mode != ULTRA_LOW_LATENCY_PCM_MODE) {
 		pr_debug("%s: remove adm device from rtac\n", __func__);
-		rtac_remove_adm_device(port_id);
+		rtac_remove_adm_device(port_id, copp_id);
 	}
 
 fail_cmd:
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 95114e0..24f5f3b 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -39,6 +39,7 @@
 
 #include <sound/apr_audio-v2.h>
 #include <sound/q6asm-v2.h>
+#include <sound/q6audio-v2.h>
 
 #include "audio_acdb.h"
 
@@ -354,7 +355,7 @@
 	session[ac->session] = 0;
 	mutex_unlock(&session_lock);
 	ac->session = 0;
-	ac->perf_mode = 0;
+	ac->perf_mode = LEGACY_PCM_MODE;
 	ac->fptr_cache_ops = NULL;
 	return;
 }
@@ -810,7 +811,7 @@
 	ac->cb = cb;
 	ac->priv = priv;
 	ac->io_mode = SYNC_IO_MODE;
-	ac->perf_mode = false;
+	ac->perf_mode = LEGACY_PCM_MODE;
 	ac->fptr_cache_ops = NULL;
 	ac->apr = apr_register("ADSP", "ASM", \
 				(apr_fn)q6asm_callback,\
@@ -1256,6 +1257,7 @@
 		case ASM_STREAM_CMD_OPEN_READ_V3:
 		case ASM_STREAM_CMD_OPEN_WRITE_V3:
 		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
+		case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
 		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
 		case ASM_CMD_ADD_TOPOLOGIES:
@@ -1694,7 +1696,7 @@
 	open.bits_per_sample = bits_per_sample;
 	open.mode_flags = 0x0;
 
-	if (ac->perf_mode) {
+	if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
 		open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION <<
 				ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
 	} else {
@@ -1744,6 +1746,7 @@
 			rc);
 		goto fail_cmd;
 	}
+	ac->io_mode |= TUN_READ_IO_MODE;
 	return 0;
 fail_cmd:
 	return -EINVAL;
@@ -1779,8 +1782,10 @@
 
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
 	open.mode_flags = 0x00;
-	if (ac->perf_mode)
+	if (ac->perf_mode == ULTRA_LOW_LATENCY_PCM_MODE)
 		open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
+	else if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
+		open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
 	else {
 		open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
 		if (is_gapless_mode)
@@ -1837,6 +1842,7 @@
 			rc);
 		goto fail_cmd;
 	}
+	ac->io_mode |= TUN_WRITE_IO_MODE;
 	return 0;
 fail_cmd:
 	return -EINVAL;
@@ -1977,6 +1983,49 @@
 	return -EINVAL;
 }
 
+int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_loopback_v2 open;
+
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("%s APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s: session[%d]", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
+
+	open.mode_flags = 0;
+	open.src_endpointype = 0;
+	open.sink_endpointype = 0;
+	/* source endpoint : matrix */
+	open.postprocopo_id = get_asm_topology();
+	if (open.postprocopo_id == 0)
+		open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+	open.bits_per_sample = bits_per_sample;
+	open.reserved = 0;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("%s open failed op[0x%x]rc[%d]\n", __func__,
+				open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s timeout. waited for open_loopback rc[%d]\n",
+				__func__, rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
 int q6asm_run(struct audio_client *ac, uint32_t flags,
 		uint32_t msw_ts, uint32_t lsw_ts)
 {
@@ -4217,9 +4266,11 @@
 {
 	int cnt = 0;
 	int loopcnt = 0;
+	int used;
 	struct audio_port_data *port = NULL;
 
 	if (ac->io_mode & SYNC_IO_MODE) {
+		used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
 		mutex_lock(&ac->cmd_lock);
 		for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
 			port = &ac->port[loopcnt];
@@ -4229,7 +4280,7 @@
 			while (cnt >= 0) {
 				if (!port->buf)
 					continue;
-				port->buf[cnt].used = 1;
+				port->buf[cnt].used = used;
 				cnt--;
 			}
 		}
diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
index f74dbe2..701dfef 100644
--- a/sound/soc/msm/qdsp6v2/rtac.c
+++ b/sound/soc/msm/qdsp6v2/rtac.c
@@ -556,7 +556,8 @@
 	/* Check if device already added */
 	if (rtac_adm_data.num_of_dev != 0) {
 		for (; i < rtac_adm_data.num_of_dev; i++) {
-			if (rtac_adm_data.device[i].afe_port == port_id) {
+			if (rtac_adm_data.device[i].afe_port == port_id &&
+			    rtac_adm_data.device[i].copp == copp_id) {
 				add_popp(i, port_id, popp_id);
 				goto done;
 			}
@@ -609,7 +610,7 @@
 	}
 }
 
-void rtac_remove_adm_device(u32 port_id)
+void rtac_remove_adm_device(u32 port_id, u32 copp_id)
 {
 	s32 i;
 	pr_debug("%s: port_id = %d\n", __func__, port_id);
@@ -619,7 +620,8 @@
 
 	/* look for device */
 	for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
-		if (rtac_adm_data.device[i].afe_port == port_id) {
+		if (rtac_adm_data.device[i].afe_port == port_id &&
+		    rtac_adm_data.device[i].copp == copp_id) {
 			memset(&rtac_adm_data.device[i], 0,
 				   sizeof(rtac_adm_data.device[i]));
 			rtac_adm_data.num_of_dev--;
@@ -870,6 +872,8 @@
 	for (port_index = 0; port_index < AFE_MAX_PORTS; port_index++) {
 		if (adm_get_copp_id(port_index) == copp_id)
 			break;
+		if (adm_get_lowlatency_copp_id(port_index) == copp_id)
+			break;
 	}
 	if (port_index >= AFE_MAX_PORTS) {
 		pr_err("%s: Could not find port index for copp = %d\n",