Merge "USB: ehci-msm-hsic: Make driver less verbose"
diff --git a/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt b/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt
deleted file mode 100644
index 01301be..0000000
--- a/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-* MSM PC Debug Counters
-
-MSM PC debug counter reserves 16 registers in the IMEM memory space which
-maintains a count on the state of power collapse on each core. This count
-will be useful to debug the power collapse state on each core.
-
-The required nodes for MSM PC Debug Counters are:
-
-- compatible: "qcom,pc-cntr"
-- reg: physical IMEM address reserved for PC counters
-
-Example:
-
-qcom,pc-cntr@fe800000 {
-		compatible = "qcom,pc-cntr";
-		reg = <0xfe800664 0x40>;
-	};
-
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index b429072..a372912 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -5,6 +5,9 @@
 the kernel to be notified of idle and suspend states and when called, follows
 through the set of instructions in putting the application cores to the lowest
 power mode possible.
+The PC debug counter reserves 16 registers in the IMEM memory space which maintains
+a count on the state of power collapse on each core. This count will be useful to
+debug the power collapse state on each core.
 
 The required properties for PM-8x60 are:
 
@@ -12,17 +15,22 @@
 
 The optional properties are:
 
+- reg: physical IMEM address reserved for PC counters and the size
 - qcom,use-sync-timer: Indicates whether the target uses the synchronized QTimer.
 - qcom,pc-mode: Indicates the type of power collapse used by the target. The
-           valid values for this are:
+	valid values for this are:
 	0  (Power collapse terminates in TZ; integrated L2 cache controller)
 	1, (Power collapse doesn't terminate in TZ; external L2 cache controller)
 	2  (Power collapse terminates in TZ; external L2 cache controller)
+- qcom,saw-turns-off-pll: Version of SAW2.1 or can turn off the HFPLL, when
+	doing power collapse and so the core need to switch to Global PLL before
+	PC.
 
 Example:
 
-qcom,pm-8x60 {
+qcom,pm-8x60@fe800664 {
 		compatible = "qcom,pm-8x60";
+		reg = <0xfe800664 0x40>;
 		qcom,pc-mode = <0>;
 		qcom,use-sync-timer;
 	};
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 939f77b..4b912f3 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -1,25 +1,51 @@
 Qualcomm Serial Peripheral Interface (SPI)
 
 Required properties:
-- compatible : should be "qcom,spi-qup-v2".
-- reg : offset and length of the QUP register map.
-- interrupts : should contain the QUP core interrupt.
-- spi-max-frequency : specifies maximum SPI clock frequency, Units - Hz.
+- compatible : Should be "qcom,spi-qup-v2".
+- reg : Offset and length of the register regions for the device
+- reg-names : Register region names referenced in reg above.
+	Required register resource entries are:
+	"spi_physical" : Physical address of controller register blocks.
+- interrupts : Interrupt numbers used by this controller
+- interrupt-names : Interrupt resource names referenced in interrupts above.
+	Required interrupt resource entries are:
+	"spi_irq" : QUP-core interrupt.
+- spi-max-frequency : Specifies maximum SPI clock frequency, Units - Hz.
+
+Required alias:
+- The desired bus-number is specified via an alias with the following format
+	'spi{n}' where n is the bus number.
 
 Optional properties:
-- gpios : specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
+- gpios : Specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
   that order.
-- cs-gpios : specifies the gpio pins to be used for chipselects.
+- cs-gpios : Specifies the gpio pins to be used for chipselects.
+- qcom,infinite-mode: When missing or set to zero, QUP uses infinite-mode. When
+  value is non-zero, the value is the number of words in maximum transfer
+  length.
 
-SPI slave nodes must be children of the SPI master node and contain
+Optional properties which are required for support of BAM-mode:
+- qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW
+  version support latest features (e.g. BAM) and then enable them. Should be
+  removed for legacy HW.
+- qcom,use-bam : Boolean. When present, enables BAM-mode.
+- qcom,bam-consumer-pipe-index : BAM consumer-pipe index.
+- qcom,bam-producer-pipe-index : BAM producer-pipe index.
+- reg-names : register region names referenced in reg.
+	Required register resource for BAM are:
+	"spi_bam_physical" : Physical address of BAM for this controller.
+- interrupt-names : interrupt resource names referenced in interrupts.
+	Required interrupt resource from BAM are:
+	"spi_bam_irq" : BAM interrupt used by the controller.
+
+Optional SPI slave nodes must be children of the SPI master node and contain
 the following properties.
-- reg : (required) chip select address of device.
-- compatible : (required) name of SPI device following generic names
-  recommended practice
+- reg: (required) chip-select address of the device.
+- compatible : (required) Name of SPI device following generic names.
 - spi-max-frequency : (required) Maximum SPI clocking speed of device in Hz
-- interrupts : (recommended) should contain the SPI slave interrupt number
+- interrupts : (recommended) Should contain the SPI slave interrupt number
   encoded depending on the type of the interrupt controller.
-- interrupt-parent : (recommended) the phandle for the interrupt controller
+- interrupt-parent : (recommended) The phandle for the interrupt controller
   that services interrupts for this device.
 - spi-cpol : (optional) Empty property indicating device requires inverse
   clock polarity (CPOL) mode
@@ -29,18 +55,30 @@
   chip select active high
 
 Example:
-	spi@f9924000 {
-		compatible = "qcom,spi-qup-v2";
-		reg = <0xf9924000 0x1000>;
-		interrupts = <0 96 0>;
-		spi-max-frequency = <24000000>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		device@0 {
-			compatible = "spidev";
-			reg = <0>;
-			spi-max-frequency = <5000000>;
-		};
+	aliases {
+		spi0 = &spi_0;
 	};
 
+	spi_0: spi@f9923000 {
+		compatible = "qcom,spi-qup-v2";
+
+		reg-names = "spi_physical", "spi_bam_physical";
+		reg = <0xf9923000 0x1000>,
+			<0xf9904000 0x10000>;
+		interrupt-names = "spi_irq", "spi_bam_irq";
+		interrupts = <0 95 0>, <0 238 0>;
+
+		spi-max-frequency = <19200000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		gpios = <&msmgpio 3 0>, /* CLK  */
+			<&msmgpio 1 0>, /* MISO */
+			<&msmgpio 0 0>; /* MOSI */
+		cs-gpios = <&msmgpio 9 0>;
+
+		qcom,infinite-mode = <0>;
+		qcom,use-bam;
+		qcom,bam-consumer-pipe-index = <12>;
+		qcom,bam-producer-pipe-index = <13>;
+		qcom,ver-reg-exists;
+	};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index f9b9e33..2de5fad 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -419,13 +419,9 @@
 			<40  95>;
 	};
 
-	qcom,pc-cntr@fe805664 {
-		compatible = "qcom,pc-cntr";
-		reg = <0xfe805664 0x40>;
-	};
-
-	qcom,pm-8x60 {
+	qcom,pm-8x60@fe805664 {
 		compatible = "qcom,pm-8x60";
+		reg = <0xfe805664 0x40>;
 		qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
 		qcom,use-sync-timer;
 	};
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index 584869d..c974884 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -71,6 +71,7 @@
 	};
 
 	venus_sec_bitstream: qcom,iommu-ctx@fdc8d000 {
+		qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84>;
 		label = "venus_sec_bitstream";
 	};
 
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 212812c..e6376d4 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -25,6 +25,11 @@
 	compatible = "qcom,msm8974";
 	interrupt-parent = <&intc>;
 
+	aliases {
+		spi0 = &spi_0;
+		spi7 = &spi_7;
+	};
+
 	intc: interrupt-controller@F9000000 {
 		compatible = "qcom,msm-qgic2";
 		interrupt-controller;
@@ -381,9 +386,8 @@
 		qcom,bam-dma-res-pipes = <6>;
 	};
 
-	spi_epm: spi@f9966000 {
+	spi_7: spi_epm: spi@f9966000 {
 		compatible = "qcom,spi-qup-v2";
-		cell-index = <7>;
 		reg = <0xf9966000 0x1000>;
 		interrupts = <0 104 0>;
 		spi-max-frequency = <19200000>;
@@ -572,8 +576,7 @@
 		qcom,i2c-src-freq = <19200000>;
 	};
 
-	spi@f9923000 {
-		cell-index = <0>;
+	spi_0: spi@f9923000 {
 		compatible = "qcom,spi-qup-v2";
 		reg = <0xf9923000 0x1000>;
 		interrupts = <0 95 0>;
diff --git a/arch/arm/boot/dts/msm9625-v2-1-cdp.dts b/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
new file mode 100644
index 0000000..8702184
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
@@ -0,0 +1,99 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625-v2-1.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625V2.1 CDP";
+	compatible = "qcom,msm9625-cdp", "qcom,msm9625";
+	qcom,msm-id = <134 1 0x20001>, <152 1 0x20001>, <149 1 0x20001>,
+		      <150 1 0x20001>, <151 1 0x20001>, <148 1 0x20001>,
+		      <173 1 0x20001>, <174 1 0x20001>, <175 1 0x20001>;
+
+	i2c@f9925000 {
+		charger@57 {
+			compatible = "summit,smb137c";
+			reg = <0x57>;
+			summit,chg-current-ma = <1500>;
+			summit,term-current-ma = <50>;
+			summit,pre-chg-current-ma = <100>;
+			summit,float-voltage-mv = <4200>;
+			summit,thresh-voltage-mv = <3000>;
+			summit,recharge-thresh-mv = <75>;
+			summit,system-voltage-mv = <4250>;
+			summit,charging-timeout = <382>;
+			summit,pre-charge-timeout = <48>;
+			summit,therm-current-ua = <10>;
+			summit,temperature-min = <4>; /*  0 C */
+			summit,temperature-max = <3>; /* 45 C */
+		};
+	};
+
+	wlan0: qca,wlan {
+		cell-index = <0>;
+		compatible = "qca,ar6004-sdio";
+		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+	};
+};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		/* ext_2p95v regulator enable config */
+		qcom,mode = <1>; /* Digital output */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,invert = <0>; /* Output low */
+		qcom,out-strength = <1>; /* Low */
+		qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
+		qcom,src-sel = <0>; /* Constant */
+		qcom,master-en = <1>; /* Enable GPIO */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+};
+
+&pm8019_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625-v2-1-mtp.dts b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
new file mode 100644
index 0000000..2dc040c
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
@@ -0,0 +1,99 @@
+/* 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625-v2-1.dtsi"
+
+/ {
+	model = "Qualcomm MSM 9625V2.1 MTP";
+	compatible = "qcom,msm9625-mtp", "qcom,msm9625";
+	qcom,msm-id = <134 7 0x20001>, <152 7 0x20001>, <149 7 0x20001>,
+		      <150 7 0x20001>, <151 7 0x20001>, <148 7 0x20001>,
+		      <173 7 0x20001>, <174 7 0x20001>, <175 7 0x20001>;
+
+	i2c@f9925000 {
+		charger@57 {
+			compatible = "summit,smb137c";
+			reg = <0x57>;
+			summit,chg-current-ma = <1500>;
+			summit,term-current-ma = <50>;
+			summit,pre-chg-current-ma = <100>;
+			summit,float-voltage-mv = <4200>;
+			summit,thresh-voltage-mv = <3000>;
+			summit,recharge-thresh-mv = <75>;
+			summit,system-voltage-mv = <4250>;
+			summit,charging-timeout = <382>;
+			summit,pre-charge-timeout = <48>;
+			summit,therm-current-ua = <10>;
+			summit,temperature-min = <4>; /*  0 C */
+			summit,temperature-max = <3>; /* 45 C */
+		};
+	};
+
+	wlan0: qca,wlan {
+		cell-index = <0>;
+		compatible = "qca,ar6004-sdio";
+		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+	};
+};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+	gpio@c000 { /* GPIO 1 */
+	};
+
+	gpio@c100 { /* GPIO 2 */
+	};
+
+	gpio@c200 { /* GPIO 3 */
+	};
+
+	gpio@c300 { /* GPIO 4 */
+		/* ext_2p95v regulator enable config */
+		qcom,mode = <1>; /* Digital output */
+		qcom,output-type = <0>; /* CMOS */
+		qcom,invert = <0>; /* Output low */
+		qcom,out-strength = <1>; /* Low */
+		qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
+		qcom,src-sel = <0>; /* Constant */
+		qcom,master-en = <1>; /* Enable GPIO */
+	};
+
+	gpio@c400 { /* GPIO 5 */
+	};
+
+	gpio@c500 { /* GPIO 6 */
+	};
+};
+
+&pm8019_mpps {
+	mpp@a000 { /* MPP 1 */
+	};
+
+	mpp@a100 { /* MPP 2 */
+	};
+
+	mpp@a200 { /* MPP 3 */
+	};
+
+	mpp@a300 { /* MPP 4 */
+	};
+
+	mpp@a400 { /* MPP 5 */
+	};
+
+	mpp@a500 { /* MPP 6 */
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625-v2-1.dtsi b/arch/arm/boot/dts/msm9625-v2-1.dtsi
new file mode 100644
index 0000000..c3c2c49
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1.dtsi
@@ -0,0 +1,36 @@
+/* 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.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm9625.dtsi file.
+ */
+
+/include/ "msm9625.dtsi"
+
+/ {
+	qcom,msm-imem@fe807800 {
+		compatible = "qcom,msm-imem";
+		reg = <0xfe807800 0x1000>; /* Address and size of IMEM */
+	};
+
+	android_usb@fe8078c8 {
+		compatible = "qcom,android-usb";
+		reg = <0xfe8078c8 0xc8>;
+		qcom,android-usb-swfi-latency = <100>;
+	};
+};
+
+&ipa_hw {
+	qcom,ipa-hw-ver = <2>; /* IPA h-w revision */
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d5a33ee..922616c 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -21,6 +21,10 @@
 	compatible = "qcom,msm9625";
 	interrupt-parent = <&intc>;
 
+	aliases {
+		spi0 = &spi_0;
+	};
+
 	intc: interrupt-controller@F9000000 {
 		compatible = "qcom,msm-qgic2";
 		interrupt-controller;
@@ -186,8 +190,7 @@
 		interrupt-names = "bam_irq";
 	};
 
-	spi@f9924000 {
-		cell-index = <0>;
+	spi_0: spi@f9924000 {
 		compatible = "qcom,spi-qup-v2";
 		reg = <0xf9924000 0x1000>;
 		interrupts = <0 96 0>;
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 85b1bb3..8fb93d0 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -790,7 +790,7 @@
 			 */
 			if (cpu_pmu &&
 				cpu_pmu->plat_device->dev.platform_data) {
-				irq = platform_get_irq(cpu_pmu->plat_device, 1);
+				irq = platform_get_irq(cpu_pmu->plat_device, 0);
 				smp_call_function_single((int)hcpu,
 						disable_irq_callback, &irq, 1);
 			}
@@ -803,7 +803,7 @@
 			 */
 			if (cpu_pmu &&
 				cpu_pmu->plat_device->dev.platform_data) {
-				irq = platform_get_irq(cpu_pmu->plat_device, 1);
+				irq = platform_get_irq(cpu_pmu->plat_device, 0);
 				smp_call_function_single((int)hcpu,
 						enable_irq_callback, &irq, 1);
 			}
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index b451d08..202b8dd 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -68,6 +68,8 @@
         dtb-$(CONFIG_ARCH_MSM9625)	+= msm9625-v1-rumi.dtb
 	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-cdp.dtb
 	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-1-mtp.dtb
+	dtb-$(CONFIG_ARCH_MSM9625)      += msm9625-v2-1-cdp.dtb
 
 # MSM8226
    zreladdr-$(CONFIG_ARCH_MSM8226)	:= 0x00008000
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
index 5b72a3f..dd3f346 100644
--- a/arch/arm/mach-msm/bms-batterydata-desay.c
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -83,4 +83,5 @@
 	.pc_temp_ocv_lut	= &desay_5200_pc_temp_ocv,
 	.pc_sf_lut		= &desay_5200_pc_sf,
 	.default_rbatt_mohm	= 156,
+	.rbatt_capacitive_mohm	= 50,
 };
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 824cf6b..0c39df6 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -105,4 +105,5 @@
 	.pc_temp_ocv_lut	= &pc_temp_ocv,
 	.rbatt_sf_lut		= &rbatt_sf,
 	.default_rbatt_mohm	= 236,
+	.rbatt_capacitive_mohm	= 50,
 };
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index a89ea61..beb064b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2723,7 +2723,6 @@
 	&apq8064_device_uart_gsbi1,
 	&apq8064_device_uart_gsbi4,
 	&msm_device_sps_apq8064,
-	&msm8064_pc_cntr,
 };
 
 static struct platform_device *common_i2s_devices[] __initdata = {
@@ -2888,7 +2887,6 @@
 #ifdef CONFIG_MSM_ROTATOR
 	&msm_rotator_device,
 #endif
-	&msm8064_pc_cntr,
 };
 
 static struct platform_device
@@ -3861,11 +3859,13 @@
 	if (cpu_is_apq8064ab())
 		apq8064ab_update_krait_spm();
 	if (cpu_is_krait_v3()) {
-		msm_pm_set_tz_retention_flag(0);
+		struct msm_pm_init_data_type *pdata =
+			msm8064_pm_8x60.dev.platform_data;
+		pdata->retention_calls_tz = false;
 		apq8064ab_update_retention_spm();
-	} else {
-		msm_pm_set_tz_retention_flag(1);
 	}
+	platform_device_register(&msm8064_pm_8x60);
+
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index d974452..d045040 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -63,11 +63,9 @@
 		 * hardware revisions - maybe once that is done, this can be
 		 * reverted.
 		 */
-		.always_on = 1,
 		.lpm_sup = 1,
 		.hpm_uA = 800000, /* 800mA */
 		.lpm_uA = 9000,
-		.reset_at_init = true,
 	},
 };
 
@@ -311,13 +309,11 @@
 	 * This change to the boards will be true for newer versions of the SoC
 	 * as well.
 	 */
-	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 1 &&
-			SOCINFO_VERSION_MINOR(socinfo_get_version()) >= 2) ||
-			machine_is_msm8930_cdp()) {
-		msm8960_sdc3_data.vreg_data->vdd_data->always_on = false;
-		msm8960_sdc3_data.vreg_data->vdd_data->reset_at_init = false;
+	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1 &&
+			SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2) {
+		msm8960_sdc3_data.vreg_data->vdd_data->always_on = true;
+		msm8960_sdc3_data.vreg_data->vdd_data->reset_at_init = true;
 	}
-
 	/* SDC3: External card slot */
 	if (!machine_is_msm8930_cdp()) {
 		msm8960_sdc3_data.wpswitch_gpio = 0;
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index a8e117f..25ba1aa 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2473,7 +2473,6 @@
 	&msm8930_iommu_domain_device,
 	&msm_tsens_device,
 	&msm8930_cache_dump_device,
-	&msm8930_pc_cntr,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -2955,11 +2954,14 @@
 	msm8930_i2c_init();
 	msm8930_init_gpu();
 	if (cpu_is_krait_v3()) {
-		msm_pm_set_tz_retention_flag(0);
+		struct msm_pm_init_data_type *pdata =
+			msm8930_pm_8x60.dev.platform_data;
+		pdata->retention_calls_tz = false;
 		msm8930ab_update_retention_spm();
-	} else {
-		msm_pm_set_tz_retention_flag(1);
 	}
+
+	platform_device_register(&msm8930_pm_8x60);
+
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 	msm8930_init_buses();
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 6524832..95f618a 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2955,7 +2955,6 @@
 	&msm8960_cache_dump_device,
 	&msm8960_iommu_domain_device,
 	&msm_tsens_device,
-	&msm8960_pc_cntr,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -3488,11 +3487,13 @@
 	if (cpu_is_msm8960ab())
 		msm8960ab_update_krait_spm();
 	if (cpu_is_krait_v3()) {
-		msm_pm_set_tz_retention_flag(0);
+		struct msm_pm_init_data_type *pdata =
+			msm8960_pm_8x60.dev.platform_data;
+		pdata->retention_calls_tz = false;
 		msm8960ab_update_retention_spm();
-	} else {
-		msm_pm_set_tz_retention_flag(1);
 	}
+	platform_device_register(&msm8960_pm_8x60);
+
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	msm_spm_l2_init(msm_spm_l2_data);
 
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index c45cf11..02a753a 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -5299,6 +5299,7 @@
 	&msm_device_tz_log,
 	&msm_rtb_device,
 	&msm8660_iommu_domain_device,
+	&msm8660_pm_8x60,
 };
 
 #ifdef CONFIG_ION_MSM
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 77c91b8..e87c7b5 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -72,18 +72,19 @@
 	struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
 {
 	int ret = 0;
-	int i = 0;
+	int i;
 	enum msm_pm_sleep_mode pm_mode;
-	struct cpuidle_state_usage *st_usage = NULL;
 
 	cpu_pm_enter();
 
-	pm_mode = msm_pm_idle_prepare(dev, drv, index);
-	dev->last_residency = msm_pm_idle_enter(pm_mode);
+	pm_mode = msm_pm_idle_enter(dev, drv, index);
+
 	for (i = 0; i < dev->state_count; i++) {
-		st_usage = &dev->states_usage[i];
-		if ((enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage)
-		    == pm_mode) {
+		struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
+		enum msm_pm_sleep_mode last_mode =
+			(enum msm_pm_sleep_mode)cpuidle_get_statedata(st_usage);
+
+		if (last_mode == pm_mode) {
 			ret = i;
 			break;
 		}
@@ -95,7 +96,7 @@
 	return ret;
 }
 
-static void __init msm_cpuidle_set_states(void)
+static void __devinit msm_cpuidle_set_states(void)
 {
 	int i = 0;
 	int state_count = 0;
@@ -151,7 +152,7 @@
 	dev->state_count = state_count; /* Per cpu state count */
 }
 
-int __init msm_cpuidle_init(void)
+int __devinit msm_cpuidle_init(void)
 {
 	unsigned int cpu = 0;
 	int ret = 0;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f87c540..10ee1e3 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -49,6 +49,7 @@
 #include <mach/mpm.h>
 #include <mach/iommu_domains.h>
 #include <mach/msm_cache_dump.h>
+#include "pm.h"
 
 /* Address of GSBI blocks */
 #define MSM_GSBI1_PHYS		0x12440000
@@ -120,11 +121,24 @@
 	},
 };
 
-struct platform_device msm8064_pc_cntr = {
-	.name		= "pc-cntr",
+static uint32_t msm_pm_cp15_regs[] = {0x4501, 0x5501, 0x6501, 0x7501, 0x0500};
+
+static struct msm_pm_init_data_type msm_pm_data = {
+	.retention_calls_tz = true,
+	.cp15_data.save_cp15 = true,
+	.cp15_data.qsb_pc_vdd = 0x98,
+	.cp15_data.reg_data = &msm_pm_cp15_regs[0],
+	.cp15_data.reg_saved_state_size = ARRAY_SIZE(msm_pm_cp15_regs),
+};
+
+struct platform_device msm8064_pm_8x60 = {
+	.name		= "pm-8x60",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(msm8064_resources_pccntr),
 	.resource	= msm8064_resources_pccntr,
+	.dev = {
+		.platform_data = &msm_pm_data,
+	},
 };
 
 static struct msm_watchdog_pdata msm_watchdog_pdata = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index aad512e..6fe8ccb 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.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
@@ -32,6 +32,7 @@
 #include "rpm_rbcpr_stats.h"
 #include "footswitch.h"
 #include "acpuclock-krait.h"
+#include "pm.h"
 
 #ifdef CONFIG_MSM_MPM
 #include <mach/mpm.h>
@@ -48,11 +49,18 @@
 	},
 };
 
-struct platform_device msm8930_pc_cntr = {
-	.name		= "pc-cntr",
+static struct msm_pm_init_data_type msm_pm_data = {
+	.retention_calls_tz = true,
+};
+
+struct platform_device msm8930_pm_8x60 = {
+	.name		= "pm-8x60",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(msm8930_resources_pccntr),
 	.resource	= msm8930_resources_pccntr,
+	.dev = {
+		.platform_data = &msm_pm_data,
+	},
 };
 
 struct msm_rpm_platform_data msm8930_rpm_data __initdata = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index c3748fa..6a344be 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -53,6 +53,7 @@
 #include <mach/msm_dcvs.h>
 #include <mach/iommu_domains.h>
 #include <mach/socinfo.h>
+#include "pm.h"
 
 #ifdef CONFIG_MSM_MPM
 #include <mach/mpm.h>
@@ -116,11 +117,18 @@
 	},
 };
 
-struct platform_device msm8960_pc_cntr = {
-	.name		= "pc-cntr",
+static struct msm_pm_init_data_type msm_pm_data = {
+	.retention_calls_tz = true,
+};
+
+struct platform_device msm8960_pm_8x60 = {
+	.name		= "pm-8x60",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(msm8960_resources_pccntr),
 	.resource	= msm8960_resources_pccntr,
+	.dev = {
+		.platform_data = &msm_pm_data,
+	},
 };
 
 static struct resource resources_otg[] = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 58416c7..cfa9281 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -3181,3 +3181,9 @@
 		.platform_data = &msm8660_iommu_domain_pdata,
 	}
 };
+
+struct platform_device msm8660_pm_8x60 = {
+	.name		= "pm-8x60",
+	.id		= -1,
+};
+
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index d3810a2..53eca3e 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-msm/devices.h
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -113,11 +113,11 @@
 extern struct platform_device msm_device_sdc3;
 extern struct platform_device msm_device_sdc4;
 
+extern struct platform_device msm8960_pm_8x60;
+extern struct platform_device msm8064_pm_8x60;
+extern struct platform_device msm8930_pm_8x60;
 extern struct platform_device msm9615_pm_8x60;
-
-extern struct platform_device msm8960_pc_cntr;
-extern struct platform_device msm8064_pc_cntr;
-extern struct platform_device msm8930_pc_cntr;
+extern struct platform_device msm8660_pm_8x60;
 
 extern struct platform_device msm_device_gadget_peripheral;
 extern struct platform_device msm_device_hsusb_host;
diff --git a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
index 9cd4f3f..a183f0e 100644
--- a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
+++ b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
 	USB_GADGET_XPORT_TTY,
 	USB_GADGET_XPORT_SDIO,
 	USB_GADGET_XPORT_SMD,
+	USB_GADGET_XPORT_QTI,
 	USB_GADGET_XPORT_BAM,
 	USB_GADGET_XPORT_BAM2BAM,
 	USB_GADGET_XPORT_BAM2BAM_IPA,
@@ -38,6 +39,8 @@
 		return "SDIO";
 	case USB_GADGET_XPORT_SMD:
 		return "SMD";
+	case USB_GADGET_XPORT_QTI:
+		return "QTI";
 	case USB_GADGET_XPORT_BAM:
 		return "BAM";
 	case USB_GADGET_XPORT_BAM2BAM:
@@ -63,6 +66,8 @@
 		return USB_GADGET_XPORT_SDIO;
 	if (!strncasecmp("SMD", name, XPORT_STR_LEN))
 		return USB_GADGET_XPORT_SMD;
+	if (!strncasecmp("QTI", name, XPORT_STR_LEN))
+		return USB_GADGET_XPORT_QTI;
 	if (!strncasecmp("BAM", name, XPORT_STR_LEN))
 		return USB_GADGET_XPORT_BAM;
 	if (!strncasecmp("BAM2BAM", name, XPORT_STR_LEN))
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index dec62f0..539a4fe 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -66,18 +66,12 @@
 	atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
 		MSM_LPM_STATE_ENTER, &sleep_data);
 
-	ret = msm_rpm_enter_sleep();
-	if (ret) {
-		pr_warn("%s(): RPM failed to enter sleep err:%d\n",
-				__func__, ret);
-		goto bail;
-	}
 	if (from_idle)
 		debug_mask = msm_lpm_lvl_dbg_msk &
-				MSM_LPM_LVL_DBG_IDLE_LIMITS;
+			MSM_LPM_LVL_DBG_IDLE_LIMITS;
 	else
 		debug_mask = msm_lpm_lvl_dbg_msk &
-				MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+			MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
 
 	if (debug_mask)
 		pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
@@ -88,6 +82,19 @@
 				l->vdd_dig_upper_bound);
 
 	ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
+	if (ret) {
+		pr_warn("%s() LPM resources failed to enter sleep\n",
+				__func__);
+		goto bail;
+	}
+	if (notify_rpm) {
+		ret = msm_rpm_enter_sleep(debug_mask);
+		if (ret) {
+			pr_warn("%s(): RPM failed to enter sleep err:%d\n",
+					__func__, ret);
+			goto bail;
+		}
+	}
 bail:
 	return ret;
 }
@@ -95,9 +102,11 @@
 static void msm_lpm_exit_sleep(void *limits, bool from_idle,
 		bool notify_rpm, bool collapsed)
 {
-	msm_rpm_exit_sleep();
+
 	msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
 				from_idle, notify_rpm, collapsed);
+	if (notify_rpm)
+		msm_rpm_exit_sleep();
 	atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
 			MSM_LPM_STATE_EXIT, NULL);
 }
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 5d7fc94..a62ee92 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.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
@@ -668,7 +668,8 @@
 	}
 	msm_lpm_get_rpm_notif = true;
 
-	msm_mpm_enter_sleep(sclk_count, from_idle);
+	if (notify_rpm)
+		msm_mpm_enter_sleep(sclk_count, from_idle);
 
 	return ret;
 }
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index 0db6e68..a8d4fdb 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -37,15 +37,11 @@
 
 void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls) {}
 
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv, int index)
 {
 	return -ENOSYS;
 }
 
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
-{
-	return -ENOSYS;
-}
-
 void msm_pm_enable_retention(bool enable) {}
+
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 8c942ad..bbd0852 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -25,6 +25,7 @@
 	"0  msm: perf: add debug patch logging framework\n"
 	"1  Perf: Restore counter after powercollapse for generic ARM PMU's\n"
 	"2  Perf: Toggle PMU IRQ when CPU's are hotplugged\n"
+	"3  Perf: Correct irq for CPU hotplug detection\n"
 ;
 
 static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 7f8d3b9..0263faf 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -167,7 +167,7 @@
 
 	/* Assert Q6 resets */
 	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
-	val = (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
+	val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
 	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
 
 	/* Kill power at block headswitch */
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 0b08238..b52d284 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/debugfs.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -40,7 +41,6 @@
 #ifdef CONFIG_VFP
 #include <asm/vfp.h>
 #endif
-
 #include "acpuclock.h"
 #include "clock.h"
 #include "avs.h"
@@ -54,9 +54,27 @@
 #include <mach/event_timer.h>
 #define CREATE_TRACE_POINTS
 #include "trace_msm_low_power.h"
-/******************************************************************************
- * Debug Definitions
- *****************************************************************************/
+
+#define SCM_L2_RETENTION	(0x2)
+#define SCM_CMD_TERMINATE_PC	(0x2)
+
+#define GET_CPU_OF_ATTR(attr) \
+	(container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
+
+#define SCLK_HZ (32768)
+#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
+
+#define NUM_OF_COUNTERS 3
+#define MAX_BUF_SIZE  512
+
+static int msm_pm_debug_mask = 1;
+module_param_named(
+	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 enum {
 	MSM_PM_DEBUG_SUSPEND = BIT(0),
@@ -70,24 +88,12 @@
 	MSM_PM_DEBUG_HOTPLUG = BIT(8),
 };
 
-static int msm_pm_debug_mask = 1;
-module_param_named(
-	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-static int msm_pm_retention_tz_call;
-
-/******************************************************************************
- * Sleep Modes and Parameters
- *****************************************************************************/
 enum {
 	MSM_PM_MODE_ATTR_SUSPEND,
 	MSM_PM_MODE_ATTR_IDLE,
 	MSM_PM_MODE_ATTR_NR,
 };
 
-#define SCM_L2_RETENTION	(0x2)
-#define SCM_CMD_TERMINATE_PC	(0x2)
-
 static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
 	[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
 	[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
@@ -98,9 +104,6 @@
 	struct kobj_attribute ka;
 };
 
-#define GET_CPU_OF_ATTR(attr) \
-	(container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
-
 struct msm_pm_sysfs_sleep_mode {
 	struct kobject *kobj;
 	struct attribute_group attr_group;
@@ -116,10 +119,15 @@
 		"standalone_power_collapse",
 };
 
-static struct msm_pm_init_data_type msm_pm_init_data;
 static struct hrtimer pm_hrtimer;
 static struct msm_pm_sleep_ops pm_sleep_ops;
 static bool msm_pm_ldo_retention_enabled = true;
+static bool msm_pm_use_sync_timer;
+static struct msm_pm_cp15_save_data cp15_data;
+static bool msm_pm_retention_calls_tz;
+static uint32_t msm_pm_max_sleep_time;
+static bool msm_no_ramp_down_pc;
+
 /*
  * Write out the attribute.
  */
@@ -166,9 +174,6 @@
 	return ret;
 }
 
-/*
- * Read in the new attribute value.
- */
 static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
 	struct kobj_attribute *attr, const char *buf, size_t count)
 {
@@ -205,10 +210,7 @@
 	return ret ? ret : count;
 }
 
-/*
- * Add sysfs entries for one cpu.
- */
-static int __init msm_pm_mode_sysfs_add_cpu(
+static int __devinit msm_pm_mode_sysfs_add_cpu(
 	unsigned int cpu, struct kobject *modes_kobj)
 {
 	char cpu_name[8];
@@ -291,10 +293,7 @@
 	return ret;
 }
 
-/*
- * Add sysfs entries for the sleep modes.
- */
-static int __init msm_pm_mode_sysfs_add(void)
+int __devinit msm_pm_mode_sysfs_add(void)
 {
 	struct kobject *module_kobj;
 	struct kobject *modes_kobj;
@@ -328,10 +327,6 @@
 	return ret;
 }
 
-/******************************************************************************
- * Configure Hardware before/after Low Power Mode
- *****************************************************************************/
-
 /*
  * Configure hardware registers in preparation for Apps power down.
  */
@@ -374,22 +369,6 @@
 	return;
 }
 
-
-/******************************************************************************
- * Suspend Max Sleep Time
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
-	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-#endif
-
-#define SCLK_HZ (32768)
-#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
-
-static uint32_t msm_pm_max_sleep_time;
-
 /*
  * Convert time from nanoseconds to slow clock ticks, then cap it to the
  * specified limit
@@ -408,36 +387,21 @@
 	if (max_sleep_time_ns == 0) {
 		msm_pm_max_sleep_time = 0;
 	} else {
-		msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
+		msm_pm_max_sleep_time =
+			(uint32_t)msm_pm_convert_and_cap_time(
 			max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
 
 		if (msm_pm_max_sleep_time == 0)
 			msm_pm_max_sleep_time = 1;
 	}
 
-	if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
+	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 		pr_info("%s: Requested %lld ns Giving %u sclk ticks\n",
-			__func__, max_sleep_time_ns, msm_pm_max_sleep_time);
+			__func__, max_sleep_time_ns,
+			msm_pm_max_sleep_time);
 }
 EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
 
-struct reg_data {
-	uint32_t reg;
-	uint32_t val;
-};
-
-static struct reg_data reg_saved_state[] = {
-	{ .reg = 0x4501, },
-	{ .reg = 0x5501, },
-	{ .reg = 0x6501, },
-	{ .reg = 0x7501, },
-	{ .reg = 0x0500, },
-};
-
-static unsigned int active_vdd;
-static bool msm_pm_save_cp15;
-static const unsigned int pc_vdd = 0x98;
-
 static void msm_pm_save_cpu_reg(void)
 {
 	int i;
@@ -455,11 +419,12 @@
 	 * rate. Then restore the active vdd before switching the acpuclk rate.
 	 */
 	if (msm_pm_get_l2_flush_flag() == 1) {
-		active_vdd = msm_spm_get_vdd(0);
-		for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
-			reg_saved_state[i].val =
-				get_l2_indirect_reg(reg_saved_state[i].reg);
-		msm_spm_set_vdd(0, pc_vdd);
+		cp15_data.active_vdd = msm_spm_get_vdd(0);
+		for (i = 0; i < cp15_data.reg_saved_state_size; i++)
+			cp15_data.reg_val[i] =
+				get_l2_indirect_reg(
+					cp15_data.reg_data[i]);
+		msm_spm_set_vdd(0, cp15_data.qsb_pc_vdd);
 	}
 }
 
@@ -472,22 +437,20 @@
 		return;
 
 	if (msm_pm_get_l2_flush_flag() == 1) {
-		for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
-			set_l2_indirect_reg(reg_saved_state[i].reg,
-					reg_saved_state[i].val);
-		msm_spm_set_vdd(0, active_vdd);
+		for (i = 0; i < cp15_data.reg_saved_state_size; i++)
+			set_l2_indirect_reg(
+					cp15_data.reg_data[i],
+					cp15_data.reg_val[i]);
+		msm_spm_set_vdd(0, cp15_data.active_vdd);
 	}
 }
 
-static void *msm_pm_idle_rs_limits;
-
 static void msm_pm_swfi(void)
 {
 	msm_pm_config_hw_before_swfi();
 	msm_arch_idle();
 }
 
-
 static void msm_pm_retention(void)
 {
 	int ret = 0;
@@ -496,7 +459,7 @@
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
 	WARN_ON(ret);
 
-	if (msm_pm_retention_tz_call)
+	if (msm_pm_retention_calls_tz)
 		scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
 					SCM_L2_RETENTION);
 	else
@@ -567,7 +530,7 @@
 static bool msm_pm_power_collapse(bool from_idle)
 {
 	unsigned int cpu = smp_processor_id();
-	unsigned long saved_acpuclk_rate;
+	unsigned long saved_acpuclk_rate = 0;
 	unsigned int avsdscr;
 	unsigned int avscsr;
 	bool collapsed;
@@ -584,28 +547,28 @@
 	avscsr = avs_get_avscsr();
 	avs_set_avscsr(0); /* Disable AVS */
 
-	if (cpu_online(cpu))
+	if (cpu_online(cpu) && !msm_no_ramp_down_pc)
 		saved_acpuclk_rate = acpuclk_power_collapse();
-	else
-		saved_acpuclk_rate = 0;
 
 	if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
 			cpu, __func__, saved_acpuclk_rate);
 
-	if (msm_pm_save_cp15)
+	if (cp15_data.save_cp15)
 		msm_pm_save_cpu_reg();
 
 	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
 
-	if (msm_pm_save_cp15)
+	if (cp15_data.save_cp15)
 		msm_pm_restore_cpu_reg();
 
 	if (cpu_online(cpu)) {
 		if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
 			pr_info("CPU%u: %s: restore clock rate to %lu\n",
 				cpu, __func__, saved_acpuclk_rate);
-		if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
+		if (!msm_no_ramp_down_pc &&
+			acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC)
+				< 0)
 			pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
 				cpu, __func__, saved_acpuclk_rate);
 	} else {
@@ -635,15 +598,9 @@
 	return collapsed;
 }
 
-static void msm_pm_target_init(void)
-{
-	if (cpu_is_apq8064())
-		msm_pm_save_cp15 = true;
-}
-
 static int64_t msm_pm_timer_enter_idle(void)
 {
-	if (msm_pm_init_data.use_sync_timer)
+	if (msm_pm_use_sync_timer)
 		return ktime_to_ns(tick_nohz_get_sleep_length());
 
 	return msm_timer_enter_idle();
@@ -651,7 +608,7 @@
 
 static void msm_pm_timer_exit_idle(bool timer_halted)
 {
-	if (msm_pm_init_data.use_sync_timer)
+	if (msm_pm_use_sync_timer)
 		return;
 
 	msm_timer_exit_idle((int) timer_halted);
@@ -661,7 +618,7 @@
 {
 	int64_t time = 0;
 
-	if (msm_pm_init_data.use_sync_timer)
+	if (msm_pm_use_sync_timer)
 		return ktime_to_ns(ktime_get());
 
 	time = msm_timer_get_sclk_time(period);
@@ -673,7 +630,7 @@
 
 static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
 {
-	if (msm_pm_init_data.use_sync_timer)
+	if (msm_pm_use_sync_timer)
 		return ktime_to_ns(ktime_get()) - time;
 
 	if (time != 0) {
@@ -765,8 +722,9 @@
 	}
 }
 
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
-		struct cpuidle_driver *drv, int index)
+static int msm_pm_idle_prepare(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index,
+		void **msm_pm_idle_rs_limits)
 {
 	int i;
 	unsigned int power_usage = -1;
@@ -793,9 +751,9 @@
 		struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
 		enum msm_pm_sleep_mode mode;
 		bool allow;
-		void *rs_limits = NULL;
 		uint32_t power;
 		int idx;
+		void *rs_limits = NULL;
 
 		mode = (enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage);
 		idx = MSM_PM_MODE(dev->cpu, mode);
@@ -805,11 +763,9 @@
 
 		switch (mode) {
 		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-			if (num_online_cpus() > 1) {
+			if (num_online_cpus() > 1)
 				allow = false;
-				break;
-			}
-			/* fall through */
+			break;
 		case MSM_PM_SLEEP_MODE_RETENTION:
 			/*
 			 * The Krait BHS regulator doesn't have enough head
@@ -817,62 +773,41 @@
 			 * has disabled retention
 			 */
 			if (!msm_pm_ldo_retention_enabled)
-				break;
-
-			if (!allow)
-				break;
-
-			if (msm_pm_retention_tz_call &&
-				num_online_cpus() > 1) {
 				allow = false;
-				break;
-			}
-			/* fall through */
 
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
-			if (!allow)
-				break;
-			/* fall through */
-
-		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
-			if (!allow)
-				break;
-			/* fall through */
-
-			if (pm_sleep_ops.lowest_limits)
-				rs_limits = pm_sleep_ops.lowest_limits(true,
-						mode, &time_param, &power);
-
-			if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
-				pr_info("CPU%u: %s: %s, latency %uus, "
-					"sleep %uus, limit %p\n",
-					dev->cpu, __func__, state->desc,
-					time_param.latency_us,
-					time_param.sleep_us, rs_limits);
-
-			if (!rs_limits)
+			if (msm_pm_retention_calls_tz && num_online_cpus() > 1)
 				allow = false;
 			break;
-
+		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+			break;
 		default:
 			allow = false;
 			break;
 		}
 
+		if (!allow)
+			continue;
+
+		if (pm_sleep_ops.lowest_limits)
+			rs_limits = pm_sleep_ops.lowest_limits(true,
+					mode, &time_param, &power);
+
 		if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
-			pr_info("CPU%u: %s: allow %s: %d\n",
-				dev->cpu, __func__, state->desc, (int)allow);
+			pr_info("CPU%u:%s:%s, latency %uus, slp %uus, lim %p\n",
+					dev->cpu, __func__, state->desc,
+					time_param.latency_us,
+					time_param.sleep_us, rs_limits);
+		if (!rs_limits)
+			continue;
 
-		if (allow) {
-			if (power < power_usage) {
-				power_usage = power;
-				modified_time_us = time_param.modified_time_us;
-				ret = mode;
-			}
-
-			if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == mode)
-				msm_pm_idle_rs_limits = rs_limits;
+		if (power < power_usage) {
+			power_usage = power;
+			modified_time_us = time_param.modified_time_us;
+			ret = mode;
+			*msm_pm_idle_rs_limits = rs_limits;
 		}
+
 	}
 
 	if (modified_time_us && !dev->cpu)
@@ -885,11 +820,27 @@
 	return ret;
 }
 
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
+	struct cpuidle_driver *drv, int index)
 {
 	int64_t time;
-	int exit_stat;
 	bool collapsed = 1;
+	int exit_stat = -1;
+	enum msm_pm_sleep_mode sleep_mode;
+	void *msm_pm_idle_rs_limits = NULL;
+	int sleep_delay = 1;
+	int ret = -ENODEV;
+	int64_t timer_expiration = 0;
+	int notify_rpm = false;
+	bool timer_halted = false;
+
+	sleep_mode = msm_pm_idle_prepare(dev, drv, index,
+		&msm_pm_idle_rs_limits);
+
+	if (!msm_pm_idle_rs_limits) {
+		sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+		goto cpuidle_enter_bail;
+	}
 
 	if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: mode %d\n",
@@ -897,6 +848,22 @@
 
 	time = ktime_to_ns(ktime_get());
 
+	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+		notify_rpm = true;
+		timer_expiration = msm_pm_timer_enter_idle();
+
+		sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
+			timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
+		if (sleep_delay == 0) /* 0 would mean infinite time */
+			sleep_delay = 1;
+	}
+
+	if (pm_sleep_ops.enter_sleep)
+		ret = pm_sleep_ops.enter_sleep(sleep_delay,
+			msm_pm_idle_rs_limits, true, notify_rpm);
+	if (ret)
+		goto cpuidle_enter_bail;
+
 	switch (sleep_mode) {
 	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
 		msm_pm_swfi();
@@ -913,39 +880,16 @@
 		exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
 		break;
 
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
-		int64_t timer_expiration = 0;
-		bool timer_halted = false;
-		uint32_t sleep_delay;
-		int ret = -ENODEV;
-		int notify_rpm =
-			(sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE);
-		timer_expiration = msm_pm_timer_enter_idle();
-
-		sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
-			timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
-		if (sleep_delay == 0) /* 0 would mean infinite time */
-			sleep_delay = 1;
-
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
 		if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
 			clock_debug_print_enabled();
 
-		if (pm_sleep_ops.enter_sleep)
-			ret = pm_sleep_ops.enter_sleep(sleep_delay,
-					msm_pm_idle_rs_limits,
-					true, notify_rpm);
-		if (!ret) {
-			collapsed = msm_pm_power_collapse(true);
-			timer_halted = true;
+		collapsed = msm_pm_power_collapse(true);
+		timer_halted = true;
 
-			if (pm_sleep_ops.exit_sleep)
-				pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits,
-						true, notify_rpm, collapsed);
-		}
-		msm_pm_timer_exit_idle(timer_halted);
 		exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+		msm_pm_timer_exit_idle(timer_halted);
 		break;
-	}
 
 	case MSM_PM_SLEEP_MODE_NOT_SELECTED:
 		goto cpuidle_enter_bail;
@@ -957,16 +901,24 @@
 		break;
 	}
 
-	time = ktime_to_ns(ktime_get()) - time;
-	msm_pm_add_stat(exit_stat, time);
-	msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode,
-				collapsed);
+	if (pm_sleep_ops.exit_sleep)
+		pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits, true,
+				notify_rpm, collapsed);
 
+	time = ktime_to_ns(ktime_get()) - time;
+	msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode, collapsed);
+	if (exit_stat >= 0)
+		msm_pm_add_stat(exit_stat, time);
 	do_div(time, 1000);
-	return (int) time;
+	dev->last_residency = (int) time;
+	return sleep_mode;
 
 cpuidle_enter_bail:
-	return 0;
+	dev->last_residency = 0;
+	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
+		msm_pm_timer_exit_idle(timer_halted);
+	sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+	return sleep_mode;
 }
 
 void msm_pm_cpu_enter_lowpower(unsigned int cpu)
@@ -1060,17 +1012,16 @@
 
 		clock_debug_print_enabled();
 
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
 		if (msm_pm_sleep_time_override > 0) {
 			int64_t ns = NSEC_PER_SEC *
 				(int64_t) msm_pm_sleep_time_override;
 			msm_pm_set_max_sleep_time(ns);
 			msm_pm_sleep_time_override = 0;
 		}
-#endif /* CONFIG_MSM_SLEEP_TIME_OVERRIDE */
+
 		if (pm_sleep_ops.lowest_limits)
 			rs_limits = pm_sleep_ops.lowest_limits(false,
-			MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
+		MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
 
 		if (rs_limits) {
 			if (pm_sleep_ops.enter_sleep)
@@ -1104,7 +1055,6 @@
 		msm_pm_swfi();
 	}
 
-
 enter_exit:
 	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 		pr_info("%s: return\n", __func__);
@@ -1112,66 +1062,18 @@
 	return 0;
 }
 
-static struct platform_suspend_ops msm_pm_ops = {
-	.enter = msm_pm_enter,
-	.valid = suspend_valid_only_mem,
-};
-
-/******************************************************************************
- * Initialization routine
- *****************************************************************************/
 void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
 {
 	if (ops)
 		pm_sleep_ops = *ops;
 }
 
-void __init msm_pm_set_tz_retention_flag(unsigned int flag)
-{
-	msm_pm_retention_tz_call = flag;
-}
-
-static int __devinit msm_pc_debug_probe(struct platform_device *pdev)
-{
-	struct resource *res = NULL;
-	int i ;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		goto fail;
-
-	msm_pc_debug_counters_phys = res->start;
-	WARN_ON(resource_size(res) < SZ_64);
-	msm_pc_debug_counters = devm_ioremap_nocache(&pdev->dev, res->start,
-					resource_size(res));
-
-	if (!msm_pc_debug_counters)
-		goto fail;
-
-	for (i = 0; i < resource_size(res)/4; i++)
-		__raw_writel(0, msm_pc_debug_counters + i * 4);
-	return 0;
-fail:
-	msm_pc_debug_counters = 0;
-	msm_pc_debug_counters_phys = 0;
-	return -EFAULT;
-}
-
-static struct of_device_id msm_pc_debug_table[] = {
-	{.compatible = "qcom,pc-cntr"},
-	{},
+static const struct platform_suspend_ops msm_pm_ops = {
+	.enter = msm_pm_enter,
+	.valid = suspend_valid_only_mem,
 };
 
-static struct platform_driver msm_pc_counter_driver = {
-	.probe = msm_pc_debug_probe,
-	.driver = {
-		.name = "pc-cntr",
-		.owner = THIS_MODULE,
-		.of_match_table = msm_pc_debug_table,
-	},
-};
-
-static int __init msm_pm_init(void)
+static int __devinit msm_pm_init(void)
 {
 	pgd_t *pc_pgd;
 	pmd_t *pmd;
@@ -1186,7 +1088,6 @@
 	unsigned long exit_phys;
 
 	/* Page table for cores to come back up safely. */
-
 	pc_pgd = pgd_alloc(&init_mm);
 	if (!pc_pgd)
 		return -ENOMEM;
@@ -1225,18 +1126,13 @@
 
 	msm_pm_mode_sysfs_add();
 	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
-
 	suspend_set_ops(&msm_pm_ops);
-	msm_pm_target_init();
 	hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 	msm_cpuidle_init();
-	platform_driver_register(&msm_pc_counter_driver);
 
 	return 0;
 }
 
-late_initcall(msm_pm_init);
-
 static void __devinit msm_pm_set_flush_fn(uint32_t pc_mode)
 {
 	msm_pm_disable_l2_fn = NULL;
@@ -1249,41 +1145,203 @@
 	}
 }
 
+struct msm_pc_debug_counters_buffer {
+	void __iomem *reg;
+	u32 len;
+	char buf[MAX_BUF_SIZE];
+};
+
+static inline u32 msm_pc_debug_counters_read_register(
+		void __iomem *reg, int index , int offset)
+{
+	return readl_relaxed(reg + (index * 4 + offset) * 4);
+}
+
+static char *counter_name[] = {
+		"PC Entry Counter",
+		"Warmboot Entry Counter",
+		"PC Bailout Counter"
+};
+
+static int msm_pc_debug_counters_copy(
+		struct msm_pc_debug_counters_buffer *data)
+{
+	int j;
+	u32 stat;
+	unsigned int cpu;
+
+	for_each_possible_cpu(cpu) {
+		data->len += scnprintf(data->buf + data->len,
+				sizeof(data->buf)-data->len,
+				"CPU%d\n", cpu);
+
+			for (j = 0; j < NUM_OF_COUNTERS; j++) {
+				stat = msm_pc_debug_counters_read_register(
+						data->reg, cpu, j);
+				data->len += scnprintf(data->buf + data->len,
+					sizeof(data->buf)-data->len,
+					"\t%s : %d\n", counter_name[j],
+					stat);
+		}
+
+	}
+
+	return data->len;
+}
+
+static int msm_pc_debug_counters_file_read(struct file *file,
+		char __user *bufu, size_t count, loff_t *ppos)
+{
+	struct msm_pc_debug_counters_buffer *data;
+
+	data = file->private_data;
+
+	if (!data)
+		return -EINVAL;
+
+	if (!bufu || count < 0)
+		return -EINVAL;
+
+	if (!access_ok(VERIFY_WRITE, bufu, count))
+		return -EFAULT;
+
+	if (*ppos >= data->len && data->len == 0)
+		data->len = msm_pc_debug_counters_copy(data);
+
+	return simple_read_from_buffer(bufu, count, ppos,
+			data->buf, data->len);
+}
+
+static int msm_pc_debug_counters_file_open(struct inode *inode,
+		struct file *file)
+{
+	struct msm_pc_debug_counters_buffer *buf;
+	void __iomem *msm_pc_debug_counters_reg;
+
+	msm_pc_debug_counters_reg = inode->i_private;
+
+	if (!msm_pc_debug_counters_reg)
+		return -EINVAL;
+
+	file->private_data = kzalloc(
+		sizeof(struct msm_pc_debug_counters_buffer), GFP_KERNEL);
+
+	if (!file->private_data) {
+		pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
+		__func__, sizeof(struct msm_pc_debug_counters_buffer));
+
+		return -ENOMEM;
+	}
+
+	buf = file->private_data;
+	buf->reg = msm_pc_debug_counters_reg;
+
+	return 0;
+}
+
+static int msm_pc_debug_counters_file_close(struct inode *inode,
+		struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static const struct file_operations msm_pc_debug_counters_fops = {
+	.open = msm_pc_debug_counters_file_open,
+	.read = msm_pc_debug_counters_file_read,
+	.release = msm_pc_debug_counters_file_close,
+	.llseek = no_llseek,
+};
+
 static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
 {
 	char *key = NULL;
+	struct dentry *dent = NULL;
 	uint32_t val = 0;
+	struct resource *res = NULL;
+	int i ;
+	struct msm_pm_init_data_type pdata_local;
 	int ret = 0;
 
+	memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res) {
+		msm_pc_debug_counters_phys = res->start;
+		WARN_ON(resource_size(res) < SZ_64);
+		msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+		if (msm_pc_debug_counters)
+			for (i = 0; i < resource_size(res)/4; i++)
+				__raw_writel(0, msm_pc_debug_counters + i * 4);
+
+	}
+
+	if (!msm_pc_debug_counters) {
+		msm_pc_debug_counters = 0;
+		msm_pc_debug_counters_phys = 0;
+	} else {
+		dent = debugfs_create_file("pc_debug_counter", S_IRUGO, NULL,
+				msm_pc_debug_counters,
+				&msm_pc_debug_counters_fops);
+		if (!dent)
+			pr_err("%s: ERROR debugfs_create_file failed\n",
+					__func__);
+	}
+
 	if (!pdev->dev.of_node) {
 		struct msm_pm_init_data_type *d = pdev->dev.platform_data;
 
 		if (!d)
 			goto pm_8x60_probe_done;
 
-		msm_pm_init_data.pc_mode = d->pc_mode;
-		msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
-		msm_pm_init_data.use_sync_timer = d->use_sync_timer;
+		memcpy(&pdata_local, d, sizeof(struct msm_pm_init_data_type));
+
 	} else {
 		key = "qcom,pc-mode";
 		ret = of_property_read_u32(pdev->dev.of_node, key, &val);
-
 		if (ret) {
 			pr_debug("%s: Cannot read %s,defaulting to 0",
 					__func__, key);
 			val = MSM_PM_PC_TZ_L2_INT;
 			ret = 0;
 		}
-
-		msm_pm_init_data.pc_mode = val;
-		msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
+		pdata_local.pc_mode = val;
 
 		key = "qcom,use-sync-timer";
-		msm_pm_init_data.use_sync_timer =
+		pdata_local.use_sync_timer =
 			of_property_read_bool(pdev->dev.of_node, key);
+
+		key = "qcom,saw-turns-off-pll";
+		msm_no_ramp_down_pc = of_property_read_bool(pdev->dev.of_node,
+					key);
 	}
 
+	if (pdata_local.cp15_data.reg_data &&
+		pdata_local.cp15_data.reg_saved_state_size > 0) {
+		cp15_data.reg_data = kzalloc(sizeof(uint32_t) *
+				pdata_local.cp15_data.reg_saved_state_size,
+				GFP_KERNEL);
+		if (!cp15_data.reg_data)
+			return -ENOMEM;
+
+		cp15_data.reg_val = kzalloc(sizeof(uint32_t) *
+				pdata_local.cp15_data.reg_saved_state_size,
+				GFP_KERNEL);
+		if (cp15_data.reg_val)
+			return -ENOMEM;
+
+		memcpy(cp15_data.reg_data, pdata_local.cp15_data.reg_data,
+			pdata_local.cp15_data.reg_saved_state_size *
+			sizeof(uint32_t));
+	}
+
+	msm_pm_set_flush_fn(pdata_local.pc_mode);
+	msm_pm_use_sync_timer = pdata_local.use_sync_timer;
+	msm_pm_retention_calls_tz = pdata_local.retention_calls_tz;
+
 pm_8x60_probe_done:
+	msm_pm_init();
 	return ret;
 }
 
@@ -1305,4 +1363,4 @@
 {
 	return platform_driver_register(&msm_pm_8x60_driver);
 }
-module_init(msm_pm_8x60_init);
+device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 399194a..af0744c 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -97,8 +97,19 @@
 					external L2 cache controller */
 };
 
+struct msm_pm_cp15_save_data {
+	bool save_cp15;
+	uint32_t active_vdd;
+	uint32_t qsb_pc_vdd;
+	uint32_t reg_saved_state_size;
+	uint32_t *reg_data;
+	uint32_t *reg_val;
+};
+
 struct msm_pm_init_data_type {
 	enum msm_pm_pc_mode_type pc_mode;
+	bool retention_calls_tz;
+	struct msm_pm_cp15_save_data cp15_data;
 	bool use_sync_timer;
 };
 
@@ -108,10 +119,9 @@
 };
 
 void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv, int index);
 void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
 void msm_pm_cpu_enter_lowpower(unsigned int cpu);
 void __init msm_pm_set_tz_retention_flag(unsigned int flag);
 void msm_pm_enable_retention(bool enable);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 654f547..e6b9549 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -897,6 +897,11 @@
 	struct audio_client *ac;
 	struct audio_aio_write_param param;
 
+	if (!audio || !buf_node) {
+		pr_err("%s NULL pointer audio=[0x%p], buf_node=[0x%p]\n",
+			__func__, audio, buf_node);
+		return;
+	}
 	pr_debug("%s[%p]: Send write buff %p phy %lx len %d meta_enable = %d\n",
 		__func__, audio, buf_node, buf_node->paddr,
 		buf_node->buf.data_len,
@@ -922,8 +927,7 @@
 	if (!audio->buf_cfg.meta_info_enable)
 		param.flags = 0xFF00;
 
-	if ((buf_node != NULL) &&
-		(buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET))
+	if (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET)
 		param.flags |= AUDIO_DEC_EOF_SET;
 
 	param.uid = param.paddr;
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
index b9815a5..16de77e 100644
--- a/arch/arm/mach-msm/rpm-notifier.h
+++ b/arch/arm/mach-msm/rpm-notifier.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
@@ -40,8 +40,12 @@
 
 /**
  * msm_rpm_enter_sleep - Notify RPM driver to prepare for entering sleep
+ *
+ * @bool - flag to enable print contents of sleep buffer.
+ *
+ * return 0 on success errno on failure.
  */
-int msm_rpm_enter_sleep(void);
+int msm_rpm_enter_sleep(bool print);
 
 /**
  * msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 4295fd4..b84ade9 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/rbtree.h>
 #include <mach/socinfo.h>
 #include <mach/msm_smd.h>
 #include <mach/rpm-smd.h>
@@ -62,6 +63,9 @@
 };
 
 #define DEFAULT_BUFFER_SIZE 256
+#define DEBUG_PRINT_BUFFER_SIZE 512
+#define MAX_SLEEP_BUFFER 128
+
 #define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
 #define INV_RSC "resource does not exist"
 #define ERR "err\0"
@@ -106,6 +110,11 @@
 	uint32_t data_len;
 };
 
+struct kvp {
+	unsigned int k;
+	unsigned int s;
+};
+
 struct msm_rpm_kvp_data {
 	uint32_t key;
 	uint32_t nbytes; /* number of bytes */
@@ -113,6 +122,301 @@
 	bool valid;
 };
 
+struct slp_buf {
+	struct rb_node node;
+	char ubuf[MAX_SLEEP_BUFFER];
+	char *buf;
+	bool valid;
+};
+static struct rb_root tr_root = RB_ROOT;
+
+static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq);
+static uint32_t msm_rpm_get_next_msg_id(void);
+
+static inline unsigned int get_rsc_type(char *buf)
+{
+	struct rpm_message_header *h;
+	h = (struct rpm_message_header *)
+		(buf + sizeof(struct rpm_request_header));
+	return h->resource_type;
+}
+
+static inline unsigned int get_rsc_id(char *buf)
+{
+	struct rpm_message_header *h;
+	h = (struct rpm_message_header *)
+		(buf + sizeof(struct rpm_request_header));
+	return h->resource_id;
+}
+
+#define get_data_len(buf) \
+	(((struct rpm_message_header *) \
+	  (buf + sizeof(struct rpm_request_header)))->data_len)
+
+#define get_req_len(buf) \
+	(((struct rpm_request_header *)(buf))->request_len)
+
+#define get_msg_id(buf) \
+	(((struct rpm_message_header *) \
+	  (buf + sizeof(struct rpm_request_header)))->msg_id)
+
+
+static inline int get_buf_len(char *buf)
+{
+	return get_req_len(buf) + sizeof(struct rpm_request_header);
+}
+
+static inline struct kvp *get_first_kvp(char *buf)
+{
+	return (struct kvp *)(buf + sizeof(struct rpm_request_header)
+			+ sizeof(struct rpm_message_header));
+}
+
+static inline struct kvp *get_next_kvp(struct kvp *k)
+{
+	return (struct kvp *)((void *)k + sizeof(*k) + k->s);
+}
+
+static inline void *get_data(struct kvp *k)
+{
+	return (void *)k + sizeof(*k);
+}
+
+
+static void delete_kvp(char *msg, struct kvp *d)
+{
+	struct kvp *n;
+	int dec, size;
+
+	n = get_next_kvp(d);
+	dec = (void *)n - (void *)d;
+	size = get_data_len(msg) - ((void *)n - (void *)get_first_kvp(msg));
+
+	memcpy((void *)d, (void *)n, size);
+
+	get_data_len(msg) -= dec;
+	get_req_len(msg) -= dec;
+}
+
+static inline void update_kvp_data(struct kvp *dest, struct kvp *src)
+{
+	memcpy(get_data(dest), get_data(src), src->s);
+}
+
+static void add_kvp(char *buf, struct kvp *n)
+{
+	int inc = sizeof(*n) + n->s;
+	BUG_ON((get_req_len(buf) + inc) > MAX_SLEEP_BUFFER);
+
+	memcpy(buf + get_buf_len(buf), n, inc);
+
+	get_data_len(buf) += inc;
+	get_req_len(buf) += inc;
+}
+
+static struct slp_buf *tr_search(struct rb_root *root, char *slp)
+{
+	unsigned int type = get_rsc_type(slp);
+	unsigned int id = get_rsc_id(slp);
+
+	struct rb_node *node = root->rb_node;
+
+	while (node) {
+		struct slp_buf *cur = rb_entry(node, struct slp_buf, node);
+		unsigned int ctype = get_rsc_type(cur->buf);
+		unsigned int cid = get_rsc_id(cur->buf);
+
+		if (type < ctype)
+			node = node->rb_left;
+		else if (type > ctype)
+			node = node->rb_right;
+		else if (id < cid)
+			node = node->rb_left;
+		else if (id > cid)
+			node = node->rb_right;
+		else
+			return cur;
+	}
+	return NULL;
+}
+
+static int tr_insert(struct rb_root *root, struct slp_buf *slp)
+{
+	unsigned int type = get_rsc_type(slp->buf);
+	unsigned int id = get_rsc_id(slp->buf);
+
+	struct rb_node **node = &(root->rb_node), *parent = NULL;
+
+	while (*node) {
+		struct slp_buf *curr = rb_entry(*node, struct slp_buf, node);
+		unsigned int ctype = get_rsc_type(curr->buf);
+		unsigned int cid = get_rsc_id(curr->buf);
+
+		parent = *node;
+
+		if (type < ctype)
+			node = &((*node)->rb_left);
+		else if (type > ctype)
+			node = &((*node)->rb_right);
+		else if (id < cid)
+			node = &((*node)->rb_left);
+		else if (id > cid)
+			node = &((*node)->rb_right);
+		else
+			return -EINVAL;
+	}
+
+	rb_link_node(&slp->node, parent, node);
+	rb_insert_color(&slp->node, root);
+	slp->valid = true;
+	return 0;
+}
+
+#define for_each_kvp(buf, k) \
+	for (k = (struct kvp *)get_first_kvp(buf); \
+		((void *)k - (void *)get_first_kvp(buf)) < get_data_len(buf);\
+		k = get_next_kvp(k))
+
+
+static void tr_update(struct slp_buf *s, char *buf)
+{
+	struct kvp *e, *n;
+
+	for_each_kvp(buf, n) {
+		for_each_kvp(s->buf, e) {
+			if (n->k == e->k) {
+				if (n->s == e->s) {
+					void *e_data = get_data(e);
+					void *n_data = get_data(n);
+					if (memcmp(e_data, n_data, n->s)) {
+						update_kvp_data(e, n);
+						s->valid = true;
+					}
+				} else {
+					delete_kvp(s->buf, e);
+					add_kvp(s->buf, n);
+					s->valid = true;
+				}
+				break;
+			}
+		}
+	}
+}
+
+int msm_rpm_smd_buffer_request(char *buf, int size, gfp_t flag)
+{
+	struct slp_buf *slp;
+	static DEFINE_SPINLOCK(slp_buffer_lock);
+	unsigned long flags;
+
+	if (size > MAX_SLEEP_BUFFER)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&slp_buffer_lock, flags);
+	slp = tr_search(&tr_root, buf);
+
+	if (!slp) {
+		slp = kzalloc(sizeof(struct slp_buf), GFP_ATOMIC);
+		if (!slp) {
+			spin_unlock_irqrestore(&slp_buffer_lock, flags);
+			return -ENOMEM;
+		}
+		slp->buf = PTR_ALIGN(&slp->ubuf[0], sizeof(u32));
+		memcpy(slp->buf, buf, size);
+		if (tr_insert(&tr_root, slp))
+			pr_err("%s(): Error updating sleep request\n",
+					__func__);
+	} else {
+		/* handle unsent requests */
+		tr_update(slp, buf);
+	}
+
+	spin_unlock_irqrestore(&slp_buffer_lock, flags);
+
+	return 0;
+}
+static void msm_rpm_print_sleep_buffer(struct slp_buf *s)
+{
+	char buf[DEBUG_PRINT_BUFFER_SIZE] = {0};
+	int pos;
+	int buflen = DEBUG_PRINT_BUFFER_SIZE;
+	char ch[5] = {0};
+	u32 type;
+	struct kvp *e;
+
+	if (!s)
+		return;
+
+	if (!s->valid)
+		return;
+
+	type = get_rsc_type(s->buf);
+	memcpy(ch, &type, sizeof(u32));
+
+	pos = scnprintf(buf, buflen,
+			"Sleep request type = 0x%08x(%s)",
+			get_rsc_type(s->buf), ch);
+	pos += scnprintf(buf + pos, buflen - pos, " id = 0%x",
+			get_rsc_id(s->buf));
+	for_each_kvp(s->buf, e) {
+		int i;
+		char *data = get_data(e);
+
+		memcpy(ch, &e->k, sizeof(u32));
+
+		pos += scnprintf(buf + pos, buflen - pos,
+				"\n\t\tkey = 0x%08x(%s)",
+				e->k, ch);
+		pos += scnprintf(buf + pos, buflen - pos,
+				" sz= %d data =", e->s);
+
+		for (i = 0; i < e->s; i++)
+			pos += scnprintf(buf + pos, buflen - pos,
+					" 0x%02X", data[i]);
+	}
+	pos += scnprintf(buf + pos, buflen - pos, "\n");
+	printk(buf);
+}
+
+static int msm_rpm_flush_requests(bool print)
+{
+	struct rb_node *t;
+	int ret;
+
+	for (t = rb_first(&tr_root); t; t = rb_next(t)) {
+
+		struct slp_buf *s = rb_entry(t, struct slp_buf, node);
+
+		if (!s->valid)
+			continue;
+
+		if (print)
+			msm_rpm_print_sleep_buffer(s);
+
+		get_msg_id(s->buf) = msm_rpm_get_next_msg_id();
+		ret = msm_rpm_send_smd_buffer(s->buf,
+				get_buf_len(s->buf), true);
+		/* By not adding the message to a wait list we can reduce
+		 * latency involved in waiting for a ACK from RPM. The ACK
+		 * messages will be processed when we wakeup from sleep but
+		 * processing should be minimal
+		 * msm_rpm_wait_for_ack_noirq(get_msg_id(s->buf));
+		 */
+
+		WARN_ON(ret != get_buf_len(s->buf));
+
+		trace_rpm_send_message(true, MSM_RPM_CTX_SLEEP_SET,
+				get_rsc_type(s->buf),
+				get_rsc_id(s->buf),
+				get_msg_id(s->buf));
+
+		s->valid = false;
+	}
+	return 0;
+
+}
+
+
 static atomic_t msm_rpm_msg_id = ATOMIC_INIT(0);
 
 static struct msm_rpm_driver_data msm_rpm_data;
@@ -450,7 +754,12 @@
 		}
 		elem = NULL;
 	}
-	WARN_ON(!elem);
+	/* Special case where the sleep driver doesn't
+	 * wait for ACKs. This would decrease the latency involved with
+	 * entering RPM assisted power collapse.
+	 */
+	if (!elem)
+		trace_rpm_ack_recd(0, msg_id);
 
 	spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
 }
@@ -544,8 +853,6 @@
 	}
 }
 
-#define DEBUG_PRINT_BUFFER_SIZE 512
-
 static void msm_rpm_log_request(struct msm_rpm_request *cdata)
 {
 	char buf[DEBUG_PRINT_BUFFER_SIZE];
@@ -677,13 +984,42 @@
 	pos += scnprintf(buf + pos, buflen - pos, "\n");
 	printk(buf);
 }
+static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq)
+{
+	unsigned long flags;
+	int ret;
 
+	spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+	ret = smd_write_avail(msm_rpm_data.ch_info);
+
+	while ((ret = smd_write_avail(msm_rpm_data.ch_info)) < size) {
+		if (ret < 0)
+			break;
+		if (!noirq) {
+			spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
+					flags);
+			cpu_relax();
+			spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+		} else
+			udelay(5);
+	}
+
+	if (ret < 0) {
+		pr_err("%s(): SMD not initialized\n", __func__);
+		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+		return ret;
+	}
+
+	ret = smd_write(msm_rpm_data.ch_info, buf, size);
+	spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+	return ret;
+
+}
 static int msm_rpm_send_data(struct msm_rpm_request *cdata,
 		int msg_type, bool noirq)
 {
 	uint8_t *tmpbuff;
 	int i, ret, msg_size;
-	unsigned long flags;
 
 	int req_hdr_sz, msg_hdr_sz;
 
@@ -695,8 +1031,6 @@
 
 	cdata->req_hdr.service_type = msm_rpm_request_service[msg_type];
 
-	cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
-
 	cdata->req_hdr.request_len = cdata->msg_hdr.data_len + msg_hdr_sz;
 	msg_size = cdata->req_hdr.request_len + req_hdr_sz;
 
@@ -714,8 +1048,6 @@
 
 	tmpbuff = cdata->buf;
 
-	memcpy(tmpbuff, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
-
 	tmpbuff += req_hdr_sz + msg_hdr_sz;
 
 	for (i = 0; (i < cdata->write_idx); i++) {
@@ -740,6 +1072,17 @@
 
 	}
 
+	memcpy(cdata->buf, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
+
+	if ((cdata->msg_hdr.set == MSM_RPM_CTX_SLEEP_SET) &&
+		!msm_rpm_smd_buffer_request(cdata->buf, msg_size,
+			GFP_FLAG(noirq)))
+		return 1;
+
+	cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
+
+	memcpy(cdata->buf + req_hdr_sz, &cdata->msg_hdr, msg_hdr_sz);
+
 	if (msm_rpm_debug_mask
 	    & (MSM_RPM_LOG_REQUEST_PRETTY | MSM_RPM_LOG_REQUEST_RAW))
 		msm_rpm_log_request(cdata);
@@ -755,29 +1098,7 @@
 
 	msm_rpm_add_wait_list(cdata->msg_hdr.msg_id);
 
-	spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
-
-	ret = smd_write_avail(msm_rpm_data.ch_info);
-
-	if (ret < 0) {
-		pr_err("%s(): SMD not initialized\n", __func__);
-		spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
-		return 0;
-	}
-
-	while ((ret < msg_size)) {
-		if (!noirq) {
-			spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
-					flags);
-			cpu_relax();
-			spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
-		} else
-			udelay(5);
-		ret = smd_write_avail(msm_rpm_data.ch_info);
-	}
-
-	ret = smd_write(msm_rpm_data.ch_info, &cdata->buf[0], msg_size);
-	spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+	ret = msm_rpm_send_smd_buffer(&cdata->buf[0], msg_size, noirq);
 
 	if (ret == msg_size) {
 		trace_rpm_send_message(noirq, cdata->msg_hdr.set,
@@ -958,11 +1279,13 @@
  * During power collapse, the rpm driver disables the SMD interrupts to make
  * sure that the interrupt doesn't wakes us from sleep.
  */
-int msm_rpm_enter_sleep(void)
+int msm_rpm_enter_sleep(bool print)
 {
 	if (standalone)
 		return 0;
 
+	msm_rpm_flush_requests(print);
+
 	return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true);
 }
 EXPORT_SYMBOL(msm_rpm_enter_sleep);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 19e48759..56623c9 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -134,6 +134,16 @@
 	uint32_t pmic_die_revision;
 };
 
+struct socinfo_v8 {
+	struct socinfo_v7 v7;
+
+	/* only valid when format==8*/
+	uint32_t pmic_model_1;
+	uint32_t pmic_die_revision_1;
+	uint32_t pmic_model_2;
+	uint32_t pmic_die_revision_2;
+};
+
 static union {
 	struct socinfo_v1 v1;
 	struct socinfo_v2 v2;
@@ -142,6 +152,7 @@
 	struct socinfo_v5 v5;
 	struct socinfo_v6 v6;
 	struct socinfo_v7 v7;
+	struct socinfo_v8 v8;
 } *socinfo;
 
 static enum msm_cpu cpu_of_id[] = {
@@ -865,6 +876,7 @@
 	device_create_file(msm_soc_device, &msm_soc_attr_vendor);
 
 	switch (legacy_format) {
+	case 8:
 	case 7:
 		device_create_file(msm_soc_device,
 					&msm_soc_attr_pmic_model);
@@ -1054,6 +1066,7 @@
 			socinfo->v5.accessory_chip,
 			socinfo->v6.hw_platform_subtype);
 		break;
+	case 8:
 	case 7:
 		pr_info("%s: v%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u\n",
 			__func__,
@@ -1076,7 +1089,11 @@
 
 int __init socinfo_init(void)
 {
-	socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v7));
+	socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v8));
+
+	if (!socinfo)
+		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+				sizeof(struct socinfo_v7));
 
 	if (!socinfo)
 		socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index 764b044..ba88a42 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -465,8 +465,11 @@
 	}
 
 	ret = kgsl_gem_init_obj(dev, file_priv, obj, &handle);
-	if (ret)
+	if (ret) {
+		drm_gem_object_release(obj);
+		DRM_ERROR("Unable to initialize GEM object ret = %d\n", ret);
 		return ret;
+	}
 
 	create->handle = handle;
 	return 0;
@@ -539,6 +542,106 @@
 }
 
 int
+kgsl_gem_create_from_ion_ioctl(struct drm_device *dev, void *data,
+		      struct drm_file *file_priv)
+{
+	struct drm_kgsl_gem_create_from_ion *args = data;
+	struct drm_gem_object *obj;
+	struct ion_handle *ion_handle;
+	struct drm_kgsl_gem_object *priv;
+	struct sg_table *sg_table;
+	struct scatterlist *s;
+	int ret, handle;
+	unsigned long size;
+
+	ion_handle = ion_import_dma_buf(kgsl_drm_ion_client, args->ion_fd);
+	if (IS_ERR_OR_NULL(ion_handle)) {
+		DRM_ERROR("Unable to import dmabuf.  Error number = %d\n",
+			(int)PTR_ERR(ion_handle));
+		return -EINVAL;
+	}
+
+	ion_handle_get_size(kgsl_drm_ion_client, ion_handle, &size);
+
+	if (size == 0) {
+		ion_free(kgsl_drm_ion_client, ion_handle);
+		DRM_ERROR(
+		"cannot create GEM object from zero size ION buffer\n");
+		return -EINVAL;
+	}
+
+	obj = drm_gem_object_alloc(dev, size);
+
+	if (obj == NULL) {
+		ion_free(kgsl_drm_ion_client, ion_handle);
+		DRM_ERROR("Unable to allocate the GEM object\n");
+		return -ENOMEM;
+	}
+
+	ret = kgsl_gem_init_obj(dev, file_priv, obj, &handle);
+	if (ret) {
+		ion_free(kgsl_drm_ion_client, ion_handle);
+		drm_gem_object_release(obj);
+		DRM_ERROR("Unable to initialize GEM object ret = %d\n", ret);
+		return ret;
+	}
+
+	priv = obj->driver_private;
+	priv->ion_handle = ion_handle;
+
+	priv->type = DRM_KGSL_GEM_TYPE_KMEM;
+	list_add(&priv->list, &kgsl_mem_list);
+
+	priv->pagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+
+	priv->memdesc.pagetable = priv->pagetable;
+
+	sg_table = ion_sg_table(kgsl_drm_ion_client,
+		priv->ion_handle);
+	if (IS_ERR_OR_NULL(priv->ion_handle)) {
+		DRM_ERROR("Unable to get ION sg table\n");
+		ion_free(kgsl_drm_ion_client,
+			priv->ion_handle);
+		priv->ion_handle = NULL;
+		kgsl_mmu_putpagetable(priv->pagetable);
+		drm_gem_object_release(obj);
+		kfree(priv);
+		return -ENOMEM;
+	}
+
+	priv->memdesc.sg = sg_table->sgl;
+
+	/* Calculate the size of the memdesc from the sglist */
+
+	priv->memdesc.sglen = 0;
+
+	for (s = priv->memdesc.sg; s != NULL; s = sg_next(s)) {
+		priv->memdesc.size += s->length;
+		priv->memdesc.sglen++;
+	}
+
+	ret = kgsl_mmu_map(priv->pagetable, &priv->memdesc,
+		GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+	if (ret) {
+		DRM_ERROR("kgsl_mmu_map failed.  ret = %d\n", ret);
+		ion_free(kgsl_drm_ion_client,
+			priv->ion_handle);
+		priv->ion_handle = NULL;
+		kgsl_mmu_putpagetable(priv->pagetable);
+		drm_gem_object_release(obj);
+		kfree(priv);
+		return -ENOMEM;
+	}
+
+	priv->bufs[0].offset = 0;
+	priv->bufs[0].gpuaddr = priv->memdesc.gpuaddr;
+	priv->flags |= DRM_KGSL_GEM_FLAG_MAPPED;
+
+	args->handle = handle;
+	return 0;
+}
+
+int
 kgsl_gem_get_ion_fd_ioctl(struct drm_device *dev, void *data,
 			struct drm_file *file_priv)
 {
@@ -563,6 +666,12 @@
 		if (priv->ion_handle) {
 			args->ion_fd = ion_share_dma_buf(
 				kgsl_drm_ion_client, priv->ion_handle);
+			if (args->ion_fd < 0) {
+				DRM_ERROR(
+				"Could not share ion buffer. Error = %d\n",
+					args->ion_fd);
+				ret = -EINVAL;
+			}
 		} else {
 			DRM_ERROR("GEM object has no ion memory allocated.\n");
 			ret = -EINVAL;
@@ -1266,6 +1375,8 @@
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_MMAP, kgsl_gem_mmap_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_BUFINFO, kgsl_gem_get_bufinfo_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_ION_FD, kgsl_gem_get_ion_fd_ioctl, 0),
+	DRM_IOCTL_DEF_DRV(KGSL_GEM_CREATE_FROM_ION,
+		kgsl_gem_create_from_ion_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_BUFCOUNT,
 		      kgsl_gem_set_bufcount_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_ACTIVE, kgsl_gem_set_active_ioctl, 0),
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 2945b7b..89335f3 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1001,7 +1001,7 @@
 	}
 
 	/* Set the CPU latency to 501usec to allow low latency PC modes */
-	pwr->pm_qos_latency = 3;
+	pwr->pm_qos_latency = 501;
 
 	pm_runtime_enable(device->parentdev);
 	register_early_suspend(&device->display_off);
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index c447231..abb5bbc 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -1529,7 +1529,7 @@
 static ssize_t fwu_sysfs_config_id_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	unsigned char config_id[8];
+	unsigned char config_id[4];
 	/* device config id */
 	fwu->fn_ptr->read(fwu->rmi4_data,
 				fwu->f34_fd.ctrl_base_addr,
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 4b1b1c7..9f0ad19 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
@@ -122,6 +122,7 @@
 		CPP_DBG("Read failed\n");
 		tmp = 0xDEADBEEF;
 	}
+
 	return tmp;
 }
 
@@ -207,6 +208,48 @@
 	return IRQ_HANDLED;
 }
 
+static void msm_cpp_boot_hw(struct cpp_device *cpp_dev)
+{
+	disable_irq(cpp_dev->irq->start);
+
+	msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
+	msm_camera_io_w(0x1, cpp_dev->base +
+				 MSM_CPP_MICRO_BOOT_START);
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+
+	/*Trigger MC to jump to start address*/
+	msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_JUMP_ADDRESS, cpp_dev->base);
+
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+	msm_cpp_poll(cpp_dev->base, 0x1);
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_JUMP_ACK);
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+
+	/*Get Bootloader Version*/
+	msm_cpp_write(MSM_CPP_CMD_GET_BOOTLOADER_VER, cpp_dev->base);
+	pr_info("MC Bootloader Version: 0x%x\n",
+		   msm_cpp_read(cpp_dev->base));
+
+	/*Get Firmware Version*/
+	msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_MSG_ID_CMD, cpp_dev->base);
+	msm_cpp_write(0x1, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
+	msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base);
+
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+	msm_cpp_poll(cpp_dev->base, 0x2);
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_FW_VER);
+	pr_info("CPP FW Version: 0x%x\n", msm_cpp_read(cpp_dev->base));
+	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+	enable_irq(cpp_dev->irq->start);
+	msm_camera_io_w_mb(0x8, cpp_dev->base +
+		MSM_CPP_MICRO_IRQGEN_MASK);
+	msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
+		MSM_CPP_MICRO_IRQGEN_CLR);
+}
+
 static int cpp_init_hardware(struct cpp_device *cpp_dev)
 {
 	int rc = 0;
@@ -261,7 +304,8 @@
 	}
 
 	msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
-
+	if (cpp_dev->is_firmware_loaded == 1)
+		msm_cpp_boot_hw(cpp_dev);
 	return rc;
 req_irq_fail:
 	iounmap(cpp_dev->vbif_base);
@@ -365,6 +409,9 @@
 	pr_info("CPP FW Version: 0x%x\n", msm_cpp_read(cpp_dev->base));
 	msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
 
+	/*Disable MC clock*/
+	/*msm_camera_io_w(0x0, cpp_dev->base +
+					   MSM_CPP_MICRO_CLKEN_CTL);*/
 }
 
 static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
@@ -398,16 +445,6 @@
 	if (cpp_dev->cpp_open_cnt == 1) {
 		cpp_init_hardware(cpp_dev);
 		cpp_init_mem(cpp_dev);
-		disable_irq(cpp_dev->irq->start);
-
-		cpp_load_fw(cpp_dev);
-
-		enable_irq(cpp_dev->irq->start);
-
-		msm_camera_io_w_mb(0x8, cpp_dev->base +
-			MSM_CPP_MICRO_IRQGEN_MASK);
-		msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
-			MSM_CPP_MICRO_IRQGEN_CLR);
 		cpp_dev->state = CPP_STATE_IDLE;
 	}
 	mutex_unlock(&cpp_dev->mutex);
@@ -657,6 +694,15 @@
 	mutex_lock(&cpp_dev->mutex);
 	CPP_DBG("E cmd: %d\n", cmd);
 	switch (cmd) {
+	case VIDIOC_MSM_CPP_LOAD_FIRMWARE: {
+		if (cpp_dev->is_firmware_loaded == 0) {
+			disable_irq(cpp_dev->irq->start);
+			cpp_load_fw(cpp_dev);
+			enable_irq(cpp_dev->irq->start);
+			cpp_dev->is_firmware_loaded = 1;
+		}
+		break;
+	}
 	case VIDIOC_MSM_CPP_CFG:
 		rc = msm_cpp_cfg(cpp_dev, ioctl_ptr);
 		break;
@@ -899,6 +945,7 @@
 	msm_queue_init(&cpp_dev->realtime_q, "frame");
 	msm_queue_init(&cpp_dev->processing_q, "frame");
 	cpp_dev->cpp_open_cnt = 0;
+	cpp_dev->is_firmware_loaded = 0;
 
 	return rc;
 
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 8deff72..e8e37ed 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -131,6 +131,7 @@
 	struct regulator *fs_cpp;
 	struct mutex mutex;
 	enum cpp_state state;
+	uint8_t is_firmware_loaded;
 
 	int domain_num;
 	struct iommu_domain *domain;
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 8e2aa30..125c699 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.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
@@ -26,7 +26,7 @@
 		unsigned long align, unsigned long *iova,
 		unsigned long *buffer_size, int flags)
 {
-	int rc;
+	int rc = 0;
 	if (!iova || !buffer_size || !hndl || !clnt) {
 		dprintk(VIDC_ERR, "Invalid params: %p, %p, %p, %p\n",
 				clnt, hndl, iova, buffer_size);
@@ -71,6 +71,7 @@
 	struct ion_handle *hndl;
 	unsigned long iova = 0;
 	unsigned long buffer_size = 0;
+	unsigned long ionflags = 0;
 	int rc = 0;
 	int align = SZ_4K;
 	hndl = ion_import_dma_buf(client->clnt, fd);
@@ -84,7 +85,20 @@
 	mem->domain = domain;
 	mem->partition_num = partition;
 	mem->flags = flags;
-
+	rc = ion_handle_get_flags(client->clnt, hndl, &ionflags);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
+		goto fail_map;
+	}
+	if (ION_IS_CACHED(ionflags)) {
+		mem->kvaddr = ion_map_kernel(client->clnt, hndl);
+		if (!mem->kvaddr) {
+			dprintk(VIDC_ERR,
+					"Failed to map shared mem in kernel\n");
+			rc = -EIO;
+			goto fail_map;
+		}
+	}
 	if (flags & SMEM_SECURE)
 		align = ALIGN(align, SZ_1M);
 
@@ -103,7 +117,9 @@
 		mem->device_addr, mem->size);
 	return rc;
 fail_device_address:
-	ion_unmap_kernel(client->clnt, hndl);
+	if (mem->kvaddr)
+		ion_unmap_kernel(client->clnt, hndl);
+fail_map:
 	ion_free(client->clnt, hndl);
 fail_import_fd:
 	return rc;
@@ -243,31 +259,79 @@
 	return mem;
 }
 
-static int ion_mem_clean_invalidate(struct smem_client *clt,
-	struct msm_smem *mem)
+static int ion_cache_operations(struct smem_client *client,
+	struct msm_smem *mem, enum smem_cache_ops cache_op)
 {
-	/*
-	 * Note: We're always mapping into iommu as uncached
-	 * as a result we don't need to flush/clean anything
-	 */
-	return 0;
+	unsigned long ionflag = 0;
+	int rc = 0;
+	int msm_cache_ops = 0;
+	if (!mem || !client) {
+		dprintk(VIDC_ERR, "Invalid params: %p, %p\n",
+			mem, client);
+		return -EINVAL;
+	}
+	rc = ion_handle_get_flags(client->clnt,	mem->smem_priv,
+		&ionflag);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"ion_handle_get_flags failed: %d\n", rc);
+		goto cache_op_failed;
+	}
+	if (ION_IS_CACHED(ionflag)) {
+		switch (cache_op) {
+		case SMEM_CACHE_CLEAN:
+			msm_cache_ops = ION_IOC_CLEAN_CACHES;
+			break;
+		case SMEM_CACHE_INVALIDATE:
+			msm_cache_ops = ION_IOC_INV_CACHES;
+			break;
+		case SMEM_CACHE_CLEAN_INVALIDATE:
+			msm_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+			break;
+		default:
+			dprintk(VIDC_ERR, "cache operation not supported\n");
+			rc = -EINVAL;
+			goto cache_op_failed;
+		}
+		if (mem->kvaddr) {
+			rc = msm_ion_do_cache_op(client->clnt,
+					(struct ion_handle *)mem->smem_priv,
+					(unsigned long *) mem->kvaddr,
+					(unsigned long)mem->size,
+					msm_cache_ops);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"cache operation failed %d\n", rc);
+				goto cache_op_failed;
+			}
+		} else {
+			dprintk(VIDC_WARN,
+				"cache operation failed as no kernel mapping\n");
+		}
+	}
+cache_op_failed:
+	return rc;
 }
 
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem)
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+		enum smem_cache_ops cache_op)
 {
 	struct smem_client *client = clt;
-	int rc;
-	if (!client || !mem) {
-		dprintk(VIDC_ERR, "Invalid  client/handle passed\n");
+	int rc = 0;
+	if (!client) {
+		dprintk(VIDC_ERR, "Invalid params: %p\n",
+			client);
 		return -EINVAL;
 	}
 	switch (client->mem_type) {
 	case SMEM_ION:
-		rc = ion_mem_clean_invalidate(client, mem);
+		rc = ion_cache_operations(client, mem, cache_op);
+		if (rc)
+			dprintk(VIDC_ERR,
+			"Failed cache operations: %d\n", rc);
 		break;
 	default:
 		dprintk(VIDC_ERR, "Mem type not supported\n");
-		rc = -EINVAL;
 		break;
 	}
 	return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index 6e40bef..d1c8293 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.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
@@ -37,6 +37,13 @@
 	void *smem_priv;
 };
 
+enum smem_cache_ops {
+	SMEM_CACHE_CLEAN,
+	SMEM_CACHE_INVALIDATE,
+	SMEM_CACHE_CLEAN_INVALIDATE,
+};
+
+
 void *msm_smem_new_client(enum smem_type mtype);
 struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
 		int domain, int partition, int map_kernel);
@@ -44,5 +51,6 @@
 void msm_smem_delete_client(void *clt);
 struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, int
 		domain, int partition, int flags);
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+		enum smem_cache_ops);
 #endif
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 6480bf5..54047eb 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -181,10 +181,12 @@
 err_invalid_input:
 	return ret;
 }
-static u32 device_to_uvaddr(struct list_head *list, u32 device_addr)
+
+static struct buffer_info *device_to_uvaddr(
+	struct list_head *list, u32 device_addr)
 {
-	struct buffer_info *temp;
-	u32 uvaddr = 0;
+	struct buffer_info *temp = NULL;
+	int found = 0;
 	int i;
 	if (!list || !device_addr) {
 		dprintk(VIDC_ERR, "Invalid input\n");
@@ -198,16 +200,16 @@
 						== device_addr)  {
 					dprintk(VIDC_INFO,
 					"Found same fd buffer\n");
-					uvaddr = temp->uvaddr[i];
+					found = 1;
 					break;
 				}
 			}
-			if (uvaddr)
+			if (found)
 				break;
 		}
 	}
 err_invalid_input:
-	return uvaddr;
+	return temp;
 }
 
 static int msm_v4l2_open(struct file *filp)
@@ -544,9 +546,10 @@
 		b->m.planes[i].m.userptr = binfo->device_addr[i];
 		dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
 				binfo->device_addr[i]);
-		if (binfo->handle[i]) {
-			rc = msm_smem_clean_invalidate(v4l2_inst->mem_client,
-					binfo->handle[i]);
+		if (binfo->handle[i] &&
+			(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+					binfo->handle[i], SMEM_CACHE_CLEAN);
 			if (rc) {
 				dprintk(VIDC_ERR,
 					"Failed to clean caches: %d\n", rc);
@@ -566,6 +569,7 @@
 	int i;
 	struct msm_v4l2_vid_inst *v4l2_inst;
 	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	struct buffer_info *buffer_info;
 	if (b->length > VIDEO_MAX_PLANES) {
 		dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
 			b->length);
@@ -585,9 +589,10 @@
 				!b->m.planes[i].m.userptr) {
 			continue;
 		}
-		b->m.planes[i].m.userptr = device_to_uvaddr(
+		buffer_info = device_to_uvaddr(
 				&v4l2_inst->registered_bufs,
 				b->m.planes[i].m.userptr);
+		b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
 		if (!b->m.planes[i].m.userptr) {
 			dprintk(VIDC_ERR,
 			"Failed to find user virtual address, 0x%lx, %d, %d\n",
@@ -595,6 +600,16 @@
 			rc = -EINVAL;
 			goto fail_dq_buf;
 		}
+		if (buffer_info->handle[i] &&
+			(b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+			rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+				buffer_info->handle[i], SMEM_CACHE_INVALIDATE);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to clean caches: %d\n", rc);
+				goto fail_dq_buf;
+			}
+		}
 	}
 fail_dq_buf:
 	return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 12469a5..7a51728 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -913,7 +913,7 @@
 		case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
 			return HAL_H264_LEVEL_42;
 		case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
-			return HAL_H264_LEVEL_3;
+			return HAL_H264_LEVEL_5;
 		case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
 			return HAL_H264_LEVEL_51;
 		default:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 9f5f5af..6a83334 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -362,9 +362,7 @@
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
 	struct v4l2_event dqevent;
-	struct v4l2_control control = {0};
 	struct msm_vidc_cb_event *event_notify;
-	int rc = 0;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		dqevent.id = 0;
@@ -372,16 +370,7 @@
 		switch (event_notify->hal_event_type) {
 		case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
 			dqevent.type =
-				V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
-			control.id =
-				V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
-			rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
-			if (rc)
-				dprintk(VIDC_WARN,
-					"Failed to get Smooth streamng flag\n");
-			if (!rc && control.value == true)
-				dqevent.type =
-					V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+				V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
 			break;
 		case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
 			dqevent.type =
@@ -1929,6 +1918,12 @@
 				rc = -ENOMEM;
 				goto err_no_mem;
 			}
+			rc = msm_smem_cache_operations(inst->mem_client,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+				"Failed to clean cache may cause undefined behavior\n");
+			}
 			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
 			if (!binfo) {
 				dprintk(VIDC_ERR, "Out of memory\n");
@@ -2014,6 +2009,12 @@
 				rc = -ENOMEM;
 				goto err_no_mem;
 			}
+			rc = msm_smem_cache_operations(inst->mem_client,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+				"Failed to clean cache may cause undefined behavior\n");
+			}
 			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
 			if (!binfo) {
 				dprintk(VIDC_ERR, "Out of memory\n");
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 80fc832..52150e9 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -353,20 +353,19 @@
 		rc = -ENOMEM;
 		goto fail_smem_alloc;
 	}
-	rc = msm_smem_clean_invalidate(clnt, alloc);
-	if (rc) {
-		dprintk(VIDC_ERR, "NOTE: Failed to clean caches\n");
-		goto fail_clean_cache;
-	}
 	dprintk(VIDC_DBG, "venus_hfi_alloc:ptr=%p,size=%d",
 			alloc->kvaddr, size);
+	rc = msm_smem_cache_operations(clnt, alloc,
+		SMEM_CACHE_CLEAN);
+	if (rc) {
+		dprintk(VIDC_WARN, "Failed to clean cache\n");
+		dprintk(VIDC_WARN, "This may result in undefined behavior\n");
+	}
 	vmem->mem_size = alloc->size;
 	vmem->mem_data = alloc;
 	vmem->align_virtual_addr = (u8 *) alloc->kvaddr;
 	vmem->align_device_addr = (u8 *)alloc->device_addr;
 	return rc;
-fail_clean_cache:
-	msm_smem_free(clnt, alloc);
 fail_smem_alloc:
 	return rc;
 }
@@ -2601,6 +2600,12 @@
 		return -EINVAL;
 	}
 
+	rc = venus_hfi_iommu_attach(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to attach iommu");
+		goto fail_iommu_attach;
+	}
+
 	if (!device->resources.fw.cookie)
 		device->resources.fw.cookie = subsystem_get("venus");
 
@@ -2620,21 +2625,18 @@
 	rc = protect_cp_mem(device);
 	if (rc) {
 		dprintk(VIDC_ERR, "Failed to protect memory\n");
-		goto fail_iommu_attach;
+		goto fail_protect_mem;
 	}
 
-	rc = venus_hfi_iommu_attach(device);
-	if (rc) {
-		dprintk(VIDC_ERR, "Failed to attach iommu");
-		goto fail_iommu_attach;
-	}
 	return rc;
-fail_iommu_attach:
+fail_protect_mem:
 	venus_hfi_disable_clks(device);
 fail_enable_clks:
 	subsystem_put(device->resources.fw.cookie);
 	device->resources.fw.cookie = NULL;
 fail_load_fw:
+	venus_hfi_iommu_detach(device);
+fail_iommu_attach:
 	return rc;
 }
 
@@ -2647,9 +2649,9 @@
 		return;
 	}
 	if (device->resources.fw.cookie) {
-		venus_hfi_iommu_detach(device);
 		venus_hfi_disable_clks(device);
 		subsystem_put(device->resources.fw.cookie);
+		venus_hfi_iommu_detach(device);
 		device->resources.fw.cookie = NULL;
 	}
 }
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 4ea7013..6c60e04 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -59,12 +59,12 @@
 };
 
 static char *taiko_supplies[] = {
-	"cdc-vdd-buck", "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
+	WCD9XXX_SUPPLY_BUCK_NAME, "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
 	"cdc-vdd-a-1p2v", "cdc-vddcx-1", "cdc-vddcx-2",
 };
 
 static char *tapan_supplies[] = {
-	"cdc-vdd-buck", "cdc-vdd-h", "cdc-vdd-px",
+	WCD9XXX_SUPPLY_BUCK_NAME, "cdc-vdd-h", "cdc-vdd-px",
 	"cdc-vdd-a-1p2v", "cdc-vdd-cx"
 };
 
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 82d58ef..13e23e8 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -136,6 +136,7 @@
 	int			amux_2_trim_delta;
 	uint16_t		prev_last_good_ocv_raw;
 	int			rconn_mohm;
+	int			rbatt_capacitive_mohm;
 	struct mutex		last_ocv_uv_mutex;
 	int			last_ocv_uv;
 	int			last_ocv_temp_decidegc;
@@ -847,8 +848,8 @@
 {
 	int ibat_ua, vbat_uv, ocv_est_uv;
 	int rc;
-
-	int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
+	int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm
+				+ chip->rbatt_capacitive_mohm;
 
 	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
 							&ibat_ua,
@@ -917,7 +918,10 @@
 	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
 							&ibat_ua,
 							&vbat_uv);
-
+	/*
+	 * don't include rbatt and rbatt_capacitve since we expect this to
+	 * be used with a fake battery which does not have internal resistnaces
+	 */
 	ocv_est_uv = vbat_uv + (ibat_ua * the_chip->rconn_mohm) / 1000;
 	pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv);
 	the_chip->last_ocv_uv = ocv_est_uv;
@@ -1072,6 +1076,10 @@
 	pr_debug("adding rconn_mohm = %d rbatt = %d\n",
 				the_chip->rconn_mohm, rbatt);
 
+	rbatt += the_chip->rbatt_capacitive_mohm;
+	pr_debug("adding rbatt_capacitive_mohm = %d rbatt = %d\n",
+				the_chip->rbatt_capacitive_mohm, rbatt);
+
 	if (is_between(20, 10, soc_rbatt))
 		rbatt = rbatt
 			+ ((20 - soc_rbatt) * chip->delta_rbatt_mohm) / 10;
@@ -1583,6 +1591,8 @@
 }
 EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
 
+#define SIGN(x) ((x) < 0 ? -1 : 1)
+
 static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
 			int batt_temp,
 			int chargecycles,
@@ -1597,7 +1607,6 @@
 	int pc, new_pc;
 	int batt_temp_degc = batt_temp / 10;
 	int ocv;
-	int count = 0;
 
 	rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
 	rc = div_s64(rc, 100) + cc_uah + uuc_uah;
@@ -1611,17 +1620,55 @@
 	new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv);
 	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
 
-	/* try 10 times to get a close enough pc */
-	while (abs(new_pc - pc) > 1 && count++ < 10) {
+	if (abs(new_pc - pc) > 0) {
+		/* Maximum spins to make in while-loop when searching in
+		 * full resolution.
+		 */
+		const unsigned int max_spin_count =
+			chip->max_voltage_uv / 1000 - chip->v_cutoff + 1;
+		unsigned int count = 0;
 		int delta_mv = 5;
+		int diff = abs(new_pc - pc);
+		char sign = SIGN(new_pc - pc);
+		char old_sign;
+		int old_diff;
+		int old_ocv;
 
-		if (new_pc > pc)
-			delta_mv = -1 * delta_mv;
+		do {
+			count++;
+			old_ocv = ocv;
+			old_diff = diff;
+			old_sign = sign;
 
-		ocv = ocv + delta_mv;
-		new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
-				batt_temp_degc, ocv);
-		pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+			if (new_pc > pc)
+				ocv -= delta_mv;
+			else
+				ocv += delta_mv;
+
+			new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+							batt_temp_degc, ocv);
+			pr_debug("test revlookup pc = %d for ocv = %d\n",
+				new_pc, ocv);
+			diff = abs(new_pc - pc);
+			sign = SIGN(new_pc - pc);
+
+			if (sign != old_sign) {
+				if (delta_mv == 5) {
+					/*
+					 * we crossed our desired PC probably
+					 * becuase we were overcorrecting
+					 */
+					delta_mv = 1;
+				} else {
+					/* we crossed our desired PC even with
+					 * 1mV steps, choose the best of two */
+					if (diff > old_diff)
+						ocv = old_ocv;
+
+					break;
+				}
+			}
+		} while (count <= max_spin_count && diff > 0);
 	}
 
 	*ocv_uv = ocv * 1000;
@@ -2869,6 +2916,8 @@
 		chip->default_rbatt_mohm
 				= palladium_1500_data.default_rbatt_mohm;
 		chip->delta_rbatt_mohm = palladium_1500_data.delta_rbatt_mohm;
+		chip->rbatt_capacitive_mohm
+			= palladium_1500_data.rbatt_capacitive_mohm;
 		return 0;
 desay:
 		chip->fcc = desay_5200_data.fcc;
@@ -2878,6 +2927,8 @@
 		chip->rbatt_sf_lut = desay_5200_data.rbatt_sf_lut;
 		chip->default_rbatt_mohm = desay_5200_data.default_rbatt_mohm;
 		chip->delta_rbatt_mohm = desay_5200_data.delta_rbatt_mohm;
+		chip->rbatt_capacitive_mohm
+			= desay_5200_data.rbatt_capacitive_mohm;
 		return 0;
 }
 
@@ -3008,9 +3059,9 @@
 	int ret = 0;
 	struct pm8921_soc_params raw;
 
-	mutex_lock(&the_chip->bms_output_lock);
+	mutex_lock(&the_chip->last_ocv_uv_mutex);
 	read_soc_params_raw(the_chip, &raw, 300);
-	mutex_unlock(&the_chip->bms_output_lock);
+	mutex_lock(&the_chip->last_ocv_uv_mutex);
 
 	*val = 0;
 
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index b3fd5bc..f87a443 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -295,6 +295,7 @@
 	bool				btc_panic_if_cant_stop_chg;
 	int				stop_chg_upon_expiry;
 	bool				disable_aicl;
+	int				usb_type;
 };
 
 /* user space parameter to limit usb current */
@@ -1561,7 +1562,7 @@
 			return 0;
 		}
 
-		type = the_chip->usb_psy.type;
+		type = the_chip->usb_type;
 		if (type == POWER_SUPPLY_TYPE_USB_DCP ||
 			type == POWER_SUPPLY_TYPE_USB_ACA ||
 			type == POWER_SUPPLY_TYPE_USB_CDP)
@@ -1694,7 +1695,7 @@
 	case POWER_SUPPLY_PROP_ONLINE:
 		val->intval = 0;
 
-		if (the_chip->usb_psy.type == POWER_SUPPLY_TYPE_USB)
+		if (the_chip->usb_type == POWER_SUPPLY_TYPE_USB)
 			val->intval = is_usb_chg_plugged_in(the_chip);
 
 		break;
@@ -2360,7 +2361,7 @@
 	if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
 		return -EINVAL;
 
-	the_chip->usb_psy.type = type;
+	the_chip->usb_type = type;
 	power_supply_changed(&the_chip->usb_psy);
 	power_supply_changed(&the_chip->dc_psy);
 	return 0;
@@ -4902,6 +4903,7 @@
 		pm8921_chg_btc_override_init(chip);
 
 	chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
+	chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
 
 	chip->usb_psy.name = "usb";
 	chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
@@ -4948,9 +4950,6 @@
 	platform_set_drvdata(pdev, chip);
 	the_chip = chip;
 
-	/* set initial state of the USB charger type to UNKNOWN */
-	power_supply_set_supply_type(&chip->usb_psy, POWER_SUPPLY_TYPE_UNKNOWN);
-
 	wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
 	INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
 	INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 6135e71..7f60128 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2375,7 +2375,7 @@
 
 	of_property_read_u32(node, "spi-max-frequency",
 			&pdata->max_clock_speed);
-	of_property_read_u32(node, "infinite_mode",
+	of_property_read_u32(node, "qcom,infinite-mode",
 			&pdata->infinite_mode);
 
 	pdata->ver_reg_exists = of_property_read_bool(node
@@ -2485,13 +2485,12 @@
 			goto err_probe_exit;
 		}
 
-		rc = of_property_read_u32(pdev->dev.of_node,
-				"cell-index", &pdev->id);
-		if (rc)
+		rc = of_alias_get_id(pdev->dev.of_node, "spi");
+		if (rc < 0)
 			dev_warn(&pdev->dev,
 				"using default bus_num %d\n", pdev->id);
 		else
-			master->bus_num = pdev->id;
+			master->bus_num = pdev->id = rc;
 
 		for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
 			dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 6df0c96..76d75ea 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -60,6 +60,7 @@
 #include "u_smd.c"
 #include "u_bam.c"
 #include "u_rmnet_ctrl_smd.c"
+#include "u_rmnet_ctrl_qti.c"
 #include "u_ctrl_hsic.c"
 #include "u_data_hsic.c"
 #include "u_ctrl_hsuart.c"
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 935a540..d69e850 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -224,6 +224,16 @@
 	.bmNetworkCapabilities = 0x20,
 };
 
+static struct usb_cdc_ext_mbb_desc ext_mbb_desc = {
+	.bLength =	sizeof ext_mbb_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_EXT_MBB_TYPE,
+
+	.bcdMbbExtendedVersion =	cpu_to_le16(0x0100),
+	.bMaxOutstandingCmdMsges =	64,
+	.wMTU =	1500,
+};
+
 /* the default data interface has no endpoints ... */
 static struct usb_interface_descriptor mbim_data_nop_intf = {
 	.bLength =		sizeof mbim_data_nop_intf,
@@ -286,6 +296,7 @@
 	(struct usb_descriptor_header *) &mbim_control_intf,
 	(struct usb_descriptor_header *) &mbim_header_desc,
 	(struct usb_descriptor_header *) &mbb_desc,
+	(struct usb_descriptor_header *) &ext_mbb_desc,
 	(struct usb_descriptor_header *) &fs_mbim_notify_desc,
 	/* data interface, altsettings 0 and 1 */
 	(struct usb_descriptor_header *) &mbim_data_nop_intf,
@@ -330,6 +341,7 @@
 	(struct usb_descriptor_header *) &mbim_control_intf,
 	(struct usb_descriptor_header *) &mbim_header_desc,
 	(struct usb_descriptor_header *) &mbb_desc,
+	(struct usb_descriptor_header *) &ext_mbb_desc,
 	(struct usb_descriptor_header *) &hs_mbim_notify_desc,
 	/* data interface, altsettings 0 and 1 */
 	(struct usb_descriptor_header *) &mbim_data_nop_intf,
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index e6613e8..0d8fa0f 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -55,6 +55,7 @@
 #define NR_RMNET_PORTS	3
 static unsigned int nr_rmnet_ports;
 static unsigned int no_ctrl_smd_ports;
+static unsigned int no_ctrl_qti_ports;
 static unsigned int no_ctrl_hsic_ports;
 static unsigned int no_ctrl_hsuart_ports;
 static unsigned int no_data_bam_ports;
@@ -402,6 +403,14 @@
 			return ret;
 		}
 		break;
+	case USB_GADGET_XPORT_QTI:
+		ret = gqti_ctrl_connect(&dev->port);
+		if (ret) {
+			pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
+					__func__, ret);
+			return ret;
+		}
+		break;
 	case USB_GADGET_XPORT_HSIC:
 		ret = ghsic_ctrl_connect(&dev->port, port_num);
 		if (ret) {
@@ -436,7 +445,10 @@
 		if (ret) {
 			pr_err("%s: gbam_connect failed: err:%d\n",
 					__func__, ret);
-			gsmd_ctrl_disconnect(&dev->port, port_num);
+			if (cxport == USB_GADGET_XPORT_QTI)
+				gqti_ctrl_disconnect(&dev->port);
+			else
+				gsmd_ctrl_disconnect(&dev->port, port_num);
 			return ret;
 		}
 		break;
@@ -484,6 +496,9 @@
 	case USB_GADGET_XPORT_SMD:
 		gsmd_ctrl_disconnect(&dev->port, port_num);
 		break;
+	case USB_GADGET_XPORT_QTI:
+		gqti_ctrl_disconnect(&dev->port);
+		break;
 	case USB_GADGET_XPORT_HSIC:
 		ghsic_ctrl_disconnect(&dev->port, port_num);
 		break;
@@ -1170,6 +1185,7 @@
 
 	nr_rmnet_ports = 0;
 	no_ctrl_smd_ports = 0;
+	no_ctrl_qti_ports = 0;
 	no_data_bam_ports = 0;
 	no_data_bam2bam_ports = 0;
 	no_ctrl_hsic_ports = 0;
@@ -1215,6 +1231,10 @@
 		rmnet_port->ctrl_xport_num = no_ctrl_smd_ports;
 		no_ctrl_smd_ports++;
 		break;
+	case USB_GADGET_XPORT_QTI:
+		rmnet_port->ctrl_xport_num = no_ctrl_qti_ports;
+		no_ctrl_qti_ports++;
+		break;
 	case USB_GADGET_XPORT_HSIC:
 		rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports;
 		no_ctrl_hsic_ports++;
@@ -1268,6 +1288,7 @@
 
 	nr_rmnet_ports = 0;
 	no_ctrl_smd_ports = 0;
+	no_ctrl_qti_ports = 0;
 	no_data_bam_ports = 0;
 	no_ctrl_hsic_ports = 0;
 	no_data_hsic_ports = 0;
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index 81ba223..cea9369 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -55,5 +55,7 @@
 int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
 void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
 int gsmd_ctrl_setup(unsigned int count);
+int gqti_ctrl_connect(struct grmnet *gr);
+void gqti_ctrl_disconnect(struct grmnet *gr);
 
 #endif /* __U_RMNET_H*/
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_qti.c b/drivers/usb/gadget/u_rmnet_ctrl_qti.c
new file mode 100644
index 0000000..e92978f
--- /dev/null
+++ b/drivers/usb/gadget/u_rmnet_ctrl_qti.c
@@ -0,0 +1,519 @@
+/*
+ * 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/wait.h>
+#include <linux/poll.h>
+#include <linux/usb/rmnet_ctrl_qti.h>
+
+#include "u_rmnet.h"
+
+struct rmnet_ctrl_qti_port {
+	struct grmnet		*port_usb;
+
+	bool		is_open;
+
+	atomic_t	connected;
+	atomic_t	line_state;
+
+	atomic_t	open_excl;
+	atomic_t	read_excl;
+	atomic_t	write_excl;
+	atomic_t	ioctl_excl;
+
+	wait_queue_head_t read_wq;
+
+	struct list_head	cpkt_req_q;
+
+	spinlock_t			lock;
+};
+static struct rmnet_ctrl_qti_port *ctrl_port;
+
+static inline int rmnet_ctrl_lock(atomic_t *excl)
+{
+	if (atomic_inc_return(excl) == 1) {
+		return 0;
+	} else {
+		atomic_dec(excl);
+		return -EBUSY;
+	}
+}
+
+static inline void rmnet_ctrl_unlock(atomic_t *excl)
+{
+	atomic_dec(excl);
+}
+
+static void rmnet_ctrl_queue_notify(struct rmnet_ctrl_qti_port *port)
+{
+	unsigned long		flags;
+	struct rmnet_ctrl_pkt	*cpkt = NULL;
+
+	pr_debug("%s: Queue empty packet for QTI", __func__);
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (!port->is_open) {
+		pr_err("%s: rmnet ctrl file handler %p is not open",
+			   __func__, port);
+		spin_unlock_irqrestore(&port->lock, flags);
+		return;
+	}
+
+	cpkt = alloc_rmnet_ctrl_pkt(0, GFP_ATOMIC);
+	if (!cpkt) {
+		pr_err("%s: Unable to allocate reset function pkt\n", __func__);
+		spin_unlock_irqrestore(&port->lock, flags);
+		return;
+	}
+
+	list_add_tail(&cpkt->list, &port->cpkt_req_q);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	pr_debug("%s: Wake up read queue", __func__);
+	wake_up(&port->read_wq);
+}
+
+static int grmnet_ctrl_qti_send_cpkt_tomodem(u8 portno,
+	void *buf, size_t len)
+{
+	unsigned long		flags;
+	struct rmnet_ctrl_qti_port	*port = ctrl_port;
+	struct rmnet_ctrl_pkt *cpkt;
+
+	if (len > MAX_QTI_PKT_SIZE) {
+		pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
+				len, MAX_QTI_PKT_SIZE);
+		return -EINVAL;
+	}
+
+	cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC);
+	if (IS_ERR(cpkt)) {
+		pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
+		return -ENOMEM;
+	}
+
+	memcpy(cpkt->buf, buf, len);
+	cpkt->len = len;
+
+	pr_debug("%s: Add to cpkt_req_q packet with len = %d\n", __func__, len);
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* drop cpkt if port is not open */
+	if (!port->is_open) {
+		pr_err("rmnet file handler %p is not open", port);
+		spin_unlock_irqrestore(&port->lock, flags);
+		free_rmnet_ctrl_pkt(cpkt);
+		return 0;
+	}
+
+	list_add_tail(&cpkt->list, &port->cpkt_req_q);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* wakeup read thread */
+	pr_debug("%s: Wake up read queue", __func__);
+	wake_up(&port->read_wq);
+
+	return 0;
+}
+
+static void
+gqti_ctrl_notify_modem(void *gptr, u8 portno, int val)
+{
+	struct rmnet_ctrl_qti_port	*port = ctrl_port;
+
+	atomic_set(&port->line_state, val);
+
+	/* send 0 len pkt to qti to notify state change */
+	rmnet_ctrl_queue_notify(port);
+}
+
+int gqti_ctrl_connect(struct grmnet *gr)
+{
+	struct rmnet_ctrl_qti_port	*port;
+	unsigned long		flags;
+
+	pr_debug("%s: grmnet:%p\n", __func__, gr);
+
+	if (!gr) {
+		pr_err("%s: grmnet port is null\n", __func__);
+		return -ENODEV;
+	}
+
+	port = ctrl_port;
+
+	spin_lock_irqsave(&port->lock, flags);
+	port->port_usb = gr;
+	gr->send_encap_cmd = grmnet_ctrl_qti_send_cpkt_tomodem;
+	gr->notify_modem = gqti_ctrl_notify_modem;
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	atomic_set(&port->connected, 1);
+	wake_up(&port->read_wq);
+
+	if (port && port->port_usb && port->port_usb->connect)
+		port->port_usb->connect(port->port_usb);
+
+	return 0;
+}
+
+void gqti_ctrl_disconnect(struct grmnet *gr)
+{
+	struct rmnet_ctrl_qti_port	*port = ctrl_port;
+	unsigned long		flags;
+	struct rmnet_ctrl_pkt	*cpkt;
+
+	pr_debug("%s: grmnet:%p\n", __func__, gr);
+
+	if (!gr) {
+		pr_err("%s: grmnet port is null\n", __func__);
+		return;
+	}
+
+	if (port && port->port_usb && port->port_usb->disconnect)
+		port->port_usb->disconnect(port->port_usb);
+
+	atomic_set(&port->connected, 0);
+	atomic_set(&port->line_state, 0);
+	spin_lock_irqsave(&port->lock, flags);
+	port->port_usb = 0;
+	gr->send_encap_cmd = 0;
+	gr->notify_modem = 0;
+
+	while (!list_empty(&port->cpkt_req_q)) {
+		cpkt = list_first_entry(&port->cpkt_req_q,
+					struct rmnet_ctrl_pkt, list);
+
+		list_del(&cpkt->list);
+		free_rmnet_ctrl_pkt(cpkt);
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* send 0 len pkt to qti to notify state change */
+	rmnet_ctrl_queue_notify(port);
+}
+
+static int rmnet_ctrl_open(struct inode *ip, struct file *fp)
+{
+	unsigned long		flags;
+
+	pr_debug("Open rmnet_ctrl_qti device file\n");
+
+	if (rmnet_ctrl_lock(&ctrl_port->open_excl)) {
+		pr_debug("Already opened\n");
+		return -EBUSY;
+	}
+
+	fp->private_data = ctrl_port;
+
+	spin_lock_irqsave(&ctrl_port->lock, flags);
+	ctrl_port->is_open = true;
+	spin_unlock_irqrestore(&ctrl_port->lock, flags);
+
+	return 0;
+}
+
+static int rmnet_ctrl_release(struct inode *ip, struct file *fp)
+{
+	unsigned long		flags;
+	struct rmnet_ctrl_qti_port *port = fp->private_data;
+
+	pr_debug("Close rmnet control file");
+
+	spin_lock_irqsave(&port->lock, flags);
+	port->is_open = false;
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	rmnet_ctrl_unlock(&port->open_excl);
+
+	return 0;
+}
+
+static ssize_t
+rmnet_ctrl_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
+{
+	struct rmnet_ctrl_qti_port *port = fp->private_data;
+	struct rmnet_ctrl_pkt *cpkt = NULL;
+	unsigned long flags;
+	int ret = 0;
+
+	pr_debug("%s: Enter(%d)\n", __func__, count);
+
+	if (count > MAX_QTI_PKT_SIZE) {
+		pr_err("Buffer size is too big %d, should be at most %d\n",
+			count, MAX_QTI_PKT_SIZE);
+		return -EINVAL;
+	}
+
+	if (rmnet_ctrl_lock(&port->read_excl)) {
+		pr_err("Previous reading is not finished yet\n");
+		return -EBUSY;
+	}
+
+	/* block until online */
+	while (!(atomic_read(&port->connected))) {
+		pr_debug("Not connected. Wait.\n");
+		ret = wait_event_interruptible(port->read_wq,
+			atomic_read(&port->connected));
+		if (ret < 0) {
+			rmnet_ctrl_unlock(&port->read_excl);
+			if (ret == -ERESTARTSYS)
+				return -ERESTARTSYS;
+			else
+				return -EINTR;
+		}
+	}
+
+	/* block until a new packet is available */
+	do {
+		spin_lock_irqsave(&port->lock, flags);
+		if (!list_empty(&port->cpkt_req_q))
+			break;
+		spin_unlock_irqrestore(&port->lock, flags);
+
+		pr_debug("%s: Requests list is empty. Wait.\n", __func__);
+		ret = wait_event_interruptible(port->read_wq,
+					!list_empty(&port->cpkt_req_q));
+		if (ret < 0) {
+			pr_debug("Waiting failed\n");
+			rmnet_ctrl_unlock(&port->read_excl);
+			return -ERESTARTSYS;
+		}
+	} while (1);
+
+	cpkt = list_first_entry(&port->cpkt_req_q, struct rmnet_ctrl_pkt,
+							list);
+	list_del(&cpkt->list);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	if (cpkt->len > count) {
+		pr_err("cpkt size too big:%d > buf size:%d\n",
+				cpkt->len, count);
+		rmnet_ctrl_unlock(&port->read_excl);
+		free_rmnet_ctrl_pkt(cpkt);
+		return -ENOMEM;
+	}
+
+	pr_debug("%s: cpkt size:%d\n", __func__, cpkt->len);
+
+
+	rmnet_ctrl_unlock(&port->read_excl);
+
+	ret = copy_to_user(buf, cpkt->buf, cpkt->len);
+	if (ret) {
+		pr_err("copy_to_user failed: err %d\n", ret);
+		ret = -EFAULT;
+	} else {
+		pr_debug("%s: copied %d bytes to user\n", __func__, cpkt->len);
+		ret = cpkt->len;
+	}
+
+	free_rmnet_ctrl_pkt(cpkt);
+
+	return ret;
+}
+
+static ssize_t
+rmnet_ctrl_write(struct file *fp, const char __user *buf, size_t count,
+		   loff_t *pos)
+{
+	struct rmnet_ctrl_qti_port *port = fp->private_data;
+	void *kbuf;
+	unsigned long flags;
+	int ret = 0;
+
+	pr_debug("%s: Enter(%d)", __func__, count);
+
+	if (!count) {
+		pr_debug("zero length ctrl pkt\n");
+		return -EINVAL;
+	}
+
+	if (count > MAX_QTI_PKT_SIZE) {
+		pr_debug("given pkt size too big:%d > max_pkt_size:%d\n",
+				count, MAX_QTI_PKT_SIZE);
+		return -EINVAL;
+	}
+
+	if (rmnet_ctrl_lock(&port->write_excl)) {
+		pr_err("Previous writing not finished yet\n");
+		return -EBUSY;
+	}
+
+	if (!atomic_read(&port->connected)) {
+		pr_debug("USB cable not connected\n");
+		rmnet_ctrl_unlock(&port->write_excl);
+		return -EPIPE;
+	}
+
+	kbuf = kmalloc(count, GFP_KERNEL);
+	if (!kbuf) {
+		pr_err("failed to allocate ctrl pkt\n");
+		rmnet_ctrl_unlock(&port->write_excl);
+		return -ENOMEM;
+	}
+	ret = copy_from_user(kbuf, buf, count);
+	if (ret) {
+		pr_err("copy_from_user failed err:%d\n", ret);
+		kfree(kbuf);
+		rmnet_ctrl_unlock(&port->write_excl);
+		return -EFAULT;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (port->port_usb && port->port_usb->send_cpkt_response) {
+		ret = port->port_usb->send_cpkt_response(port->port_usb,
+							kbuf, count);
+		if (ret) {
+			pr_err("failed to send ctrl packet. error=%d\n", ret);
+			spin_unlock_irqrestore(&port->lock, flags);
+			kfree(kbuf);
+			rmnet_ctrl_unlock(&port->write_excl);
+			return ret;
+		}
+	} else {
+		pr_err("send_cpkt_response callback is NULL\n");
+		spin_unlock_irqrestore(&port->lock, flags);
+		kfree(kbuf);
+		rmnet_ctrl_unlock(&port->write_excl);
+		return -EINVAL;
+	}
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	kfree(kbuf);
+	rmnet_ctrl_unlock(&port->write_excl);
+
+	pr_debug("%s: Exit(%d)", __func__, count);
+
+	return count;
+
+}
+
+static long rmnet_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
+{
+	struct rmnet_ctrl_qti_port *port = fp->private_data;
+	int val, ret = 0;
+
+	pr_debug("%s: Received command %d", __func__, cmd);
+
+	if (rmnet_ctrl_lock(&port->ioctl_excl))
+		return -EBUSY;
+
+	switch (cmd) {
+	case FRMNET_CTRL_GET_LINE_STATE:
+		val = atomic_read(&port->line_state);
+		ret = copy_to_user((void __user *)arg, &val, sizeof(val));
+		if (ret) {
+			pr_err("copying to user space failed");
+			ret = -EFAULT;
+		}
+		pr_debug("%s: Sent line_state: %d", __func__,
+				 atomic_read(&port->line_state));
+		break;
+	default:
+		pr_err("wrong parameter");
+		ret = -EINVAL;
+	}
+
+	rmnet_ctrl_unlock(&port->ioctl_excl);
+
+	return ret;
+}
+
+static unsigned int rmnet_ctrl_poll(struct file *file, poll_table *wait)
+{
+	struct rmnet_ctrl_qti_port *port = file->private_data;
+	unsigned long flags;
+	unsigned int mask = 0;
+
+	if (!port) {
+		pr_err("%s on a NULL device\n", __func__);
+		return POLLERR;
+	}
+
+	poll_wait(file, &port->read_wq, wait);
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (!list_empty(&port->cpkt_req_q)) {
+		mask |= POLLIN | POLLRDNORM;
+		pr_debug("%s sets POLLIN for rmnet_ctrl_qti_port\n", __func__);
+	}
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return mask;
+}
+
+/* file operations for rmnet device /dev/rmnet_ctrl */
+static const struct file_operations rmnet_ctrl_fops = {
+	.owner = THIS_MODULE,
+	.open = rmnet_ctrl_open,
+	.release = rmnet_ctrl_release,
+	.read = rmnet_ctrl_read,
+	.write = rmnet_ctrl_write,
+	.unlocked_ioctl = rmnet_ctrl_ioctl,
+	.poll = rmnet_ctrl_poll,
+};
+
+static struct miscdevice rmnet_device = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "rmnet_ctrl",
+	.fops = &rmnet_ctrl_fops,
+};
+
+static int __init gqti_ctrl_init(void)
+{
+	int ret;
+	struct rmnet_ctrl_qti_port *port = NULL;
+
+	port = kzalloc(sizeof(struct rmnet_ctrl_qti_port), GFP_KERNEL);
+	if (!port) {
+		pr_err("Failed to allocate rmnet control device\n");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&port->cpkt_req_q);
+	spin_lock_init(&port->lock);
+
+	atomic_set(&port->open_excl, 0);
+	atomic_set(&port->read_excl, 0);
+	atomic_set(&port->write_excl, 0);
+	atomic_set(&port->ioctl_excl, 0);
+	atomic_set(&port->connected, 0);
+	atomic_set(&port->line_state, 0);
+
+	init_waitqueue_head(&port->read_wq);
+
+	ctrl_port = port;
+
+	ret = misc_register(&rmnet_device);
+	if (ret) {
+		pr_err("rmnet control driver failed to register");
+		goto fail_init;
+	}
+
+	return ret;
+
+fail_init:
+	kfree(port);
+	ctrl_port = NULL;
+	return ret;
+}
+module_init(gqti_ctrl_init);
+
+static void __exit gqti_ctrl_cleanup(void)
+{
+	misc_deregister(&rmnet_device);
+
+	kfree(ctrl_port);
+	ctrl_port = NULL;
+}
+module_exit(gqti_ctrl_cleanup);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 0922f44..fbae011 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-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
@@ -780,6 +780,7 @@
 		case MDP_ARGB_8888:
 		case MDP_RGBA_8888:
 		case MDP_BGRA_8888:
+		case MDP_BGRX_8888:
 		case MDP_RGBX_8888:
 		case MDP_RGB_565:
 		case MDP_BGR_565:
@@ -967,6 +968,7 @@
 	case MDP_ARGB_8888:
 	case MDP_RGBA_8888:
 	case MDP_BGRA_8888:
+	case MDP_BGRX_8888:
 	case MDP_RGBX_8888:
 		return OVERLAY_TYPE_RGB;
 	case MDP_YCRYCB_H2V1:
@@ -1137,6 +1139,23 @@
 		pipe->element0 = C1_B_Cb;	/* B */
 		pipe->bpp = 4;		/* 4 bpp */
 		break;
+	case MDP_BGRX_8888:
+		pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+		pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+		pipe->a_bit = 3;        /* alpha, 4 bits */
+		pipe->r_bit = 3;        /* R, 8 bits */
+		pipe->b_bit = 3;        /* B, 8 bits */
+		pipe->g_bit = 3;        /* G, 8 bits */
+		pipe->alpha_enable = 0;
+		pipe->unpack_tight = 1;
+		pipe->unpack_align_msb = 0;
+		pipe->unpack_count = 3;
+		pipe->element3 = C3_ALPHA;      /* alpha */
+		pipe->element2 = C2_R_Cr;       /* R */
+		pipe->element1 = C0_G_Y;        /* G */
+		pipe->element0 = C1_B_Cb;       /* B */
+		pipe->bpp = 4;          /* 4 bpp */
+		break;
 	case MDP_YCRYCB_H2V1:
 		pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
 		pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
@@ -1324,6 +1343,7 @@
 	case MDP_XRGB_8888:
 	case MDP_ARGB_8888:
 	case MDP_BGRA_8888:
+	case MDP_BGRX_8888:
 		b_start = 0;
 		g_start = 8;
 		r_start = 16;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 198e2a2..5c89938 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -417,9 +417,6 @@
 					mfd->op_enable);
 		if (ret)
 			pr_warn("can't turn on display!\n");
-
-		if (mfd->vsync_pending)
-			mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
 	}
 	mfd->is_power_setting = false;
 	complete_all(&mfd->power_set_comp);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 455f725..5158974 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -32,8 +32,6 @@
 #define MAX_MIXER_HEIGHT	2400
 #define MAX_IMG_WIDTH		0x3FFF
 #define MAX_IMG_HEIGHT		0x3FFF
-#define MIN_DST_W		10
-#define MIN_DST_H		10
 #define MAX_DST_W		MAX_MIXER_WIDTH
 #define MAX_DST_H		MAX_MIXER_HEIGHT
 #define MAX_PLANES		4
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 5e9659f..0c891f9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -57,10 +57,19 @@
 				      struct mdss_mdp_format_params *fmt)
 {
 	u32 xres, yres;
+	u32 min_src_size, min_dst_size;
 
 	xres = mfd->fbi->var.xres;
 	yres = mfd->fbi->var.yres;
 
+	if (mfd->mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
+		min_src_size = fmt->is_yuv ? 2 : 1;
+		min_dst_size = 1;
+	} else {
+		min_src_size = fmt->is_yuv ? 10 : 5;
+		min_dst_size = 2;
+	}
+
 	if (req->z_order >= MDSS_MDP_MAX_STAGE) {
 		pr_err("zorder %d out of range\n", req->z_order);
 		return -ERANGE;
@@ -68,7 +77,7 @@
 
 	if (req->src.width > MAX_IMG_WIDTH ||
 	    req->src.height > MAX_IMG_HEIGHT ||
-	    req->src_rect.w == 0 || req->src_rect.h == 0 ||
+	    req->src_rect.w < min_src_size || req->src_rect.h < min_src_size ||
 	    CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
 	    CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height)) {
 		pr_err("invalid source image img wh=%dx%d rect=%d,%d,%d,%d\n",
@@ -78,7 +87,7 @@
 		return -EOVERFLOW;
 	}
 
-	if (req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
+	if (req->dst_rect.w < min_dst_size || req->dst_rect.h < min_dst_size ||
 	    req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H) {
 		pr_err("invalid destination resolution (%dx%d)",
 		       req->dst_rect.w, req->dst_rect.h);
@@ -151,10 +160,6 @@
 			pr_err("invalid odd src resolution or coordinates\n");
 			return -EINVAL;
 		}
-		if ((req->dst_rect.w & 0x1) || (req->dst_rect.h & 0x1)) {
-			pr_err("invalid odd dst resolution\n");
-			return -EINVAL;
-		}
 	}
 
 	return 0;
@@ -265,14 +270,16 @@
 		pipe->params_changed = true;
 	}
 
-	if (req->id == MSMFB_NEW_REQUEST) {
-		mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
-		if (!mixer) {
-			pr_err("unable to get mixer\n");
-			return -ENODEV;
-		}
+	mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+	if (!mixer) {
+		pr_err("unable to get mixer\n");
+		return -ENODEV;
+	}
 
-		if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
+	if (req->id == MSMFB_NEW_REQUEST) {
+		if (req->flags & MDP_OV_PIPE_FORCE_DMA)
+			pipe_type = MDSS_MDP_PIPE_TYPE_DMA;
+		else if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
 			pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
 		else
 			pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
@@ -308,6 +315,21 @@
 			pr_err("invalid pipe ndx=%x\n", req->id);
 			return pipe ? PTR_ERR(pipe) : -ENODEV;
 		}
+
+		if (pipe->mixer != mixer) {
+			if (!mixer->ctl || (mixer->ctl->mfd != mfd)) {
+				pr_err("Can't switch mixer %d->%d pnum %d!\n",
+						pipe->mixer->num, mixer->num,
+						pipe->num);
+				mdss_mdp_pipe_unmap(pipe);
+				return -EINVAL;
+			}
+			pr_debug("switching pipe mixer %d->%d pnum %d\n",
+					pipe->mixer->num, mixer->num,
+					pipe->num);
+			mdss_mdp_mixer_pipe_unstage(pipe);
+			pipe->mixer = mixer;
+		}
 	}
 
 	pipe->flags = req->flags;
@@ -1308,6 +1330,11 @@
 	rc = mdss_mdp_ctl_start(mfd->ctl);
 	if (rc == 0) {
 		atomic_inc(&ov_active_panels);
+
+		if (mfd->vsync_pending) {
+			mfd->vsync_pending = 0;
+			mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
+		}
 	} else {
 		mdss_mdp_ctl_destroy(mfd->ctl);
 		mfd->ctl = NULL;
diff --git a/include/drm/kgsl_drm.h b/include/drm/kgsl_drm.h
index 7ffae9d..41f7c29 100644
--- a/include/drm/kgsl_drm.h
+++ b/include/drm/kgsl_drm.h
@@ -20,6 +20,7 @@
 #define DRM_KGSL_GEM_UNLOCK_ON_TS 0x0D
 #define DRM_KGSL_GEM_CREATE_FD 0x0E
 #define DRM_KGSL_GEM_GET_ION_FD 0x0F
+#define DRM_KGSL_GEM_CREATE_FROM_ION 0x10
 
 #define DRM_IOCTL_KGSL_GEM_CREATE \
 DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE, struct drm_kgsl_gem_create)
@@ -80,6 +81,10 @@
 DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GET_ION_FD, \
 struct drm_kgsl_gem_get_ion_fd)
 
+#define DRM_IOCTL_KGSL_GEM_CREATE_FROM_ION \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE_FROM_ION, \
+struct drm_kgsl_gem_create_from_ion)
+
 /* Maximum number of sub buffers per GEM object */
 #define DRM_KGSL_GEM_MAX_BUFFERS 2
 
@@ -199,4 +204,9 @@
 	uint32_t handle;
 };
 
+struct drm_kgsl_gem_create_from_ion {
+	uint32_t ion_fd;
+	uint32_t handle;
+};
+
 #endif
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
index 5ff1cfb..f27ceca 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -89,6 +89,8 @@
  *			readings from bms are not available.
  * @delta_rbatt_mohm:	the resistance to be added towards lower soc to
  *			compensate for battery capacitance.
+ * @rbatt_capacitve_mohm: the resistance to be added to compensate for
+ *				battery capacitance
  */
 
 struct bms_battery_data {
@@ -100,6 +102,7 @@
 	struct sf_lut		*rbatt_sf_lut;
 	int			default_rbatt_mohm;
 	int			delta_rbatt_mohm;
+	int			rbatt_capacitive_mohm;
 };
 
 #if defined(CONFIG_PM8921_BMS) || \
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 3ebf091..aed549e 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -29,6 +29,8 @@
 	(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
 #define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
 
+#define WCD9XXX_SUPPLY_BUCK_NAME "cdc-vdd-buck"
+
 #define SITAR_VERSION_1P0 0
 #define SITAR_VERSION_1P1 1
 #define SITAR_IS_1P0(ver) \
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
index 9c44e8b..412341a 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -196,4 +196,85 @@
 #define WCD9XXX_A_MAD_ANA_CTRL			(0x150)
 #define WCD9XXX_A_MAD_ANA_CTRL__POR		(0xF1)
 
+
+#define WCD9XXX_A_CDC_CLK_OTHR_CTL			(0x30C)
+#define WCD9XXX_A_CDC_CLK_OTHR_CTL__POR				(0x00)
+
+/* Class H related common registers */
+#define WCD9XXX_A_BUCK_MODE_1			(0x181)
+#define WCD9XXX_A_BUCK_MODE_1__POR				(0x21)
+#define WCD9XXX_A_BUCK_MODE_2			(0x182)
+#define WCD9XXX_A_BUCK_MODE_2__POR				(0xFF)
+#define WCD9XXX_A_BUCK_MODE_3			(0x183)
+#define WCD9XXX_A_BUCK_MODE_3__POR				(0xCC)
+#define WCD9XXX_A_BUCK_MODE_4			(0x184)
+#define WCD9XXX_A_BUCK_MODE_4__POR				(0x3A)
+#define WCD9XXX_A_BUCK_MODE_5			(0x185)
+#define WCD9XXX_A_BUCK_MODE_5__POR				(0x00)
+#define WCD9XXX_A_BUCK_CTRL_VCL_1			(0x186)
+#define WCD9XXX_A_BUCK_CTRL_VCL_1__POR				(0x48)
+#define WCD9XXX_A_BUCK_CTRL_VCL_2			(0x187)
+#define WCD9XXX_A_BUCK_CTRL_VCL_2__POR				(0xA3)
+#define WCD9XXX_A_BUCK_CTRL_VCL_3			(0x188)
+#define WCD9XXX_A_BUCK_CTRL_VCL_3__POR				(0x82)
+#define WCD9XXX_A_BUCK_CTRL_CCL_1			(0x189)
+#define WCD9XXX_A_BUCK_CTRL_CCL_1__POR				(0xAB)
+#define WCD9XXX_A_BUCK_CTRL_CCL_2			(0x18A)
+#define WCD9XXX_A_BUCK_CTRL_CCL_2__POR				(0xDC)
+#define WCD9XXX_A_BUCK_CTRL_CCL_3			(0x18B)
+#define WCD9XXX_A_BUCK_CTRL_CCL_3__POR				(0x6A)
+#define WCD9XXX_A_BUCK_CTRL_CCL_4			(0x18C)
+#define WCD9XXX_A_BUCK_CTRL_CCL_4__POR				(0x58)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_1			(0x18D)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_1__POR				(0x50)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_2			(0x18E)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_2__POR				(0x64)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_3			(0x18F)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_3__POR				(0x77)
+#define WCD9XXX_A_BUCK_TMUX_A_D			(0x190)
+#define WCD9XXX_A_BUCK_TMUX_A_D__POR				(0x00)
+#define WCD9XXX_A_NCP_EN			(0x192)
+#define WCD9XXX_A_NCP_EN__POR				(0xFE)
+#define WCD9XXX_A_NCP_STATIC			(0x194)
+#define WCD9XXX_A_NCP_STATIC__POR				(0x28)
+#define WCD9XXX_A_NCP_BUCKREF			(0x191)
+#define WCD9XXX_A_NCP_BUCKREF__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_B1_CTL			(0x320)
+#define WCD9XXX_A_CDC_CLSH_B1_CTL__POR				(0xE4)
+#define WCD9XXX_A_CDC_CLSH_B2_CTL			(0x321)
+#define WCD9XXX_A_CDC_CLSH_B2_CTL__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_B3_CTL			(0x322)
+#define WCD9XXX_A_CDC_CLSH_B3_CTL__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS			(0x323)
+#define WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS__POR			(0x00)
+#define WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD			(0x324)
+#define WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD__POR			(0x12)
+#define WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD			(0x325)
+#define WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD__POR			(0x0C)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD			(0x326)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD__POR		(0x18)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD			(0x327)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD__POR		(0x23)
+#define WCD9XXX_A_CDC_CLSH_K_ADDR			(0x328)
+#define WCD9XXX_A_CDC_CLSH_K_ADDR__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_K_DATA			(0x329)
+#define WCD9XXX_A_CDC_CLSH_K_DATA__POR				(0xA4)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L			(0x32A)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L__POR				(0xD7)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U			(0x32B)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U__POR				(0x05)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L			(0x32C)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L__POR				(0x60)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U			(0x32D)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U__POR				(0x09)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR			(0x32E)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH			(0x32F)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR			(0x330)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR__POR				(0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH			(0x331)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH__POR				(0x00)
+
+
 #endif
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index 471f10a..f0c4915 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -49,6 +49,10 @@
 			(AUDIO_MAX_COMMON_IOCTL_NUM+21), unsigned)
 #define AUDIO_SET_LSM_CAL		_IOW(AUDIO_IOCTL_MAGIC, \
 			(AUDIO_MAX_COMMON_IOCTL_NUM+22), unsigned)
+#define AUDIO_SET_ADM_CUSTOM_TOPOLOGY	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+23), unsigned)
+#define AUDIO_SET_ASM_CUSTOM_TOPOLOGY	_IOW(AUDIO_IOCTL_MAGIC, \
+			(AUDIO_MAX_COMMON_IOCTL_NUM+24), unsigned)
 
 #define	AUDIO_MAX_ACDB_IOCTL	(AUDIO_MAX_COMMON_IOCTL_NUM+30)
 
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 3ec966b..bc35d14 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -114,6 +114,7 @@
 	MDP_BGR_565,      /* BGR 565 planer */
 	MDP_BGR_888,      /* BGR 888 */
 	MDP_Y_CBCR_H2V2_VENUS,
+	MDP_BGRX_8888,   /* BGRX 8888 */
 	MDP_IMGTYPE_LIMIT,
 	MDP_RGB_BORDERFILL,	/* border fill pipe */
 	MDP_FB_FORMAT = MDP_IMGTYPE2_START,    /* framebuffer format */
@@ -166,6 +167,7 @@
 #define MDP_BACKEND_COMPOSITION		0x00040000
 #define MDP_BORDERFILL_SUPPORTED	0x00010000
 #define MDP_SECURE_OVERLAY_SESSION      0x00008000
+#define MDP_OV_PIPE_FORCE_DMA		0x00004000
 #define MDP_MEMORY_ID_TYPE_FB		0x00001000
 
 #define MDP_TRANSP_NOP 0xffffffff
diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h
index 2b39f69..478734f 100644
--- a/include/linux/usb/cdc.h
+++ b/include/linux/usb/cdc.h
@@ -54,6 +54,7 @@
 #define USB_CDC_OBEX_TYPE		0x15
 #define USB_CDC_NCM_TYPE		0x1a
 #define USB_CDC_MBB_TYPE		0x1b	/* mbb_desc */
+#define USB_CDC_EXT_MBB_TYPE		0x1c
 
 /* "Header Functional Descriptor" from CDC spec  5.2.3.1 */
 struct usb_cdc_header_desc {
@@ -203,6 +204,17 @@
 	__u8	bmNetworkCapabilities;
 } __packed;
 
+/* "Extended MBIM Functional Descriptor" */
+struct usb_cdc_ext_mbb_desc {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	__le16	bcdMbbExtendedVersion;
+	__u8	bMaxOutstandingCmdMsges;
+	__le16	wMTU;
+} __packed;
+
 /*-------------------------------------------------------------------------*/
 
 /*
diff --git a/include/linux/usb/rmnet_ctrl_qti.h b/include/linux/usb/rmnet_ctrl_qti.h
new file mode 100644
index 0000000..5038396
--- /dev/null
+++ b/include/linux/usb/rmnet_ctrl_qti.h
@@ -0,0 +1,12 @@
+#ifndef __LINUX_USB_U_RMNET_CTRL_QTI_H
+#define __LINUX_USB_U_RMNET_CTRL_QTI_H
+
+#include <linux/ioctl.h>
+
+#define MAX_QTI_PKT_SIZE 2048
+
+#define FRMNET_CTRL_IOCTL_MAGIC	'r'
+#define FRMNET_CTRL_GET_LINE_STATE	_IOR(FRMNET_CTRL_IOCTL_MAGIC, 2, int)
+
+
+#endif /* __LINUX_USB_U_RMNET_CTRL_QTI_H */
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 939c4e3..b003f99 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -102,6 +102,9 @@
 #define VIDIOC_MSM_CPP_GET_INST_INFO \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t)
 
+#define VIDIOC_MSM_CPP_LOAD_FIRMWARE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t)
+
 #define V4L2_EVENT_CPP_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 0)
 
 struct msm_camera_v4l2_ioctl_t {
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index badbd8e..e909195 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2012 The Linux Foundation.  All rights reserved.
+   Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -63,6 +63,7 @@
 #define BT_SECURITY_LOW		1
 #define BT_SECURITY_MEDIUM	2
 #define BT_SECURITY_HIGH	3
+#define BT_SECURITY_VERY_HIGH	4
 
 #define BT_DEFER_SETUP	7
 #define BT_FLUSHABLE	8
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 4555b08..cad737a 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6215,6 +6215,22 @@
 #define VOICE_CMD_GET_PARAM				0x0001133E
 #define VOICE_EVT_GET_PARAM_ACK				0x00011008
 
+/* Set Q6 topologies */
+#define ASM_CMD_ADD_TOPOLOGIES				0x00010DBE
+#define ADM_CMD_ADD_TOPOLOGIES				0x00010335
+
+/* structure used for both ioctls */
+struct cmd_set_topologies {
+	struct apr_hdr hdr;
+	u32		payload_addr_lsw;
+	/* LSW of parameter data payload address.*/
+	u32		payload_addr_msw;
+	/* MSW of parameter data payload address.*/
+	u32		mem_map_handle;
+	/* Memory map handle returned by mem map command */
+	u32		payload_size;
+	/* Size in bytes of the variable payload in shared memory */
+} __packed;
 
 /* SRS TRUMEDIA start */
 /* topology */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 15d3585..198773c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+   Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -2046,7 +2046,7 @@
 							sizeof(cp), &cp);
 		goto unlock;
 	} else  if (!(lmp_ssp_capable(conn)) && conn->auth_initiator &&
-		(conn->pending_sec_level == BT_SECURITY_HIGH)) {
+		(conn->pending_sec_level == BT_SECURITY_VERY_HIGH)) {
 		conn->pending_sec_level = BT_SECURITY_MEDIUM;
 	}
 
@@ -2669,6 +2669,12 @@
 		BT_DBG("Conn pending sec level is %d, ssp is %d, key len is %d",
 			conn->pending_sec_level, conn->ssp_mode, key->pin_len);
 	}
+	if (conn && (conn->ssp_mode == 0) &&
+		(conn->pending_sec_level == BT_SECURITY_VERY_HIGH) &&
+		(key->pin_len != 16)) {
+		BT_DBG("Security is high ignoring this key");
+		goto not_found;
+	}
 
 	if (key->key_type == 0x04 && conn && conn->auth_type != 0xff &&
 						(conn->auth_type & 0x01)) {
@@ -2853,14 +2859,14 @@
 
 		conn->ssp_mode = (ev->features[0] & 0x01);
 		/*In case if remote device ssp supported/2.0 device
-		reduce the security level to MEDIUM if it is HIGH*/
+		reduce the security level to MEDIUM if it is VERY HIGH*/
 		if (!conn->ssp_mode && conn->auth_initiator &&
-			(conn->pending_sec_level == BT_SECURITY_HIGH))
+			(conn->pending_sec_level == BT_SECURITY_VERY_HIGH))
 			conn->pending_sec_level = BT_SECURITY_MEDIUM;
 
 		if (conn->ssp_mode && conn->auth_initiator &&
 			conn->io_capability != 0x03) {
-			conn->pending_sec_level = BT_SECURITY_HIGH;
+			conn->pending_sec_level = BT_SECURITY_VERY_HIGH;
 			conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM;
 		}
 	}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6eab6d0..fd9088a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2012 The Linux Foundation.  All rights reserved.
+   Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
    Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
    Copyright (C) 2010 Google Inc.
 
@@ -610,6 +610,7 @@
 {
 	if (sk->sk_type == SOCK_RAW) {
 		switch (l2cap_pi(sk)->sec_level) {
+		case BT_SECURITY_VERY_HIGH:
 		case BT_SECURITY_HIGH:
 			return HCI_AT_DEDICATED_BONDING_MITM;
 		case BT_SECURITY_MEDIUM:
@@ -621,12 +622,14 @@
 		if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
 			l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
 
-		if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+		if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH ||
+			l2cap_pi(sk)->sec_level == BT_SECURITY_VERY_HIGH)
 			return HCI_AT_NO_BONDING_MITM;
 		else
 			return HCI_AT_NO_BONDING;
 	} else {
 		switch (l2cap_pi(sk)->sec_level) {
+		case BT_SECURITY_VERY_HIGH:
 		case BT_SECURITY_HIGH:
 			return HCI_AT_GENERAL_BONDING_MITM;
 		case BT_SECURITY_MEDIUM:
@@ -7533,7 +7536,8 @@
 		if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
 			l2cap_sock_clear_timer(sk);
 			l2cap_sock_set_timer(sk, HZ * 5);
-		} else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+		} else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH ||
+			l2cap_pi(sk)->sec_level == BT_SECURITY_VERY_HIGH)
 			__l2cap_sock_close(sk, ECONNREFUSED);
 	} else {
 		if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index dc4bf2f..d1914ea 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -262,6 +262,7 @@
 	__u8 auth_type;
 
 	switch (d->sec_level) {
+	case BT_SECURITY_VERY_HIGH:
 	case BT_SECURITY_HIGH:
 		auth_type = HCI_AT_GENERAL_BONDING_MITM;
 		break;
@@ -2163,7 +2164,8 @@
 				set_bit(RFCOMM_SEC_PENDING, &d->flags);
 				rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
 				continue;
-			} else if (d->sec_level == BT_SECURITY_HIGH) {
+			} else if (d->sec_level == BT_SECURITY_HIGH ||
+				d->sec_level == BT_SECURITY_VERY_HIGH) {
 				__rfcomm_dlc_close(d, ECONNREFUSED);
 				continue;
 			}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 66cc1f0..216068f 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -707,12 +707,13 @@
 			break;
 		}
 
-		if (sec.level > BT_SECURITY_HIGH) {
+		if (sec.level > BT_SECURITY_VERY_HIGH) {
 			err = -EINVAL;
 			break;
 		}
 
 		rfcomm_pi(sk)->sec_level = sec.level;
+		BT_DBG("set to %d", sec.level);
 		break;
 
 	case BT_DEFER_SETUP:
@@ -763,6 +764,7 @@
 			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
 			break;
 		case BT_SECURITY_HIGH:
+		case BT_SECURITY_VERY_HIGH:
 			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
 							RFCOMM_LM_SECURE;
 			break;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 517779f..4a83020 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -213,6 +213,7 @@
 static __u8 seclevel_to_authreq(__u8 level)
 {
 	switch (level) {
+	case BT_SECURITY_VERY_HIGH:
 	case BT_SECURITY_HIGH:
 		return SMP_AUTH_MITM | SMP_AUTH_BONDING;
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 0f14dc3..a09dab3 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -51,7 +51,7 @@
 snd-soc-wcd9304-objs := wcd9304.o wcd9304-tables.o
 snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
 snd-soc-cs8427-objs := cs8427.o
-snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o
+snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o wcd9xxx-common.o
 snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o
 snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o
 snd-soc-wl1273-objs := wl1273.o
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 1746502..6f601c1 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -36,6 +36,7 @@
 #include <linux/gpio.h>
 #include "wcd9320.h"
 #include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
 
 static atomic_t kp_taiko_priv;
 static int spkr_drv_wrnd_param_set(const char *val,
@@ -69,6 +70,7 @@
 #define TAIKO_SLIM_IRQ_PORT_CLOSED (1 << 2)
 #define TAIKO_MCLK_CLK_12P288MHZ 12288000
 #define TAIKO_MCLK_CLK_9P6HZ 9600000
+
 enum {
 	AIF1_PB = 0,
 	AIF1_CAP,
@@ -233,6 +235,10 @@
 	struct wcd9xxx_resmgr resmgr;
 	/* mbhc module */
 	struct wcd9xxx_mbhc mbhc;
+
+	/* class h specific data */
+	struct wcd9xxx_clsh_cdc_data clsh_d;
+
 };
 
 static const u32 comp_shift[] = {
@@ -354,73 +360,6 @@
 	return 0;
 }
 
-static int taiko_codec_enable_class_h_clk(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-
-	pr_debug("%s %s  %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLSH_B1_CTL, 0x01, 0x01);
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLSH_B1_CTL, 0x01, 0x00);
-		break;
-	}
-	return 0;
-}
-
-static int taiko_codec_enable_class_h(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-
-	pr_debug("%s %s  %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x02);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_4, 0xFF, 0xFF);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x04);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x80);
-		usleep_range(1000, 1000);
-		break;
-	}
-	return 0;
-}
-
-static int taiko_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
-		struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-
-	pr_debug("%s %s %d\n", __func__, w->name, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, w->reg, 0x01, 0x01);
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
-		break;
-
-	case SND_SOC_DAPM_POST_PMU:
-		usleep_range(1000, 1000);
-		break;
-
-	case SND_SOC_DAPM_PRE_PMD:
-	    snd_soc_update_bits(codec, w->reg, 0x01, 0x00);
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
-		break;
-	}
-	return 0;
-}
-
-
 static int taiko_get_anc_slot(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
@@ -905,6 +844,17 @@
 static const struct soc_enum cf_rxmix7_enum =
 	SOC_ENUM_SINGLE(TAIKO_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
 
+static const char * const class_h_dsm_text[] = {
+	"ZERO", "DSM_HPHL_RX1", "DSM_SPKR_RX7"
+};
+
+static const struct soc_enum class_h_dsm_enum =
+	SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_CLSH_CTL, 4, 3, class_h_dsm_text);
+
+static const struct snd_kcontrol_new class_h_dsm_mux =
+	SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
+
+
 static const struct snd_kcontrol_new taiko_snd_controls[] = {
 
 	SOC_ENUM_EXT("EAR PA Gain", taiko_ear_pa_gain_enum[0],
@@ -1842,11 +1792,12 @@
 
 	if (enable) {
 		taiko->adc_count++;
-		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+						0x2, 0x2);
 	} else {
 		taiko->adc_count--;
 		if (!taiko->adc_count)
-			snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL,
+			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
 					    0x2, 0x0);
 	}
 }
@@ -1934,6 +1885,7 @@
 		struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 	u16 lineout_gain_reg;
 
 	pr_debug("%s %d %s\n", __func__, event, w->name);
@@ -1962,11 +1914,19 @@
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
+		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+						 WCD9XXX_CLSH_STATE_LO,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
+		pr_debug("%s: sleeping 3 ms after %s PA turn on\n",
 				__func__, w->name);
-		usleep_range(16000, 16000);
+		usleep_range(3000, 3000);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+						 WCD9XXX_CLSH_STATE_LO,
+						 WCD9XXX_CLSH_REQ_DISABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
 		break;
 	}
@@ -2515,18 +2475,52 @@
 	}
 	return 0;
 }
-static int taiko_hphr_dac_event(struct snd_soc_dapm_widget *w,
+
+static int taiko_hphl_dac_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x02, 0x02);
+		wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_HPHL,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x02, 0x00);
+	}
+	return 0;
+}
+
+static int taiko_hphr_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x04, 0x04);
+		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+		wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_HPHR,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+							0x04, 0x00);
 		snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
 		break;
 	}
@@ -2539,14 +2533,17 @@
 	struct snd_soc_codec *codec = w->codec;
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 	enum wcd9xxx_notify_event e_pre_on, e_post_off;
+	u8 req_clsh_state;
 
 	pr_debug("%s: %s event = %d\n", __func__, w->name, event);
 	if (w->shift == 5) {
 		e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
 		e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
+		req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
 	} else if (w->shift == 4) {
 		e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
 		e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+		req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
 	} else {
 		pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
 		return -EINVAL;
@@ -2559,29 +2556,27 @@
 		break;
 
 	case SND_SOC_DAPM_POST_PMU:
-		usleep_range(10000, 10000);
+		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+						 req_clsh_state,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
 
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x20, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x04);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
 
-		usleep_range(10, 10);
+		usleep_range(5000, 5000);
 		break;
 
 	case SND_SOC_DAPM_POST_PMD:
 		/* Let MBHC module know PA turned off */
 		wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_off);
 
-		/*
-		 * schedule work is required because at the time HPH PA DAPM
-		 * event callback is called by DAPM framework, CODEC dapm mutex
-		 * would have been locked while snd_soc_jack_report also
-		 * attempts to acquire same lock.
-		 */
+		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+						 req_clsh_state,
+						 WCD9XXX_CLSH_REQ_DISABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
+
 		pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
 			 w->name);
-		usleep_range(10000, 10000);
+		usleep_range(5000, 5000);
 		break;
 	}
 	return 0;
@@ -2598,11 +2593,16 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+						 WCD9XXX_CLSH_STATE_LO,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
 		snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
 		break;
 
@@ -2757,15 +2757,11 @@
 	{"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
 	{"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
 
-	/* Change Pump */
-	{"CP", NULL, "CLASS_H_CLK"},
-
 	/* Earpiece (RX MIX1) */
 	{"EAR", NULL, "EAR PA"},
 	{"EAR PA", NULL, "EAR_PA_MIXER"},
 	{"EAR_PA_MIXER", NULL, "DAC1"},
-	{"DAC1", NULL, "CLASS_H_EAR"},
-	{"CLASS_H_EAR", NULL, "CP"},
+	{"DAC1", NULL, "RX_BIAS"},
 
 	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
 	{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
@@ -2777,15 +2773,11 @@
 
 	{"HPHL", NULL, "HPHL_PA_MIXER"},
 	{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+	{"HPHL DAC", NULL, "RX_BIAS"},
 
 	{"HPHR", NULL, "HPHR_PA_MIXER"},
 	{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
-
-	{"HPHL DAC", NULL, "CLASS_H_HPH_L"},
-	{"CLASS_H_HPH_L", NULL, "CP"},
-
-	{"HPHR DAC", NULL, "CLASS_H_HPH_R"},
-	{"CLASS_H_HPH_R", NULL, "CP"},
+	{"HPHR DAC", NULL, "RX_BIAS"},
 
 	{"ANC", NULL, "ANC1 MUX"},
 	{"ANC", NULL, "ANC2 MUX"},
@@ -2800,8 +2792,8 @@
 
 	{"ANC", NULL, "CDC_CONN"},
 
-	{"DAC1", "Switch", "RX1 CHAIN"},
-	{"HPHL DAC", "Switch", "RX1 CHAIN"},
+	{"DAC1", "Switch", "CLASS_H_DSM MUX"},
+	{"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
 	{"HPHR DAC", NULL, "RX2 CHAIN"},
 
 	{"LINEOUT1", NULL, "LINEOUT1 PA"},
@@ -2810,30 +2802,20 @@
 	{"LINEOUT4", NULL, "LINEOUT4 PA"},
 	{"SPK_OUT", NULL, "SPK PA"},
 
-	{"LINEOUT1 PA", NULL, "CP"},
 	{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
 	{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
 
-	{"LINEOUT2 PA", NULL, "CP"},
 	{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
 	{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
 
-	{"LINEOUT3 PA", NULL, "CP"},
 	{"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
 	{"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
 
-	{"LINEOUT4 PA", NULL, "CP"},
 	{"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
 	{"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
 
-	{"CP", NULL, "CLASS_H_LINEOUTS_PA"},
-	{"CLASS_H_LINEOUTS_PA", NULL, "CLASS_H_CLK"},
-
-
-
 	{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
 
-
 	{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
 	{"RDAC5 MUX", "DEM4", "RX4 MIX1"},
 
@@ -2850,12 +2832,13 @@
 	{"SPK DAC", NULL, "RX7 MIX2"},
 	{"SPK DAC", NULL, "VDD_SPKDRV"},
 
+	{"CLASS_H_DSM MUX", "DSM_HPHL_RX1", "RX1 CHAIN"},
+
 	{"RX1 CHAIN", NULL, "RX1 MIX2"},
 	{"RX2 CHAIN", NULL, "RX2 MIX2"},
 	{"RX1 CHAIN", NULL, "ANC"},
 	{"RX2 CHAIN", NULL, "ANC"},
 
-	{"CLASS_H_CLK", NULL, "RX_BIAS"},
 	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT2 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT3 DAC", NULL, "RX_BIAS"},
@@ -3986,24 +3969,81 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
 
 	pr_debug("%s %s %d\n", __func__, w->name, event);
 
 	switch (event) {
-		break;
 	case SND_SOC_DAPM_POST_PMU:
-
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x20, 0x00);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x04);
-		snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
+		wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_EAR,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
 
 		usleep_range(5000, 5000);
 		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_EAR,
+						 WCD9XXX_CLSH_REQ_DISABLE,
+						 WCD9XXX_CLSH_EVENT_POST_PA);
+		usleep_range(5000, 5000);
+	}
+	return 0;
+}
+
+static int taiko_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+
+	pr_debug("%s %s %d\n", __func__, w->name, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+						 WCD9XXX_CLSH_STATE_EAR,
+						 WCD9XXX_CLSH_REQ_ENABLE,
+						 WCD9XXX_CLSH_EVENT_PRE_DAC);
+		break;
+	}
+
+	return 0;
+}
+
+static int taiko_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	u8 reg_val, zoh_mux_val = 0x00;
+
+	pr_debug("%s: event = %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		reg_val = snd_soc_read(codec, TAIKO_A_CDC_CONN_CLSH_CTL);
+
+		if ((reg_val & 0x30) == 0x10)
+			zoh_mux_val = 0x04;
+		else if ((reg_val & 0x30) == 0x20)
+			zoh_mux_val = 0x08;
+
+		if (zoh_mux_val != 0x00)
+			snd_soc_update_bits(codec,
+					TAIKO_A_CDC_CONN_CLSH_CTL,
+					0x0C, zoh_mux_val);
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, TAIKO_A_CDC_CONN_CLSH_CTL,
+							0x0C, 0x00);
+		break;
 	}
 	return 0;
 }
 
+
 /* Todo: Have seperate dapm widgets for I2S and Slimbus.
  * Might Need to have callbacks registered only for slimbus
  */
@@ -4012,10 +4052,12 @@
 	SND_SOC_DAPM_OUTPUT("EAR"),
 
 	SND_SOC_DAPM_PGA_E("EAR PA", TAIKO_A_RX_EAR_EN, 4, 0, NULL, 0,
-			taiko_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
+			taiko_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
+			SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_MIXER("DAC1", TAIKO_A_RX_EAR_EN, 6, 0, dac1_switch,
-		ARRAY_SIZE(dac1_switch)),
+	SND_SOC_DAPM_MIXER_E("DAC1", TAIKO_A_RX_EAR_EN, 6, 0, dac1_switch,
+		ARRAY_SIZE(dac1_switch), taiko_codec_ear_dac_event,
+		SND_SOC_DAPM_PRE_PMU),
 
 	SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
 				AIF1_PB, 0, taiko_codec_enable_slimrx,
@@ -4055,8 +4097,9 @@
 	SND_SOC_DAPM_PGA_E("HPHL", TAIKO_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
 		taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_MIXER("HPHL DAC", TAIKO_A_RX_HPH_L_DAC_CTL, 7, 0,
-		hphl_switch, ARRAY_SIZE(hphl_switch)),
+	SND_SOC_DAPM_MIXER_E("HPHL DAC", TAIKO_A_RX_HPH_L_DAC_CTL, 7, 0,
+		hphl_switch, ARRAY_SIZE(hphl_switch), taiko_hphl_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_PGA_E("HPHR", TAIKO_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
 		taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
@@ -4192,36 +4235,20 @@
 	SND_SOC_DAPM_MUX("RDAC7 MUX", SND_SOC_NOPM, 0, 0,
 		&rx_dac7_mux),
 
-	SND_SOC_DAPM_SUPPLY("CLASS_H_CLK", TAIKO_A_CDC_CLK_OTHR_CTL, 0, 0,
-		taiko_codec_enable_class_h_clk, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_PRE_PMD),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_EAR", TAIKO_A_CDC_CLSH_B1_CTL, 4, 0,
-		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
-		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
-		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CLASS_H_LINEOUTS_PA", SND_SOC_NOPM, 0, 0,
-		taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
-	SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
-		taiko_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
+		&class_h_dsm_mux, taiko_codec_dsm_mux_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
 		taiko_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
 
-	SND_SOC_DAPM_SUPPLY("CDC_I2S_RX_CONN", TAIKO_A_CDC_CLK_OTHR_CTL, 5, 0,
+	SND_SOC_DAPM_SUPPLY("CDC_I2S_RX_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 5, 0,
 			    NULL, 0),
 
 	/* TX */
 
-	SND_SOC_DAPM_SUPPLY("CDC_CONN", TAIKO_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+	SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
 		0),
 
 	SND_SOC_DAPM_SUPPLY("LDO_H", TAIKO_A_LDO_H_MODE_1, 7, 0,
@@ -4540,84 +4567,6 @@
 	return IRQ_HANDLED;
 }
 
-static const struct taiko_reg_mask_val taiko_1_0_class_h_ear[] = {
-
-	/* CLASS-H EAR  IDLE_THRESHOLD Table */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_IDLE_EAR_THSD, 0x26),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_FCLKONLY_EAR_THSD, 0x2C),
-
-	/* CLASS-H EAR I_PA_FACT Table. */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_L,	0xA9),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_U, 0x07),
-
-	/* CLASS-H EAR Voltage Headroom , Voltage Min. */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_HD_EAR, 0x0D),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_MIN_EAR, 0x3A),
-
-	/* CLASS-H EAR K values --chnages from load. */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_ADDR, 0x08),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x1B),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x2D),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x36),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x37),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	/** end of Ear PA load 32 */
-};
-
-static const struct taiko_reg_mask_val taiko_1_0_class_h_hph[] = {
-
-	/* CLASS-H HPH  IDLE_THRESHOLD Table */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_IDLE_HPH_THSD, 0x13),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x19),
-
-	/* CLASS-H HPH I_PA_FACT Table */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_L,	0x9A),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_U, 0x06),
-
-	/* CLASS-H HPH Voltage Headroom , Voltage Min */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_HD_HPH, 0x0D),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_MIN_HPH, 0x1D),
-
-	/* CLASS-H HPH K values --chnages from load .*/
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_ADDR, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0xAE),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x01),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x1C),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x25),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x27),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-};
-
-static int taiko_config_ear_class_h(struct snd_soc_codec *codec, u32 ear_load)
-{
-	u32 i;
-
-	if (ear_load  != 32)
-		return -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(taiko_1_0_class_h_ear); i++)
-		snd_soc_write(codec, taiko_1_0_class_h_ear[i].reg,
-				taiko_1_0_class_h_ear[i].val);
-	return 0;
-}
-
-static int taiko_config_hph_class_h(struct snd_soc_codec *codec, u32 hph_load)
-{
-	u32 i;
-	if (hph_load  != 16)
-		return -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(taiko_1_0_class_h_hph); i++)
-		snd_soc_write(codec, taiko_1_0_class_h_hph[i].reg,
-				taiko_1_0_class_h_hph[i].val);
-	return 0;
-}
-
 static int taiko_handle_pdata(struct taiko_priv *taiko)
 {
 	struct snd_soc_codec *codec = taiko->codec;
@@ -4756,14 +4705,11 @@
 		 0x00 : 0x16);
 	snd_soc_update_bits(codec, TAIKO_A_MICB_4_CTL, 0x1E, value);
 
-	taiko_config_ear_class_h(codec, 32);
-	taiko_config_hph_class_h(codec, 16);
-
 done:
 	return rc;
 }
 
-static const struct taiko_reg_mask_val taiko_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_reg_defaults[] = {
 
 	/* set MCLk to 9.6 */
 	TAIKO_REG_VAL(TAIKO_A_CHIP_CTL, 0x02),
@@ -4772,24 +4718,6 @@
 	/* EAR PA deafults  */
 	TAIKO_REG_VAL(TAIKO_A_RX_EAR_CMBUFF, 0x05),
 
-	/* BUCK and NCP defaults for EAR and HS */
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_1, 0x5B),
-
-	/* CLASS-H defaults for EAR and HS */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x04),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x01),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x05),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x35),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B3_CTL, 0x30),
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B3_CTL, 0x3B),
-
-	/*
-	 * For CLASS-H, Enable ANC delay buffer,
-	 * set HPHL and EAR PA ref gain to 0 DB.
-	 */
-	TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B1_CTL, 0x26),
-
 	/* RX deafults */
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B5_CTL, 0x78),
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B5_CTL, 0x78),
@@ -4811,25 +4739,31 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
 };
 
-static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
 	/*
 	 * The following only need to be written for Taiko 1.0 parts.
 	 * Taiko 2.0 will have appropriate defaults for these registers.
 	 */
 
 	/* BUCK default */
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x50),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x50),
+
+	/* Required defaults for class H operation */
+	TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xF4),
+	TAIKO_REG_VAL(TAIKO_A_BIAS_CURR_CTL_2, 0x08),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
 
 	/* Choose max non-overlap time for NCP */
 	TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
 	/* Use 25mV/50mV for deltap/m to reduce ripple */
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x08),
 	/*
 	 * Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
 	 * Note that the other bits of this register will be changed during
 	 * Rx PA bring up.
 	 */
-	TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
 	/* Reduce HPH DAC bias to 70% */
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
 	/*Reduce EAR DAC bias to 70% */
@@ -4858,7 +4792,7 @@
  * Don't update TAIKO_A_CHIP_CTL, TAIKO_A_BUCK_CTRL_CCL_1 and
  * TAIKO_A_RX_EAR_CMBUFF as those are updated in taiko_reg_defaults
  */
-static const struct taiko_reg_mask_val taiko_2_0_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_2_0_reg_defaults[] = {
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_1_GAIN, 0x2),
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_2_GAIN, 0x2),
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_1_2_ADC_IB, 0x44),
@@ -4868,9 +4802,9 @@
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_GAIN, 0x2),
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_6_GAIN, 0x2),
 	TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_6_ADC_IB, 0x44),
-	TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x8),
-	TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x51),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x8),
+	TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
 	TAIKO_REG_VAL(TAIKO_A_NCP_DTEST, 0x10),
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xA4),
 	TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
@@ -4931,7 +4865,7 @@
 	}
 }
 
-static const struct taiko_reg_mask_val taiko_codec_reg_init_val[] = {
+static const struct wcd9xxx_reg_mask_val taiko_codec_reg_init_val[] = {
 	/* Initialize current threshold to 350MA
 	 * number of wait and run cycles to 4096
 	 */
@@ -4949,9 +4883,6 @@
 	{TAIKO_A_RX_LINE_4_GAIN, 0x20, 0x20},
 	{TAIKO_A_SPKR_DRV_GAIN, 0x04, 0x04},
 
-	/* CLASS H config */
-	{TAIKO_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
-
 	/* Use 16 bit sample size for TX1 to TX6 */
 	{TAIKO_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
 	{TAIKO_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
@@ -5101,6 +5032,24 @@
 	return 0;
 }
 
+static int taiko_codec_get_buck_mv(struct snd_soc_codec *codec)
+{
+	int buck_volt = WCD9XXX_CDC_BUCK_UNSUPPORTED;
+	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_pdata *pdata = taiko->resmgr.pdata;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		if (!strncmp(pdata->regulator[i].name,
+					 WCD9XXX_SUPPLY_BUCK_NAME,
+					 sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
+			buck_volt = pdata->regulator[i].min_uV;
+			break;
+		}
+	}
+	return buck_volt;
+}
+
 static int taiko_codec_probe(struct snd_soc_codec *codec)
 {
 	struct wcd9xxx *control;
@@ -5132,8 +5081,10 @@
 			tx_hpf_corner_freq_callback);
 	}
 
+
 	snd_soc_codec_set_drvdata(codec, taiko);
 
+
 	/* codec resmgr module init */
 	wcd9xxx = codec->control_data;
 	pdata = dev_get_platdata(codec->dev->parent);
@@ -5144,6 +5095,9 @@
 		return ret;
 	}
 
+	taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
+	wcd9xxx_clsh_init(&taiko->clsh_d);
+
 	/* init and start mbhc */
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
 	if (ret) {
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index aea31db..89a0b9f 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -41,12 +41,6 @@
 	TAIKO_PID_MIC_20_UA,
 };
 
-struct taiko_reg_mask_val {
-	u16	reg;
-	u8	mask;
-	u8	val;
-};
-
 enum taiko_mbhc_analog_pwr_cfg {
 	TAIKO_ANALOG_PWR_COLLAPSED = 0,
 	TAIKO_ANALOG_PWR_ON,
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
new file mode 100644
index 0000000..dbf2e39
--- /dev/null
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -0,0 +1,591 @@
+/* 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/module.h>
+#include <sound/soc.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include "wcd9xxx-common.h"
+
+#define CLSH_COMPUTE_EAR 0x01
+#define CLSH_COMPUTE_HPH_L 0x02
+#define CLSH_COMPUTE_HPH_R 0x03
+
+#define BUCK_VREF_2V 0xFF
+#define BUCK_VREF_1P8V 0xE6
+
+#define NCP_FCLK_LEVEL_8 0x08
+#define NCP_FCLK_LEVEL_5 0x05
+
+#define BUCK_SETTLE_TIME_US 50
+#define NCP_SETTLE_TIME_US 50
+
+static inline void wcd9xxx_enable_clsh_block(
+	struct snd_soc_codec *codec,
+	bool on)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+		0x01, on ? 0x01 : 0x00);
+}
+
+static inline void wcd9xxx_enable_anc_delay(
+	struct snd_soc_codec *codec,
+	bool on)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+		0x02, on ? 0x02 : 0x00);
+}
+
+static inline void wcd9xxx_enable_ncp(
+	struct snd_soc_codec *codec,
+	bool on)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
+		0x01, on ? 0x01 : 0x00);
+}
+
+static inline void wcd9xxx_enable_buck(
+	struct snd_soc_codec *codec,
+	bool on)
+{
+	snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+		0x80, on ? 0x80 : 0x00);
+}
+
+static int cdc_lo_count;
+
+static void (*clsh_state_fp[NUM_CLSH_STATES])
+			(struct snd_soc_codec *,
+			 struct wcd9xxx_clsh_cdc_data *,
+			 u8 req_state, bool req_type);
+
+static const char *state_to_str(u8 state)
+{
+	if (state == WCD9XXX_CLSH_STATE_IDLE)
+		return "STATE_IDLE";
+	else if (state == WCD9XXX_CLSH_STATE_EAR)
+		return "STATE_EAR";
+	else if (state == WCD9XXX_CLSH_STATE_HPHL)
+		return "STATE_HPH_L";
+	else if (state == WCD9XXX_CLSH_STATE_HPHR)
+		return "STATE_HPH_R";
+	else if (state == (WCD9XXX_CLSH_STATE_HPHL
+				| WCD9XXX_CLSH_STATE_HPHR))
+		return "STATE_HPH_L_R";
+	else if (state == WCD9XXX_CLSH_STATE_LO)
+		return "STATE_LO";
+
+	return "UNKNOWN_STATE";
+}
+
+static void wcd9xxx_cfg_clsh_buck(
+		struct snd_soc_codec *codec)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_BUCK_CTRL_CCL_4, 0x0B, 0x00},
+		{WCD9XXX_A_BUCK_CTRL_CCL_1, 0xF0, 0x50},
+		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0x03, 0x00},
+		{WCD9XXX_A_BUCK_CTRL_CCL_3, 0x0B, 0x00},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+						    reg_set[i].val);
+
+	dev_dbg(codec->dev, "%s: Programmed buck parameters", __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_common(
+		struct snd_soc_codec *codec)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 0, 0},
+		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 2, 1 << 2},
+		{WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, (0x1 << 4), 0},
+		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 0), 0x01},
+		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 2), (0x01 << 2)},
+		{WCD9XXX_A_CDC_CLSH_B2_CTL, (0xf << 4), (0x03 << 4)},
+		{WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 4), (0x03 << 4)},
+		{WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 0), (0x0B)},
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 5), (0x01 << 5)},
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 1), (0x01 << 1)},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+						    reg_set[i].val);
+
+	dev_dbg(codec->dev, "%s: Programmed class H controller common parameters",
+			 __func__);
+}
+
+static void wcd9xxx_chargepump_request(
+	struct snd_soc_codec *codec, bool on)
+{
+	static int cp_count;
+
+	if (on && (++cp_count == 1)) {
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+							0x01, 0x01);
+		dev_info(codec->dev, "%s: Charge Pump enabled, count = %d\n",
+				__func__, cp_count);
+	}
+
+	else if (!on) {
+		if (--cp_count < 0) {
+			dev_dbg(codec->dev, "%s: Unbalanced disable for charge pump\n",
+					__func__);
+			if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
+					& 0x01) {
+				dev_info(codec->dev, "%s: Actual chargepump is ON\n",
+						__func__);
+			}
+			cp_count = 0;
+			WARN_ON(1);
+		}
+
+		if (cp_count == 0) {
+			snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+							0x01, 0x00);
+			dev_dbg(codec->dev, "%s: Charge pump disabled, count = %d\n",
+					__func__, cp_count);
+		}
+	}
+}
+
+static inline void wcd9xxx_clsh_computation_request(
+	struct snd_soc_codec *codec, int compute_pa, bool on)
+{
+	u8 reg_val, reg_mask;
+
+	switch (compute_pa) {
+	case CLSH_COMPUTE_EAR:
+		reg_mask = 0x10;
+		reg_val = (on ? 0x10 : 0x00);
+		break;
+	case CLSH_COMPUTE_HPH_L:
+		reg_mask = 0x08;
+		reg_val = (on ? 0x08 : 0x00);
+		break;
+	case CLSH_COMPUTE_HPH_R:
+		reg_mask = 0x04;
+		reg_val = (on ? 0x04 : 0x00);
+		break;
+	default:
+		dev_dbg(codec->dev, "%s: class h computation PA request incorrect\n",
+			   __func__);
+		return;
+	}
+
+	snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+						reg_mask, reg_val);
+
+}
+
+static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
+		u8 buck_vref)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_BUCK_MODE_5, 0x02, 0x03},
+		{WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
+		{WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
+		{WCD9XXX_A_BUCK_MODE_1, 0x08, 0x00},
+		{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
+		{WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
+		{WCD9XXX_A_BUCK_MODE_1, 0x80, 0x80},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg,
+					reg_set[i].mask, reg_set[i].val);
+
+	dev_dbg(codec->dev, "%s: Done\n", __func__);
+	usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US);
+}
+
+static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_BUCK_MODE_5, 0x02, 0x00},
+		{WCD9XXX_A_NCP_STATIC, 0x20, 0x00},
+		{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x04},
+		{WCD9XXX_A_BUCK_MODE_3, 0x08, 0x08},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg,
+					reg_set[i].mask, reg_set[i].val);
+
+	dev_dbg(codec->dev, "%s: completed clsh mode settings after PA enable\n",
+		   __func__);
+
+}
+
+static void wcd9xxx_set_fclk_enable_ncp(struct snd_soc_codec *codec,
+		u8 fclk_level)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_NCP_STATIC, 0x20, 0x20},
+		{WCD9XXX_A_NCP_EN, 0x01, 0x01},
+	};
+	snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+						0x010, 0x00);
+	snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+						0x0F, fclk_level);
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg,
+					reg_set[i].mask, reg_set[i].val);
+
+	usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
+
+	dev_dbg(codec->dev, "%s: set ncp done\n", __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 7), 0},
+		{WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR, (0x3f << 0), 0x0D},
+		{WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR, (0x3f << 0), 0x3A},
+
+		/* Under assumption that EAR load is 10.7ohm */
+		{WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD, (0x3f << 0), 0x26},
+		{WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD, (0x3f << 0), 0x2C},
+		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xff, 0xA9},
+		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U, 0xff, 0x07},
+		{WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
+		{WCD9XXX_A_CDC_CLSH_K_ADDR, (0xf << 0), 0x08},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1b},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2d},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x36},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg,
+					reg_set[i].mask, reg_set[i].val);
+
+	dev_dbg(codec->dev, "%s: Programmed Class H controller EAR specific params\n",
+			 __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_hph(struct snd_soc_codec *codec)
+{
+	int i;
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 6), 0},
+		{WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH, 0x3f, 0x0D},
+		{WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH, 0x3f, 0x1D},
+
+		/* Under assumption that HPH load is 16ohm per channel */
+		{WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0x3f, 0x13},
+		{WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x1f, 0x19},
+		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
+		{WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
+		{WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
+		{WCD9XXX_A_CDC_CLSH_K_ADDR, 0x0f, 0},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
+		{WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+	};
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+							reg_set[i].val);
+	dev_dbg(codec->dev, "%s: Programmed Class H controller HPH specific params\n",
+			 __func__);
+}
+
+static void wcd9xxx_clsh_turnoff_postpa
+	(struct snd_soc_codec *codec)
+{
+
+	int i;
+
+	const struct wcd9xxx_reg_mask_val reg_set[] = {
+		{WCD9XXX_A_NCP_EN, 0x01, 0x00},
+		{WCD9XXX_A_BUCK_MODE_1, 0x80, 0x00},
+		{WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10, 0x00},
+	};
+
+	wcd9xxx_chargepump_request(codec, false);
+
+	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+		snd_soc_update_bits(codec, reg_set[i].reg,
+				reg_set[i].mask, reg_set[i].val);
+
+	wcd9xxx_enable_clsh_block(codec, false);
+
+	dev_dbg(codec->dev, "%s: Done\n", __func__);
+}
+
+static void wcd9xxx_clsh_state_idle(struct snd_soc_codec *codec,
+			struct wcd9xxx_clsh_cdc_data *clsh_d,
+			u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+		dev_dbg(codec->dev, "%s: wrong transition, cannot enable IDLE state\n",
+			   __func__);
+	} else {
+		if (req_state == WCD9XXX_CLSH_STATE_EAR) {
+			wcd9xxx_clsh_turnoff_postpa(codec);
+		} else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
+			wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_L, false);
+			wcd9xxx_clsh_turnoff_postpa(codec);
+		} else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
+			wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_R, false);
+			wcd9xxx_clsh_turnoff_postpa(codec);
+		} else if (req_state == WCD9XXX_CLSH_STATE_LO) {
+			wcd9xxx_enable_ncp(codec, false);
+			wcd9xxx_enable_buck(codec, false);
+		}
+	}
+}
+
+static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
+			struct wcd9xxx_clsh_cdc_data *clsh_d,
+			u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+		wcd9xxx_cfg_clsh_buck(codec);
+		wcd9xxx_cfg_clsh_param_common(codec);
+		wcd9xxx_cfg_clsh_param_ear(codec);
+		wcd9xxx_enable_clsh_block(codec, true);
+		wcd9xxx_chargepump_request(codec, true);
+		wcd9xxx_enable_anc_delay(codec, true);
+		wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_EAR, true);
+		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+		dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
+	} else {
+		dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
+	}
+}
+
+static void wcd9xxx_clsh_state_hph_l(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+		wcd9xxx_cfg_clsh_buck(codec);
+		wcd9xxx_cfg_clsh_param_common(codec);
+		wcd9xxx_cfg_clsh_param_hph(codec);
+		wcd9xxx_enable_clsh_block(codec, true);
+		wcd9xxx_chargepump_request(codec, true);
+		wcd9xxx_enable_anc_delay(codec, true);
+		wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_L, true);
+		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+		dev_dbg(codec->dev, "%s: Done\n", __func__);
+	} else {
+		if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
+			wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_R, false);
+		} else {
+			dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
+					__func__);
+		}
+	}
+}
+
+static void wcd9xxx_clsh_state_hph_r(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+
+		wcd9xxx_cfg_clsh_buck(codec);
+		wcd9xxx_cfg_clsh_param_common(codec);
+		wcd9xxx_cfg_clsh_param_hph(codec);
+		wcd9xxx_enable_clsh_block(codec, true);
+		wcd9xxx_chargepump_request(codec, true);
+		wcd9xxx_enable_anc_delay(codec, true);
+		wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_R, true);
+		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+		dev_dbg(codec->dev, "%s: Done\n", __func__);
+	} else {
+		if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
+			wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_L, false);
+		} else {
+			dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
+					__func__);
+		}
+	}
+}
+
+static void wcd9xxx_clsh_state_hph_st(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+		wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_L, true);
+		wcd9xxx_clsh_computation_request(codec,
+				CLSH_COMPUTE_HPH_R, true);
+	} else {
+		dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
+	}
+}
+
+static void wcd9xxx_clsh_state_lo(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable)
+{
+	if (is_enable) {
+		if (++cdc_lo_count > 1)
+			return;
+
+		wcd9xxx_enable_buck_mode(codec, BUCK_VREF_1P8V);
+		wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_5);
+
+		if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
+			wcd9xxx_enable_buck(codec, false);
+			snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+							0x20, 0x01);
+			wcd9xxx_enable_ncp(codec, true);
+			msleep(NCP_SETTLE_TIME_US);
+
+		} else {
+			snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
+							0x40, 0x00);
+			wcd9xxx_enable_ncp(codec, true);
+			msleep(NCP_SETTLE_TIME_US);
+			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+							0x01, 0x01);
+			snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+							0xFB, (0x02 << 2));
+		}
+		snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+							0x04, 0x00);
+	} else {
+		dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
+	}
+}
+
+static void wcd9xxx_clsh_state_err(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *clsh_d,
+		u8 req_state, bool is_enable)
+{
+	dev_dbg(codec->dev, "%s Wrong request for class H state machine requested to %s %s"
+			, __func__, is_enable ? "enable" : "disable",
+			state_to_str(req_state));
+	WARN_ON(1);
+}
+
+void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
+		u8 req_state, bool req_type, u8 clsh_event)
+{
+	u8 old_state, new_state;
+
+	switch (clsh_event) {
+
+	case WCD9XXX_CLSH_EVENT_PRE_DAC:
+
+		/* PRE_DAC event should be used only for Enable */
+		BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
+
+		old_state = cdc_clsh_d->state;
+		new_state = old_state | req_state;
+
+		(*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
+							req_state, req_type);
+		cdc_clsh_d->state = new_state;
+		dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+			__func__, state_to_str(old_state),
+			state_to_str(cdc_clsh_d->state));
+
+		break;
+
+	case WCD9XXX_CLSH_EVENT_POST_PA:
+
+		if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
+			if (req_state == WCD9XXX_CLSH_STATE_LO
+					&& --cdc_lo_count > 0)
+				break;
+
+			old_state = cdc_clsh_d->state;
+			new_state = old_state & (~req_state);
+
+			if (new_state < NUM_CLSH_STATES) {
+				(*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
+							req_state, req_type);
+				cdc_clsh_d->state = new_state;
+				dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+					__func__, state_to_str(old_state),
+					state_to_str(cdc_clsh_d->state));
+
+			} else {
+				dev_dbg(codec->dev, "%s: wrong new state = %x\n",
+						__func__, new_state);
+			}
+
+
+		} else if (req_state != WCD9XXX_CLSH_STATE_LO) {
+			wcd9xxx_clsh_enable_post_pa(codec);
+		}
+
+		break;
+	}
+
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_clsh_fsm);
+
+void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh)
+{
+	int i;
+	clsh->state = WCD9XXX_CLSH_STATE_IDLE;
+
+	for (i = 0; i < NUM_CLSH_STATES; i++)
+		clsh_state_fp[i] = wcd9xxx_clsh_state_err;
+
+	clsh_state_fp[WCD9XXX_CLSH_STATE_IDLE] = wcd9xxx_clsh_state_idle;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
+						wcd9xxx_clsh_state_hph_l;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR] =
+						wcd9xxx_clsh_state_hph_r;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST] =
+						wcd9xxx_clsh_state_hph_st;
+	clsh_state_fp[WCD9XXX_CLSH_STATE_LO] = wcd9xxx_clsh_state_lo;
+
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_clsh_init);
+
+MODULE_DESCRIPTION("WCD9XXX Common");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
new file mode 100644
index 0000000..743ab0c
--- /dev/null
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+#ifndef WCD9XXX_CODEC_COMMON
+
+#define WCD9XXX_CODEC_COMMON
+
+#define WCD9XXX_CLSH_REQ_ENABLE true
+#define WCD9XXX_CLSH_REQ_DISABLE false
+
+#define WCD9XXX_CLSH_EVENT_PRE_DAC 0x01
+#define WCD9XXX_CLSH_EVENT_POST_PA 0x02
+
+/* Basic states for Class H state machine.
+ * represented as a bit mask within a u8 data type
+ * bit 0: EAR mode
+ * bit 1: HPH Left mode
+ * bit 2: HPH Right mode
+ * bit 3: Lineout mode
+ * bit 4: Ultrasound mode
+ */
+#define	WCD9XXX_CLSH_STATE_IDLE 0x00
+#define	WCD9XXX_CLSH_STATE_EAR (0x01 << 0)
+#define	WCD9XXX_CLSH_STATE_HPHL (0x01 << 1)
+#define	WCD9XXX_CLSH_STATE_HPHR (0x01 << 2)
+#define	WCD9XXX_CLSH_STATE_LO (0x01 << 3)
+#define NUM_CLSH_STATES ((0x01 << 4) - 1)
+
+/* Derived State: Bits 1 and 2 should be set for Headphone stereo */
+#define WCD9XXX_CLSH_STATE_HPH_ST (WCD9XXX_CLSH_STATE_HPHL | \
+						WCD9XXX_CLSH_STATE_HPHR)
+
+
+struct wcd9xxx_reg_mask_val {
+	u16	reg;
+	u8	mask;
+	u8	val;
+};
+
+/* Class H data that the codec driver will maintain */
+struct wcd9xxx_clsh_cdc_data {
+	u8 state;
+	int buck_mv;
+};
+
+
+enum wcd9xxx_buck_volt {
+	WCD9XXX_CDC_BUCK_UNSUPPORTED = 0,
+	WCD9XXX_CDC_BUCK_MV_1P8 = 1800000,
+	WCD9XXX_CDC_BUCK_MV_2P15 = 2150000,
+};
+
+extern void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
+		struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
+		u8 req_state, bool req_type, u8 clsh_event);
+
+extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh);
+
+#endif
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 58fdc1b..b71132e 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -66,6 +66,12 @@
 	/* VocProc dev cfg cal*/
 	struct acdb_atomic_cal_block	vocproc_dev_cal;
 
+	/* Custom topology */
+	struct acdb_atomic_cal_block	adm_custom_topology;
+	struct acdb_atomic_cal_block	asm_custom_topology;
+	atomic_t			valid_adm_custom_top;
+	atomic_t			valid_asm_custom_top;
+
 	/* AFE cal */
 	struct acdb_atomic_cal_block	afe_cal[MAX_AUDPROC_TYPES];
 
@@ -134,6 +140,106 @@
 	atomic_set(&acdb_data.asm_topology, topology);
 }
 
+void reset_custom_topology_flags(void)
+{
+	atomic_set(&acdb_data.valid_adm_custom_top, 1);
+	atomic_set(&acdb_data.valid_asm_custom_top, 1);
+}
+
+void get_adm_custom_topology(struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	if (atomic_read(&acdb_data.valid_adm_custom_top) == 0) {
+		cal_block->cal_size = 0;
+		goto done;
+	}
+	atomic_set(&acdb_data.valid_adm_custom_top, 0);
+
+	cal_block->cal_size =
+		atomic_read(&acdb_data.adm_custom_topology.cal_size);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.adm_custom_topology.cal_paddr);
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.adm_custom_topology.cal_kvaddr);
+done:
+	return;
+}
+
+void store_adm_custom_topology(struct cal_block *cal_block)
+{
+	pr_debug("%s,\n", __func__);
+
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			(long)atomic64_read(&acdb_data.mem_len));
+		goto done;
+	}
+
+	atomic_set(&acdb_data.adm_custom_topology.cal_size,
+		cal_block->cal_size);
+	atomic_set(&acdb_data.adm_custom_topology.cal_paddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+	atomic_set(&acdb_data.adm_custom_topology.cal_kvaddr,
+		cal_block->cal_offset +
+		atomic64_read(&acdb_data.kvaddr));
+done:
+	return;
+}
+
+void get_asm_custom_topology(struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	if (atomic_read(&acdb_data.valid_asm_custom_top) == 0) {
+		cal_block->cal_size = 0;
+		goto done;
+	}
+	atomic_set(&acdb_data.valid_asm_custom_top, 0);
+
+	cal_block->cal_size =
+		atomic_read(&acdb_data.asm_custom_topology.cal_size);
+	cal_block->cal_paddr =
+		atomic_read(&acdb_data.asm_custom_topology.cal_paddr);
+	cal_block->cal_kvaddr =
+		atomic_read(&acdb_data.asm_custom_topology.cal_kvaddr);
+done:
+	return;
+}
+
+void store_asm_custom_topology(struct cal_block *cal_block)
+{
+	pr_debug("%s,\n", __func__);
+
+	if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+		pr_err("%s: offset %d is > mem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			(long)atomic64_read(&acdb_data.mem_len));
+		goto done;
+	}
+
+	atomic_set(&acdb_data.asm_custom_topology.cal_size,
+		cal_block->cal_size);
+	atomic_set(&acdb_data.asm_custom_topology.cal_paddr,
+		cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+	atomic_set(&acdb_data.asm_custom_topology.cal_kvaddr,
+		cal_block->cal_offset +
+		atomic64_read(&acdb_data.kvaddr));
+done:
+	return;
+}
+
 void get_voice_cal_allocation(struct acdb_cal_block *cal_block)
 {
 	cal_block->cal_size = ACDB_TOTAL_VOICE_ALLOCATION;
@@ -672,6 +778,8 @@
 			__func__);
 	}
 
+	atomic_set(&acdb_data.valid_adm_custom_top, 1);
+	atomic_set(&acdb_data.valid_asm_custom_top, 1);
 	atomic_inc(&usage_count);
 	return result;
 }
@@ -925,6 +1033,12 @@
 	case AUDIO_SET_LSM_CAL:
 		store_lsm_cal((struct cal_block *)data);
 		goto done;
+	case AUDIO_SET_ADM_CUSTOM_TOPOLOGY:
+		store_adm_custom_topology((struct cal_block *)data);
+		goto done;
+	case AUDIO_SET_ASM_CUSTOM_TOPOLOGY:
+		store_asm_custom_topology((struct cal_block *)data);
+		goto done;
 	default:
 		pr_err("ACDB=> ACDB ioctl not found!\n");
 	}
@@ -998,6 +1112,8 @@
 	memset(&acdb_data, 0, sizeof(acdb_data));
 	mutex_init(&acdb_data.acdb_mutex);
 	atomic_set(&usage_count, 0);
+	atomic_set(&acdb_data.valid_adm_custom_top, 1);
+	atomic_set(&acdb_data.valid_asm_custom_top, 1);
 
 	return misc_register(&acdb_misc);
 }
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 8528e3c..0b6110d 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -46,6 +46,9 @@
 uint32_t get_adm_rx_topology(void);
 uint32_t get_adm_tx_topology(void);
 uint32_t get_asm_topology(void);
+void reset_custom_topology_flags(void);
+void get_adm_custom_topology(struct acdb_cal_block *cal_block);
+void get_asm_custom_topology(struct acdb_cal_block *cal_block);
 void get_voice_cal_allocation(struct acdb_cal_block *cal_block);
 void get_lsm_cal(struct acdb_cal_block *cal_block);
 void get_anc_cal(struct acdb_cal_block *cal_block);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index bc11304..685deef 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -46,8 +46,11 @@
 
 /* 0 - (MAX_AUDPROC_TYPES -1):				audproc handles */
 /* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1):	audvol handles */
-	atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES)];
+/* + 1 for custom ADM topology */
+	atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES) + 1];
 	atomic_t mem_map_cal_index;
+
+	int set_custom_topology;
 };
 
 static struct adm_ctl			this_adm;
@@ -309,6 +312,8 @@
 				atomic_set(&this_adm.copp_stat[i], 0);
 			}
 			this_adm.apr = NULL;
+			reset_custom_topology_flags();
+			this_adm.set_custom_topology = 1;
 		}
 		pr_debug("Resetting calibration blocks");
 		for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
@@ -350,6 +355,7 @@
 			case ADM_CMD_DEVICE_CLOSE_V5:
 			case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
 			case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
+			case ADM_CMD_ADD_TOPOLOGIES:
 				pr_debug("%s: Basic callback received, wake up.\n",
 					__func__);
 				atomic_set(&this_adm.copp_stat[index], 1);
@@ -435,6 +441,87 @@
 	return 0;
 }
 
+void send_adm_custom_topology(int port_id)
+{
+	struct acdb_cal_block		cal_block;
+	struct cmd_set_topologies	adm_top;
+	int				index;
+	int				result;
+	int				size = 4096;
+
+	get_adm_custom_topology(&cal_block);
+	if (cal_block.cal_size == 0) {
+		pr_debug("%s: no cal to send addr= 0x%x\n",
+				__func__, cal_block.cal_paddr);
+		goto done;
+	}
+
+	index = afe_get_port_index(port_id);
+	if (index < 0 || index >= AFE_MAX_PORTS) {
+		pr_err("%s: invalid port idx %d portid %#x\n",
+				__func__, index, port_id);
+		goto done;
+	}
+
+	if (this_adm.set_custom_topology) {
+		/* specific index 4 for adm topology memory */
+		atomic_set(&this_adm.mem_map_cal_index, 4);
+
+		/* Only call this once */
+		this_adm.set_custom_topology = 0;
+
+		result = adm_memory_map_regions(port_id, &cal_block.cal_paddr,
+					0, &size, 1);
+		if (result < 0) {
+			pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
+				__func__, cal_block.cal_paddr,
+			       cal_block.cal_size);
+			goto done;
+		}
+	}
+
+
+	adm_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	adm_top.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(adm_top));
+	adm_top.hdr.src_svc = APR_SVC_ADM;
+	adm_top.hdr.src_domain = APR_DOMAIN_APPS;
+	adm_top.hdr.src_port = port_id;
+	adm_top.hdr.dest_svc = APR_SVC_ADM;
+	adm_top.hdr.dest_domain = APR_DOMAIN_ADSP;
+	adm_top.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	adm_top.hdr.token = port_id;
+	adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
+	adm_top.payload_addr_lsw = cal_block.cal_paddr;
+	adm_top.payload_addr_msw = 0;
+	adm_top.mem_map_handle = atomic_read(&this_adm.mem_map_cal_handles[4]);
+	adm_top.payload_size = cal_block.cal_size;
+
+	atomic_set(&this_adm.copp_stat[index], 0);
+	pr_debug("%s: Sending ADM_CMD_ADD_TOPOLOGIES payload = 0x%x, size = %d\n",
+		__func__, adm_top.payload_addr_lsw,
+		adm_top.payload_size);
+	result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_top);
+	if (result < 0) {
+		pr_err("%s: Set topologies failed port = 0x%x payload = 0x%x\n",
+			__func__, port_id, cal_block.cal_paddr);
+		goto done;
+	}
+	/* Wait for the callback */
+	result = wait_event_timeout(this_adm.wait[index],
+		atomic_read(&this_adm.copp_stat[index]),
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!result) {
+		pr_err("%s: Set topologies timed out port = 0x%x, payload = 0x%x\n",
+			__func__, port_id, cal_block.cal_paddr);
+		goto done;
+	}
+
+done:
+	return;
+}
+
 static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
 {
 	s32				result = 0;
@@ -684,6 +771,7 @@
 		rtac_set_adm_handle(this_adm.apr);
 	}
 
+	send_adm_custom_topology(port_id);
 
 	/* Create a COPP if port id are not enabled */
 	if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
@@ -1154,6 +1242,7 @@
 {
 	int i = 0;
 	this_adm.apr = NULL;
+	this_adm.set_custom_topology = 1;
 
 	for (i = 0; i < AFE_MAX_PORTS; i++) {
 		atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 3d8d5eb..b832c41 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -106,6 +106,9 @@
 static int out_cold_index;
 static char *out_buffer;
 static char *in_buffer;
+static int set_custom_topology;
+static int topology_map_handle;
+
 static int audio_output_latency_dbgfs_open(struct inode *inode,
 							struct file *file)
 {
@@ -341,6 +344,90 @@
 	return;
 }
 
+void send_asm_custom_topology(struct audio_client *ac)
+{
+	struct acdb_cal_block		cal_block;
+	struct cmd_set_topologies	asm_top;
+	struct audio_buffer		*buf;
+	struct asm_buffer_node		*buf_node = NULL;
+	struct list_head		*ptr, *next;
+	int				result;
+	int				size = 4096;
+
+	get_asm_custom_topology(&cal_block);
+	if (cal_block.cal_size == 0) {
+		pr_debug("%s: no cal to send addr= 0x%x\n",
+				__func__, cal_block.cal_paddr);
+		goto done;
+	}
+
+	if (set_custom_topology) {
+		/* Only call this once */
+		set_custom_topology = 0;
+
+		/* Use first asm buf to map memory */
+		buf = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
+		if (!buf) {
+			pr_debug("%s: could not allocate temp memory\n",
+				__func__);
+			goto done;
+		}
+		buf[0].phys = cal_block.cal_paddr;
+		ac->port[0].buf = buf;
+
+		result = q6asm_memory_map_regions(ac, 0, size, 1, 1);
+		if (result < 0) {
+			pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
+				__func__, cal_block.cal_paddr,
+				cal_block.cal_size);
+			goto done;
+		}
+
+		list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+			buf_node = list_entry(ptr, struct asm_buffer_node,
+						list);
+			if (buf_node->buf_addr_lsw == cal_block.cal_paddr) {
+				topology_map_handle =  buf_node->mmap_hdl;
+				break;
+			}
+		}
+
+		kfree(buf);
+	}
+
+	q6asm_add_hdr(ac, &asm_top.hdr, APR_PKT_SIZE(APR_HDR_SIZE,
+						sizeof(asm_top)), TRUE);
+
+	asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
+	asm_top.payload_addr_lsw = cal_block.cal_paddr;
+	asm_top.payload_addr_msw = 0;
+	asm_top.mem_map_handle = topology_map_handle;
+	asm_top.payload_size = cal_block.cal_size;
+
+	 pr_debug("%s: Sending ASM_CMD_ADD_TOPOLOGIES payload = 0x%x, size = %d, map handle = 0x%x\n",
+		__func__, asm_top.payload_addr_lsw,
+		asm_top.payload_size, asm_top.mem_map_handle);
+
+	result = apr_send_pkt(ac->apr, (uint32_t *) &asm_top);
+	if (result < 0) {
+		pr_err("%s: Set topologies failed payload = 0x%x\n",
+			__func__, cal_block.cal_paddr);
+		goto done;
+	}
+
+	result = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (result < 0) {
+		pr_err("%s: Set topologies failed payload = 0x%x\n",
+			__func__, cal_block.cal_paddr);
+		goto done;
+	}
+
+
+done:
+	return;
+}
+
 int q6asm_audio_client_buf_free(unsigned int dir,
 			struct audio_client *ac)
 {
@@ -563,6 +650,8 @@
 	atomic_set(&ac->cmd_state, 0);
 	atomic_set(&ac->nowait_cmd_cnt, 0);
 
+	send_asm_custom_topology(ac);
+
 	pr_debug("%s: session[%d]\n", __func__, ac->session);
 
 	return ac;
@@ -822,6 +911,8 @@
 		apr_reset(this_mmap.apr);
 		atomic_set(&this_mmap.ref_cnt, 0);
 		this_mmap.apr = NULL;
+		reset_custom_topology_flags();
+		set_custom_topology = 1;
 		return 0;
 	}
 	sid = (data->token >> 8) & 0x0F;
@@ -956,6 +1047,8 @@
 					(uint32_t *)data->payload, ac->priv);
 		apr_reset(ac->apr);
 		ac->apr = NULL;
+		reset_custom_topology_flags();
+		set_custom_topology = 1;
 		return 0;
 	}
 
@@ -997,6 +1090,7 @@
 		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
 		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+		case ASM_CMD_ADD_TOPOLOGIES:
 		pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
 				__func__, payload[0], payload[1]);
 			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
@@ -3564,6 +3658,7 @@
 {
 	pr_debug("%s\n", __func__);
 	memset(session, 0, sizeof(session));
+	set_custom_topology = 1;
 
 	config_debug_fs_init();