Merge "msm: kgsl: Map ebi memory to kernel" into msm-3.4
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-clkdiv.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-clkdiv.txt
new file mode 100644
index 0000000..67303eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-clkdiv.txt
@@ -0,0 +1,43 @@
+* qpnp-clkdiv
+
+clkdiv configures the clock frequency of a set of outputs on the PMIC.
+These clocks are typically wired through alternate functions on
+gpio pins.
+
+Required properties :
+ - reg : The address and size of the peripheral. Size should be 0x1000, and the
+         address may vary.
+ - qcom,cxo-freq : The frequency of the cxo clock in Hz.
+
+Optional properties :
+ - qcom,cxo-div : Integer to divide the CXO clock by when constructing the
+		  output frequency. Please see the definitions in
+		  include/linux/qpnp-clkdiv.h to choose the appropriate value.
+ - qcom,enable : 0 == disable clock output
+		 1 == enable clock output.
+
+Note: if an optional property is not specified, no device configuration will
+      occur at probe time.
+
+Client required properties :
+ - <consumer name>-clk : A phandle to the corresponding divclk device. The
+			      consumer name refers to the name that will be
+			      passed to qpnp_clkdiv_get(), and allows for a
+			      client specific name to be associated with each
+			      divclk.
+
+Clkdiv device example :
+
+...
+	pm8941_clkdiv1: clkdiv@5b00 {
+		reg = <0x5b00 0x1000>;
+		qcom,cxo-freq = <19200000>;
+		qcom,cxo-div = <1>;
+		qcom,enable = <1>;
+	};
+
+Client device example :
+...
+	client {
+		my-clk = &pm8941_clkdiv1;
+	};
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 2e7f9c3..46b39ec 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -2,38 +2,93 @@
 
 The qpnp-power-on is a driver which supports the power-on(PON)
 peripheral on Qualcomm PMICs. The supported functionality includes
-power on/off reason, power-key press/release detection and other PON
-features. This peripheral is connected to the host processor via the SPMI
-interface.
+power on/off reason, key press/release detection, PMIC reset configurations
+and other PON specifc features. The PON module supports multiple physical
+power-on (KPDPWR_N, CBLPWR) and reset (KPDPWR_N, RESIN, KPDPWR+RESIN) sources.
+This peripheral is connected to the host processor via the SPMI interface.
 
 Required properties:
 - compatible:	Must be "qcom,qpnp-power-on"
 - reg:		Specifies the SPMI address and size for this PON (power-on) peripheral
-- interrupts:	Specifies the interrupt associated with the power-key.
+- interrupts:	Specifies the interrupt associated with PON.
 
 Optional properties:
-- qcom,pon-key-enable:		Enable power-key detection. It enables monitoring
-				of the KPDPWR_N line (connected to the power-key).
-- qcom,pon-key-dbc-delay:	The debouce delay for the power-key interrupt
+- qcom,pon-dbc-delay:		The debouce delay for the power-key interrupt
 				specifed in us. The value ranges from 2 seconds
 				to 1/64 of a second. Possible values are -
 				- 2, 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64
 				- Intermediate value is rounded down to the
 				nearest valid value.
-- qcom,pon-key-pull-up:		The intial state of the KPDPWR_N pin
-				(connected to the power-key)
+- qcom,pon_1 ...pon_n		These represent the child nodes which describe
+				the properties (reset, key) for each of the pon
+				reset source. All the child nodes are optional,
+				if none of them are specified the driver fails
+				to register.
+
+All the below properties are in the sub-node section (properties of the child
+node).
+
+- qcom,pull-up:			The initial state of the reset pin under
+				consideration.
 				0 = No pull-up
 				1 = pull-up enabled
-
-If any of the above optional property is not defined, the driver will continue
-with the default hardware state.
+				This property is optional and is set to '0'
+				if not specified.
+- qcom,pon-type			The type of PON/RESET source. The driver
+				currently supports KPDPWR(0) and RESIN(1)
+				pon/reset sources. This property must be
+				specified.
+- qcom,support-reset		Indicates if this PON source supports
+				reset functionality.
+				0 = Not supported
+				1 = Supported
+				This property is optional and is set to '0'
+				if not specified.
+- qcom,s1-timer			The debouce timer for the BARK interrupt for
+				that reset source. Value is specified in ms.
+				Supported values are -
+				- 0, 32, 56, 80, 128, 184, 272, 408, 608, 904
+				  1352, 2048, 3072, 4480, 6720, 10256
+				This property must be specified only if
+				'support-reset' is set to 1.
+- qcom,s2-timer			The debouce timer for the S2 reset specified
+				in ms. On the expiry of this timer, the PMIC
+				executes the reset sequence. Supoprted values -
+				- 0, 10, 50, 100, 250, 500, 1000, 2000
+				This property is required only if
+				'support-reset' is set to 1.
+- qcom,s2-type			The type of reset associated with this source.
+				The supported resets are -
+				SOFT(0), WARM(1), SHUTDOWN(4), HARD(7)
+				This property is required only if
+				'support-reset' is set to 1.
+- linux,code			The input key-code associated with the reset source.
+				The reset source in its default configuration can be
+				used to support standard keys. This property is optional.
 
 Example:
 	qcom,power-on@800 {
 		compatible = "qcom,qpnp-power-on";
 		reg = <0x800 0x100>;
-		interrupts = <0x0 0x8 0x1>;
-		qcom,pon-key-enable= <true>;
-		qcom,pon-key-pull-up = <true>;
-		qcom,pon-key-dbc-delay = <15625>;
+		interrupts = <0x0 0x8 0x0>,
+			     <0x0 0x8 0x1>,
+			     <0x0 0x8 0x4>;
+		interrupt-names = "kpdpwr", "resin", "resin-bark";
+		qcom,pon-dbc-delay = <15625>;
+
+		qcom,pon_1 {
+			qcom,pon-type = <0>;
+			qcom,pull-up = <1>;
+			linux,code = <116>;
+		};
+
+		qcom,pon_2 {
+			qcom,pon-type = <1>;
+			qcom,support-reset = <1>;
+			qcom,pull-up = <1>;
+			qcom,s1-timer = <3072>;
+			qcom,s2-timer = <2000>;
+			qcom,s2-type = <1>;
+			linux,code = <114>;
+		};
 	}
diff --git a/Documentation/devicetree/bindings/qdsp/adsp-loader.txt b/Documentation/devicetree/bindings/qdsp/adsp-loader.txt
new file mode 100644
index 0000000..74e58dc
--- /dev/null
+++ b/Documentation/devicetree/bindings/qdsp/adsp-loader.txt
@@ -0,0 +1,10 @@
+* MSM Application DSP loader binding
+
+Required properties:
+- compatible : "qcom,adsp-loader"
+
+Example:
+
+	qcom,msm-adsp-loader {
+		compatible = "qcom,adsp-loader";
+	};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index ee0a264..84bc68b 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -25,11 +25,27 @@
 		qcom,power-on@800 {
 			compatible = "qcom,qpnp-power-on";
 			reg = <0x800 0x100>;
-			interrupts = <0x0 0x8 0x0>;
-			interrupt-names = "power-key";
-			qcom,pon-key-enable = <1>;
-			qcom,pon-key-dbc-delay = <15625>;
-			qcom,pon-key-pull-up = <1>;
+			interrupts = <0x0 0x8 0x0>,
+				     <0x0 0x8 0x1>,
+				     <0x0 0x8 0x4>;
+			interrupt-names = "kpdpwr", "resin", "resin-bark";
+			qcom,pon-dbc-delay = <15625>;
+
+			qcom,pon_1 {
+				qcom,pon-type = <0>;
+				qcom,pull-up = <1>;
+				linux,code = <116>;
+			};
+
+			qcom,pon_2 {
+				qcom,pon-type = <1>;
+				qcom,support-reset = <1>;
+				qcom,pull-up = <1>;
+				qcom,s1-timer = <0>;
+				qcom,s2-timer = <2000>;
+				qcom,s2-type = <1>;
+				linux,code = <114>;
+			};
 		};
 
 		pm8941_gpios {
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
index 323fac4..5d93fa3 100644
--- a/arch/arm/boot/dts/msm8974-gpio.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpio.dtsi
@@ -25,14 +25,26 @@
 			};
 
 			gpio@c200 {
+				qcom,mode = <0>;
+				qcom,pull = <0>;
+				qcom,vin-sel = <2>;
+				qcom,select = <0>;
 				status = "ok";
 			};
 
 			gpio@c300 {
+				qcom,mode = <0>;
+				qcom,pull = <0>;
+				qcom,vin-sel = <2>;
+				qcom,select = <0>;
 				status = "ok";
 			};
 
 			gpio@c400 {
+				qcom,mode = <0>;
+				qcom,pull = <0>;
+				qcom,vin-sel = <2>;
+				qcom,select = <0>;
 				status = "ok";
 			};
 
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
new file mode 100644
index 0000000..d14e014
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -0,0 +1,32 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	qcom,mdss_mdp@fd900000 {
+		compatible = "qcom,mdss_mdp";
+		reg = <0xfd900000 0x22100>;
+		interrupts = <0 72 0>;
+		vdd-supply = <&gdsc_mdss>;
+	};
+
+	mdss_dsi: qcom,mdss_dsi@fd922800 {
+		compatible = "qcom,msm-mdss-dsi";
+		reg = <0xfd922800 0x5ac>,
+			<0xfd8c2000 0x01000>;
+	};
+
+	qcom,mdss_wb_panel {
+		compatible = "qcom,mdss_wb";
+		qcom,mdss_pan_res = <640 480>;
+		qcom,mdss_pan_bpp = <24>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c5b53d7..166a17d 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -18,6 +18,7 @@
 /include/ "msm-gdsc.dtsi"
 /include/ "msm8974-ion.dtsi"
 /include/ "msm8974-gpu.dtsi"
+/include/ "msm8974-mdss.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974";
@@ -85,7 +86,8 @@
 	usb@f9a55000 {
 		compatible = "qcom,hsusb-otg";
 		reg = <0xf9a55000 0x400>;
-		interrupts = <0 134 0>;
+		interrupts = <0 134 0 0 140 0>;
+		interrupt-names = "core_irq", "async_irq";
 		HSUSB_VDDCX-supply = <&pm8841_s2>;
 		HSUSB_1p8-supply = <&pm8941_l6>;
 		HSUSB_3p3-supply = <&pm8941_l24>;
@@ -656,28 +658,6 @@
 		compatible = "qcom,qseecom";
 	};
 
-	qcom,mdss_mdp@fd900000 {
-		cell-index = <0>;
-		compatible = "qcom,mdss_mdp";
-		reg = <0xfd900000 0x22100>;
-		interrupts = <0 72 0>;
-		vdd-supply = <&gdsc_mdss>;
-	};
-
-	mdss_dsi: qcom,mdss_dsi@fd922800 {
-		cell-index = <1>;
-		compatible = "qcom,msm-mdss-dsi";
-		reg = <0xfd922800 0x5ac>,
-			<0xfd8c0000 0x01000>;
-	};
-
-	qcom,mdss_wb_panel {
-		cell-index = <1>;
-		compatible = "qcom,mdss_wb";
-		qcom,mdss_pan_res = <640 480>;
-		qcom,mdss_pan_bpp = <24>;
-	};
-
 	qcom,wdt@f9017000 {
 		compatible = "qcom,msm-watchdog";
 		reg = <0xf9017000 0x1000>;
@@ -788,6 +768,37 @@
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
 	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&pm8941_gpios 3 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&pm8941_gpios 4 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8941_gpios 5 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
 };
 
 /include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 595ecd29..32e9cc6 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -173,7 +173,8 @@
 	read_lock_irqsave(&device_info->lock, flags);
 
 	list_for_each_entry(b, &device_info->safe_buffers, node)
-		if (b->safe_dma_addr == safe_dma_addr) {
+		if (b->safe_dma_addr <= safe_dma_addr &&
+		    b->safe_dma_addr + b->size > safe_dma_addr) {
 			rb = b;
 			break;
 		}
@@ -254,7 +255,7 @@
 	if (buf == NULL) {
 		dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
 		       __func__, ptr);
-		return ~0;
+		return DMA_ERROR_CODE;
 	}
 
 	dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
@@ -320,7 +321,7 @@
 
 	ret = needs_bounce(dev, dma_addr, size);
 	if (ret < 0)
-		return ~0;
+		return DMA_ERROR_CODE;
 
 	if (ret == 0) {
 		__dma_page_cpu_to_dev(page, offset, size, dir);
@@ -329,7 +330,7 @@
 
 	if (PageHighMem(page)) {
 		dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n");
-		return ~0;
+		return DMA_ERROR_CODE;
 	}
 
 	return map_single(dev, page_address(page) + offset, size, dir);
@@ -362,9 +363,10 @@
 EXPORT_SYMBOL(__dma_unmap_page);
 
 int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
-		unsigned long off, size_t sz, enum dma_data_direction dir)
+		size_t sz, enum dma_data_direction dir)
 {
 	struct safe_buffer *buf;
+	unsigned long off;
 
 	dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n",
 		__func__, addr, off, sz, dir);
@@ -373,6 +375,8 @@
 	if (!buf)
 		return 1;
 
+	off = addr - buf->safe_dma_addr;
+
 	BUG_ON(buf->direction != dir);
 
 	dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
@@ -391,9 +395,10 @@
 EXPORT_SYMBOL(dmabounce_sync_for_cpu);
 
 int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
-		unsigned long off, size_t sz, enum dma_data_direction dir)
+		size_t sz, enum dma_data_direction dir)
 {
 	struct safe_buffer *buf;
+	unsigned long off;
 
 	dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n",
 		__func__, addr, off, sz, dir);
@@ -402,6 +407,8 @@
 	if (!buf)
 		return 1;
 
+	off = addr - buf->safe_dma_addr;
+
 	BUG_ON(buf->direction != dir);
 
 	dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index e231db6..53193a1 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -105,6 +105,8 @@
 CONFIG_IPV6_MIP6=y
 CONFIG_IPV6_MULTIPLE_TABLES=y
 CONFIG_IPV6_SUBTREES=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
@@ -126,6 +128,7 @@
 # CONFIG_MSM_RMNET is not set
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
@@ -259,3 +262,19 @@
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
+
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+
+CONFIG_BT_HCISMD=y
+CONFIG_MSM_BT_POWER=y
+
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index dc988ff..d055a53 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -10,6 +10,8 @@
 #include <asm-generic/dma-coherent.h>
 #include <asm/memory.h>
 
+#define DMA_ERROR_CODE	(~0)
+
 #ifdef __arch_page_to_dma
 #error Please update to __arch_pfn_to_dma
 #endif
@@ -123,7 +125,7 @@
  */
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
-	return dma_addr == ~0;
+	return dma_addr == DMA_ERROR_CODE;
 }
 
 /*
@@ -304,19 +306,17 @@
 /*
  * Private functions
  */
-int dmabounce_sync_for_cpu(struct device *, dma_addr_t, unsigned long,
-		size_t, enum dma_data_direction);
-int dmabounce_sync_for_device(struct device *, dma_addr_t, unsigned long,
-		size_t, enum dma_data_direction);
+int dmabounce_sync_for_cpu(struct device *, dma_addr_t, size_t, enum dma_data_direction);
+int dmabounce_sync_for_device(struct device *, dma_addr_t, size_t, enum dma_data_direction);
 #else
 static inline int dmabounce_sync_for_cpu(struct device *d, dma_addr_t addr,
-	unsigned long offset, size_t size, enum dma_data_direction dir)
+	size_t size, enum dma_data_direction dir)
 {
 	return 1;
 }
 
 static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr,
-	unsigned long offset, size_t size, enum dma_data_direction dir)
+	size_t size, enum dma_data_direction dir)
 {
 	return 1;
 }
@@ -491,6 +491,33 @@
 	__dma_unmap_page(dev, handle, size, dir);
 }
 
+
+static inline void dma_sync_single_for_cpu(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	BUG_ON(!valid_dma_direction(dir));
+
+	debug_dma_sync_single_for_cpu(dev, handle, size, dir);
+
+	if (!dmabounce_sync_for_cpu(dev, handle, size, dir))
+		return;
+
+	__dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir);
+}
+
+static inline void dma_sync_single_for_device(struct device *dev,
+		dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+	BUG_ON(!valid_dma_direction(dir));
+
+	debug_dma_sync_single_for_device(dev, handle, size, dir);
+
+	if (!dmabounce_sync_for_device(dev, handle, size, dir))
+		return;
+
+	__dma_single_cpu_to_dev(dma_to_virt(dev, handle), size, dir);
+}
+
 /**
  * dma_sync_single_range_for_cpu
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
@@ -513,40 +540,14 @@
 		dma_addr_t handle, unsigned long offset, size_t size,
 		enum dma_data_direction dir)
 {
-	BUG_ON(!valid_dma_direction(dir));
-
-	debug_dma_sync_single_for_cpu(dev, handle + offset, size, dir);
-
-	if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir))
-		return;
-
-	__dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir);
+	dma_sync_single_for_cpu(dev, handle + offset, size, dir);
 }
 
 static inline void dma_sync_single_range_for_device(struct device *dev,
 		dma_addr_t handle, unsigned long offset, size_t size,
 		enum dma_data_direction dir)
 {
-	BUG_ON(!valid_dma_direction(dir));
-
-	debug_dma_sync_single_for_device(dev, handle + offset, size, dir);
-
-	if (!dmabounce_sync_for_device(dev, handle, offset, size, dir))
-		return;
-
-	__dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir);
-}
-
-static inline void dma_sync_single_for_cpu(struct device *dev,
-		dma_addr_t handle, size_t size, enum dma_data_direction dir)
-{
-	dma_sync_single_range_for_cpu(dev, handle, 0, size, dir);
-}
-
-static inline void dma_sync_single_for_device(struct device *dev,
-		dma_addr_t handle, size_t size, enum dma_data_direction dir)
-{
-	dma_sync_single_range_for_device(dev, handle, 0, size, dir);
+	dma_sync_single_for_device(dev, handle + offset, size, dir);
 }
 
 /*
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 7b6f42a..84560dc 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -313,7 +313,6 @@
  * We provide our own arch_get_unmapped_area to cope with VIPT caches.
  */
 #define HAVE_ARCH_UNMAPPED_AREA
-#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
 
 /*
  * remap a physical page `pfn' of size `size' with page protection `prot'
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 07209d7..8e2bb29 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -126,8 +126,6 @@
 
 #endif
 
-#define HAVE_ARCH_PICK_MMAP_LAYOUT
-
 #endif
 
 #endif /* __ASM_ARM_PROCESSOR_H */
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 145375d..38f1d2b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -254,7 +254,7 @@
 	select SPARSE_IRQ
 	select MSM_RPM_SMD
 	select REGULATOR
-	select MSM_QDSP6_APR
+	select MSM_QDSP6_APRV2
 	select MSM_QDSP6V2_CODECS
 	select MSM_AUDIO_QDSP6V2 if SND_SOC
 	select MSM_RPM_REGULATOR_SMD
@@ -2136,11 +2136,6 @@
 	help
 	  Enables embedded trace collection on MSM8660
 
-config MSM_SLEEP_STATS
-	bool "Enable exporting of MSM sleep stats to userspace"
-	depends on CPU_IDLE
-	default n
-
 config MSM_SLEEP_STATS_DEVICE
 	bool "Enable exporting of MSM sleep device stats to userspace"
 
@@ -2207,6 +2202,16 @@
 	  used by audio driver to configure QDSP6's
 	  ASM, ADM and AFE.
 
+config MSM_QDSP6_APRV2
+	bool "Audio QDSP6 APRv2 support"
+	depends on MSM_SMD
+	default n
+	help
+	  Enable APRv2 IPC protocol support between
+	  application processor and QDSP6. APR is
+	  used by audio driver to configure QDSP6's
+	  ASM, ADM and AFE.
+
 config MSM_QDSP6_CODECS
 	bool "Audio Codecs on QDSP6 APR "
 	depends on MSM_SMD
@@ -2244,6 +2249,16 @@
           AAC, AMRNB, AMRWB, EVRC, MP3, QCELP among
           others.
 
+config MSM_ADSP_LOADER
+        tristate "ADSP loader support"
+        select SND_SOC_MSM_APRV2_INTF
+	depends on MSM_AUDIO_QDSP6V2 && m
+        help
+          Enable ADSP image loader.
+	  The ADSP loader brings ADSP out of reset
+	  for the platforms that use APRv2.
+	  Say M if you want to enable this module.
+
 config MSM_ULTRASOUND
 	bool "MSM ultrasound support"
 	depends on MSM_AUDIO_QDSP6
@@ -2454,6 +2469,19 @@
 	  algorithm and the algorithm returns a frequency for the core which is
 	  passed to the frequency change driver.
 
+config MSM_CPR
+	tristate "Use MSM CPR in S/W mode"
+	help
+	  Enable CPR (core power reduction) in S/W mode, where the processor
+	  get's the notification from CPR block and programs the PMIC.
+
+config MSM_VP_REGULATOR
+	tristate "Use MSM PMIC8029 C2 regulator"
+	depends on ARCH_MSM8625
+	help
+	  Enable MSM PMIC8029 C2 regulator support using APC_PLEVEL access
+	  for MSMs like 8625.
+
 config HAVE_ARCH_HAS_CURRENT_TIMER
 	bool
 
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 83e559f..f763d49 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -350,7 +350,6 @@
 obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
 
 
-obj-$(CONFIG_MSM_SLEEP_STATS) += idle_stats.o
 obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
 obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_dcvs_idle.o
 obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o
@@ -379,3 +378,9 @@
 obj-$(CONFIG_MSM_HSIC_SYSMON_TEST) += hsic_sysmon_test.o
 
 obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o
+obj-$(CONFIG_MSM_CPR) += msm_cpr.o
+obj-$(CONFIG_MSM_VP_REGULATOR) += msm_vp.o
+
+ifdef CONFIG_MSM_CPR
+obj-$(CONFIG_DEBUG_FS) += msm_cpr-debug.o
+endif
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 1f39d3f..0f1ddc0 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -360,6 +360,7 @@
 };
 
 #define MAX_VOLTAGE_MV          4200
+#define CHG_TERM_MA		100
 static struct pm8921_charger_platform_data
 apq8064_pm8921_chg_pdata __devinitdata = {
 	.safety_time		= 180,
@@ -368,7 +369,7 @@
 	.min_voltage		= 3200,
 	.uvd_thresh_voltage	= 4050,
 	.resume_voltage_delta	= 100,
-	.term_current		= 100,
+	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
 	.warm_temp		= 40,
 	.temp_check_period	= 1,
@@ -389,12 +390,14 @@
 
 static struct pm8921_bms_platform_data
 apq8064_pm8921_bms_pdata __devinitdata = {
-	.battery_type		= BATT_UNKNOWN,
-	.r_sense		= 10,
-	.v_cutoff		= 3400,
-	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
-	.shutdown_soc_valid_limit = 20,
-	.adjust_soc_low_threshold = 25,
+	.battery_type			= BATT_UNKNOWN,
+	.r_sense			= 10,
+	.v_cutoff			= 3400,
+	.max_voltage_uv			= MAX_VOLTAGE_MV * 1000,
+	.rconn_mohm			= 18,
+	.shutdown_soc_valid_limit	= 20,
+	.adjust_soc_low_threshold	= 25,
+	.chg_term_ua			= CHG_TERM_MA * 1000,
 };
 
 static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 68a85c0..ab9004f 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2242,6 +2242,7 @@
 	&apq_lpa_pcm,
 	&apq_compr_dsp,
 	&apq_multi_ch_pcm,
+	&apq_lowlatency_pcm,
 	&apq_pcm_hostless,
 	&apq_cpudai_afe_01_rx,
 	&apq_cpudai_afe_01_tx,
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index c16f55d..e3479eb 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -207,6 +207,7 @@
 };
 
 #define MAX_VOLTAGE_MV		4200
+#define CHG_TERM_MA		100
 static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
 	.safety_time		= 180,
 	.update_time		= 60000,
@@ -214,7 +215,7 @@
 	.min_voltage		= 3200,
 	.uvd_thresh_voltage	= 4050,
 	.resume_voltage_delta	= 100,
-	.term_current		= 100,
+	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
 	.warm_temp		= 40,
 	.temp_check_period	= 1,
@@ -340,12 +341,13 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
-	.battery_type		= BATT_UNKNOWN,
-	.r_sense		= 10,
-	.v_cutoff		= 3400,
-	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
-	.shutdown_soc_valid_limit = 20,
-	.adjust_soc_low_threshold = 25,
+	.battery_type			= BATT_UNKNOWN,
+	.r_sense			= 10,
+	.v_cutoff			= 3400,
+	.max_voltage_uv			= MAX_VOLTAGE_MV * 1000,
+	.shutdown_soc_valid_limit	= 20,
+	.adjust_soc_low_threshold	= 25,
+	.chg_term_ua			= CHG_TERM_MA * 1000,
 };
 
 static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index d5014bd..a7147b5 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2298,6 +2298,7 @@
 	&msm_cpudai_incall_record_tx,
 	&msm_pcm_hostless,
 	&msm_multi_ch_pcm,
+	&msm_lowlatency_pcm,
 };
 
 static void __init msm8930_i2c_init(void)
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 46d317b..8d75ee9 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -394,6 +394,7 @@
 };
 
 #define MAX_VOLTAGE_MV		4200
+#define CHG_TERM_MA		100
 static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
 	.safety_time		= 180,
 	.update_time		= 60000,
@@ -401,7 +402,7 @@
 	.min_voltage		= 3200,
 	.uvd_thresh_voltage	= 4050,
 	.resume_voltage_delta	= 100,
-	.term_current		= 100,
+	.term_current		= CHG_TERM_MA,
 	.cool_temp		= 10,
 	.warm_temp		= 40,
 	.temp_check_period	= 1,
@@ -420,13 +421,14 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
-	.battery_type		= BATT_UNKNOWN,
-	.r_sense		= 10,
-	.v_cutoff		= 3400,
-	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
-	.rconn_mohm		= 18,
-	.shutdown_soc_valid_limit = 20,
-	.adjust_soc_low_threshold = 25,
+	.battery_type			= BATT_UNKNOWN,
+	.r_sense			= 10,
+	.v_cutoff			= 3400,
+	.max_voltage_uv			= MAX_VOLTAGE_MV * 1000,
+	.rconn_mohm			= 18,
+	.shutdown_soc_valid_limit	= 20,
+	.adjust_soc_low_threshold	= 25,
+	.chg_term_ua			= CHG_TERM_MA * 1000,
 };
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 22a5021..641c144 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2695,6 +2695,7 @@
 	&android_usb_device,
 	&msm_pcm,
 	&msm_multi_ch_pcm,
+	&msm_lowlatency_pcm,
 	&msm_pcm_routing,
 	&msm_cpudai0,
 	&msm_cpudai1,
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 7b50db5..b67d982 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -513,7 +513,8 @@
 	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
 	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
 	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
-	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))| \
+	(1<<MSM_ADSP_CODEC_AC3)
 #define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
 	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
 	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 95ec7ca..6fa45c6 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -459,7 +459,8 @@
 	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
 	(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
 	(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
-	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+	(1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))| \
+	(1<<MSM_ADSP_CODEC_AC3)
 #define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
 	(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
 	(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 91e9272..e4bcfa9 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -770,6 +770,7 @@
 static DEFINE_CLK_VOTER(ocmemgx_gfx3d_clk, &ocmemgx_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ocmemgx_msmbus_clk, &ocmemgx_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ocmemgx_core_clk, &ocmemgx_clk.c, LONG_MAX);
 
 static DEFINE_CLK_VOTER(pnoc_sdcc1_clk, &pnoc_clk.c, 0);
 static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, 0);
@@ -5006,6 +5007,8 @@
 	CLK_LOOKUP("core_clk", oxilicx_axi_clk.c, "fdb10000.qcom,iommu"),
 	CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb10000.qcom,iommu"),
 	CLK_LOOKUP("alt_core_clk", oxili_gfx3d_clk.c, "fdb10000.qcom,iommu"),
+	CLK_LOOKUP("core_clk", ocmemgx_core_clk.c, "fdd00000.qcom,ocmem"),
+	CLK_LOOKUP("iface_clk", ocmemcx_ocmemnoc_clk.c, "fdd00000.qcom,ocmem"),
 	CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdc84000.qcom,iommu"),
 	CLK_LOOKUP("alt_core_clk", venus0_vcodec0_clk.c, "fdc84000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", venus0_axi_clk.c, "fdc84000.qcom,iommu"),
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index e4ec4d4..de97186 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -68,29 +68,6 @@
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
 };
 
-
-#ifdef CONFIG_MSM_SLEEP_STATS
-static DEFINE_PER_CPU(struct atomic_notifier_head, msm_cpuidle_notifiers);
-
-int msm_cpuidle_register_notifier(unsigned int cpu, struct notifier_block *nb)
-{
-	struct atomic_notifier_head *head =
-		&per_cpu(msm_cpuidle_notifiers, cpu);
-
-	return atomic_notifier_chain_register(head, nb);
-}
-EXPORT_SYMBOL(msm_cpuidle_register_notifier);
-
-int msm_cpuidle_unregister_notifier(unsigned int cpu, struct notifier_block *nb)
-{
-	struct atomic_notifier_head *head =
-		&per_cpu(msm_cpuidle_notifiers, cpu);
-
-	return atomic_notifier_chain_unregister(head, nb);
-}
-EXPORT_SYMBOL(msm_cpuidle_unregister_notifier);
-#endif
-
 static int msm_cpuidle_enter(
 	struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
 {
@@ -98,17 +75,9 @@
 	int i = 0;
 	enum msm_pm_sleep_mode pm_mode;
 	struct cpuidle_state_usage *st_usage = NULL;
-#ifdef CONFIG_MSM_SLEEP_STATS
-	struct atomic_notifier_head *head =
-			&__get_cpu_var(msm_cpuidle_notifiers);
-#endif
 
 	local_irq_disable();
 
-#ifdef CONFIG_MSM_SLEEP_STATS
-	atomic_notifier_call_chain(head, MSM_CPUIDLE_STATE_ENTER, NULL);
-#endif
-
 #ifdef CONFIG_CPU_PM
 	cpu_pm_enter();
 #endif
@@ -128,10 +97,6 @@
 	cpu_pm_exit();
 #endif
 
-#ifdef CONFIG_MSM_SLEEP_STATS
-	atomic_notifier_call_chain(head, MSM_CPUIDLE_STATE_EXIT, NULL);
-#endif
-
 	local_irq_enable();
 
 	return ret;
@@ -219,16 +184,3 @@
 
 	return 0;
 }
-
-static int __init msm_cpuidle_early_init(void)
-{
-#ifdef CONFIG_MSM_SLEEP_STATS
-	unsigned int cpu;
-
-	for_each_possible_cpu(cpu)
-		ATOMIC_INIT_NOTIFIER_HEAD(&per_cpu(msm_cpuidle_notifiers, cpu));
-#endif
-	return 0;
-}
-
-early_initcall(msm_cpuidle_early_init);
diff --git a/arch/arm/mach-msm/dal_axi.c b/arch/arm/mach-msm/dal_axi.c
index 739b7dc..1d873ca 100644
--- a/arch/arm/mach-msm/dal_axi.c
+++ b/arch/arm/mach-msm/dal_axi.c
@@ -17,6 +17,8 @@
 #define DALRPC_PORT_NAME  "DAL00"
 
 enum {
+	DALRPC_AXI_ALLOCATE = DALDEVICE_FIRST_DEVICE_API_IDX + 1,
+	DALRPC_AXI_FREE = DALDEVICE_FIRST_DEVICE_API_IDX + 2,
 	DALRPC_AXI_CONFIGURE_BRIDGE = DALDEVICE_FIRST_DEVICE_API_IDX + 11
 };
 
@@ -38,6 +40,67 @@
 
 };
 
+static void *cam_dev_handle;
+static int __axi_free(int mode)
+{
+	int rc = 0;
+
+	if (!cam_dev_handle)
+		return rc;
+
+	rc = dalrpc_fcn_0(DALRPC_AXI_FREE, cam_dev_handle, mode);
+	if (rc) {
+		printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+			__func__, rc);
+		goto fail_dal_fcn_0;
+	}
+
+	/* close device handle */
+	rc = daldevice_detach(cam_dev_handle);
+	if (rc) {
+		printk(KERN_ERR "%s: failed to detach AXI bus device (%d)\n",
+			__func__, rc);
+		goto fail_dal_attach_detach;
+	}
+	cam_dev_handle = NULL;
+	return 0;
+
+fail_dal_fcn_0:
+	(void)daldevice_detach(cam_dev_handle);
+	cam_dev_handle = NULL;
+fail_dal_attach_detach:
+	return rc;
+}
+
+static int __axi_allocate(int mode)
+{
+	int rc;
+
+	/* get device handle */
+	rc = daldevice_attach(DALDEVICEID_AXI, DALRPC_PORT_NAME,
+				DALRPC_DEST_MODEM, &cam_dev_handle);
+	if (rc) {
+		printk(KERN_ERR "%s: failed to attach AXI bus device (%d)\n",
+			__func__, rc);
+		goto fail_dal_attach_detach;
+	}
+
+	rc = dalrpc_fcn_0(DALRPC_AXI_ALLOCATE, cam_dev_handle, mode);
+	if (rc) {
+		printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+			__func__, rc);
+		goto fail_dal_fcn_0;
+	}
+
+	return 0;
+
+fail_dal_fcn_0:
+	(void)daldevice_detach(cam_dev_handle);
+	cam_dev_handle = NULL;
+fail_dal_attach_detach:
+	return rc;
+}
+
 static int axi_configure_bridge_grfx_sync_mode(int bridge_mode)
 {
 	int rc;
@@ -82,7 +145,15 @@
 	return rc;
 }
 
+int axi_free(mode)
+{
+	return __axi_free(mode);
+}
 
+int axi_allocate(mode)
+{
+	return __axi_allocate(mode);
+}
 
 int set_grp2d_async(void)
 {
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index e5261b0..c6a0441 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -736,6 +736,11 @@
 	.id     = -1,
 };
 
+struct platform_device apq_lowlatency_pcm = {
+	.name   = "msm-lowlatency-pcm-dsp",
+	.id     = -1,
+};
+
 struct platform_device apq_pcm_hostless = {
 	.name	= "msm-pcm-hostless",
 	.id	= -1,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index ecfafa8..8a4b3f4 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1954,6 +1954,11 @@
 	.id	= -1,
 };
 
+struct platform_device msm_lowlatency_pcm = {
+	.name	= "msm-lowlatency-pcm-dsp",
+	.id	= -1,
+};
+
 struct platform_device msm_pcm_routing = {
 	.name	= "msm-pcm-routing",
 	.id	= -1,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 55c1e03..3587672 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -206,6 +206,7 @@
 
 extern struct platform_device msm_pcm;
 extern struct platform_device msm_multi_ch_pcm;
+extern struct platform_device msm_lowlatency_pcm;
 extern struct platform_device msm_pcm_routing;
 extern struct platform_device msm_cpudai0;
 extern struct platform_device msm_cpudai1;
@@ -269,6 +270,7 @@
 extern struct platform_device apq_lpa_pcm;
 extern struct platform_device apq_compr_dsp;
 extern struct platform_device apq_multi_ch_pcm;
+extern struct platform_device apq_lowlatency_pcm;
 extern struct platform_device apq_pcm_hostless;
 extern struct platform_device apq_cpudai_afe_01_rx;
 extern struct platform_device apq_cpudai_afe_01_tx;
diff --git a/arch/arm/mach-msm/idle_stats.c b/arch/arm/mach-msm/idle_stats.c
deleted file mode 100644
index f4d3a27..0000000
--- a/arch/arm/mach-msm/idle_stats.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/cdev.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/hrtimer.h>
-#include <linux/interrupt.h>
-#include <linux/ktime.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-#include <linux/sched.h>
-#include <asm/uaccess.h>
-
-#include "idle_stats.h"
-#include <mach/cpuidle.h>
-
-/******************************************************************************
- * Debug Definitions
- *****************************************************************************/
-
-enum {
-	MSM_IDLE_STATS_DEBUG_API = BIT(0),
-	MSM_IDLE_STATS_DEBUG_SIGNAL = BIT(1),
-	MSM_IDLE_STATS_DEBUG_MIGRATION = BIT(2),
-};
-
-static int msm_idle_stats_debug_mask;
-module_param_named(
-	debug_mask, msm_idle_stats_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-
-/******************************************************************************
- * Driver Definitions
- *****************************************************************************/
-
-#define MSM_IDLE_STATS_DRIVER_NAME "msm_idle_stats"
-
-static dev_t msm_idle_stats_dev_nr;
-static struct cdev msm_idle_stats_cdev;
-static struct class *msm_idle_stats_class;
-
-/******************************************************************************
- * Device Definitions
- *****************************************************************************/
-
-struct msm_idle_stats_device {
-	unsigned int cpu;
-	struct mutex mutex;
-	struct notifier_block notifier;
-
-	int64_t collection_expiration;
-	struct msm_idle_stats stats;
-	struct hrtimer timer;
-
-	wait_queue_head_t wait_q;
-	atomic_t collecting;
-};
-
-static DEFINE_SPINLOCK(msm_idle_stats_devs_lock);
-static DEFINE_PER_CPU(struct msm_idle_stats_device *, msm_idle_stats_devs);
-
-/******************************************************************************
- *
- *****************************************************************************/
-
-static inline int64_t msm_idle_stats_bound_interval(int64_t interval)
-{
-	if (interval <= 0)
-		return 1;
-
-	if (interval > UINT_MAX)
-		return UINT_MAX;
-
-	return interval;
-}
-
-static enum hrtimer_restart msm_idle_stats_timer(struct hrtimer *timer)
-{
-	struct msm_idle_stats_device *stats_dev;
-	unsigned int cpu;
-	int64_t now;
-	int64_t interval;
-
-	stats_dev = container_of(timer, struct msm_idle_stats_device, timer);
-	cpu = get_cpu();
-
-	if (cpu != stats_dev->cpu) {
-		if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_MIGRATION)
-			pr_info("%s: timer migrated from cpu%u to cpu%u\n",
-				__func__, stats_dev->cpu, cpu);
-
-		stats_dev->stats.event = MSM_IDLE_STATS_EVENT_TIMER_MIGRATED;
-		goto timer_exit;
-	}
-
-	now = ktime_to_us(ktime_get());
-	interval = now - stats_dev->stats.last_busy_start;
-
-	if (stats_dev->stats.busy_timer > 0 &&
-			interval >= stats_dev->stats.busy_timer - 1)
-		stats_dev->stats.event =
-			MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED;
-	else
-		stats_dev->stats.event =
-			MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED;
-
-timer_exit:
-	atomic_set(&stats_dev->collecting, 0);
-	wake_up_interruptible(&stats_dev->wait_q);
-
-	put_cpu();
-	return HRTIMER_NORESTART;
-}
-
-static void msm_idle_stats_pre_idle(struct msm_idle_stats_device *stats_dev)
-{
-	int64_t now;
-	int64_t interval;
-
-	if (smp_processor_id() != stats_dev->cpu) {
-		WARN_ON(1);
-		return;
-	}
-
-	if (!atomic_read(&stats_dev->collecting))
-		return;
-
-	hrtimer_cancel(&stats_dev->timer);
-
-	now = ktime_to_us(ktime_get());
-	interval = now - stats_dev->stats.last_busy_start;
-	interval = msm_idle_stats_bound_interval(interval);
-
-	stats_dev->stats.busy_intervals[stats_dev->stats.nr_collected]
-		= (__u32) interval;
-	stats_dev->stats.last_idle_start = now;
-}
-
-static void msm_idle_stats_post_idle(struct msm_idle_stats_device *stats_dev)
-{
-	int64_t now;
-	int64_t interval;
-	int64_t timer_interval;
-	int rc;
-
-	if (smp_processor_id() != stats_dev->cpu) {
-		WARN_ON(1);
-		return;
-	}
-
-	if (!atomic_read(&stats_dev->collecting))
-		return;
-
-	now = ktime_to_us(ktime_get());
-	interval = now - stats_dev->stats.last_idle_start;
-	interval = msm_idle_stats_bound_interval(interval);
-
-	stats_dev->stats.idle_intervals[stats_dev->stats.nr_collected]
-		= (__u32) interval;
-	stats_dev->stats.nr_collected++;
-	stats_dev->stats.last_busy_start = now;
-
-	if (stats_dev->stats.nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS) {
-		stats_dev->stats.event = MSM_IDLE_STATS_EVENT_COLLECTION_FULL;
-		goto post_idle_collection_done;
-	}
-
-	timer_interval = stats_dev->collection_expiration - now;
-	if (timer_interval <= 0) {
-		stats_dev->stats.event =
-			MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED;
-		goto post_idle_collection_done;
-	}
-
-	if (stats_dev->stats.busy_timer > 0 &&
-			timer_interval > stats_dev->stats.busy_timer)
-		timer_interval = stats_dev->stats.busy_timer;
-
-	rc = hrtimer_start(&stats_dev->timer,
-		ktime_set(0, timer_interval * 1000), HRTIMER_MODE_REL_PINNED);
-	WARN_ON(rc);
-
-	return;
-
-post_idle_collection_done:
-	atomic_set(&stats_dev->collecting, 0);
-	wake_up_interruptible(&stats_dev->wait_q);
-}
-
-static int msm_idle_stats_notified(struct notifier_block *nb,
-	unsigned long val, void *v)
-{
-	struct msm_idle_stats_device *stats_dev = container_of(
-				nb, struct msm_idle_stats_device, notifier);
-
-	if (val == MSM_CPUIDLE_STATE_EXIT)
-		msm_idle_stats_post_idle(stats_dev);
-	else
-		msm_idle_stats_pre_idle(stats_dev);
-
-	return 0;
-}
-
-static int msm_idle_stats_collect(struct file *filp,
-				  unsigned int cmd, unsigned long arg)
-{
-	struct msm_idle_stats_device *stats_dev;
-	struct msm_idle_stats *stats;
-	int rc;
-
-	stats_dev = (struct msm_idle_stats_device *) filp->private_data;
-	stats = &stats_dev->stats;
-
-	rc = mutex_lock_interruptible(&stats_dev->mutex);
-	if (rc) {
-		if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_SIGNAL)
-			pr_info("%s: interrupted while waiting on device "
-				"mutex\n", __func__);
-
-		rc = -EINTR;
-		goto collect_exit;
-	}
-
-	if (atomic_read(&stats_dev->collecting)) {
-		pr_err("%s: inconsistent state\n", __func__);
-		rc = -EBUSY;
-		goto collect_unlock_exit;
-	}
-
-	rc = copy_from_user(stats, (void *)arg, sizeof(*stats));
-	if (rc) {
-		rc = -EFAULT;
-		goto collect_unlock_exit;
-	}
-
-	if (stats->nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS ||
-			stats->busy_timer > MSM_IDLE_STATS_MAX_TIMER ||
-			stats->collection_timer > MSM_IDLE_STATS_MAX_TIMER) {
-		rc = -EINVAL;
-		goto collect_unlock_exit;
-	}
-
-	if (get_cpu() != stats_dev->cpu) {
-		put_cpu();
-		rc = -EACCES;
-		goto collect_unlock_exit;
-	}
-
-	/*
-	 * When collection_timer == 0, stop collecting at the next
-	 * post idle.
-	 */
-	stats_dev->collection_expiration =
-		ktime_to_us(ktime_get()) + stats->collection_timer;
-
-	/*
-	 * Enable collection before starting any timer.
-	 */
-	atomic_set(&stats_dev->collecting, 1);
-
-	/*
-	 * When busy_timer == 0, do not set any busy timer.
-	 */
-	if (stats->busy_timer > 0) {
-		rc = hrtimer_start(&stats_dev->timer,
-			ktime_set(0, stats->busy_timer * 1000),
-			HRTIMER_MODE_REL_PINNED);
-		WARN_ON(rc);
-	}
-
-	put_cpu();
-	if (wait_event_interruptible(stats_dev->wait_q,
-			!atomic_read(&stats_dev->collecting))) {
-		if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_SIGNAL)
-			pr_info("%s: interrupted while waiting on "
-				"collection\n", __func__);
-
-		hrtimer_cancel(&stats_dev->timer);
-		atomic_set(&stats_dev->collecting, 0);
-
-		rc = -EINTR;
-		goto collect_unlock_exit;
-	}
-
-	stats->return_timestamp = ktime_to_us(ktime_get());
-
-	rc = copy_to_user((void *)arg, stats, sizeof(*stats));
-	if (rc) {
-		rc = -EFAULT;
-		goto collect_unlock_exit;
-	}
-
-collect_unlock_exit:
-	mutex_unlock(&stats_dev->mutex);
-
-collect_exit:
-	return rc;
-}
-
-static int msm_idle_stats_open(struct inode *inode, struct file *filp)
-{
-	struct msm_idle_stats_device *stats_dev;
-	int rc;
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: enter\n", __func__);
-
-	rc = nonseekable_open(inode, filp);
-	if (rc) {
-		pr_err("%s: failed to set nonseekable\n", __func__);
-		goto open_bail;
-	}
-
-	stats_dev = (struct msm_idle_stats_device *)
-			kzalloc(sizeof(*stats_dev), GFP_KERNEL);
-	if (!stats_dev) {
-		pr_err("%s: failed to allocate device struct\n", __func__);
-		rc = -ENOMEM;
-		goto open_bail;
-	}
-
-	stats_dev->cpu = MINOR(inode->i_rdev);
-	mutex_init(&stats_dev->mutex);
-	stats_dev->notifier.notifier_call = msm_idle_stats_notified;
-	hrtimer_init(&stats_dev->timer,
-			CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
-	stats_dev->timer.function = msm_idle_stats_timer;
-	init_waitqueue_head(&stats_dev->wait_q);
-	atomic_set(&stats_dev->collecting, 0);
-
-	filp->private_data = stats_dev;
-
-	/*
-	 * Make sure only one device exists per cpu.
-	 */
-	spin_lock(&msm_idle_stats_devs_lock);
-	if (per_cpu(msm_idle_stats_devs, stats_dev->cpu)) {
-		spin_unlock(&msm_idle_stats_devs_lock);
-		rc = -EBUSY;
-		goto open_free_bail;
-	}
-
-	per_cpu(msm_idle_stats_devs, stats_dev->cpu) = stats_dev;
-	spin_unlock(&msm_idle_stats_devs_lock);
-
-	rc = msm_cpuidle_register_notifier(stats_dev->cpu,
-						&stats_dev->notifier);
-	if (rc) {
-		pr_err("%s: failed to register idle notification\n", __func__);
-		goto open_null_bail;
-	}
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: done\n", __func__);
-	return 0;
-
-open_null_bail:
-	spin_lock(&msm_idle_stats_devs_lock);
-	per_cpu(msm_idle_stats_devs, stats_dev->cpu) = NULL;
-	spin_unlock(&msm_idle_stats_devs_lock);
-
-open_free_bail:
-	kfree(stats_dev);
-
-open_bail:
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: exit, %d\n", __func__, rc);
-	return rc;
-}
-
-static int msm_idle_stats_release(struct inode *inode, struct file *filp)
-{
-	struct msm_idle_stats_device *stats_dev;
-	int rc;
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: enter\n", __func__);
-
-	stats_dev = (struct msm_idle_stats_device *) filp->private_data;
-	rc = msm_cpuidle_unregister_notifier(stats_dev->cpu,
-						&stats_dev->notifier);
-	WARN_ON(rc);
-
-	spin_lock(&msm_idle_stats_devs_lock);
-	per_cpu(msm_idle_stats_devs, stats_dev->cpu) = NULL;
-	spin_unlock(&msm_idle_stats_devs_lock);
-	filp->private_data = NULL;
-
-	hrtimer_cancel(&stats_dev->timer);
-	kfree(stats_dev);
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: done\n", __func__);
-	return 0;
-}
-
-static long msm_idle_stats_ioctl(struct file *filp, unsigned int cmd,
-				unsigned long arg)
-{
-	int rc;
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: enter\n", __func__);
-
-	switch (cmd) {
-	case MSM_IDLE_STATS_IOC_COLLECT:
-		rc = msm_idle_stats_collect(filp, cmd, arg);
-		break;
-
-	default:
-		rc = -ENOTTY;
-		break;
-	}
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: exit, %d\n", __func__, rc);
-	return rc;
-}
-
-/******************************************************************************
- *
- *****************************************************************************/
-
-static const struct file_operations msm_idle_stats_fops = {
-	.owner   = THIS_MODULE,
-	.open    = msm_idle_stats_open,
-	.release = msm_idle_stats_release,
-	.unlocked_ioctl   = msm_idle_stats_ioctl,
-};
-
-static int __init msm_idle_stats_init(void)
-{
-	unsigned int nr_cpus = num_possible_cpus();
-	struct device *dev;
-	int rc;
-	int i;
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: enter\n", __func__);
-
-	rc = alloc_chrdev_region(&msm_idle_stats_dev_nr,
-			0, nr_cpus, MSM_IDLE_STATS_DRIVER_NAME);
-	if (rc) {
-		pr_err("%s: failed to allocate device number, rc %d\n",
-			__func__, rc);
-		goto init_bail;
-	}
-
-	msm_idle_stats_class = class_create(THIS_MODULE,
-					MSM_IDLE_STATS_DRIVER_NAME);
-	if (IS_ERR(msm_idle_stats_class)) {
-		pr_err("%s: failed to create device class\n", __func__);
-		rc = -ENOMEM;
-		goto init_unreg_bail;
-	}
-
-	for (i = 0; i < nr_cpus; i++) {
-		dev = device_create(msm_idle_stats_class, NULL,
-				msm_idle_stats_dev_nr + i, NULL,
-				MSM_IDLE_STATS_DRIVER_NAME "%d", i);
-
-		if (!dev) {
-			pr_err("%s: failed to create device %d\n",
-				__func__, i);
-			rc = -ENOMEM;
-			goto init_remove_bail;
-		}
-	}
-
-	cdev_init(&msm_idle_stats_cdev, &msm_idle_stats_fops);
-	msm_idle_stats_cdev.owner = THIS_MODULE;
-
-	/*
-	 * Call cdev_add() last, after everything else is initialized and
-	 * the driver is ready to accept system calls.
-	 */
-	rc = cdev_add(&msm_idle_stats_cdev, msm_idle_stats_dev_nr, nr_cpus);
-	if (rc) {
-		pr_err("%s: failed to register char device, rc %d\n",
-			__func__, rc);
-		goto init_remove_bail;
-	}
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: done\n", __func__);
-	return 0;
-
-init_remove_bail:
-	for (i = i - 1; i >= 0; i--)
-		device_destroy(
-			msm_idle_stats_class, msm_idle_stats_dev_nr + i);
-
-	class_destroy(msm_idle_stats_class);
-
-init_unreg_bail:
-	unregister_chrdev_region(msm_idle_stats_dev_nr, nr_cpus);
-
-init_bail:
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: exit, %d\n", __func__, rc);
-	return rc;
-}
-
-static void __exit msm_idle_stats_exit(void)
-{
-	unsigned int nr_cpus = num_possible_cpus();
-	int i;
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: enter\n", __func__);
-
-	cdev_del(&msm_idle_stats_cdev);
-
-	for (i = nr_cpus - 1; i >= 0; i--)
-		device_destroy(
-			msm_idle_stats_class, msm_idle_stats_dev_nr + i);
-
-	class_destroy(msm_idle_stats_class);
-	unregister_chrdev_region(msm_idle_stats_dev_nr, nr_cpus);
-
-	if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
-		pr_info("%s: done\n", __func__);
-}
-
-module_init(msm_idle_stats_init);
-module_exit(msm_idle_stats_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("idle stats driver");
-MODULE_VERSION("1.0");
diff --git a/arch/arm/mach-msm/idle_stats.h b/arch/arm/mach-msm/idle_stats.h
deleted file mode 100644
index 6c8db1e..0000000
--- a/arch/arm/mach-msm/idle_stats.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __ARCH_ARM_MACH_MSM_IDLE_STATS_H
-#define __ARCH_ARM_MACH_MSM_IDLE_STATS_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-enum msm_idle_stats_event {
-	MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED = 1,
-	MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED = 2,
-	MSM_IDLE_STATS_EVENT_COLLECTION_FULL = 3,
-	MSM_IDLE_STATS_EVENT_TIMER_MIGRATED = 4,
-};
-
-/*
- * All time, timer, and time interval values are in units of
- * microseconds unless stated otherwise.
- */
-#define MSM_IDLE_STATS_NR_MAX_INTERVALS 100
-#define MSM_IDLE_STATS_MAX_TIMER 1000000
-
-struct msm_idle_stats {
-	__u32 busy_timer;
-	__u32 collection_timer;
-
-	__u32 busy_intervals[MSM_IDLE_STATS_NR_MAX_INTERVALS];
-	__u32 idle_intervals[MSM_IDLE_STATS_NR_MAX_INTERVALS];
-	__u32 nr_collected;
-	__s64 last_busy_start;
-	__s64 last_idle_start;
-
-	enum msm_idle_stats_event event;
-	__s64 return_timestamp;
-};
-
-#define MSM_IDLE_STATS_IOC_MAGIC  0xD8
-#define MSM_IDLE_STATS_IOC_COLLECT  \
-		_IOWR(MSM_IDLE_STATS_IOC_MAGIC, 1, struct msm_idle_stats)
-
-#endif  /* __ARCH_ARM_MACH_MSM_IDLE_STATS_H */
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index f529522..ab246a5 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -334,6 +334,7 @@
 	MSM_ADSP_CODEC_AMRWB = 11,
 	MSM_ADSP_CODEC_EVRC = 12,
 	MSM_ADSP_CODEC_WMAPRO = 13,
+	MSM_ADSP_CODEC_AC3 = 23,
 	MSM_ADSP_MODE_TUNNEL = 24,
 	MSM_ADSP_MODE_NONTUNNEL = 25,
 	MSM_ADSP_MODE_LP = 26,
diff --git a/arch/arm/mach-msm/include/mach/cpuidle.h b/arch/arm/mach-msm/include/mach/cpuidle.h
index 8566e7f..af773a0 100644
--- a/arch/arm/mach-msm/include/mach/cpuidle.h
+++ b/arch/arm/mach-msm/include/mach/cpuidle.h
@@ -37,23 +37,4 @@
 static inline int msm_cpuidle_init(void) { return -ENOSYS; }
 #endif
 
-#ifdef CONFIG_MSM_SLEEP_STATS
-enum {
-	MSM_CPUIDLE_STATE_ENTER,
-	MSM_CPUIDLE_STATE_EXIT
-};
-
-int msm_cpuidle_register_notifier(unsigned int cpu,
-		struct notifier_block *nb);
-int msm_cpuidle_unregister_notifier(unsigned int cpu,
-		struct notifier_block *nb);
-#else
-static inline int msm_cpuidle_register_notifier(unsigned int cpu,
-		struct notifier_block *nb)
-{ return -ENODEV; }
-static inline int msm_cpuidle_unregister_notifier(unsigned int cpu,
-		struct notifier_block *nb)
-{ return -ENODEV; }
-#endif
-
 #endif /* __ARCH_ARM_MACH_MSM_CPUIDLE_H */
diff --git a/arch/arm/mach-msm/include/mach/dal_axi.h b/arch/arm/mach-msm/include/mach/dal_axi.h
index 4e32aa3..84cd37f 100644
--- a/arch/arm/mach-msm/include/mach/dal_axi.h
+++ b/arch/arm/mach-msm/include/mach/dal_axi.h
@@ -17,5 +17,7 @@
 int set_grp2d_async(void);
 int set_grp3d_async(void);
 int set_grp_xbar_async(void);
-
+int axi_allocate(int mode);
+int axi_free(int mode);
+#define AXI_FLOW_VIEWFINDER_HI	243
 #endif  /* _DAL_AXI_H */
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
index fb61d54..1458afe 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
@@ -37,6 +37,9 @@
 #define MSM8974_TLMM_PHYS	0xFD510000
 #define MSM8974_TLMM_SIZE	SZ_16K
 
+#define MSM8974_MPM2_PSHOLD_PHYS	0xFC4AB000
+#define MSM8974_MPM2_PSHOLD_SIZE	SZ_4K
+
 #ifdef CONFIG_DEBUG_MSM8974_UART
 #define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
 #define MSM_DEBUG_UART_PHYS	0xF991E000
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index 4f90ea5..17156b1 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -126,6 +126,9 @@
 #define MSM_HDMI_PHYS		0x04A00000
 #define MSM_HDMI_SIZE		SZ_4K
 
+/* Needed to keep the unified iomap happy */
+#define MSM_MPM2_PSHOLD_BASE	MSM_TLMM_BASE
+
 #ifdef CONFIG_DEBUG_MSM8660_UART
 #define MSM_DEBUG_UART_BASE	0xFBC40000
 #define MSM_DEBUG_UART_PHYS	0x19C40000
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 7085db7..4c849d4 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -93,6 +93,7 @@
 #define MSM_SCU_BASE		IOMEM(0xFA104000)	/*  4K */
 #define MSM_CFG_CTL_BASE	IOMEM(0xFA105000)	/*  4K */
 #define MSM_CLK_CTL_SH2_BASE	IOMEM(0xFA106000)	/*  4K */
+#define MSM_MPM2_PSHOLD_BASE	IOMEM(0xFA107000)	/*  4k */
 #define MSM_MDC_BASE		IOMEM(0xFA400000)	/*  1M */
 #define MSM_AD5_BASE		IOMEM(0xFA900000)	/*  13M (D00000)
 							  0xFB600000 */
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index e20e768..a5b0275 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -17,6 +17,7 @@
  *  Client drivers should use wrappers available in ocmem.h
  **/
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <asm/io.h>
 #include <mach/msm_iomap.h>
 #include "ocmem.h"
@@ -74,6 +75,8 @@
 	void __iomem *vbase;
 	unsigned long size;
 	unsigned long base;
+	struct clk *core_clk;
+	struct clk *iface_clk;
 	struct ocmem_partition *parts;
 	int nr_parts;
 	void __iomem *reg_base;
@@ -208,4 +211,8 @@
 unsigned long process_quota(int);
 int ocmem_memory_off(int, unsigned long, unsigned long);
 int ocmem_memory_on(int, unsigned long, unsigned long);
+int ocmem_enable_core_clock(void);
+int ocmem_enable_iface_clock(void);
+void ocmem_disable_core_clock(void);
+void ocmem_disable_iface_clock(void);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
index 98f20a2..3115299 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
@@ -414,6 +414,7 @@
 /*
  * Command Structure to configure Per decoder Parameters (AMRWB)
  */
+#define ADEC_PARAMS_AC3_INDEX 14
 
 struct audpp_cmd_cfg_adec_params_amrwb {
 	   audpp_cmd_cfg_adec_params_common     common;
@@ -424,6 +425,18 @@
 	sizeof(struct audpp_cmd_cfg_adec_params_amrwb)
 
 /*
+ * Command Structure to configure Per decoder Parameters (AC3)
+ */
+
+struct audpp_cmd_cfg_adec_params_ac3 {
+	audpp_cmd_cfg_adec_params_common	common;
+	unsigned short				index[ADEC_PARAMS_AC3_INDEX];
+} __packed;
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AC3_LEN \
+	sizeof(struct audpp_cmd_cfg_adec_params_ac3)
+
+/*
  * Command Structure to configure the  HOST PCM interface
  */
 
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index 62d7a33..296f222 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -13,13 +13,18 @@
 #ifndef __APR_H_
 #define __APR_H_
 
-#define APR_Q6_NOIMG   0
-#define APR_Q6_LOADING 1
-#define APR_Q6_LOADED  2
+#include <linux/mutex.h>
+
+enum apr_subsys_state {
+	APR_SUBSYS_DOWN,
+	APR_SUBSYS_UP,
+	APR_SUBSYS_LOADED,
+};
 
 struct apr_q6 {
 	void *pil;
-	uint32_t state;
+	atomic_t q6_state;
+	atomic_t modem_state;
 	struct mutex lock;
 };
 
@@ -138,6 +143,12 @@
 	struct apr_svc svc[APR_SVC_MAX];
 };
 
+int apr_load_adsp_image(void);
+struct apr_client *apr_get_client(int dest_id, int client_id);
+int apr_wait_for_device_up(int dest_id);
+int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
+		int *svc_idx, int *svc_id);
+void apr_cb_func(void *buf, int len, void *priv);
 struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
 					uint32_t src_port, void *priv);
 inline int apr_fill_hdr(void *handle, uint32_t *buf, uint16_t src_port,
@@ -149,4 +160,9 @@
 void change_q6_state(int state);
 void q6audio_dsp_not_responding(void);
 void apr_reset(void *handle);
+enum apr_subsys_state apr_get_modem_state(void);
+void apr_set_modem_state(enum apr_subsys_state state);
+enum apr_subsys_state apr_get_q6_state(void);
+int apr_set_q6_state(enum apr_subsys_state state);
+void apr_set_subsys_state(void);
 #endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index a2f2c31..89964de 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -300,6 +300,7 @@
 	MSM_CHIP_DEVICE(QGIC_CPU, MSM8974),
 	MSM_CHIP_DEVICE(APCS_GCC, MSM8974),
 	MSM_CHIP_DEVICE(TLMM, MSM8974),
+	MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8974),
 	{
 		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
 		.length =   MSM_SHARED_RAM_SIZE,
diff --git a/arch/arm/mach-msm/msm_cpr-debug.c b/arch/arm/mach-msm/msm_cpr-debug.c
new file mode 100644
index 0000000..723423c
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr-debug.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+struct msm_cpr_debug_device {
+	struct mutex	debug_mutex;
+	struct dentry	*dir;
+	int		addr_offset;
+	void __iomem	*base;
+};
+
+static inline
+void write_reg(struct msm_cpr_debug_device *cpr, u32 value)
+{
+	writel_relaxed(value, cpr->base + cpr->addr_offset);
+}
+
+static inline u32 read_reg(struct msm_cpr_debug_device *cpr)
+{
+	return readl_relaxed(cpr->base + cpr->addr_offset);
+}
+
+static bool msm_cpr_debug_addr_is_valid(int addr)
+{
+	if (addr < 0 || addr > 0x15C) {
+		pr_err("CPR register address is invalid: %d\n", addr);
+		return false;
+	}
+	return true;
+}
+
+static int msm_cpr_debug_data_set(void *data, u64 val)
+{
+	struct msm_cpr_debug_device *debugdev = data;
+	uint32_t reg = val;
+
+	mutex_lock(&debugdev->debug_mutex);
+
+	if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset))
+		write_reg(debugdev, reg);
+
+	mutex_unlock(&debugdev->debug_mutex);
+	return 0;
+}
+
+static int msm_cpr_debug_data_get(void *data, u64 *val)
+{
+	struct msm_cpr_debug_device *debugdev = data;
+	uint32_t reg;
+
+	mutex_lock(&debugdev->debug_mutex);
+
+	if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset)) {
+		reg = read_reg(debugdev);
+		*val = reg;
+	}
+	mutex_unlock(&debugdev->debug_mutex);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, msm_cpr_debug_data_get,
+			msm_cpr_debug_data_set, "0x%02llX\n");
+
+static int msm_cpr_debug_addr_set(void *data, u64 val)
+{
+	struct msm_cpr_debug_device *debugdev = data;
+
+	if (msm_cpr_debug_addr_is_valid(val)) {
+		mutex_lock(&debugdev->debug_mutex);
+		debugdev->addr_offset = val;
+		mutex_unlock(&debugdev->debug_mutex);
+	}
+
+	return 0;
+}
+
+static int msm_cpr_debug_addr_get(void *data, u64 *val)
+{
+	struct msm_cpr_debug_device *debugdev = data;
+
+	mutex_lock(&debugdev->debug_mutex);
+
+	if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset))
+		*val = debugdev->addr_offset;
+
+	mutex_unlock(&debugdev->debug_mutex);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, msm_cpr_debug_addr_get,
+			msm_cpr_debug_addr_set, "0x%03llX\n");
+
+int msm_cpr_debug_init(void *data)
+{
+	char *name = "cpr-debug";
+	struct msm_cpr_debug_device *debugdev;
+	struct dentry *dir;
+	struct dentry *temp;
+	int rc;
+
+	debugdev = kzalloc(sizeof(struct msm_cpr_debug_device), GFP_KERNEL);
+	if (debugdev == NULL) {
+		pr_err("kzalloc failed\n");
+		return -ENOMEM;
+	}
+
+	dir = debugfs_create_dir(name, NULL);
+	if (dir == NULL || IS_ERR(dir)) {
+		pr_err("debugfs_create_dir failed: rc=%ld\n", PTR_ERR(dir));
+		rc = PTR_ERR(dir);
+		goto dir_error;
+	}
+
+	temp = debugfs_create_file("address", S_IRUGO | S_IWUSR, dir, debugdev,
+				   &debug_addr_fops);
+	if (temp == NULL || IS_ERR(temp)) {
+		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+		rc = PTR_ERR(temp);
+		goto file_error;
+	}
+
+	temp = debugfs_create_file("data", S_IRUGO | S_IWUSR, dir, debugdev,
+				   &debug_data_fops);
+	if (temp == NULL  || IS_ERR(temp)) {
+		pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+		rc = PTR_ERR(temp);
+		goto file_error;
+	}
+	debugdev->base = data;
+	debugdev->addr_offset = -1;
+	debugdev->dir = dir;
+	mutex_init(&debugdev->debug_mutex);
+
+	return 0;
+
+file_error:
+	debugfs_remove_recursive(dir);
+dir_error:
+	kfree(debugdev);
+
+	return rc;
+}
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
new file mode 100644
index 0000000..f4272f3
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -0,0 +1,861 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/irqs.h>
+
+#include "msm_cpr.h"
+
+#define MODULE_NAME "msm-cpr"
+
+/* Need platform device handle for suspend and resume APIs */
+static struct platform_device *cpr_pdev;
+
+struct msm_cpr {
+	int curr_osc;
+	int cpr_mode;
+	int prev_mode;
+	uint32_t floor;
+	uint32_t ceiling;
+	void __iomem *base;
+	unsigned int irq;
+	struct mutex cpr_mutex;
+	struct regulator *vreg_cx;
+	const struct msm_cpr_config *config;
+	struct notifier_block freq_transition;
+	struct msm_cpr_vp_data *vp;
+};
+
+/* Need to maintain state data for suspend and resume APIs */
+static struct msm_cpr_reg cpr_save_state;
+
+static inline
+void cpr_write_reg(struct msm_cpr *cpr, u32 offset, u32 value)
+{
+	writel_relaxed(value, cpr->base + offset);
+}
+
+static inline u32 cpr_read_reg(struct msm_cpr *cpr, u32 offset)
+{
+	return readl_relaxed(cpr->base + offset);
+}
+
+static
+void cpr_modify_reg(struct msm_cpr *cpr, u32 offset, u32 mask, u32 value)
+{
+	u32 reg_val;
+
+	reg_val = readl_relaxed(cpr->base + offset);
+	reg_val &= ~mask;
+	reg_val |= value;
+	writel_relaxed(reg_val, cpr->base + offset);
+}
+
+#ifdef DEBUG
+static void cpr_regs_dump_all(struct msm_cpr *cpr)
+{
+	pr_debug("RBCPR_GCNT_TARGET(%d): 0x%x\n",
+		cpr->curr_osc, readl_relaxed(cpr->base +
+		RBCPR_GCNT_TARGET(cpr->curr_osc)));
+	pr_debug("RBCPR_TIMER_INTERVAL: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_TIMER_INTERVAL));
+	pr_debug("RBIF_TIMER_ADJUST: 0x%x\n",
+		readl_relaxed(cpr->base + RBIF_TIMER_ADJUST));
+	pr_debug("RBIF_LIMIT: 0x%x\n",
+		readl_relaxed(cpr->base + RBIF_LIMIT));
+	pr_debug("RBCPR_STEP_QUOT: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_STEP_QUOT));
+	pr_debug("RBIF_SW_VLEVEL: 0x%x\n",
+		readl_relaxed(cpr->base + RBIF_SW_VLEVEL));
+	pr_debug("RBCPR_DEBUG1: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_DEBUG1));
+	pr_debug("RBCPR_RESULT_0: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_RESULT_0));
+	pr_debug("RBCPR_RESULT_1: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_RESULT_1));
+	pr_debug("RBCPR_QUOT_AVG: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_QUOT_AVG));
+	pr_debug("RBCPR_CTL: 0x%x\n",
+		readl_relaxed(cpr->base + RBCPR_CTL));
+	pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+		cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
+	pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+		cpr_read_reg(cpr, RBIF_IRQ_STATUS));
+}
+#endif
+
+/* Enable the CPR H/W Block */
+static void cpr_enable(struct msm_cpr *cpr)
+{
+	mutex_lock(&cpr->cpr_mutex);
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+	mutex_unlock(&cpr->cpr_mutex);
+}
+
+/* Disable the CPR H/W Block */
+static void cpr_disable(struct msm_cpr *cpr)
+{
+	mutex_lock(&cpr->cpr_mutex);
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
+	mutex_unlock(&cpr->cpr_mutex);
+}
+
+static int32_t cpr_poll_result(struct msm_cpr *cpr)
+{
+	uint32_t val = 0;
+	int8_t rc = 0;
+
+	rc = readl_poll_timeout(cpr->base + RBCPR_RESULT_0, val, ~val & BUSY_M,
+				10, 1000);
+	if (rc)
+		pr_info("%s: RBCPR_RESULT_0 read error: %d\n",
+			 __func__, rc);
+	return rc;
+}
+
+static int32_t cpr_poll_result_done(struct msm_cpr *cpr)
+{
+	uint32_t val = 0;
+	int8_t rc = 0;
+
+	rc = readl_poll_timeout(cpr->base + RBIF_IRQ_STATUS, val, val & 0x1,
+				10, 1000);
+	if (rc)
+		pr_info("%s: RBCPR_IRQ_STATUS read error: %d\n",
+			 __func__, rc);
+	return rc;
+}
+
+static void
+cpr_2pt_kv_analysis(struct msm_cpr *cpr, struct msm_cpr_mode *chip_data)
+{
+	int32_t tgt_volt_mV = 0, level_uV, rc;
+	uint32_t quot1, quot2;
+
+	/**
+	 * 2 Point KV Analysis to calculate Step Quot
+	 * STEP_QUOT is number of QUOT units per PMIC step
+	 * STEP_QUOT = (quot1 - quot2) / 4
+	 *
+	 * The step quot is calculated once for every mode and stored for
+	 * later use.
+	 */
+	if (chip_data->step_quot != ~0)
+		goto out_2pt_kv;
+
+	/**
+	 * Using the value from chip_data->tgt_volt_offset
+	 * calculate the new PMIC adjusted voltages and set
+	 * the PMIC to provide this value.
+	 *
+	 * Assuming default voltage is the highest value of safe boot up
+	 * voltage, offset is always subtracted from it.
+	 *
+	 */
+	if (chip_data->tgt_volt_offset > 0) {
+		tgt_volt_mV = chip_data->calibrated_mV -
+			(chip_data->tgt_volt_offset * cpr->vp->step_size);
+	}
+	pr_debug("tgt_volt_mV = %d, calibrated_mV = %d", tgt_volt_mV,
+			chip_data->calibrated_mV);
+
+	/* level_uV = tgt_volt_mV * 1000; */
+	level_uV = 1350000;
+	/* Call the PMIC specific routine to set the voltage */
+	rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
+	if (rc) {
+		pr_err("%s: Initial voltage set at %duV failed. %d\n",
+			__func__, level_uV, rc);
+		return;
+	}
+	rc = regulator_enable(cpr->vreg_cx);
+	if (rc) {
+		pr_err("failed to enable %s, rc=%d\n", "vdd_cx", rc);
+		return;
+	}
+
+	/* Store the adjusted value of voltage */
+	chip_data->calibrated_mV = 1300;
+
+	/* Take first CPR measurement at a higher voltage to get QUOT1 */
+
+	/* Enable the Software mode of operation */
+	cpr_modify_reg(cpr, RBCPR_CTL, HW_TO_PMIC_EN_M, SW_MODE);
+
+	/* Enable the cpr measurement */
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+
+	/* IRQ is already disabled */
+	rc = cpr_poll_result_done(cpr);
+	if (rc) {
+		pr_err("%s: Quot1: Exiting due to INT_DONE poll timeout\n",
+			__func__);
+		return;
+	}
+
+	rc = cpr_poll_result(cpr);
+	if (rc) {
+		pr_err("%s: Quot1: Exiting due to BUSY poll timeout\n",
+			__func__);
+		return;
+	}
+
+	quot1 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
+
+	/* Take second CPR measurement at a lower voltage to get QUOT2 */
+	level_uV = 1300000;
+
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
+	/* Call the PMIC specific routine to set the voltage */
+	rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
+	if (rc) {
+		pr_err("%s: Voltage set at %duV failed. %d\n",
+			__func__, level_uV, rc);
+		return;
+	}
+
+	cpr_modify_reg(cpr, RBCPR_CTL, HW_TO_PMIC_EN_M, SW_MODE);
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+
+	/* cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1); */
+	rc = cpr_poll_result_done(cpr);
+	if (rc) {
+		pr_err("%s: Quot2: Exiting due to INT_DONE poll timeout\n",
+			__func__);
+		goto err_poll_result_done;
+	}
+	/* IRQ is already disabled */
+	rc = cpr_poll_result(cpr);
+	if (rc) {
+		pr_err("%s: Quot2: Exiting due to BUSY poll timeout\n",
+			__func__);
+		goto err_poll_result;
+	}
+	quot2 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
+	chip_data->step_quot = (quot1 - quot2) / 4;
+	pr_debug("%s: Calculated Step Quot is %d\n",
+			__func__, chip_data->step_quot);
+	/* Disable the cpr */
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
+
+out_2pt_kv:
+	/* Program the step quot */
+	cpr_write_reg(cpr, RBCPR_STEP_QUOT, (chip_data->step_quot & 0xFF));
+	return;
+err_poll_result:
+err_poll_result_done:
+	regulator_disable(cpr->vreg_cx);
+}
+
+static inline
+void cpr_irq_clr_and_ack(struct msm_cpr *cpr, uint32_t mask)
+{
+	/* Clear the interrupt */
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+	/* Acknowledge the Recommendation */
+	cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
+}
+
+static inline
+void cpr_irq_clr_and_nack(struct msm_cpr *cpr, uint32_t mask)
+{
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+	cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1);
+}
+
+static void cpr_irq_set(struct msm_cpr *cpr, uint32_t irq, bool enable)
+{
+	uint32_t irq_enabled;
+
+	irq_enabled = cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line));
+	if (enable == 1)
+		irq_enabled |= irq;
+	else
+		irq_enabled &= ~irq;
+	cpr_modify_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
+			INT_MASK, irq_enabled);
+}
+
+static void
+cpr_up_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
+{
+	int rc, set_volt_mV;
+	struct msm_cpr_mode *chip_data;
+
+	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+
+	/**
+	 * FIXME: Need to handle a potential race condition between
+	 * freq switch handler and CPR interrupt handler here
+	 */
+	/* Set New PMIC voltage */
+	set_volt_mV = (new_volt < chip_data->Vmax ? new_volt
+				: chip_data->Vmax);
+	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_mV * 1000,
+					set_volt_mV * 1000);
+	if (rc) {
+		pr_err("%s: Voltage set at %dmV failed. %d\n",
+			__func__, set_volt_mV, rc);
+		cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
+		return;
+	}
+	pr_debug("%s: Voltage set at %dmV\n", __func__, set_volt_mV);
+
+	/**
+	 * Save the new calibrated voltage to be re-used
+	 * whenever we return to same mode after a mode switch.
+	 */
+	chip_data->calibrated_mV = set_volt_mV;
+
+	/* Clear all the interrupts */
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+
+	/* Disable Auto ACK for Down interrupts */
+	cpr_modify_reg(cpr, RBCPR_CTL, SW_AUTO_CONT_NACK_DN_EN_M, 0);
+
+	/* Enable down interrupts to App as it might have got disabled if CPR
+	 * hit Vmin earlier. Voltage set is above Vmin now.
+	 */
+	cpr_irq_set(cpr, DOWN_INT, 1);
+
+	/* Acknowledge the Recommendation */
+	cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
+}
+
+static void
+cpr_dn_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
+{
+	int rc, set_volt_mV;
+	struct msm_cpr_mode *chip_data;
+
+	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+
+	/**
+	 * FIXME: Need to handle a potential race condition between
+	 * freq switch handler and CPR interrupt handler here
+	 */
+	/* Set New PMIC volt */
+	set_volt_mV = (new_volt > chip_data->Vmin ? new_volt
+				: chip_data->Vmin);
+	rc = regulator_set_voltage(cpr->vreg_cx, set_volt_mV * 1000,
+					set_volt_mV * 1000);
+	if (rc) {
+		pr_err("%s: Voltage at %dmV failed %d\n",
+			__func__, set_volt_mV, rc);
+		cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
+		return;
+	}
+	pr_debug("%s: Voltage set at %dmV\n", __func__, set_volt_mV);
+
+	/**
+	 * Save the new calibrated voltage to be re-used
+	 * whenever we return to same mode after a mode switch.
+	 */
+	chip_data->calibrated_mV = set_volt_mV;
+
+	/* Clear all the interrupts */
+	cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+
+	if (new_volt <= chip_data->Vmin) {
+		/*
+		 * Disable down interrupt to App after we hit Vmin
+		 * It shall be enabled after we service an up interrupt
+		 *
+		 * A race condition between freq switch handler and CPR
+		 * interrupt handler is possible. So, do not disable
+		 * interrupt if a freq switch already caused a mode
+		 * change since we need this interrupt in the new mode.
+		 */
+		if (cpr->cpr_mode == cpr->prev_mode) {
+			/* Enable Auto ACK for CPR Down Flags
+			 * while DOWN_INT to App is disabled */
+			cpr_modify_reg(cpr, RBCPR_CTL,
+					SW_AUTO_CONT_NACK_DN_EN_M,
+					SW_AUTO_CONT_NACK_DN_EN);
+			cpr_irq_set(cpr, DOWN_INT, 0);
+			pr_debug("%s: DOWN_INT disabled\n", __func__);
+		}
+	}
+	/* Acknowledge the Recommendation */
+	cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
+}
+
+static void cpr_set_vdd(struct msm_cpr *cpr, enum cpr_action action)
+{
+	uint32_t curr_volt, new_volt, error_step;
+	struct msm_cpr_mode *chip_data;
+
+	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+	error_step = cpr_read_reg(cpr, RBCPR_RESULT_0) >> 2;
+	error_step &= 0xF;
+	curr_volt = chip_data->calibrated_mV;
+
+	if (action == UP) {
+		/**
+		 * Using up margin in the comparison helps avoid having to
+		 * change up threshold values in chip register.
+		 */
+		if (error_step < (cpr->config->up_threshold +
+					cpr->config->up_margin)) {
+			/* FIXME: Avoid repeated dn interrupts if we are here */
+			pr_debug("UP_INT error step too small to set\n");
+			cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
+			return;
+		}
+
+		/* Calculte new PMIC voltage */
+		new_volt = curr_volt + (error_step * cpr->vp->step_size);
+		pr_debug("UP_INT: new_volt: %d\n", new_volt);
+		cpr_up_event_handler(cpr, new_volt);
+
+	} else if (action == DOWN) {
+		/**
+		 * Using down margin in the comparison helps avoid having to
+		 * change down threshold values in chip register.
+		 */
+		if (error_step < (cpr->config->dn_threshold +
+					cpr->config->dn_margin)) {
+			/* FIXME: Avoid repeated dn interrupts if we are here */
+			pr_debug("DOWN_INT error_step too small to set\n");
+			cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
+			return;
+		}
+
+		/* Calculte new PMIC voltage */
+		new_volt = curr_volt - (error_step * cpr->vp->step_size);
+		pr_debug("DOWN_INT: new_volt: %d\n", new_volt);
+		cpr_dn_event_handler(cpr, new_volt);
+	}
+}
+
+static irqreturn_t cpr_irq0_handler(int irq, void *dev_id)
+{
+	struct msm_cpr *cpr = dev_id;
+	uint32_t reg_val, ctl_reg;
+
+	reg_val = cpr_read_reg(cpr, RBIF_IRQ_STATUS);
+	ctl_reg = cpr_read_reg(cpr, RBCPR_CTL);
+
+	/* Following sequence of handling is as per each IRQ's priority */
+	if (reg_val & BIT(4)) {
+		pr_debug(" CPR:IRQ %d occured for UP Flag\n", irq);
+		cpr_set_vdd(cpr, UP);
+
+	} else if ((reg_val & BIT(2)) && !(ctl_reg & SW_AUTO_CONT_NACK_DN_EN)) {
+		pr_debug(" CPR:IRQ %d occured for Down Flag\n", irq);
+		cpr_set_vdd(cpr, DOWN);
+
+	} else if (reg_val & BIT(1)) {
+		pr_debug(" CPR:IRQ %d occured for Min Flag\n", irq);
+		cpr_irq_clr_and_nack(cpr, BIT(1) | BIT(0));
+
+	} else if (reg_val & BIT(5)) {
+		pr_debug(" CPR:IRQ %d occured for MAX Flag\n", irq);
+		cpr_irq_clr_and_nack(cpr, BIT(5) | BIT(0));
+
+	} else if (reg_val & BIT(3)) {
+		/* SW_AUTO_CONT_ACK_EN is enabled */
+		pr_debug(" CPR:IRQ %d occured for Mid Flag\n", irq);
+	}
+	return IRQ_HANDLED;
+}
+
+static void cpr_config(struct msm_cpr *cpr)
+{
+	uint32_t delay_count, cnt = 0, rc, tmp_uV;
+	struct msm_cpr_mode *chip_data;
+
+	chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+
+	/* Program the SW vlevel */
+	cpr_modify_reg(cpr, RBIF_SW_VLEVEL, SW_VLEVEL_M,
+			cpr->config->sw_vlevel);
+
+	/* Set the floor and ceiling values */
+	cpr->floor =  cpr->config->floor;
+	cpr->ceiling = cpr->config->ceiling;
+
+	/* Program the Ceiling & Floor values */
+	cpr_modify_reg(cpr, RBIF_LIMIT, (CEILING_M | FLOOR_M),
+					((cpr->ceiling << 6) | cpr->floor));
+
+	/* Program the Up and Down Threshold values */
+	cpr_modify_reg(cpr, RBCPR_CTL, UP_THRESHOLD_M | DN_THRESHOLD_M,
+			cpr->config->up_threshold << 24 |
+			cpr->config->dn_threshold << 28);
+
+	cpr->curr_osc = chip_data->ring_osc;
+
+	/**
+	 * Program the gate count and target values
+	 * for all the ring oscilators
+	 */
+	while (cnt < NUM_OSC) {
+		cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cnt),
+				(GCNT_M | TARGET_M),
+				(chip_data->ring_osc_data[cnt].gcnt << 12 |
+				chip_data->ring_osc_data[cnt].target_count));
+		pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cnt,
+			readl_relaxed(cpr->base + RBCPR_GCNT_TARGET(cnt)));
+		cnt++;
+	}
+
+	/* Configure the step quot */
+	cpr_2pt_kv_analysis(cpr, chip_data);
+
+	/**
+	 * Call the PMIC specific routine to set the voltage
+	 * Set with an extra step since it helps as per
+	 * characterization data.
+	 */
+	chip_data->calibrated_mV +=  cpr->vp->step_size;
+	tmp_uV = chip_data->calibrated_mV * 1000;
+	rc = regulator_set_voltage(cpr->vreg_cx, tmp_uV, tmp_uV);
+	if (rc)
+		pr_err("%s: Voltage set failed %d\n", __func__, rc);
+
+	/* Program the Timer for default delay between CPR measurements */
+	delay_count = 0xFFFF;
+	cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL, delay_count);
+
+	/* Enable the Timer */
+	cpr_modify_reg(cpr, RBCPR_CTL, TIMER_M, ENABLE_TIMER);
+
+	/* Enable Auto ACK for Mid interrupts */
+	cpr_modify_reg(cpr, RBCPR_CTL, SW_AUTO_CONT_ACK_EN_M,
+			SW_AUTO_CONT_ACK_EN);
+}
+
+static void cpr_mode_config(struct msm_cpr *cpr, enum cpr_mode mode)
+{
+	if (cpr->cpr_mode == mode)
+		return;
+
+	cpr->cpr_mode = mode;
+	pr_debug("%s: Switching to %s mode\n", __func__,
+		(mode == TURBO_MODE ? "TURBO" : "NORMAL"));
+
+	/* Configure the new mode */
+	cpr_config(cpr);
+}
+
+static int
+cpr_freq_transition(struct notifier_block *nb, unsigned long val,
+				void *data)
+{
+	struct msm_cpr *cpr = container_of(nb, struct msm_cpr, freq_transition);
+	struct cpufreq_freqs *freqs = data;
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		return 0;
+		pr_debug("pre freq change notification to cpr\n");
+
+		disable_irq(cpr->irq);
+		cpr_disable(cpr);
+		cpr->prev_mode = cpr->cpr_mode;
+		break;
+	case CPUFREQ_POSTCHANGE:
+		return 0;
+		pr_debug("post freq change notification to cpr\n");
+
+		if (freqs->new >= cpr->config->nom_freq_limit)
+			cpr_mode_config(cpr, TURBO_MODE);
+		else
+			cpr_mode_config(cpr, NORMAL_MODE);
+		/**
+		 * Enable all interrupts. One of them could be in a disabled
+		 * state if vdd had hit Vmax / Vmin earlier
+		 */
+		cpr_irq_set(cpr, (UP_INT | DOWN_INT), 1);
+
+		enable_irq(cpr->irq);
+
+		cpr_enable(cpr);
+
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int msm_cpr_resume(struct device *dev)
+{
+	struct msm_cpr *cpr = dev_get_drvdata(dev);
+	int osc_num = cpr->config->cpr_mode_data->ring_osc;
+
+	cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL,
+		cpr_save_state.rbif_timer_interval);
+	cpr_write_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
+		cpr_save_state.rbif_int_en);
+	cpr_write_reg(cpr, RBIF_LIMIT,
+		cpr_save_state.rbif_limit);
+	cpr_write_reg(cpr, RBIF_TIMER_ADJUST,
+		cpr_save_state.rbif_timer_adjust);
+	cpr_write_reg(cpr, RBCPR_GCNT_TARGET(osc_num),
+		cpr_save_state.rbcpr_gcnt_target);
+	cpr_write_reg(cpr, RBCPR_STEP_QUOT,
+		cpr_save_state.rbcpr_step_quot);
+	cpr_write_reg(cpr, RBIF_SW_VLEVEL,
+		cpr_save_state.rbif_sw_level);
+
+	cpr_enable(cpr);
+	cpr_write_reg(cpr, RBCPR_CTL,
+		cpr_save_state.rbcpr_ctl);
+	enable_irq(cpr->irq);
+
+	return 0;
+}
+
+static int msm_cpr_suspend(struct device *dev)
+
+{
+	struct msm_cpr *cpr = dev_get_drvdata(dev);
+	int osc_num = cpr->config->cpr_mode_data->ring_osc;
+
+	cpr_save_state.rbif_timer_interval =
+		cpr_read_reg(cpr, RBCPR_TIMER_INTERVAL);
+	cpr_save_state.rbif_int_en =
+		cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line));
+	cpr_save_state.rbif_limit =
+		cpr_read_reg(cpr, RBIF_LIMIT);
+	cpr_save_state.rbif_timer_adjust =
+		cpr_read_reg(cpr, RBIF_TIMER_ADJUST);
+	cpr_save_state.rbcpr_gcnt_target =
+		cpr_read_reg(cpr, RBCPR_GCNT_TARGET(osc_num));
+	cpr_save_state.rbcpr_step_quot =
+		cpr_read_reg(cpr, RBCPR_STEP_QUOT);
+	cpr_save_state.rbif_sw_level =
+		cpr_read_reg(cpr, RBIF_SW_VLEVEL);
+	cpr_save_state.rbcpr_ctl =
+		cpr_read_reg(cpr, RBCPR_CTL);
+
+	disable_irq(cpr->irq);
+	cpr_disable(cpr);
+
+	return 0;
+}
+
+void msm_cpr_pm_resume(void)
+{
+	msm_cpr_resume(&cpr_pdev->dev);
+}
+EXPORT_SYMBOL(msm_cpr_pm_resume);
+
+void msm_cpr_pm_suspend(void)
+{
+	msm_cpr_suspend(&cpr_pdev->dev);
+}
+EXPORT_SYMBOL(msm_cpr_pm_suspend);
+#endif
+
+void msm_cpr_disable(void)
+{
+	struct msm_cpr *cpr = platform_get_drvdata(cpr_pdev);
+	cpr_disable(cpr);
+}
+EXPORT_SYMBOL(msm_cpr_disable);
+
+void msm_cpr_enable(void)
+{
+	struct msm_cpr *cpr = platform_get_drvdata(cpr_pdev);
+	cpr_enable(cpr);
+}
+EXPORT_SYMBOL(msm_cpr_enable);
+
+static int __devinit msm_cpr_probe(struct platform_device *pdev)
+{
+	int res, irqn, irq_enabled;
+	struct msm_cpr *cpr;
+	const struct msm_cpr_config *pdata = pdev->dev.platform_data;
+	void __iomem *base;
+	struct resource *mem;
+
+	if (!pdata) {
+		pr_err("CPR: Platform data is not available\n");
+		return -EIO;
+	}
+
+	cpr = devm_kzalloc(&pdev->dev, sizeof(struct msm_cpr), GFP_KERNEL);
+	if (!cpr)
+		return -ENOMEM;
+
+	/* Initialize platform_data */
+	cpr->config = pdata;
+
+	cpr_pdev = pdev;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem || !mem->start) {
+		pr_err("CPR: get resource failed\n");
+		res = -ENXIO;
+		goto out;
+	}
+
+	base = ioremap_nocache(mem->start, resource_size(mem));
+	if (!base) {
+		pr_err("CPR: ioremap failed\n");
+		res = -ENOMEM;
+		goto out;
+	}
+
+	if (cpr->config->irq_line < 0) {
+		pr_err("CPR: Invalid IRQ line specified\n");
+		res = -ENXIO;
+		goto err_ioremap;
+	}
+	irqn = platform_get_irq(pdev, cpr->config->irq_line);
+	if (irqn < 0) {
+		pr_err("CPR: Unable to get irq\n");
+		res = -ENXIO;
+		goto err_ioremap;
+	}
+
+	cpr->irq = irqn;
+
+	cpr->base = base;
+
+	cpr->vp = pdata->vp_data;
+
+	mutex_init(&cpr->cpr_mutex);
+
+	/* Initialize the Voltage domain for CPR */
+	cpr->vreg_cx = regulator_get(&pdev->dev, "vddx_cx");
+	if (IS_ERR(cpr->vreg_cx)) {
+		res = PTR_ERR(cpr->vreg_cx);
+		pr_err("could not get regulator: %d\n", res);
+		goto err_reg_get;
+	}
+
+	/* Assume current mode is TURBO Mode */
+	cpr->cpr_mode = TURBO_MODE;
+	cpr->prev_mode = TURBO_MODE;
+
+	/* Initial configuration of CPR */
+	cpr_config(cpr);
+
+	platform_set_drvdata(pdev, cpr);
+
+	/* Initialze the Debugfs Entry for cpr */
+	res = msm_cpr_debug_init(cpr->base);
+	if (res) {
+		pr_err("CPR: Debugfs Creation Failed\n");
+		goto err_ioremap;
+	}
+
+	/* Register the interrupt handler for IRQ 0 */
+	res = request_threaded_irq(irqn, NULL, cpr_irq0_handler,
+			IRQF_TRIGGER_RISING, "msm-cpr-irq0", cpr);
+	if (res) {
+		pr_err("CPR: request irq failed for IRQ %d\n", irqn);
+		goto err_ioremap;
+	}
+
+	/**
+	 * Enable the requested interrupt lines.
+	 * Do not enable MID_INT since we shall use
+	 * SW_AUTO_CONT_ACK_EN bit.
+	 */
+	irq_enabled = INT_MASK & ~MID_INT;
+	cpr_modify_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
+			INT_MASK, irq_enabled);
+
+	/* Enable the cpr */
+	cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+
+
+	cpr->freq_transition.notifier_call = cpr_freq_transition;
+	cpufreq_register_notifier(&cpr->freq_transition,
+					CPUFREQ_TRANSITION_NOTIFIER);
+
+	return res;
+
+err_reg_get:
+	free_irq(irqn, cpr);
+err_ioremap:
+	iounmap(base);
+out:
+	return res;
+}
+
+static int __devexit msm_cpr_remove(struct platform_device *pdev)
+{
+	struct msm_cpr *cpr = platform_get_drvdata(pdev);
+
+	cpufreq_unregister_notifier(&cpr->freq_transition,
+					CPUFREQ_TRANSITION_NOTIFIER);
+
+	regulator_disable(cpr->vreg_cx);
+	regulator_put(cpr->vreg_cx);
+	free_irq(cpr->irq, cpr);
+	iounmap(cpr->base);
+	mutex_destroy(&cpr->cpr_mutex);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct dev_pm_ops msm_cpr_dev_pm_ops = {
+	.suspend = msm_cpr_suspend,
+	.resume = msm_cpr_resume,
+};
+
+static struct platform_driver msm_cpr_driver = {
+	.probe = msm_cpr_probe,
+	.remove = __devexit_p(msm_cpr_remove),
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &msm_cpr_dev_pm_ops,
+#endif
+	},
+};
+
+static int __init msm_init_cpr(void)
+{
+	return platform_driver_register(&msm_cpr_driver);
+}
+
+module_init(msm_init_cpr);
+
+static void __exit msm_exit_cpr(void)
+{
+	platform_driver_unregister(&msm_cpr_driver);
+}
+
+module_exit(msm_exit_cpr);
+
+MODULE_DESCRIPTION("MSM CPR Driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/msm_cpr.h b/arch/arm/mach-msm/msm_cpr.h
new file mode 100644
index 0000000..2642b9c
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CPR_H
+#define __ARCH_ARM_MACH_MSM_CPR_H
+
+/* Register Offsets for RBCPR */
+
+/* RBCPR Gate Count and Target Registers */
+#define RBCPR_GCNT_TARGET(n)	(0x60 + 4 * n)
+
+/* RBCPR Timer Control */
+#define RBCPR_TIMER_INTERVAL	0x44
+#define RBIF_TIMER_ADJUST	0x4C
+
+/* RBCPR Config Register */
+#define RBIF_LIMIT		0x48
+#define RBCPR_STEP_QUOT		0X80
+#define RBCPR_CTL		0x90
+#define RBIF_SW_VLEVEL		0x94
+#define RBIF_CONT_ACK_CMD	0x98
+#define RBIF_CONT_NACK_CMD	0x9C
+
+/* RBCPR Result status Register */
+#define RBCPR_RESULT_0		0xA0
+#define RBCPR_RESULT_1		0xA4
+#define RBCPR_QUOT_AVG		0x118
+
+/* RBCPR DEBUG Register */
+#define RBCPR_DEBUG1		0x120
+
+/* RBCPR Interrupt Control Register */
+#define RBIF_IRQ_EN(n)		(0x100 + 4 * n)
+#define RBIF_IRQ_CLEAR		0x110
+#define RBIF_IRQ_STATUS		0x114
+
+/* Bit Mask Values */
+#define GCNT_M				0x003FF000
+#define TARGET_M			0x00000FFF
+#define SW_VLEVEL_M			0x0000003F
+#define UP_FLAG_M			0x00000010
+#define DOWN_FLAG_M			0x00000004
+#define CEILING_M			0x00000FC0
+#define FLOOR_M				0x0000003F
+#define LOOP_EN_M			0x00000001
+#define TIMER_M				0x00000008
+#define SW_AUTO_CONT_ACK_EN_M		0x00000020
+#define SW_AUTO_CONT_NACK_DN_EN_M	0x00000040
+#define HW_TO_PMIC_EN_M			BIT(4)
+#define BUSY_M				BIT(19)
+#define QUOT_SLOW_M			0x00FFF000
+#define UP_THRESHOLD_M			0x0F000000
+#define DN_THRESHOLD_M			0xF0000000
+
+/* Bit Values */
+#define ENABLE_CPR		BIT(0)
+#define DISABLE_CPR		0x0
+#define ENABLE_TIMER		BIT(3)
+#define DISABLE_TIMER		0x0
+#define SW_MODE			0x0
+#define SW_AUTO_CONT_ACK_EN	BIT(5)
+#define SW_AUTO_CONT_NACK_DN_EN	BIT(6)
+
+/* Test values for RBCPR RUMI Testing */
+#define GNT_CNT			0xC0
+#define TARGET			0xEFF
+
+#define CEILING_V		0x30
+#define FLOOR_V			0x15
+
+#define SW_LEVEL		0x20
+
+/* Interrupt Mask for All interrupt flags */
+#define INT_MASK (MIN_INT | DOWN_INT | MID_INT | UP_INT | MAX_INT)
+
+/* Number of oscilator in each sensor */
+#define NUM_OSC 8
+
+#define CPR_MODE 2
+
+/**
+ * enum cpr_mode - Modes in which cpr is used
+ */
+enum cpr_mode {
+	NORMAL_MODE = 0,
+	TURBO_MODE,
+	SVS_MODE,
+};
+
+/**
+ * enum cpr_action - Cpr actions to be taken
+ */
+enum cpr_action {
+	DOWN = 0,
+	UP,
+};
+
+/**
+ * enum cpr_interrupt
+ */
+enum cpr_interrupt {
+	DONE_INT	= BIT(0),
+	MIN_INT		= BIT(1),
+	DOWN_INT	= BIT(2),
+	MID_INT		= BIT(3),
+	UP_INT		= BIT(4),
+	MAX_INT		= BIT(5),
+};
+
+/**
+ * struct msm_vp_data - structure for VP configuration
+ * @min_volt_mV: minimum milivolt level for VP
+ * @max_volt_mV: maximum milivolt level for VP
+ * @default_volt_mV: default milivolt for VP
+ * @step_size_mV: step size of voltage
+ */
+struct msm_cpr_vp_data {
+	int min_volt;
+	int max_volt;
+	int default_volt;
+	int step_size;
+};
+
+/**
+ * struct msm_cpr_osc -  Data for CPR ring oscillator
+ * @gcnt: gate count value for the oscillator
+ * @target_count: target value for ring oscillator
+ */
+struct msm_cpr_osc {
+	int gcnt;
+	uint32_t target_count;
+};
+
+/**
+ * struct msm_cpr_mode -  Data for CPR modes of operation
+ * @msm_cpr_osc: structure for oscillator data
+ * @ring_osc: ring oscillator of the sensor
+ * @tgt_volt_offset: inital voltage offset from default value
+ * @step_quot: step Quot for CPR calcuation
+ */
+struct msm_cpr_mode {
+	struct msm_cpr_osc ring_osc_data[NUM_OSC];
+	int ring_osc;
+	int32_t tgt_volt_offset;
+	uint32_t step_quot;
+	uint32_t Vmax;
+	uint32_t Vmin;
+	uint32_t calibrated_mV;
+};
+
+/**
+ * struct msm_cpr_config -  Platform data for CPR configuration
+ * @ref_clk_khz: clock value of CPR in KHz
+ * @delay_us: timer delay in micro second
+ * @irq_line: irq line to be use (0 or 1 or 2)
+ * @msm_cpr_mode: structure for CPR mode data
+ */
+struct msm_cpr_config {
+	unsigned long ref_clk_khz;
+	unsigned long delay_us;
+	int irq_line;
+	struct msm_cpr_mode *cpr_mode_data;
+	int min_down_step;
+	uint32_t tgt_count_div_N; /* Target Cnt(Nom) = Target Cnt(Turbo) / N */
+	uint32_t floor;
+	uint32_t ceiling;
+	uint32_t sw_vlevel;
+	uint32_t up_threshold;
+	uint32_t dn_threshold;
+	uint32_t up_margin;
+	uint32_t dn_margin;
+	uint32_t nom_freq_limit;
+	struct msm_cpr_vp_data *vp_data;
+};
+
+/**
+* struct msm_cpr_config -  CPR Registers
+*/
+struct msm_cpr_reg {
+	uint32_t rbif_timer_interval;
+	uint32_t rbif_int_en;
+	uint32_t rbif_limit;
+	uint32_t rbif_timer_adjust;
+	uint32_t rbcpr_gcnt_target;
+	uint32_t rbcpr_step_quot;
+	uint32_t rbif_sw_level;
+	uint32_t rbcpr_ctl;
+};
+
+#if defined(CONFIG_MSM_CPR) || defined(CONFIG_MSM_CPR_MODULE)
+/* msm_cpr_pm_resume: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_resume(void);
+/* msm_cpr_pm_suspend: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_suspend(void);
+/* msm_cpr_enable: Used by Power Manager for GDFS */
+void msm_cpr_enable(void);
+/* msm_cpr_disable: Used by Power Manager for GDFS */
+void msm_cpr_disable(void);
+#else
+/* msm_cpr_pm_resume: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_resume(void) { }
+/* msm_cpr_pm_suspend: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_suspend(void) { }
+/* msm_cpr_enable: Used by Power Manager for GDFS */
+void msm_cpr_enable(void) { }
+/* msm_cpr_disable: Used by Power Manager for GDFS */
+void msm_cpr_disable(void) { }
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+int msm_cpr_debug_init(void *);
+#else
+static inline int msm_cpr_debug_init(void *) { return 0; }
+#endif
+#endif /* __ARCH_ARM_MACH_MSM_CPR_H */
diff --git a/arch/arm/mach-msm/msm_vp.c b/arch/arm/mach-msm/msm_vp.c
new file mode 100644
index 0000000..2569474
--- /dev/null
+++ b/arch/arm/mach-msm/msm_vp.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include <mach/msm_iomap.h>
+
+/* Address for Perf Level Registor */
+#define VDD_APC_PLEVEL_BASE (MSM_CLK_CTL_BASE + 0x0298)
+#define VDD_APC_PLEVEL(n) (VDD_APC_PLEVEL_BASE + 4 * n)
+
+/* Address for SYS_P_Level register */
+#define VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
+
+#define MV_TO_UV(mv) ((mv)*1000)
+#define UV_TO_MV(uv) (((uv)+999)/1000)
+
+#define MSM_VP_REGULATOR_DEV_NAME  "vp-regulator"
+
+/**
+ * Convert Voltage to PLEVEL register value
+ * Here x is required voltage in minivolt
+ * e.g. if Required voltage is 1200mV then
+ * required value to be programmed into the
+ * Plevel register is 0x32. This equation is
+ * based on H/W logic being used in SVS controller.
+ *
+ * Here we are taking the minimum voltage step
+ * to be 12.5mV as per H/W logic and adding 0x20
+ * is for selecting the reference voltage.
+ * 750mV is minimum voltage of MSMC2 smps.
+ */
+#define VOLT_TO_BIT(x) (((x-750)/(12500/1000)) + 0x20)
+#define VREG_VREF_SEL  (1 << 5)
+#define VREG_PD_EN     (1 << 6)
+
+/**
+ * struct msm_vp -  Structure for VP
+ * @regulator_dev: structure for regulator device
+ * @current_voltage: current voltage value
+ */
+struct msm_vp {
+	struct device		*dev;
+	struct regulator_dev	*rdev;
+	int current_voltage;
+};
+
+/* Function to change the Vdd Level */
+static int vp_reg_set_voltage(struct regulator_dev *rdev, int min_uV,
+						int max_uV, unsigned *sel)
+{
+	struct msm_vp *vp = rdev_get_drvdata(rdev);
+	uint32_t reg_val, perf_level, plevel, cur_plevel, fine_step_volt;
+
+	reg_val = readl_relaxed(VDD_SVS_PLEVEL_ADDR);
+	perf_level = reg_val & 0x07;
+
+	plevel = (min_uV - 750000) / 25000;
+	fine_step_volt = (min_uV - 750000) % 25000;
+
+	/**
+	 * Program the new voltage level for the current perf_level
+	 * in corresponding PLEVEL register.
+	 */
+	cur_plevel = readl_relaxed(VDD_APC_PLEVEL(perf_level));
+	/* clear lower 6 bits */
+	cur_plevel &= ~0x3F;
+	cur_plevel |= (plevel | VREG_VREF_SEL);
+	if (fine_step_volt >= 12500)
+		cur_plevel |= VREG_PD_EN;
+	writel_relaxed(cur_plevel, VDD_APC_PLEVEL(perf_level));
+
+	/* Clear the current perf level */
+	reg_val &= 0xF8;
+	writel_relaxed(reg_val, VDD_SVS_PLEVEL_ADDR);
+
+	/* Initiate the PMIC SSBI request to change the voltage */
+	reg_val |= (BIT(7) | perf_level << 3);
+	writel_relaxed(reg_val, VDD_SVS_PLEVEL_ADDR);
+	mb();
+	udelay(62);
+
+	if ((readl_relaxed(VDD_SVS_PLEVEL_ADDR) & 0x07) != perf_level) {
+		pr_err("Vdd Set Failed\n");
+		return -EIO;
+	}
+
+	vp->current_voltage = (min_uV / 1000);
+	return 0;
+}
+
+static int vp_reg_get_voltage(struct regulator_dev *rdev)
+{
+	struct msm_vp *vp = rdev_get_drvdata(rdev);
+
+	return MV_TO_UV(vp->current_voltage);
+}
+
+static int vp_reg_enable(struct regulator_dev *rdev)
+{
+	return 0;
+}
+
+static int vp_reg_disable(struct regulator_dev *rdev)
+{
+	return 0;
+}
+
+/* Regulator registration specific data */
+/* FIXME: should move to board-xx-regulator.c file */
+static struct regulator_consumer_supply vp_consumer =
+	REGULATOR_SUPPLY("vddx_cx", "msm-cpr");
+
+static struct regulator_init_data vp_reg_data = {
+	.constraints	= {
+		.name		= "vddx_c2",
+		.min_uV		= 750000,
+		.max_uV		= 1500000,
+		.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE |
+					REGULATOR_CHANGE_STATUS,
+		.valid_modes_mask = REGULATOR_MODE_NORMAL,
+		.boot_on	= 1,
+		.input_uV	= 0,
+		.always_on	= 1,
+	},
+	.num_consumer_supplies = 1,
+	.consumer_supplies = &vp_consumer,
+};
+
+/* Regulator specific ops */
+static struct regulator_ops vp_reg_ops = {
+	.enable			= vp_reg_enable,
+	.disable		= vp_reg_disable,
+	.get_voltage		= vp_reg_get_voltage,
+	.set_voltage		= vp_reg_set_voltage,
+};
+
+/* Regulator Description */
+static struct regulator_desc vp_reg = {
+	.name = "vddcx",
+	.id = -1,
+	.ops = &vp_reg_ops,
+	.type = REGULATOR_VOLTAGE,
+};
+
+static int __devinit msm_vp_reg_probe(struct platform_device *pdev)
+{
+	struct msm_vp *vp;
+	int rc;
+
+	vp = kzalloc(sizeof(struct msm_vp), GFP_KERNEL);
+	if (!vp) {
+		pr_err("Could not allocate memory for VP\n");
+		return -ENOMEM;
+	}
+
+	vp->rdev = regulator_register(&vp_reg, NULL, &vp_reg_data, vp, NULL);
+	if (IS_ERR(vp->rdev)) {
+		rc = PTR_ERR(vp->rdev);
+		pr_err("Failed to register regulator: %d\n", rc);
+		goto error;
+	}
+
+	platform_set_drvdata(pdev, vp);
+
+	return 0;
+error:
+	kfree(vp);
+	return rc;
+}
+
+static int __devexit msm_vp_reg_remove(struct platform_device *pdev)
+{
+	struct msm_vp *vp = platform_get_drvdata(pdev);
+
+	regulator_unregister(vp->rdev);
+	platform_set_drvdata(pdev, NULL);
+	kfree(vp);
+
+	return 0;
+}
+
+static struct platform_driver msm_vp_reg_driver = {
+	.probe	= msm_vp_reg_probe,
+	.remove = __devexit_p(msm_vp_reg_remove),
+	.driver = {
+		.name	= MSM_VP_REGULATOR_DEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init msm_vp_reg_init(void)
+{
+	return platform_driver_register(&msm_vp_reg_driver);
+}
+postcore_initcall(msm_vp_reg_init);
+
+static void __exit msm_vp_reg_exit(void)
+{
+	platform_driver_unregister(&msm_vp_reg_driver);
+}
+module_exit(msm_vp_reg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM VP regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" MSM_VP_REGULATOR_DEV_NAME);
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index a65cd21..ea408f7 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -92,11 +92,9 @@
 static void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd)
 {
 	static char alive_mask_buf[MASK_SIZE];
-	size_t count = cpulist_scnprintf(alive_mask_buf, MASK_SIZE,
+	cpulist_scnprintf(alive_mask_buf, MASK_SIZE,
 						&wdog_dd->alive_mask);
-	alive_mask_buf[count] = '\n';
-	alive_mask_buf[count++] = '\0';
-	printk(KERN_INFO "cpu alive mask from last pet\n%s", alive_mask_buf);
+	printk(KERN_INFO "cpu alive mask from last pet %s\n", alive_mask_buf);
 }
 
 static int msm_watchdog_suspend(struct device *dev)
@@ -200,8 +198,6 @@
 	if (wdog_dd->do_ipi_ping)
 		ping_other_cpus(wdog_dd);
 	pet_watchdog(wdog_dd);
-	if (wdog_dd->do_ipi_ping)
-		dump_cpu_alive_mask(wdog_dd);
 	if (enable)
 		schedule_delayed_work(&wdog_dd->dogwork_struct,
 							delay_time);
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 8819bd2..82fe2f8 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -296,6 +296,44 @@
 }
 #endif /* CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL */
 
+/* Core Clock Operations */
+int ocmem_enable_core_clock(void)
+{
+	int ret;
+	ret = clk_prepare_enable(ocmem_pdata->core_clk);
+	if (ret) {
+		pr_err("ocmem: Failed to enable core clock\n");
+		return ret;
+	}
+	pr_debug("ocmem: Enabled core clock\n");
+	return 0;
+}
+
+void ocmem_disable_core_clock(void)
+{
+	clk_disable_unprepare(ocmem_pdata->core_clk);
+	pr_debug("ocmem: Disabled core clock\n");
+}
+
+/* Branch Clock Operations */
+int ocmem_enable_iface_clock(void)
+{
+	int ret;
+	ret = clk_prepare_enable(ocmem_pdata->iface_clk);
+	if (ret) {
+		pr_err("ocmem: Failed to disable branch clock\n");
+		return ret;
+	}
+	pr_debug("ocmem: Enabled iface clock\n");
+	return 0;
+}
+
+void ocmem_disable_iface_clock(void)
+{
+	clk_disable_unprepare(ocmem_pdata->iface_clk);
+	pr_debug("ocmem: Disabled iface clock\n");
+}
+
 static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
 {
 	struct device   *dev = &pdev->dev;
@@ -526,10 +564,34 @@
 	return 0;
 }
 
+/* Enable the ocmem graphics mpU as a workaround */
+/* This will be programmed by TZ after TZ support is integrated */
+static int ocmem_init_gfx_mpu(struct platform_device *pdev)
+{
+	int rc;
+	struct device *dev = &pdev->dev;
+	void __iomem *ocmem_region_vbase = NULL;
+
+	ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
+							OCMEM_REGION_CTL_SIZE);
+	if (!ocmem_region_vbase)
+		return -EBUSY;
+
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0)
+		return rc;
+
+	writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
+	ocmem_disable_core_clock();
+	return 0;
+}
+
 static int __devinit msm_ocmem_probe(struct platform_device *pdev)
 {
 	struct device   *dev = &pdev->dev;
-	void *ocmem_region_vbase = NULL;
+	struct clk *ocmem_core_clk = NULL;
+	struct clk *ocmem_iface_clk = NULL;
 
 	if (!pdev->dev.of_node) {
 		dev_info(dev, "Missing Configuration in Device Tree\n");
@@ -548,6 +610,29 @@
 
 	dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
 
+	ocmem_core_clk = devm_clk_get(dev, "core_clk");
+
+	if (IS_ERR(ocmem_core_clk)) {
+		dev_err(dev, "Unable to get the core clock\n");
+		return PTR_ERR(ocmem_core_clk);
+	}
+
+	/* The core clock is synchronous with graphics */
+	if (clk_set_rate(ocmem_core_clk, 1000) < 0) {
+		dev_err(dev, "Set rate failed on the core clock\n");
+		return -EBUSY;
+	}
+
+	ocmem_iface_clk = devm_clk_get(dev, "iface_clk");
+
+	if (IS_ERR(ocmem_iface_clk)) {
+		dev_err(dev, "Unable to get the memory interface clock\n");
+		return PTR_ERR(ocmem_core_clk);
+	};
+
+	ocmem_pdata->core_clk = ocmem_core_clk;
+	ocmem_pdata->iface_clk = ocmem_iface_clk;
+
 	platform_set_drvdata(pdev, ocmem_pdata);
 
 	if (ocmem_core_init(pdev))
@@ -562,18 +647,14 @@
 	if (ocmem_sched_init())
 		return -EBUSY;
 
-	ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
-							OCMEM_REGION_CTL_SIZE);
-	if (!ocmem_region_vbase)
-		return -EBUSY;
-
-	/* Enable the ocmem graphics mpU as a workaround in Virtio */
-	/* This will be programmed by TZ after TZ support is integrated */
-	writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
-
 	if (ocmem_rdm_init(pdev))
 		return -EBUSY;
 
+	if (ocmem_init_gfx_mpu(pdev)) {
+		dev_err(dev, "Unable to initialize Graphics mPU\n");
+		return -EBUSY;
+	}
+
 	dev_dbg(dev, "initialized successfully\n");
 	return 0;
 }
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index d8cfefc..c7cc57e 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -384,6 +384,22 @@
 }
 
 #if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
+static int ocmem_core_set_default_state(void)
+{
+	int rc = 0;
+
+	/* The OCMEM core clock and branch clocks are always turned ON */
+	rc = ocmem_enable_core_clock();
+	if (rc < 0)
+		return rc;
+
+	rc = ocmem_enable_iface_clock();
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
 /* Initializes a region to be turned ON in wide mode */
 static int ocmem_region_set_default_state(unsigned int r_num)
 {
@@ -408,6 +424,11 @@
 {
 	return 0;
 }
+
+static int ocmem_core_set_default_state(void)
+{
+	return 0;
+}
 #endif
 
 #if defined(CONFIG_MSM_OCMEM_POWER_DEBUG)
@@ -535,6 +556,7 @@
 	unsigned start_m = num_banks;
 	unsigned end_m = num_banks;
 	unsigned long region_offset = 0;
+	int rc = 0;
 
 	if (offset < 0)
 		return -EINVAL;
@@ -555,6 +577,14 @@
 		(region_end >= num_regions))
 			return -EINVAL;
 
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0) {
+		pr_err("ocmem: Power transistion request for client %s (id: %d) failed\n",
+				get_name(id), id);
+		return rc;
+	}
+
 	mutex_lock(&region_ctrl_lock);
 
 	for (i = region_start; i <= region_end; i++) {
@@ -605,9 +635,11 @@
 
 	}
 	mutex_unlock(&region_ctrl_lock);
+	ocmem_disable_core_clock();
 	return 0;
 invalid_transition:
 	mutex_unlock(&region_ctrl_lock);
+	ocmem_disable_core_clock();
 	pr_err("ocmem_core: Invalid state transition detected for %d\n", id);
 	pr_err("ocmem_core: Offset %lx Len %lx curr_state %x new_state %x\n",
 			offset, len, curr_state, new_state);
@@ -640,10 +672,16 @@
 	bool interleaved;
 	unsigned i, j, k;
 	unsigned rsc_type = 0;
+	int rc = 0;
 
 	pdata = platform_get_drvdata(pdev);
 	ocmem_base = pdata->reg_base;
 
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0)
+		return rc;
+
 	hw_ver = ocmem_read(ocmem_base + OC_HW_PROFILE);
 
 	if (pdata->nr_regions != OCMEM_V1_REGIONS) {
@@ -684,8 +722,7 @@
 					 * num_regions, GFP_KERNEL);
 
 	if (!region_ctrl) {
-		pr_err("ocmem: Unable to allocate memory\n");
-		return -EINVAL;
+		goto err_no_mem;
 	}
 
 	mutex_init(&region_ctrl_lock);
@@ -702,8 +739,7 @@
 					sizeof(struct ocmem_hw_macro) *
 						num_banks, GFP_KERNEL);
 		if (!region->macro) {
-			pr_err("ocmem: Unable to allocate memory\n");
-			return -EINVAL;
+			goto err_no_mem;
 		}
 
 		for (j = 0; j < num_banks; j++) {
@@ -722,7 +758,7 @@
 
 			if (!req) {
 				pr_err("Unable to create RPM request\n");
-				return -EINVAL;
+				goto region_init_error;
 			}
 
 			pr_debug("rpm request type %x (rsc: %d) with %d elements\n",
@@ -733,16 +769,28 @@
 
 		if (ocmem_region_toggle(i)) {
 			pr_err("Failed to verify region %d\n", i);
-			goto hw_not_supported;
+			goto region_init_error;
 		}
 
 		if (ocmem_region_set_default_state(i)) {
 			pr_err("Failed to initialize region %d\n", i);
-			goto hw_not_supported;
+			goto region_init_error;
 		}
 	}
+
+	rc = ocmem_core_set_default_state();
+
+	if (rc < 0)
+		return rc;
+
+	ocmem_disable_core_clock();
 	return 0;
+
+err_no_mem:
+	pr_err("ocmem: Unable to allocate memory\n");
+region_init_error:
 hw_not_supported:
 	pr_err("Unsupported OCMEM h/w configuration %x\n", hw_ver);
+	ocmem_disable_core_clock();
 	return -EINVAL;
 }
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 5649021..ccbef9b 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -142,6 +142,15 @@
 	int i = 0;
 	int j = 0;
 	int status = 0;
+	int rc = 0;
+
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0) {
+		pr_err("RDM transfer failed for client %s (id: %d)\n",
+				get_name(id), id);
+		return rc;
+	}
 
 	for (i = 0, j = slot; i < num_chunks; i++, j++) {
 
@@ -196,6 +205,7 @@
 	wait_event_interruptible(dm_wq,
 		atomic_read(&dm_pending) == 0);
 
+	ocmem_disable_core_clock();
 	return 0;
 }
 
@@ -218,8 +228,16 @@
 		return -EINVAL;
 	}
 
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0) {
+		pr_err("RDM initialization failed\n");
+		return rc;
+	}
+
 	init_waitqueue_head(&dm_wq);
 	/* enable dm interrupts */
 	ocmem_write(DM_INTR_ENABLE, dm_base + DM_INTR_MASK);
+	ocmem_disable_core_clock();
 	return 0;
 }
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 75081af..3ac8e0a 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -511,18 +511,48 @@
 	return 0;
 }
 
-/* process map is a wrapper where power control will be added later */
 static int process_map(struct ocmem_req *req, unsigned long start,
 				unsigned long end)
 {
+	int rc = 0;
+
+	rc = ocmem_enable_core_clock();
+
+	if (rc < 0)
+		goto core_clock_fail;
+
+	rc = ocmem_enable_iface_clock();
+
+	if (rc < 0)
+		goto process_map_fail;
+
 	return do_map(req);
+
+process_map_fail:
+	ocmem_disable_core_clock();
+core_clock_fail:
+	pr_err("ocmem: Failed to map ocmem request\n");
+	return rc;
 }
 
-/* process unmap is a wrapper where power control will be added later */
 static int process_unmap(struct ocmem_req *req, unsigned long start,
 				unsigned long end)
 {
-	return do_unmap(req);
+	int rc = 0;
+
+	rc = do_unmap(req);
+
+	if (rc < 0)
+		goto process_unmap_fail;
+
+	ocmem_disable_iface_clock();
+	ocmem_disable_core_clock();
+
+	return 0;
+
+process_unmap_fail:
+	pr_err("ocmem: Failed to unmap ocmem request\n");
+	return rc;
 }
 
 static int __sched_grow(struct ocmem_req *req, bool can_block)
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 2d1fa80..3040a31 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -228,18 +228,6 @@
 
 static int pil_riva_shutdown(struct pil_desc *pil)
 {
-	struct riva_data *drv = dev_get_drvdata(pil->dev);
-	u32 reg;
-
-	/* Put cCPU and cCPU clock into reset */
-	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
-	reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
-	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_VAL);
-	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_EN);
-	reg |= RIVA_PMU_OVRD_EN_CCPU_RESET | RIVA_PMU_OVRD_EN_CCPU_CLK;
-	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_EN);
-	mb();
-
 	/* Assert reset to Riva */
 	writel_relaxed(1, RIVA_RESET);
 	mb();
diff --git a/arch/arm/mach-msm/qdsp5/Makefile b/arch/arm/mach-msm/qdsp5/Makefile
index 2ce0031..89648fe 100644
--- a/arch/arm/mach-msm/qdsp5/Makefile
+++ b/arch/arm/mach-msm/qdsp5/Makefile
@@ -17,4 +17,4 @@
 obj-y += snd.o snd_adie.o
 obj-$(CONFIG_ARCH_MSM7X27A) += audio_fm.o
 obj-$(CONFIG_ARCH_MSM7X27A) += audio_mvs.o
-obj-$(CONFIG_ARCH_MSM7X27A) += audio_lpa.o
+obj-$(CONFIG_ARCH_MSM7X27A) += audio_lpa.o audio_ac3.o
diff --git a/arch/arm/mach-msm/qdsp5/adsp_rm.c b/arch/arm/mach-msm/qdsp5/adsp_rm.c
index 81147f7..f67946c 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_rm.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_rm.c
@@ -33,7 +33,8 @@
 			"PCM Blocks not Sufficient",
 			"TASK is already occupied",
 			"Concurrency not supported",
-			"MIPS not sufficient"
+			"MIPS not sufficient",
+			"DDP invalid/no licence"
 			};
 static struct client {
 	wait_queue_head_t		wait;
diff --git a/arch/arm/mach-msm/qdsp5/audio_ac3.c b/arch/arm/mach-msm/qdsp5/audio_ac3.c
new file mode 100644
index 0000000..ee085c5
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_ac3.c
@@ -0,0 +1,1753 @@
+/* arch/arm/mach-msm/audio_ac3.c
+ *
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
+ *
+ * This code also borrows from audio_aac.c, which is
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+#include <linux/msm_audio_ac3.h>
+#include <linux/ion.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+#define BUFSZ			4096
+#define DMASZ			(BUFSZ * 2)
+
+#define AUDDEC_DEC_AC3		23
+
+#define PCM_BUFSZ		6168 /* maximum frame size is 512 * 6 samples */
+#define PCM_BUF_MAX_COUNT	5  /* DSP only accepts 5 buffers at most
+				    * but support 2 buffers currently
+				   */
+#define ROUTING_MODE_FTRT	1
+#define ROUTING_MODE_RT		2
+
+/* Decoder status received from AUDPPTASK */
+#define AUDPP_DEC_STATUS_SLEEP	0
+#define	AUDPP_DEC_STATUS_INIT  1
+#define AUDPP_DEC_STATUS_CFG   2
+#define AUDPP_DEC_STATUS_PLAY  3
+
+#define AUDAC3_METAFIELD_MASK 0xFFFF0000
+#define AUDAC3_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDAC3_EOS_FLG_MASK 0x01
+#define AUDAC3_EOS_NONE 0x0 /* No EOS detected */
+#define AUDAC3_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDAC3_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+	unsigned short mfield_sz; /* only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audac3_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct audac3_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audio {
+	struct buffer out[2];
+
+	spinlock_t dsp_lock;
+
+	uint8_t out_head;
+	uint8_t out_tail;
+	uint8_t out_needed;	/* number of buffers the dsp is waiting for */
+
+	atomic_t out_bytes;
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	/* Host PCM section */
+	struct buffer in[PCM_BUF_MAX_COUNT];
+	struct mutex read_lock;
+	wait_queue_head_t read_wait;	/* Wait queue for read */
+	char *read_data;	/* pointer to reader buffer */
+	int32_t read_phys;	/* physical address of reader buffer */
+	uint8_t read_next;	/* index to input buffers to be read next */
+	uint8_t fill_next;	/* index to buffer that DSP should be filling */
+	uint8_t pcm_buf_count;	/* number of pcm buffer allocated */
+	/* ---- End of Host PCM section */
+
+	struct msm_adsp_module *audplay;
+	struct audmgr audmgr;
+	struct msm_audio_ac3_config ac3_config;
+
+	/* data allocated for various buffers */
+	char *data;
+	int32_t phys;  /* physical address of write buffer */
+	void *map_v_read;
+	void *map_v_write;
+
+	int mfield; /* meta field embedded in data */
+	int rflush; /* Read  flush */
+	int wflush; /* Write flush */
+	uint8_t opened;
+	uint8_t enabled;
+	uint8_t running;
+	uint8_t stopped;	/* set when stopped, cleared on flush */
+	uint8_t pcm_feedback;
+	uint8_t buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+	enum msm_aud_decoder_state dec_state;	/* Represents decoder state */
+	int rmt_resource_released;
+
+	const char *module_name;
+	unsigned queue_id;
+	uint16_t dec_id;
+	uint32_t read_ptr_offset;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audac3_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	int eq_enable;
+	int eq_needs_commit;
+	audpp_cmd_cfg_object_params_eqalizer eq;
+	audpp_cmd_cfg_object_params_volume vol_pan;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audac3_send_data(struct audio *audio, unsigned needed);
+static void audac3_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audac3_config_hostpcm(struct audio *audio);
+static void audac3_buffer_refresh(struct audio *audio);
+static void audac3_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload);
+
+static int rmt_put_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_DISABLE;
+	cmd.dec_type = AUDDEC_DEC_AC3;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+	return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+	struct aud_codec_config_cmd cmd;
+	unsigned short client_idx;
+
+	cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+	cmd.client_id = RM_AUD_CLIENT_ID;
+	cmd.task_id = audio->dec_id;
+	cmd.enable = RMT_ENABLE;
+	cmd.dec_type = AUDDEC_DEC_AC3;
+	client_idx = ((cmd.client_id << 8) | cmd.task_id);
+	return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audac3_enable(struct audio *audio)
+{
+	struct audmgr_config cfg;
+	int rc;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+
+	if (audio->enabled)
+		return 0;
+
+	if (audio->rmt_resource_released == 1) {
+		audio->rmt_resource_released = 0;
+		rc = rmt_get_resource(audio);
+		if (rc) {
+			MM_ERR("ADSP resources are not available for AC3"\
+				" session 0x%08x on decoder: %d\n Ignoring"\
+				" error and going ahead with the playback\n",
+				(int)audio, audio->dec_id);
+		}
+	}
+
+	audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+
+	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+		cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+		cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+		cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+		cfg.codec = RPC_AUD_DEF_CODEC_AC3;
+		cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+		rc = audmgr_enable(&audio->audmgr, &cfg);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (msm_adsp_enable(audio->audplay)) {
+		MM_ERR("msm_adsp_enable(audplay) failed\n");
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+
+	if (audpp_enable(audio->dec_id, audac3_dsp_event, audio)) {
+		MM_ERR("audpp_enable() failed\n");
+		msm_adsp_disable(audio->audplay);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		return -ENODEV;
+	}
+	audio->enabled = 1;
+	return 0;
+}
+
+/* must be called with audio->lock held */
+static int audac3_disable(struct audio *audio)
+{
+	int rc = 0;
+	if (audio->enabled) {
+		audio->enabled = 0;
+		audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+		auddec_dsp_config(audio, 0);
+		rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+		else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+			rc = -EFAULT;
+		else
+			rc = 0;
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->read_wait);
+		msm_adsp_disable(audio->audplay);
+		audpp_disable(audio->dec_id, audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_disable(&audio->audmgr);
+		audio->out_needed = 0;
+		rmt_put_resource(audio);
+		audio->rmt_resource_released = 1;
+	}
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+
+static void audac3_update_pcm_buf_entry(struct audio *audio,
+					 uint32_t *payload)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	if (audio->rflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < payload[1]; index++) {
+		if (audio->in[audio->fill_next].addr
+				== payload[2 + index * 2]) {
+			MM_DBG("in[%d] ready\n", audio->fill_next);
+			audio->in[audio->fill_next].used =
+				payload[3 + index * 2];
+			if ((++audio->fill_next) == audio->pcm_buf_count)
+				audio->fill_next = 0;
+
+		} else {
+			MM_ERR("expected=%x ret=%x\n",
+				audio->in[audio->fill_next].addr,
+				payload[1 + index * 2]);
+			break;
+		}
+	}
+	if (audio->in[audio->fill_next].used == 0) {
+		audac3_buffer_refresh(audio);
+	} else {
+		MM_DBG("read cannot keep up\n");
+		audio->buf_refresh = 1;
+	}
+	wake_up(&audio->read_wait);
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+			      void (*getevent) (void *ptr, size_t len))
+{
+	struct audio *audio = data;
+	uint32_t msg[28];
+	getevent(msg, sizeof(msg));
+
+	MM_DBG("msg_id=%x\n", id);
+	switch (id) {
+	case AUDPLAY_MSG_DEC_NEEDS_DATA:
+		audac3_send_data(audio, 1);
+		break;
+	case AUDPLAY_MSG_BUFFER_UPDATE:
+		MM_DBG("\n"); /* Macro prints the file name and function */
+		audac3_update_pcm_buf_entry(audio, msg);
+		break;
+	case ADSP_MESSAGE_ID:
+		MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+		break;
+	default:
+		MM_ERR("unexpected message from decoder\n");
+	}
+}
+
+static void audac3_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+	struct audio *audio = private;
+
+	switch (id) {
+	case AUDPP_MSG_STATUS_MSG:{
+			unsigned status = msg[1];
+
+			switch (status) {
+			case AUDPP_DEC_STATUS_SLEEP: {
+				uint16_t reason = msg[2];
+				MM_DBG("decoder status:sleep reason =0x%04x\n",
+					reason);
+				if ((reason == AUDPP_MSG_REASON_MEM)
+					|| (reason ==
+					AUDPP_MSG_REASON_NODECODER)) {
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_FAILURE;
+					wake_up(&audio->wait);
+				} else if (reason == AUDPP_MSG_REASON_NONE) {
+					/* decoder is in disable state */
+					audio->dec_state =
+						MSM_AUD_DECODER_STATE_CLOSE;
+					wake_up(&audio->wait);
+				}
+				break;
+			}
+			case AUDPP_DEC_STATUS_INIT:
+				MM_DBG("decoder status: init\n");
+				if (audio->pcm_feedback)
+					audpp_cmd_cfg_routing_mode(audio);
+				else
+					audpp_cmd_cfg_adec_params(audio);
+				break;
+
+			case AUDPP_DEC_STATUS_CFG:
+				MM_DBG("decoder status: cfg\n");
+				break;
+			case AUDPP_DEC_STATUS_PLAY:
+				MM_DBG("decoder status: play\n");
+				if (audio->pcm_feedback) {
+					audac3_config_hostpcm(audio);
+					audac3_buffer_refresh(audio);
+				}
+				audio->dec_state =
+					MSM_AUD_DECODER_STATE_SUCCESS;
+				wake_up(&audio->wait);
+				break;
+			default:
+				MM_ERR("unknown decoder status\n");
+			}
+			break;
+		}
+	case AUDPP_MSG_CFG_MSG:
+		if (msg[0] == AUDPP_MSG_ENA_ENA) {
+			MM_DBG("CFG_MSG ENABLE\n");
+			auddec_dsp_config(audio, 1);
+			audio->out_needed = 0;
+			audio->running = 1;
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+			audpp_dsp_set_eq(audio->dec_id,	audio->eq_enable,
+								&audio->eq);
+			audpp_avsync(audio->dec_id, 22050);
+		} else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+			MM_DBG("CFG_MSG DISABLE\n");
+			audpp_avsync(audio->dec_id, 0);
+			audio->running = 0;
+		} else {
+			MM_DBG("CFG_MSG %d?\n", msg[0]);
+		}
+		break;
+	case AUDPP_MSG_ROUTING_ACK:
+		MM_DBG("ROUTING_ACK\n");
+		audpp_cmd_cfg_adec_params(audio);
+		break;
+	case AUDPP_MSG_FLUSH_ACK:
+		MM_DBG("FLUSH_ACK\n");
+		audio->wflush = 0;
+		audio->rflush = 0;
+		wake_up(&audio->write_wait);
+		if (audio->pcm_feedback)
+			audac3_buffer_refresh(audio);
+		break;
+	case AUDPP_MSG_PCMDMAMISSED:
+		MM_DBG("PCMDMAMISSED\n");
+		audio->teos = 1;
+		wake_up(&audio->write_wait);
+		break;
+	default:
+		MM_ERR("UNKNOWN (%d)\n", id);
+	}
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_ac3 = {
+	.event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+	msm_adsp_write(audio->audplay, audio->queue_id, \
+			cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+	u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+	memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+	cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+	if (enable)
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AC3;
+	else
+		cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+			AUDPP_CMD_DIS_DEC_V;
+
+	return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+static int get_frequency_index(unsigned short frequency)
+{
+	switch (frequency) {
+	case 48000: return 0;
+	case 44100: return 1;
+	case 32000: return 2;
+	default: return -EINVAL;
+	}
+}
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+	struct audpp_cmd_cfg_adec_params_ac3 cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+	/* dsp needs word size */
+	cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_AC3_LEN >> 1;
+	cmd.common.dec_id = audio->dec_id;
+	cmd.common.input_sampling_frequency = (audio->ac3_config).fsCod;
+
+	cmd.index[0] = (((audio->ac3_config).numChans << 8) & 0xFF00) |
+				((audio->ac3_config).wordSize & 0x00FF);
+
+	cmd.index[1] = (((audio->ac3_config).kCapableMode << 12) & 0xF000) |
+				(((audio->ac3_config).compMode << 8) & 0x0F00) |
+				(((audio->ac3_config).outLfeOn << 4) & 0x00F0) |
+				((audio->ac3_config).outputMode & 0x000F);
+
+	cmd.index[2] = ((((audio->ac3_config).stereoMode << 12) & 0xF000) |
+			(((audio->ac3_config).dualMonoMode << 8) & 0x0F00) |
+			((get_frequency_index((audio->ac3_config).fsCod) << 4)
+			& 0x00F0)) & 0xFFF0; /* last 4 bytes are reserved */
+
+	cmd.index[3] = (audio->ac3_config).pcmScaleFac;
+	cmd.index[4] = (audio->ac3_config).dynRngScaleHi;
+	cmd.index[5] = (audio->ac3_config).dynRngScaleLow;
+
+	cmd.index[6] = (((audio->ac3_config).user_downmix_flag << 8) & 0xFF00)|
+			((audio->ac3_config).user_karaoke_flag & 0x00FF);
+
+	cmd.index[7] = (audio->ac3_config).dm_address_high;
+	cmd.index[8] = (audio->ac3_config).dm_address_low;
+	cmd.index[9] = (audio->ac3_config).ko_address_high;
+	cmd.index[10] = (audio->ac3_config).ko_address_high;
+
+	cmd.index[11] = (((audio->ac3_config).max_rep_count << 1) & 0xFFFE) |
+			((audio->ac3_config).error_concealment & 0x0001);
+
+	cmd.index[12] = (((audio->ac3_config).channel_routing_mode[3] << 12)
+			& 0xF000) |
+			(((audio->ac3_config).channel_routing_mode[2] << 8)
+			& 0x0F00) |
+			(((audio->ac3_config).channel_routing_mode[1] << 4)
+			& 0x00F0) |
+			((audio->ac3_config).channel_routing_mode[0] & 0x000F);
+
+	cmd.index[13] = ((((audio->ac3_config).channel_routing_mode[5] << 12)
+			& 0xF000) |
+			(((audio->ac3_config).channel_routing_mode[4] << 8)
+			& 0x0F00)) & 0xFF00; /* last 8 bytes are reserved */
+
+	audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+	struct audpp_cmd_routing_mode cmd;
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+	cmd.object_number = audio->dec_id;
+	if (audio->pcm_feedback)
+		cmd.routing_mode = ROUTING_MODE_FTRT;
+	else
+		cmd.routing_mode = ROUTING_MODE_RT;
+
+	audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+				       unsigned idx, unsigned len)
+{
+	struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+	cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+	if (audio->mfield)
+		cmd.decoder_id = AUDAC3_METAFIELD_MASK |
+			(audio->out[idx].mfield_sz >> 1);
+	else
+		cmd.decoder_id = audio->dec_id;
+	cmd.buf_ptr = audio->out[idx].addr;
+	cmd.buf_size = len / 2;
+	cmd.partition_number = 0;
+	/* complete writes to the input buffer */
+	wmb();
+	return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audac3_buffer_refresh(struct audio *audio)
+{
+	struct audplay_cmd_buffer_refresh refresh_cmd;
+
+	refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+	refresh_cmd.num_buffers = 1;
+	refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+	refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+
+	refresh_cmd.buf_read_count = 0;
+	MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+			refresh_cmd.buf0_length);
+	(void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audac3_config_hostpcm(struct audio *audio)
+{
+	struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+	cfg_cmd.max_buffers = 1;
+	cfg_cmd.byte_swap = 0;
+	cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+	cfg_cmd.feedback_frequency = 1;
+	cfg_cmd.partition_number = 0;
+	(void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audac3_send_data(struct audio *audio, unsigned needed)
+{
+	struct buffer *frame;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (!audio->running)
+		goto done;
+
+	if (needed && !audio->wflush) {
+		/* We were called from the callback because the DSP
+		 * requested more data.  Note that the DSP does want
+		 * more data, and if a buffer was in-flight, mark it
+		 * as available (since the DSP must now be done with
+		 * it).
+		 */
+		audio->out_needed = 1;
+		frame = audio->out + audio->out_tail;
+		if (frame->used == 0xffffffff) {
+			MM_DBG("frame %d free\n", audio->out_tail);
+			frame->used = 0;
+			audio->out_tail ^= 1;
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	if (audio->out_needed) {
+		/* If the DSP currently wants data and we have a
+		 * buffer available, we will send it and reset
+		 * the needed flag.  We'll mark the buffer as in-flight
+		 * so that it won't be recycled until the next buffer
+		 * is requested
+		 */
+
+		frame = audio->out + audio->out_tail;
+		if (frame->used) {
+			BUG_ON(frame->used == 0xffffffff);
+			MM_DBG("frame %d busy\n", audio->out_tail);
+			audplay_dsp_send_data_avail(audio, audio->out_tail,
+						    frame->used);
+			frame->used = 0xffffffff;
+			audio->out_needed = 0;
+		}
+	}
+done:
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audac3_flush(struct audio *audio)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	audio->out[0].used = 0;
+	audio->out[1].used = 0;
+	audio->out_head = 0;
+	audio->out_tail = 0;
+	audio->out_needed = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	atomic_set(&audio->out_bytes, 0);
+}
+
+static void audac3_flush_pcm_buf(struct audio *audio)
+{
+	uint8_t index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+		audio->in[index].used = 0;
+	audio->buf_refresh = 0;
+	audio->read_next = 0;
+	audio->fill_next = 0;
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+/*check if func to be added to validate user data*/
+
+static void audac3_ioport_reset(struct audio *audio)
+{
+	/* Make sure read/write thread are free from
+	 * sleep and knowing that system is not able
+	 * to process io request at the moment
+	 */
+	wake_up(&audio->write_wait);
+	mutex_lock(&audio->write_lock);
+	audac3_flush(audio);
+	mutex_unlock(&audio->write_lock);
+	wake_up(&audio->read_wait);
+	mutex_lock(&audio->read_lock);
+	audac3_flush_pcm_buf(audio);
+	mutex_unlock(&audio->read_lock);
+}
+
+static int audac3_events_pending(struct audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audac3_reset_event_queue(struct audio *audio)
+{
+	unsigned long flags;
+	struct audac3_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audac3_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audac3_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+
+static long audac3_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audac3_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audac3_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audac3_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+				struct audac3_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+	if (audio->eq_enable == enable && !audio->eq_needs_commit)
+		return 0;
+
+	audio->eq_enable = enable;
+
+	if (audio->running) {
+		audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+		audio->eq_needs_commit = 0;
+	}
+	return 0;
+}
+
+static long audac3_ioctl(struct file *file, unsigned int cmd,
+			  unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	unsigned long flags = 0;
+	uint16_t enable_mask;
+	int enable;
+	int prev_state;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	int len = 0;
+
+	MM_DBG("cmd = %d\n", cmd);
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+		audio_enable_eq(audio, enable);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+	case AUDIO_SET_VOLUME:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.volume = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_PAN:
+		spin_lock_irqsave(&audio->dsp_lock, flags);
+		audio->vol_pan.pan = arg;
+		if (audio->running)
+			audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		rc = 0;
+		break;
+
+	case AUDIO_SET_EQ:
+		prev_state = audio->eq_enable;
+		audio->eq_enable = 0;
+		if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+				sizeof(audio->eq) -
+				(AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->eq_enable = prev_state;
+		audio->eq_needs_commit = 1;
+		rc = 0;
+		break;
+	}
+
+	if (-EINVAL != rc)
+		return rc;
+
+	if (cmd == AUDIO_GET_EVENT) {
+		MM_DBG("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audac3_process_event_req(audio,
+					(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		MM_DBG("AUDIO_START\n");
+		rc = audac3_enable(audio);
+		if (!rc) {
+			rc = wait_event_interruptible_timeout(audio->wait,
+				audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+				msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+			MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+			if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS) {
+				MM_ERR("In audio->dec_state !=\n");
+				rc = -ENODEV;
+			} else
+				rc = 0;
+		}
+		break;
+	case AUDIO_STOP:
+		MM_DBG("AUDIO_STOP\n");
+		rc = audac3_disable(audio);
+		audac3_ioport_reset(audio);
+		audio->stopped = 0;
+		break;
+	case AUDIO_FLUSH:
+		MM_DBG("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		audac3_ioport_reset(audio);
+		if (audio->running) {
+			audpp_flush(audio->dec_id);
+			rc = wait_event_interruptible(audio->write_wait,
+				!audio->wflush);
+			if (rc < 0) {
+				MM_ERR("AUDIO_FLUSH interrupted\n");
+				rc = -EINTR;
+			}
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		break;
+	case AUDIO_SET_CONFIG:{
+			struct msm_audio_config config;
+			if (copy_from_user
+				(&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			audio->mfield = config.meta_field;
+			rc = 0;
+			MM_DBG("AUDIO_SET_CONFIG applicable only"\
+				" for meta field configuration\n");
+			break;
+		}
+	case AUDIO_GET_CONFIG:{
+			struct msm_audio_config config;
+			config.buffer_size = BUFSZ;
+			config.buffer_count = 2;
+			config.sample_rate = (audio->ac3_config).fsCod;
+			config.channel_count = 2;
+			config.meta_field = 0;
+			config.unused[0] = 0;
+			config.unused[1] = 0;
+			config.unused[2] = 0;
+			if (copy_to_user((void *)arg, &config, sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_GET_AC3_CONFIG:{
+			if (copy_to_user((void *)arg, &audio->ac3_config,
+				sizeof(audio->ac3_config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_AC3_CONFIG:{
+			struct msm_audio_ac3_config usr_config;
+
+			if (copy_from_user
+				(&usr_config, (void *)arg,
+					sizeof(usr_config))) {
+				rc = -EFAULT;
+				break;
+			}
+
+			audio->ac3_config = usr_config;
+			rc = 0;
+			break;
+		}
+	case AUDIO_GET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			config.pcm_feedback = audio->pcm_feedback;
+			config.buffer_count = PCM_BUF_MAX_COUNT;
+			config.buffer_size = PCM_BUFSZ;
+			if (copy_to_user((void *)arg, &config, sizeof(config)))
+				rc = -EFAULT;
+			else
+				rc = 0;
+			break;
+		}
+	case AUDIO_SET_PCM_CONFIG:{
+			struct msm_audio_pcm_config config;
+			if (copy_from_user
+			    (&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+			}
+			if (config.pcm_feedback != audio->pcm_feedback) {
+
+				MM_ERR("Not sufficient permission to"\
+					" change the playback mode\n");
+				rc = -EACCES;
+				break;
+
+			}
+			if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+			    (config.buffer_count == 1))
+				config.buffer_count = PCM_BUF_MAX_COUNT;
+
+			if (config.buffer_size < PCM_BUFSZ)
+				config.buffer_size = PCM_BUFSZ;
+
+			/* Check if pcm feedback is required */
+			if ((config.pcm_feedback) && (!audio->read_data)) {
+				MM_DBG("allocate PCM buf %d\n",
+					config.buffer_count *
+					config.buffer_size);
+				handle = ion_alloc(audio->client,
+					(config.buffer_size *
+					config.buffer_count),
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				if (IS_ERR_OR_NULL(handle)) {
+					MM_ERR("Unable to alloc I/P buffs\n");
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				}
+
+				audio->input_buff_handle = handle;
+
+				rc = ion_phys(audio->client ,
+					handle, &addr, &len);
+				if (rc) {
+					MM_ERR("Invalid phy: %x sz: %x\n",
+						(unsigned int) addr,
+						(unsigned int) len);
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				} else {
+					MM_INFO("Got valid phy: %x sz: %x\n",
+						(unsigned int) audio->read_phys,
+						(unsigned int) len);
+				}
+				audio->read_phys = (int32_t)addr;
+
+				rc = ion_handle_get_flags(audio->client,
+					handle, &ionflag);
+				if (rc) {
+					MM_ERR("could not get flags\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				}
+
+				audio->map_v_read = ion_map_kernel(
+					audio->client,
+					handle, ionflag);
+				if (IS_ERR(audio->map_v_read)) {
+					MM_ERR("map of read buf failed\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+				} else {
+					uint8_t index;
+					uint32_t offset = 0;
+					audio->read_data =
+						audio->map_v_read;
+					audio->buf_refresh = 0;
+					audio->pcm_buf_count =
+					    config.buffer_count;
+					audio->read_next = 0;
+					audio->fill_next = 0;
+
+					for (index = 0;
+					     index < config.buffer_count;
+					     index++) {
+						audio->in[index].data =
+						    audio->read_data + offset;
+						audio->in[index].addr =
+						    audio->read_phys + offset;
+						audio->in[index].size =
+						    config.buffer_size;
+						audio->in[index].used = 0;
+						offset += config.buffer_size;
+					}
+					MM_DBG("read buf: phy addr"\
+						" 0x%08x kernel addr 0x%08x\n",
+						audio->read_phys,
+						(int)audio->read_data);
+					rc = 0;
+				}
+			} else {
+				rc = 0;
+			}
+			break;
+		}
+	case AUDIO_PAUSE:
+		MM_DBG("AUDIO_PAUSE %ld\n", arg);
+		rc = audpp_pause(audio->dec_id, (int) arg);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audac3_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+	struct audio *audio = file->private_data;
+	int rc = 0;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	if (!audio->running || audio->pcm_feedback) {
+		rc = -EINVAL;
+		goto done_nolock;
+	}
+
+	mutex_lock(&audio->write_lock);
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(!audio->out[0].used &&
+		!audio->out[1].used &&
+		audio->out_needed) || audio->wflush);
+
+	if (rc < 0)
+		goto done;
+	else if (audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	/* pcm dmamiss message is sent continously
+	 * when decoder is starved so no race
+	 * condition concern
+	 */
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		audio->teos || audio->wflush);
+
+	if (audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+done_nolock:
+	return rc;
+}
+
+static ssize_t audac3_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	int rc = 0;
+	if (!audio->pcm_feedback) {
+		MM_ERR("returning from read as tunnel mode\n");
+		return 0;
+		/* PCM feedback is not enabled. Nothing to read */
+	}
+	mutex_lock(&audio->read_lock);
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->read_wait,
+				(audio->in[audio->read_next].used > 0) ||
+				(audio->stopped) || (audio->rflush));
+
+		MM_DBG("wait terminated count%d\n", count);
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->rflush) {
+			rc = -EBUSY;
+			break;
+		}
+		if (count < audio->in[audio->read_next].used) {
+			/* Read must happen in frame boundary. Since driver does
+			 * not know frame size, read count must be greater or
+			 * equal to size of PCM samples
+			 */
+			MM_DBG("read stop - partial frame\n");
+			break;
+		} else {
+			MM_DBG("read from in[%d]\n", audio->read_next);
+			/* order reads from the output buffer */
+			rmb();
+			if (copy_to_user
+			    (buf, audio->in[audio->read_next].data,
+			     audio->in[audio->read_next].used)) {
+				MM_ERR("invalid addr %x\n",
+				       (unsigned int)buf);
+				rc = -EFAULT;
+				break;
+			}
+			count -= audio->in[audio->read_next].used;
+			buf += audio->in[audio->read_next].used;
+			audio->in[audio->read_next].used = 0;
+			if ((++audio->read_next) == audio->pcm_buf_count)
+				audio->read_next = 0;
+			break;
+				/* Force to exit while loop
+				 * to prevent output thread
+				 * sleep too long if data is
+				 * not ready at this moment
+				 */
+
+		}
+	}
+	/* don't feed output buffer to HW decoder during flushing
+	 * buffer refresh command will be sent once flush completes
+	 * send buf refresh command here can confuse HW decoder
+	 */
+	if (audio->buf_refresh && !audio->rflush) {
+		audio->buf_refresh = 0;
+		MM_DBG("kick start pcm feedback again\n");
+		audac3_buffer_refresh(audio);
+	}
+	mutex_unlock(&audio->read_lock);
+	if (buf > start)
+		rc = buf - start;
+	MM_DBG("read %d bytes\n", rc);
+	return rc;
+}
+
+static int audac3_process_eos(struct audio *audio,
+		const char __user *buf_start, unsigned short mfield_size)
+{
+	int rc = 0;
+	struct buffer *frame;
+
+	frame = audio->out + audio->out_head;
+
+	rc = wait_event_interruptible(audio->write_wait,
+		(audio->out_needed &&
+		audio->out[0].used == 0 &&
+		audio->out[1].used == 0)
+		|| (audio->stopped)
+		|| (audio->wflush));
+
+	if (rc < 0)
+		goto done;
+	if (audio->stopped || audio->wflush) {
+		rc = -EBUSY;
+		goto done;
+	}
+
+	if (copy_from_user(frame->data, buf_start, mfield_size)) {
+		rc = -EFAULT;
+		goto done;
+	}
+
+	frame->mfield_sz = mfield_size;
+	audio->out_head ^= 1;
+	frame->used = mfield_size;
+	audac3_send_data(audio, 0);
+
+done:
+	return rc;
+}
+
+static ssize_t audac3_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *pos)
+{
+	struct audio *audio = file->private_data;
+	const char __user *start = buf;
+	struct buffer *frame;
+	size_t xfer;
+	char *cpy_ptr;
+	unsigned short mfield_size = 0;
+	int rc = 0, eos_condition = AUDAC3_EOS_NONE;
+
+	MM_DBG("cnt=%d\n", count);
+
+	if (count & 1)
+		return -EINVAL;
+
+	mutex_lock(&audio->write_lock);
+	while (count > 0) {
+		frame = audio->out + audio->out_head;
+		cpy_ptr = frame->data;
+		rc = wait_event_interruptible(audio->write_wait,
+					      (frame->used == 0)
+						|| (audio->stopped)
+						|| (audio->wflush));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			rc = -EBUSY;
+			break;
+		}
+
+		if (audio->mfield) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (__get_user(mfield_size,
+					(unsigned short __user *) buf)) {
+					rc = -EFAULT;
+					break;
+				} else if (mfield_size > count) {
+					rc = -EINVAL;
+					break;
+				}
+				MM_DBG("mf offset_val %x\n", mfield_size);
+				if (copy_from_user(cpy_ptr, buf,
+							mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				 * contains just meta field
+				 */
+				if (cpy_ptr[AUDAC3_EOS_FLG_OFFSET] &
+						AUDAC3_EOS_FLG_MASK) {
+					MM_DBG("eos set\n");
+					eos_condition = AUDAC3_EOS_SET;
+					if (mfield_size == count) {
+						buf += mfield_size;
+						break;
+					} else
+					cpy_ptr[AUDAC3_EOS_FLG_OFFSET] &=
+						~AUDAC3_EOS_FLG_MASK;
+				}
+				 /* Check EOS to see if */
+				cpy_ptr += mfield_size;
+				count -= mfield_size;
+				buf += mfield_size;
+			 } else {
+				 mfield_size = 0;
+				 MM_DBG("continuous buffer\n");
+			 }
+			 frame->mfield_sz = mfield_size;
+		}
+
+		xfer = (count > (frame->size - mfield_size)) ?
+			(frame->size - mfield_size) : count;
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		frame->used = xfer + mfield_size;
+		audio->out_head ^= 1;
+		count -= xfer;
+		buf += xfer;
+		audac3_send_data(audio, 0);
+	}
+	if (eos_condition == AUDAC3_EOS_SET)
+		rc = audac3_process_eos(audio, start, mfield_size);
+	mutex_unlock(&audio->write_lock);
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+static int audac3_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	audac3_disable(audio);
+	if (audio->rmt_resource_released == 0)
+		rmt_put_resource(audio);
+	audac3_flush(audio);
+	audac3_flush_pcm_buf(audio);
+	msm_adsp_put(audio->audplay);
+	audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audac3_reset_event_queue(audio);
+	ion_unmap_kernel(audio->client, audio->output_buff_handle);
+	ion_free(audio->client, audio->output_buff_handle);
+	if (audio->input_buff_handle != NULL) {
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
+	}
+	ion_client_destroy(audio->client);
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audac3_post_event(struct audio *audio, int type,
+		union msm_audio_event_payload payload)
+{
+	struct audac3_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+				struct audac3_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audac3_event), GFP_ATOMIC);
+		if (!e_node) {
+			MM_ERR("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static void audac3_suspend(struct early_suspend *h)
+{
+	struct audac3_suspend_ctl *ctl =
+		container_of(h, struct audac3_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audac3_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audac3_resume(struct early_suspend *h)
+{
+	struct audac3_suspend_ctl *ctl =
+		container_of(h, struct audac3_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	MM_DBG("\n"); /* Macro prints the file name and function */
+	audac3_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audac3_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audac3_debug_read(struct file *file, char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 1024;
+	static char buffer[1024];
+	int n = 0, i;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_feedback %d\n", audio->pcm_feedback);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_buf_sz %d\n", audio->out[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_count %d\n", audio->pcm_buf_count);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"pcm_buf_sz %d\n", audio->in[0].size);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"volume %x\n", audio->vol_pan.volume);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"running %d\n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"dec state %d\n", audio->dec_state);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_needed %d\n", audio->out_needed);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_head %d\n", audio->out_head);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out_tail %d\n", audio->out_tail);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[0].used %d\n", audio->out[0].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"out[1].used %d\n", audio->out[1].used);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"buffer_refresh %d\n", audio->buf_refresh);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"read_next %d\n", audio->read_next);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+			"fill_next %d\n", audio->fill_next);
+	for (i = 0; i < audio->pcm_buf_count; i++)
+		n += scnprintf(buffer + n, debug_bufmax - n,
+				"in[%d].size %d\n", i, audio->in[i].used);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audac3_debug_fops = {
+	.read = audac3_debug_read,
+	.open = audac3_debug_open,
+};
+#endif
+
+static int audac3_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, dec_attrb, decid, i;
+	struct audac3_event *e_node = NULL;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_ac3_" + 5];
+#endif
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		MM_ERR("no memory to allocate audio instance\n");
+		rc = -ENOMEM;
+		goto done;
+	}
+	MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+	/* Allocate the decoder */
+	dec_attrb = AUDDEC_DEC_AC3;
+	if ((file->f_mode & FMODE_WRITE) &&
+			(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+		audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		dec_attrb |= MSM_AUD_MODE_TUNNEL;
+		audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+	decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+			&audio->queue_id);
+
+	if (decid < 0) {
+		MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENODEV;
+		kfree(audio);
+		goto done;
+	}
+
+	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+	client = msm_ion_client_create(UINT_MAX, "Audio_AC3_client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\n");
+		rc = -ENOMEM;
+		goto client_create_error;
+	}
+	audio->client = client;
+
+	handle = ion_alloc(client, DMASZ, SZ_4K,
+			ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client, handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_write)) {
+		MM_ERR("could not map write buffers,freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	audio->data = audio->map_v_write;
+	MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+		audio->phys, (int)audio->data);
+
+	rc = msm_adsp_get(audio->module_name, &audio->audplay,
+			&audplay_adsp_ops_ac3, audio);
+	if (rc) {
+		MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+				audio->module_name, (int)audio);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		goto err;
+	}
+
+	rc = rmt_get_resource(audio);
+	if (rc) {
+		MM_ERR("ADSP resources are not available for AC3 session"\
+			" 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+		if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+			audmgr_close(&audio->audmgr);
+		msm_adsp_put(audio->audplay);
+		goto err;
+	}
+
+	/* Initialize all locks of audio instance */
+	audio->input_buff_handle = NULL;
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->read_wait);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+
+	audio->out[0].data = audio->data + 0;
+	audio->out[0].addr = audio->phys + 0;
+	audio->out[0].size = BUFSZ;
+
+	audio->out[1].data = audio->data + BUFSZ;
+	audio->out[1].addr = audio->phys + BUFSZ;
+	audio->out[1].size = BUFSZ;
+
+	audio->vol_pan.volume = 0x3FFF;
+
+	(audio->ac3_config).wordSize = AUDAC3_DEF_WORDSIZE;
+	(audio->ac3_config).user_downmix_flag = AUDAC3_DEF_USER_DOWNMIX_FLAG;
+	(audio->ac3_config).user_karaoke_flag = AUDAC3_DEF_USER_KARAOKE_FLAG;
+	(audio->ac3_config).error_concealment = AUDAC3_DEF_ERROR_CONCEALMENT;
+	(audio->ac3_config).max_rep_count = AUDAC3_DEF_MAX_REPEAT_COUNT;
+
+	audac3_flush(audio);
+
+	file->private_data = audio;
+	audio->opened = 1;
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_ac3_%04x", audio->dec_id);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audac3_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audac3_resume;
+	audio->suspend_ctl.node.suspend = audac3_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDAC3_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audac3_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			MM_ERR("event pkt alloc failed\n");
+			break;
+		}
+	}
+done:
+	return rc;
+err:
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_flags_error:
+output_buff_get_phys_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
+	audpp_adec_free(audio->dec_id);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_ac3_fops = {
+	.owner = THIS_MODULE,
+	.open = audac3_open,
+	.release = audac3_release,
+	.read = audac3_read,
+	.write = audac3_write,
+	.unlocked_ioctl = audac3_ioctl,
+	.fsync = audac3_fsync,
+};
+
+struct miscdevice audio_ac3_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_ac3",
+	.fops = &audio_ac3_fops,
+};
+
+static int __init audac3_init(void)
+{
+	return misc_register(&audio_ac3_misc);
+
+}
+
+static void __exit audac3_exit(void)
+{
+	misc_deregister(&audio_ac3_misc);
+}
+
+module_init(audac3_init);
+module_exit(audac3_exit);
+
+MODULE_DESCRIPTION("MSM AC3 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.h b/arch/arm/mach-msm/qdsp5/audmgr.h
index 34c8488..3d8c560 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr.h
+++ b/arch/arm/mach-msm/qdsp5/audmgr.h
@@ -77,6 +77,7 @@
 	RPC_AUD_DEF_CODEC_AMR_NB,
 	RPC_AUD_DEF_CODEC_13K,
 	RPC_AUD_DEF_CODEC_EVRC,
+	RPC_AUD_DEF_CODEC_AC3,
 	RPC_AUD_DEF_CODEC_MAX_002,
 };
 
diff --git a/arch/arm/mach-msm/qdsp5/audmgr_new.h b/arch/arm/mach-msm/qdsp5/audmgr_new.h
index 3604405..2453022 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr_new.h
+++ b/arch/arm/mach-msm/qdsp5/audmgr_new.h
@@ -75,6 +75,7 @@
 	RPC_AUD_DEF_CODEC_AMR_NB,
 	RPC_AUD_DEF_CODEC_13K,
 	RPC_AUD_DEF_CODEC_EVRC,
+	RPC_AUD_DEF_CODEC_AC3,
 	RPC_AUD_DEF_CODEC_MAX_002,
 };
 
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 2ea1bc9..0c75f66 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -10,7 +10,8 @@
 obj-y += audio_mvs.o
 obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
 endif
-obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_tal.o q6core.o dsp_debug.o
+obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_v1.o apr_tal.o q6core.o dsp_debug.o
+obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o q6core.o dsp_debug.o
 obj-y += audio_acdb.o
 ifdef CONFIG_ARCH_MSM9615
 obj-y += rtac.o
@@ -23,4 +24,5 @@
 obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
 obj-$(CONFIG_MSM_QDSP6V2_CODECS) += rtac_v2.o q6audio_v2.o q6audio_v2_aio.o
 obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
 obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
diff --git a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
new file mode 100644
index 0000000..9924b52
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <mach/peripheral-loader.h>
+#include <mach/qdsp6v2/apr.h>
+
+#define Q6_PIL_GET_DELAY_MS 100
+
+struct adsp_loader_private {
+	void *pil_h;
+};
+
+static int adsp_loader_probe(struct platform_device *pdev)
+{
+	struct adsp_loader_private *priv;
+	int rc = 0;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->pil_h = pil_get("adsp");
+	if (IS_ERR(priv->pil_h)) {
+		pr_err("%s: pil get adsp failed, error:%d\n", __func__, rc);
+		devm_kfree(&pdev->dev, priv);
+		goto fail;
+	}
+
+	/* Query the DSP to check if resources are available */
+	msleep(Q6_PIL_GET_DELAY_MS);
+
+	/* Set the state of the ADSP in APR driver */
+	apr_set_q6_state(APR_SUBSYS_LOADED);
+
+	/* Query for MMPM API */
+
+	pr_info("%s: Q6/ADSP image is loaded\n", __func__);
+fail:
+	return rc;
+}
+
+static int adsp_loader_remove(struct platform_device *pdev)
+{
+	struct adsp_loader_private *priv;
+
+	priv = platform_get_drvdata(pdev);
+	pil_put(priv->pil_h);
+	pr_info("%s: Q6/ADSP image is unloaded\n", __func__);
+
+	return 0;
+}
+
+static const struct of_device_id adsp_loader_dt_match[] = {
+	{ .compatible = "qcom,adsp-loader" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adsp_loader_dt_match);
+
+static struct platform_driver adsp_loader_driver = {
+	.driver = {
+		.name = "adsp-loader",
+		.owner = THIS_MODULE,
+		.of_match_table = adsp_loader_dt_match,
+	},
+	.probe = adsp_loader_probe,
+	.remove = __devexit_p(adsp_loader_remove),
+};
+
+static int __init adsp_loader_init(void)
+{
+	return platform_driver_register(&adsp_loader_driver);
+}
+module_init(adsp_loader_init);
+
+static void __exit adsp_loader_exit(void)
+{
+	platform_driver_unregister(&adsp_loader_driver);
+}
+module_exit(adsp_loader_exit);
+
+MODULE_DESCRIPTION("ADSP Loader module");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index a0bfb27..d70da19 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -15,7 +15,6 @@
 #include <linux/types.h>
 #include <linux/uaccess.h>
 #include <linux/spinlock.h>
-#include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
@@ -36,13 +35,11 @@
 #include <mach/subsystem_notif.h>
 #include <mach/subsystem_restart.h>
 
-struct apr_q6 q6;
-struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
-static atomic_t dsp_state;
-static atomic_t modem_state;
+static struct apr_q6 q6;
+static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
 
-static wait_queue_head_t  dsp_wait;
-static wait_queue_head_t  modem_wait;
+static wait_queue_head_t dsp_wait;
+static wait_queue_head_t modem_wait;
 /* Subsystem restart: QDSP6 data, functions */
 static struct workqueue_struct *apr_reset_workqueue;
 static void apr_reset_deregister(struct work_struct *work);
@@ -51,6 +48,199 @@
 	struct work_struct work;
 };
 
+struct apr_svc_table {
+	char name[64];
+	int idx;
+	int id;
+	int client_id;
+};
+
+static const struct apr_svc_table svc_tbl_audio[] = {
+	{
+		.name = "AFE",
+		.idx = 0,
+		.id = APR_SVC_AFE,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "ASM",
+		.idx = 1,
+		.id = APR_SVC_ASM,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "ADM",
+		.idx = 2,
+		.id = APR_SVC_ADM,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "CORE",
+		.idx = 3,
+		.id = APR_SVC_ADSP_CORE,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "TEST",
+		.idx = 4,
+		.id = APR_SVC_TEST_CLIENT,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "MVM",
+		.idx = 5,
+		.id = APR_SVC_ADSP_MVM,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "CVS",
+		.idx = 6,
+		.id = APR_SVC_ADSP_CVS,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "CVP",
+		.idx = 7,
+		.id = APR_SVC_ADSP_CVP,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+	{
+		.name = "USM",
+		.idx = 8,
+		.id = APR_SVC_USM,
+		.client_id = APR_CLIENT_AUDIO,
+	},
+};
+
+static struct apr_svc_table svc_tbl_voice[] = {
+	{
+		.name = "VSM",
+		.idx = 0,
+		.id = APR_SVC_VSM,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "VPM",
+		.idx = 1,
+		.id = APR_SVC_VPM,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "MVS",
+		.idx = 2,
+		.id = APR_SVC_MVS,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "MVM",
+		.idx = 3,
+		.id = APR_SVC_MVM,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "CVS",
+		.idx = 4,
+		.id = APR_SVC_CVS,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "CVP",
+		.idx = 5,
+		.id = APR_SVC_CVP,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "SRD",
+		.idx = 6,
+		.id = APR_SVC_SRD,
+		.client_id = APR_CLIENT_VOICE,
+	},
+	{
+		.name = "TEST",
+		.idx = 7,
+		.id = APR_SVC_TEST_CLIENT,
+		.client_id = APR_CLIENT_VOICE,
+	},
+};
+
+enum apr_subsys_state apr_get_modem_state(void)
+{
+	return atomic_read(&q6.modem_state);
+}
+
+void apr_set_modem_state(enum apr_subsys_state state)
+{
+	atomic_set(&q6.modem_state, state);
+}
+
+enum apr_subsys_state apr_cmpxchg_modem_state(enum apr_subsys_state prev,
+					      enum apr_subsys_state new)
+{
+	return atomic_cmpxchg(&q6.modem_state, prev, new);
+}
+
+enum apr_subsys_state apr_get_q6_state(void)
+{
+	return atomic_read(&q6.q6_state);
+}
+EXPORT_SYMBOL_GPL(apr_get_q6_state);
+
+int apr_set_q6_state(enum apr_subsys_state state)
+{
+	pr_debug("%s: setting adsp state %d\n", __func__, state);
+	if (state < APR_SUBSYS_DOWN || state > APR_SUBSYS_LOADED)
+		return -EINVAL;
+	atomic_set(&q6.q6_state, state);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(apr_set_q6_state);
+
+enum apr_subsys_state apr_cmpxchg_q6_state(enum apr_subsys_state prev,
+					   enum apr_subsys_state new)
+{
+	return atomic_cmpxchg(&q6.q6_state, prev, new);
+}
+
+int apr_wait_for_device_up(int dest_id)
+{
+	int rc = -1;
+	if (dest_id == APR_DEST_MODEM)
+		rc = wait_event_interruptible_timeout(modem_wait,
+				    (apr_get_modem_state() == APR_SUBSYS_UP),
+				    (1 * HZ));
+	else if (dest_id == APR_DEST_QDSP6)
+		rc = wait_event_interruptible_timeout(dsp_wait,
+				    (apr_get_q6_state() == APR_SUBSYS_UP),
+				    (1 * HZ));
+	else
+		pr_err("%s: unknown dest_id %d\n", __func__, dest_id);
+	/* returns left time */
+	return rc;
+}
+
+int apr_load_adsp_image(void)
+{
+	int rc = 0;
+	mutex_lock(&q6.lock);
+	if (apr_get_q6_state() == APR_SUBSYS_UP) {
+		q6.pil = pil_get("q6");
+		if (IS_ERR(q6.pil)) {
+			rc = PTR_ERR(q6.pil);
+			pr_err("APR: Unable to load q6 image, error:%d\n", rc);
+		} else {
+			apr_set_q6_state(APR_SUBSYS_LOADED);
+			pr_debug("APR: Image is loaded, stated\n");
+		}
+	} else
+		pr_debug("APR: cannot load state %d\n", apr_get_q6_state());
+	mutex_unlock(&q6.lock);
+	return rc;
+}
+
+struct apr_client *apr_get_client(int dest_id, int client_id)
+{
+	return &client[dest_id][client_id];
+}
 
 int apr_send_pkt(void *handle, uint32_t *buf)
 {
@@ -72,11 +262,11 @@
 	}
 
 	if ((svc->dest_id == APR_DEST_QDSP6) &&
-					(atomic_read(&dsp_state) == 0)) {
-		pr_err("apr: Still dsp is not Up\n");
+	    (apr_get_q6_state() != APR_SUBSYS_LOADED)) {
+		pr_err("%s: Still dsp is not Up\n", __func__);
 		return -ENETRESET;
 	} else if ((svc->dest_id == APR_DEST_MODEM) &&
-					(atomic_read(&modem_state) == 0)) {
+		   (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
 		pr_err("apr: Still Modem is not Up\n");
 		return -ENETRESET;
 	}
@@ -111,7 +301,7 @@
 	return w_len;
 }
 
-static void apr_cb_func(void *buf, int len, void *priv)
+void apr_cb_func(void *buf, int len, void *priv)
 {
 	struct apr_client_data data;
 	struct apr_client *apr_client;
@@ -136,8 +326,7 @@
 	pr_debug("\n*****************\n");
 
 	if (!buf || len <= APR_HDR_SIZE) {
-		pr_err("APR: Improper apr pkt received:%p %d\n",
-								buf, len);
+		pr_err("APR: Improper apr pkt received:%p %d\n", buf, len);
 		return;
 	}
 	hdr = buf;
@@ -162,8 +351,7 @@
 	}
 	msg_type = hdr->hdr_field;
 	msg_type = (msg_type >> 0x08) & 0x0003;
-	if (msg_type >= APR_MSG_TYPE_MAX &&
-			msg_type != APR_BASIC_RSP_RESULT) {
+	if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) {
 		pr_err("APR: Wrong message type: %d\n", msg_type);
 		return;
 	}
@@ -180,8 +368,8 @@
 	if (hdr->src_domain == APR_DOMAIN_MODEM) {
 		src = APR_DEST_MODEM;
 		if (svc == APR_SVC_MVS || svc == APR_SVC_MVM ||
-			svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
-			svc == APR_SVC_TEST_CLIENT)
+		    svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
+		    svc == APR_SVC_TEST_CLIENT)
 			clnt = APR_CLIENT_VOICE;
 		else {
 			pr_err("APR: Wrong svc :%d\n", svc);
@@ -190,11 +378,11 @@
 	} else if (hdr->src_domain == APR_DOMAIN_ADSP) {
 		src = APR_DEST_QDSP6;
 		if (svc == APR_SVC_AFE || svc == APR_SVC_ASM ||
-			svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
-			svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
-			svc == APR_SVC_USM ||
-			svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
-			svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
+		    svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
+		    svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
+		    svc == APR_SVC_USM ||
+		    svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
+		    svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
 			clnt = APR_CLIENT_AUDIO;
 		else {
 			pr_err("APR: Wrong svc :%d\n", svc);
@@ -220,7 +408,7 @@
 	}
 	pr_debug("svc_idx = %d\n", i);
 	pr_debug("%x %x %x %p %p\n", c_svc->id, c_svc->dest_id,
-			c_svc->client_id, c_svc->fn, c_svc->priv);
+		 c_svc->client_id, c_svc->fn, c_svc->priv);
 	data.payload_size = hdr->pkt_size - hdr_size;
 	data.opcode = hdr->opcode;
 	data.src = src;
@@ -241,199 +429,39 @@
 		pr_err("APR: Rxed a packet for NULL callback\n");
 }
 
-struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
-					uint32_t src_port, void *priv)
+int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
+		int *svc_idx, int *svc_id)
 {
-	int client_id = 0;
-	int svc_idx = 0;
-	int svc_id = 0;
-	int dest_id = 0;
-	int temp_port = 0;
-	struct apr_svc *svc = NULL;
-	int rc = 0;
+	int i;
+	int size;
+	struct apr_svc_table *tbl;
+	int ret = 0;
 
-	if (!dest || !svc_name || !svc_fn)
-		return NULL;
-
-	if (!strncmp(dest, "ADSP", 4))
-		dest_id = APR_DEST_QDSP6;
-	else if (!strncmp(dest, "MODEM", 5)) {
-		dest_id = APR_DEST_MODEM;
+	if (dest_id == APR_DEST_QDSP6) {
+		tbl = (struct apr_svc_table *)&svc_tbl_audio;
+		size = ARRAY_SIZE(svc_tbl_audio);
 	} else {
-		pr_err("APR: wrong destination\n");
-		goto done;
+		tbl = (struct apr_svc_table *)&svc_tbl_voice;
+		size = ARRAY_SIZE(svc_tbl_voice);
 	}
 
-	if ((dest_id == APR_DEST_QDSP6) &&
-				(atomic_read(&dsp_state) == 0)) {
-		pr_info("%s: Wait for Lpass to bootup\n", __func__);
-		rc = wait_event_interruptible_timeout(dsp_wait,
-				(atomic_read(&dsp_state) == 1), (1 * HZ));
-		if (rc == 0) {
-			pr_err("%s: DSP is not Up\n", __func__);
-			return NULL;
-		}
-		pr_info("%s: Lpass Up\n", __func__);
-	} else if ((dest_id == APR_DEST_MODEM) &&
-					(atomic_read(&modem_state) == 0)) {
-		pr_info("%s: Wait for modem to bootup\n", __func__);
-		rc = wait_event_interruptible_timeout(modem_wait,
-			(atomic_read(&modem_state) == 1), (1 * HZ));
-		if (rc == 0) {
-			pr_err("%s: Modem is not Up\n", __func__);
-			return NULL;
-		}
-		pr_info("%s: modem Up\n", __func__);
-	}
-
-	if (!strncmp(svc_name, "AFE", 3)) {
-		client_id = APR_CLIENT_AUDIO;
-		svc_idx = 0;
-		svc_id = APR_SVC_AFE;
-	} else if (!strncmp(svc_name, "ASM", 3)) {
-		client_id = APR_CLIENT_AUDIO;
-		svc_idx = 1;
-		svc_id = APR_SVC_ASM;
-	} else if (!strncmp(svc_name, "ADM", 3)) {
-		client_id = APR_CLIENT_AUDIO;
-		svc_idx = 2;
-		svc_id = APR_SVC_ADM;
-	} else if (!strncmp(svc_name, "CORE", 4)) {
-		client_id = APR_CLIENT_AUDIO;
-		svc_idx = 3;
-		svc_id = APR_SVC_ADSP_CORE;
-	} else if (!strncmp(svc_name, "TEST", 4)) {
-		if (dest_id == APR_DEST_QDSP6) {
-			client_id = APR_CLIENT_AUDIO;
-			svc_idx = 4;
-		} else {
-			client_id = APR_CLIENT_VOICE;
-			svc_idx = 7;
-		}
-		svc_id = APR_SVC_TEST_CLIENT;
-	} else if (!strncmp(svc_name, "VSM", 3)) {
-		client_id = APR_CLIENT_VOICE;
-		svc_idx = 0;
-		svc_id = APR_SVC_VSM;
-	} else if (!strncmp(svc_name, "VPM", 3)) {
-		client_id = APR_CLIENT_VOICE;
-		svc_idx = 1;
-		svc_id = APR_SVC_VPM;
-	} else if (!strncmp(svc_name, "MVS", 3)) {
-		client_id = APR_CLIENT_VOICE;
-		svc_idx = 2;
-		svc_id = APR_SVC_MVS;
-	} else if (!strncmp(svc_name, "MVM", 3)) {
-		if (dest_id == APR_DEST_MODEM) {
-			client_id = APR_CLIENT_VOICE;
-			svc_idx = 3;
-			svc_id = APR_SVC_MVM;
-		} else {
-			client_id = APR_CLIENT_AUDIO;
-			svc_idx = 5;
-			svc_id = APR_SVC_ADSP_MVM;
-		}
-	} else if (!strncmp(svc_name, "CVS", 3)) {
-		if (dest_id == APR_DEST_MODEM) {
-			client_id = APR_CLIENT_VOICE;
-			svc_idx = 4;
-			svc_id = APR_SVC_CVS;
-		} else {
-			client_id = APR_CLIENT_AUDIO;
-			svc_idx = 6;
-			svc_id = APR_SVC_ADSP_CVS;
-		}
-	} else if (!strncmp(svc_name, "CVP", 3)) {
-		if (dest_id == APR_DEST_MODEM) {
-			client_id = APR_CLIENT_VOICE;
-			svc_idx = 5;
-			svc_id = APR_SVC_CVP;
-		} else {
-			client_id = APR_CLIENT_AUDIO;
-			svc_idx = 7;
-			svc_id = APR_SVC_ADSP_CVP;
-		}
-	} else if (!strncmp(svc_name, "SRD", 3)) {
-		client_id = APR_CLIENT_VOICE;
-		svc_idx = 6;
-		svc_id = APR_SVC_SRD;
-	} else if (!strncmp(svc_name, "USM", 3)) {
-		client_id = APR_CLIENT_AUDIO;
-		svc_idx = 8;
-		svc_id = APR_SVC_USM;
-	} else {
-		pr_err("APR: Wrong svc name\n");
-		goto done;
-	}
-
-	pr_debug("svc name = %s c_id = %d dest_id = %d\n",
-				svc_name, client_id, dest_id);
-	mutex_lock(&q6.lock);
-	if (q6.state == APR_Q6_NOIMG) {
-		q6.pil = pil_get("q6");
-		if (IS_ERR(q6.pil)) {
-			q6.pil = pil_get("adsp");
-			if (IS_ERR(q6.pil)) {
-				rc = PTR_ERR(q6.pil);
-				pr_err("APR: Unable to load q6 image, error:%d\n",
-									 rc);
-				mutex_unlock(&q6.lock);
-				return svc;
-			}
-		}
-		q6.state = APR_Q6_LOADED;
-	}
-	mutex_unlock(&q6.lock);
-	mutex_lock(&client[dest_id][client_id].m_lock);
-	if (!client[dest_id][client_id].handle) {
-		client[dest_id][client_id].handle = apr_tal_open(client_id,
-				dest_id, APR_DL_SMD, apr_cb_func, NULL);
-		if (!client[dest_id][client_id].handle) {
-			svc = NULL;
-			pr_err("APR: Unable to open handle\n");
-			mutex_unlock(&client[dest_id][client_id].m_lock);
-			goto done;
-		}
-	}
-	mutex_unlock(&client[dest_id][client_id].m_lock);
-	svc = &client[dest_id][client_id].svc[svc_idx];
-	mutex_lock(&svc->m_lock);
-	client[dest_id][client_id].id = client_id;
-	if (svc->need_reset) {
-		mutex_unlock(&svc->m_lock);
-		pr_err("APR: Service needs reset\n");
-		goto done;
-	}
-	svc->priv = priv;
-	svc->id = svc_id;
-	svc->dest_id = dest_id;
-	svc->client_id = client_id;
-	if (src_port != 0xFFFFFFFF) {
-		temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
-		pr_debug("port = %d t_port = %d\n", src_port, temp_port);
-		if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
-			pr_err("APR: temp_port out of bounds\n");
-			mutex_unlock(&svc->m_lock);
-			return NULL;
-		}
-		if (!svc->port_cnt && !svc->svc_cnt)
-			client[dest_id][client_id].svc_cnt++;
-		svc->port_cnt++;
-		svc->port_fn[temp_port] = svc_fn;
-		svc->port_priv[temp_port] = priv;
-	} else {
-		if (!svc->fn) {
-			if (!svc->port_cnt && !svc->svc_cnt)
-				client[dest_id][client_id].svc_cnt++;
-			svc->fn = svc_fn;
-			if (svc->port_cnt)
-				svc->svc_cnt++;
+	for (i = 0; i < size; i++) {
+		if (!strncmp(svc_name, tbl[i].name, strlen(tbl[i].name))) {
+			*client_id = tbl[i].client_id;
+			*svc_idx = tbl[i].idx;
+			*svc_id = tbl[i].id;
+			break;
 		}
 	}
 
-	mutex_unlock(&svc->m_lock);
-done:
-	return svc;
+	pr_debug("%s: svc_name = %s c_id = %d dest_id = %d\n",
+		 __func__, svc_name, *client_id, dest_id);
+	if (i == size) {
+		pr_err("%s: APR: Wrong svc name %s\n", __func__, svc_name);
+		ret = -EINVAL;
+	}
+
+	return ret;
 }
 
 static void apr_reset_deregister(struct work_struct *work)
@@ -489,7 +517,7 @@
 		svc->need_reset = 0x0;
 	}
 	if (client[dest_id][client_id].handle &&
-		!client[dest_id][client_id].svc_cnt) {
+	    !client[dest_id][client_id].svc_cnt) {
 		apr_tal_close(client[dest_id][client_id].handle);
 		client[dest_id][client_id].handle = NULL;
 	}
@@ -524,14 +552,7 @@
 	queue_work(apr_reset_workqueue, &apr_reset_worker->work);
 }
 
-void change_q6_state(int state)
-{
-	mutex_lock(&q6.lock);
-	q6.state = state;
-	mutex_unlock(&q6.lock);
-}
-
-int adsp_state(int state)
+static int adsp_state(int state)
 {
 	pr_info("dsp state = %d\n", state);
 	return 0;
@@ -590,12 +611,12 @@
 }
 
 static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
-								void *_cmd)
+			     void *_cmd)
 {
 	switch (code) {
 	case SUBSYS_BEFORE_SHUTDOWN:
 		pr_debug("M-Notify: Shutdown started\n");
-		atomic_set(&modem_state, 0);
+		apr_set_modem_state(APR_SUBSYS_DOWN);
 		dispatch_event(code, APR_DEST_MODEM);
 		break;
 	case SUBSYS_AFTER_SHUTDOWN:
@@ -605,10 +626,9 @@
 		pr_debug("M-notify: Bootup started\n");
 		break;
 	case SUBSYS_AFTER_POWERUP:
-		if (atomic_read(&modem_state) == 0) {
-			atomic_set(&modem_state, 1);
+		if (apr_cmpxchg_modem_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
+						APR_SUBSYS_DOWN)
 			wake_up(&modem_wait);
-		}
 		pr_debug("M-Notify: Bootup Completed\n");
 		break;
 	default:
@@ -623,12 +643,12 @@
 };
 
 static int lpass_notifier_cb(struct notifier_block *this, unsigned long code,
-								void *_cmd)
+			     void *_cmd)
 {
 	switch (code) {
 	case SUBSYS_BEFORE_SHUTDOWN:
 		pr_debug("L-Notify: Shutdown started\n");
-		atomic_set(&dsp_state, 0);
+		apr_set_q6_state(APR_SUBSYS_DOWN);
 		dispatch_event(code, APR_DEST_QDSP6);
 		break;
 	case SUBSYS_AFTER_SHUTDOWN:
@@ -638,10 +658,9 @@
 		pr_debug("L-notify: Bootup started\n");
 		break;
 	case SUBSYS_AFTER_POWERUP:
-		if (atomic_read(&dsp_state) == 0) {
-			atomic_set(&dsp_state, 1);
+		if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
+					     APR_SUBSYS_DOWN)
 			wake_up(&dsp_wait);
-		}
 		pr_debug("L-Notify: Bootup Completed\n");
 		break;
 	default:
@@ -670,8 +689,7 @@
 		}
 	mutex_init(&q6.lock);
 	dsp_debug_register(adsp_state);
-	apr_reset_workqueue =
-		create_singlethread_workqueue("apr_driver");
+	apr_reset_workqueue = create_singlethread_workqueue("apr_driver");
 	if (!apr_reset_workqueue)
 		return -ENOMEM;
 	return 0;
@@ -683,10 +701,9 @@
 	int ret = 0;
 	init_waitqueue_head(&dsp_wait);
 	init_waitqueue_head(&modem_wait);
-	atomic_set(&dsp_state, 1);
-	atomic_set(&modem_state, 1);
 	subsys_notif_register_notifier("modem", &mnb);
 	subsys_notif_register_notifier("lpass", &lnb);
+	apr_set_subsys_state();
 	return ret;
 }
 late_initcall(apr_late_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v1.c b/arch/arm/mach-msm/qdsp6v2/apr_v1.c
new file mode 100644
index 0000000..9535968
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v1.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/err.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/qdsp6v2/apr_tal.h>
+#include <mach/qdsp6v2/dsp_debug.h>
+#include <mach/peripheral-loader.h>
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+			     uint32_t src_port, void *priv)
+{
+	struct apr_client *client;
+	int client_id = 0;
+	int svc_idx = 0;
+	int svc_id = 0;
+	int dest_id = 0;
+	int temp_port = 0;
+	struct apr_svc *svc = NULL;
+	int rc = 0;
+
+	if (!dest || !svc_name || !svc_fn)
+		return NULL;
+
+	if (!strncmp(dest, "ADSP", 4))
+		dest_id = APR_DEST_QDSP6;
+	else if (!strncmp(dest, "MODEM", 5)) {
+		dest_id = APR_DEST_MODEM;
+	} else {
+		pr_err("APR: wrong destination\n");
+		goto done;
+	}
+
+	if (dest_id == APR_DEST_QDSP6 &&
+	    apr_get_q6_state() == APR_SUBSYS_DOWN) {
+		pr_info("%s: Wait for Lpass to bootup\n", __func__);
+		rc = apr_wait_for_device_up(dest_id);
+		if (rc == 0) {
+			pr_err("%s: DSP is not Up\n", __func__);
+			return NULL;
+		}
+		pr_info("%s: Lpass Up\n", __func__);
+	} else if (dest_id == APR_DEST_MODEM &&
+		   (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
+		pr_info("%s: Wait for modem to bootup\n", __func__);
+		rc = apr_wait_for_device_up(dest_id);
+		if (rc == 0) {
+			pr_err("%s: Modem is not Up\n", __func__);
+			return NULL;
+		}
+		pr_info("%s: modem Up\n", __func__);
+	}
+
+	if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
+		pr_err("%s: apr_get_svc failed\n", __func__);
+		goto done;
+	}
+
+	/* APRv1 loads ADSP image automatically */
+	apr_load_adsp_image();
+
+	client = apr_get_client(dest_id, client_id);
+	mutex_lock(&client->m_lock);
+	if (!client->handle) {
+		client->handle = apr_tal_open(client_id, dest_id, APR_DL_SMD,
+					      apr_cb_func, NULL);
+		if (!client->handle) {
+			svc = NULL;
+			pr_err("APR: Unable to open handle\n");
+			mutex_unlock(&client->m_lock);
+			goto done;
+		}
+	}
+	mutex_unlock(&client->m_lock);
+	svc = &client->svc[svc_idx];
+	mutex_lock(&svc->m_lock);
+	client->id = client_id;
+	if (svc->need_reset) {
+		mutex_unlock(&svc->m_lock);
+		pr_err("APR: Service needs reset\n");
+		goto done;
+	}
+	svc->priv = priv;
+	svc->id = svc_id;
+	svc->dest_id = dest_id;
+	svc->client_id = client_id;
+	if (src_port != 0xFFFFFFFF) {
+		temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
+		pr_debug("port = %d t_port = %d\n", src_port, temp_port);
+		if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
+			pr_err("APR: temp_port out of bounds\n");
+			mutex_unlock(&svc->m_lock);
+			return NULL;
+		}
+		if (!svc->port_cnt && !svc->svc_cnt)
+			client->svc_cnt++;
+		svc->port_cnt++;
+		svc->port_fn[temp_port] = svc_fn;
+		svc->port_priv[temp_port] = priv;
+	} else {
+		if (!svc->fn) {
+			if (!svc->port_cnt && !svc->svc_cnt)
+				client->svc_cnt++;
+			svc->fn = svc_fn;
+			if (svc->port_cnt)
+				svc->svc_cnt++;
+		}
+	}
+
+	mutex_unlock(&svc->m_lock);
+done:
+	return svc;
+}
+
+void apr_set_subsys_state(void)
+{
+	apr_set_q6_state(APR_SUBSYS_UP);
+	apr_set_modem_state(APR_SUBSYS_UP);
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v2.c b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
new file mode 100644
index 0000000..1ef189f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/qdsp6v2/apr_tal.h>
+#include <mach/qdsp6v2/dsp_debug.h>
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+			     uint32_t src_port, void *priv)
+{
+	struct apr_client *client;
+	int client_id = 0;
+	int svc_idx = 0;
+	int svc_id = 0;
+	int dest_id = 0;
+	int temp_port = 0;
+	struct apr_svc *svc = NULL;
+	int rc = 0;
+
+	if (!dest || !svc_name || !svc_fn)
+		return NULL;
+
+	if (!strncmp(dest, "ADSP", 4))
+		dest_id = APR_DEST_QDSP6;
+	else if (!strncmp(dest, "MODEM", 5)) {
+		dest_id = APR_DEST_MODEM;
+	} else {
+		pr_err("APR: wrong destination\n");
+		goto done;
+	}
+
+	if ((dest_id == APR_DEST_QDSP6)) {
+		if (apr_get_q6_state() != APR_SUBSYS_LOADED) {
+			pr_err("%s: adsp not up\n", __func__);
+			return NULL;
+		}
+		pr_info("%s: Lpass Up\n", __func__);
+	} else if ((dest_id == APR_DEST_MODEM) &&
+		   (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
+		pr_info("%s: Wait for modem to bootup\n", __func__);
+		rc = apr_wait_for_device_up(dest_id);
+		if (rc == 0) {
+			pr_err("%s: Modem is not Up\n", __func__);
+			return NULL;
+		}
+		pr_info("%s: modem Up\n", __func__);
+	}
+
+	if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
+		pr_err("%s: apr_get_svc failed\n", __func__);
+		goto done;
+	}
+
+	/* APRv2 doen't load ADSP image automatically */
+
+	client = apr_get_client(dest_id, client_id);
+	mutex_lock(&client->m_lock);
+	if (!client->handle) {
+		client->handle = apr_tal_open(client_id, dest_id, APR_DL_SMD,
+					      apr_cb_func, NULL);
+		if (!client->handle) {
+			svc = NULL;
+			pr_err("APR: Unable to open handle\n");
+			mutex_unlock(&client->m_lock);
+			goto done;
+		}
+	}
+	mutex_unlock(&client->m_lock);
+	svc = &client->svc[svc_idx];
+	mutex_lock(&svc->m_lock);
+	client->id = client_id;
+	if (svc->need_reset) {
+		mutex_unlock(&svc->m_lock);
+		pr_err("APR: Service needs reset\n");
+		goto done;
+	}
+	svc->priv = priv;
+	svc->id = svc_id;
+	svc->dest_id = dest_id;
+	svc->client_id = client_id;
+	if (src_port != 0xFFFFFFFF) {
+		temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
+		pr_debug("port = %d t_port = %d\n", src_port, temp_port);
+		if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
+			pr_err("APR: temp_port out of bounds\n");
+			mutex_unlock(&svc->m_lock);
+			return NULL;
+		}
+		if (!svc->port_cnt && !svc->svc_cnt)
+			client->svc_cnt++;
+		svc->port_cnt++;
+		svc->port_fn[temp_port] = svc_fn;
+		svc->port_priv[temp_port] = priv;
+	} else {
+		if (!svc->fn) {
+			if (!svc->port_cnt && !svc->svc_cnt)
+				client->svc_cnt++;
+			svc->fn = svc_fn;
+			if (svc->port_cnt)
+				svc->svc_cnt++;
+		}
+	}
+
+	mutex_unlock(&svc->m_lock);
+done:
+	return svc;
+}
+
+void apr_set_subsys_state(void)
+{
+	apr_set_q6_state(APR_SUBSYS_DOWN);
+	apr_set_modem_state(APR_SUBSYS_UP);
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
index edb1e7d..d7de50e 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.c
@@ -337,7 +337,7 @@
 		if (apr_handle_q)
 			apr_deregister(apr_handle_q);
 	} else if (!strncmp(l_buf + 20, "loaded", 64)) {
-		change_q6_state(APR_Q6_LOADED);
+		apr_set_q6_state(APR_SUBSYS_LOADED);
 	} else if (!strncmp(l_buf + 20, "boom", 64)) {
 		q6audio_dsp_not_responding();
 	} else if (!strncmp(l_buf + 20, "dsp_ver", 64)) {
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
index 5d18bb4..ebe1819 100644
--- a/arch/arm/mach-msm/timer.h
+++ b/arch/arm/mach-msm/timer.h
@@ -16,10 +16,10 @@
 
 extern struct sys_timer msm_timer;
 
-void __iomem *msm_timer_get_timer0_base(void);
 uint32_t msm_timer_get_sclk_ticks(void);
 int msm_timer_init_time_sync(void (*timeout)(void));
 #ifndef CONFIG_ARM_ARCH_TIMER
+void __iomem *msm_timer_get_timer0_base(void);
 int64_t msm_timer_enter_idle(void);
 void msm_timer_exit_idle(int low_power);
 int64_t msm_timer_get_sclk_time(int64_t *period);
@@ -27,5 +27,6 @@
 static inline int64_t msm_timer_enter_idle(void) { return 0; }
 static inline void msm_timer_exit_idle(int low_power) { return; }
 static inline int64_t msm_timer_get_sclk_time(int64_t *period) { return 0; }
+static inline void __iomem *msm_timer_get_timer0_base(void) { return NULL; }
 #endif
 #endif
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index b1911c4..553bece 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -181,14 +181,14 @@
 
 		pud = pud_alloc(&init_mm, pgd, base);
 		if (!pud) {
-			printk(KERN_ERR "%s: no pud tables\n", __func__);
+			pr_err("%s: no pud tables\n", __func__);
 			ret = -ENOMEM;
 			break;
 		}
 
 		pmd = pmd_alloc(&init_mm, pud, base);
 		if (!pmd) {
-			printk(KERN_ERR "%s: no pmd tables\n", __func__);
+			pr_err("%s: no pmd tables\n", __func__);
 			ret = -ENOMEM;
 			break;
 		}
@@ -196,7 +196,7 @@
 
 		pte = pte_alloc_kernel(pmd, base);
 		if (!pte) {
-			printk(KERN_ERR "%s: no pte tables\n", __func__);
+			pr_err("%s: no pte tables\n", __func__);
 			ret = -ENOMEM;
 			break;
 		}
@@ -311,7 +311,7 @@
 	int bit;
 
 	if (!consistent_pte) {
-		printk(KERN_ERR "%s: not initialised\n", __func__);
+		pr_err("%s: not initialised\n", __func__);
 		dump_stack();
 		return NULL;
 	}
@@ -370,14 +370,14 @@
 
 	c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr);
 	if (!c) {
-		printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
+		pr_err("%s: trying to free invalid coherent area: %p\n",
 		       __func__, cpu_addr);
 		dump_stack();
 		return;
 	}
 
 	if ((c->vm_end - c->vm_start) != size) {
-		printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
+		pr_err("%s: freeing wrong coherent size (%ld != %d)\n",
 		       __func__, c->vm_end - c->vm_start, size);
 		dump_stack();
 		size = c->vm_end - c->vm_start;
@@ -399,8 +399,8 @@
 		}
 
 		if (pte_none(pte) || !pte_present(pte))
-			printk(KERN_CRIT "%s: bad page in kernel page table\n",
-			       __func__);
+			pr_crit("%s: bad page in kernel page table\n",
+				__func__);
 	} while (size -= PAGE_SIZE);
 
 	flush_tlb_kernel_range(c->vm_start, c->vm_end);
@@ -584,7 +584,7 @@
 	 */
 	gfp &= ~(__GFP_COMP);
 
-	*handle = ~0;
+	*handle = DMA_ERROR_CODE;
 	size = PAGE_ALIGN(size);
 
 	if (arch_is_coherent() || nommu())
@@ -639,6 +639,10 @@
 	int ret = -ENXIO;
 #ifdef CONFIG_MMU
 	unsigned long pfn = dma_to_pfn(dev, dma_addr);
+
+	if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+		return ret;
+
 	ret = remap_pfn_range(vma, vma->vm_start,
 			      pfn + vma->vm_pgoff,
 			      vma->vm_end - vma->vm_start,
@@ -898,7 +902,7 @@
 	int i;
 
 	for_each_sg(sg, s, nents, i) {
-		if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
+		if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s),
 					    sg_dma_len(s), dir))
 			continue;
 
@@ -924,7 +928,7 @@
 	int i;
 
 	for_each_sg(sg, s, nents, i) {
-		if (!dmabounce_sync_for_device(dev, sg_dma_address(s), 0,
+		if (!dmabounce_sync_for_device(dev, sg_dma_address(s),
 					sg_dma_len(s), dir))
 			continue;
 
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index ce8cb19..06262c5 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -11,49 +11,10 @@
 #include <linux/random.h>
 #include <asm/cachetype.h>
 
-static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
-					      unsigned long pgoff)
-{
-	unsigned long base = addr & ~(SHMLBA-1);
-	unsigned long off = (pgoff << PAGE_SHIFT) & (SHMLBA-1);
-
-	if (base + off <= addr)
-		return base + off;
-
-	return base - off;
-}
-
 #define COLOUR_ALIGN(addr,pgoff)		\
 	((((addr)+SHMLBA-1)&~(SHMLBA-1)) +	\
 	 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
 
-/* gap between mmap and stack */
-#define MIN_GAP (128*1024*1024UL)
-#define MAX_GAP ((TASK_SIZE)/6*5)
-
-static int mmap_is_legacy(void)
-{
-	if (current->personality & ADDR_COMPAT_LAYOUT)
-		return 1;
-
-	if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
-		return 1;
-
-	return sysctl_legacy_va_layout;
-}
-
-static unsigned long mmap_base(unsigned long rnd)
-{
-	unsigned long gap = rlimit(RLIMIT_STACK);
-
-	if (gap < MIN_GAP)
-		gap = MIN_GAP;
-	else if (gap > MAX_GAP)
-		gap = MAX_GAP;
-
-	return PAGE_ALIGN(TASK_SIZE - gap - rnd);
-}
-
 /*
  * We need to ensure that shared mappings are correctly aligned to
  * avoid aliasing issues with VIPT caches.  We need to ensure that
@@ -107,9 +68,13 @@
 	if (len > mm->cached_hole_size) {
 	        start_addr = addr = mm->free_area_cache;
 	} else {
-	        start_addr = addr = mm->mmap_base;
+		start_addr = addr = TASK_UNMAPPED_BASE;
 	        mm->cached_hole_size = 0;
 	}
+	/* 8 bits of randomness in 20 address space bits */
+	if ((current->flags & PF_RANDOMIZE) &&
+	    !(current->personality & ADDR_NO_RANDOMIZE))
+		addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT;
 
 full_search:
 	if (do_align)
@@ -146,134 +111,6 @@
 	}
 }
 
-unsigned long
-arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
-			const unsigned long len, const unsigned long pgoff,
-			const unsigned long flags)
-{
-	struct vm_area_struct *vma;
-	struct mm_struct *mm = current->mm;
-	unsigned long addr = addr0;
-	int do_align = 0;
-	int aliasing = cache_is_vipt_aliasing();
-
-	/*
-	 * We only need to do colour alignment if either the I or D
-	 * caches alias.
-	 */
-	if (aliasing)
-		do_align = filp || (flags & MAP_SHARED);
-
-	/* requested length too big for entire address space */
-	if (len > TASK_SIZE)
-		return -ENOMEM;
-
-	if (flags & MAP_FIXED) {
-		if (aliasing && flags & MAP_SHARED &&
-		    (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
-			return -EINVAL;
-		return addr;
-	}
-
-	/* requesting a specific address */
-	if (addr) {
-		if (do_align)
-			addr = COLOUR_ALIGN(addr, pgoff);
-		else
-			addr = PAGE_ALIGN(addr);
-		vma = find_vma(mm, addr);
-		if (TASK_SIZE - len >= addr &&
-				(!vma || addr + len <= vma->vm_start))
-			return addr;
-	}
-
-	/* check if free_area_cache is useful for us */
-	if (len <= mm->cached_hole_size) {
-		mm->cached_hole_size = 0;
-		mm->free_area_cache = mm->mmap_base;
-	}
-
-	/* either no address requested or can't fit in requested address hole */
-	addr = mm->free_area_cache;
-	if (do_align) {
-		unsigned long base = COLOUR_ALIGN_DOWN(addr - len, pgoff);
-		addr = base + len;
-	}
-
-	/* make sure it can fit in the remaining address space */
-	if (addr > len) {
-		vma = find_vma(mm, addr-len);
-		if (!vma || addr <= vma->vm_start)
-			/* remember the address as a hint for next time */
-			return (mm->free_area_cache = addr-len);
-	}
-
-	if (mm->mmap_base < len)
-		goto bottomup;
-
-	addr = mm->mmap_base - len;
-	if (do_align)
-		addr = COLOUR_ALIGN_DOWN(addr, pgoff);
-
-	do {
-		/*
-		 * Lookup failure means no vma is above this address,
-		 * else if new region fits below vma->vm_start,
-		 * return with success:
-		 */
-		vma = find_vma(mm, addr);
-		if (!vma || addr+len <= vma->vm_start)
-			/* remember the address as a hint for next time */
-			return (mm->free_area_cache = addr);
-
-		/* remember the largest hole we saw so far */
-		if (addr + mm->cached_hole_size < vma->vm_start)
-			mm->cached_hole_size = vma->vm_start - addr;
-
-		/* try just below the current vma->vm_start */
-		addr = vma->vm_start - len;
-		if (do_align)
-			addr = COLOUR_ALIGN_DOWN(addr, pgoff);
-	} while (len < vma->vm_start);
-
-bottomup:
-	/*
-	 * A failed mmap() very likely causes application failure,
-	 * so fall back to the bottom-up function here. This scenario
-	 * can happen with large stack limits and large mmap()
-	 * allocations.
-	 */
-	mm->cached_hole_size = ~0UL;
-	mm->free_area_cache = TASK_UNMAPPED_BASE;
-	addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
-	/*
-	 * Restore the topdown base:
-	 */
-	mm->free_area_cache = mm->mmap_base;
-	mm->cached_hole_size = ~0UL;
-
-	return addr;
-}
-
-void arch_pick_mmap_layout(struct mm_struct *mm)
-{
-	unsigned long random_factor = 0UL;
-
-	/* 8 bits of randomness in 20 address space bits */
-	if ((current->flags & PF_RANDOMIZE) &&
-	    !(current->personality & ADDR_NO_RANDOMIZE))
-		random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT;
-
-	if (mmap_is_legacy()) {
-		mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
-		mm->get_unmapped_area = arch_get_unmapped_area;
-		mm->unmap_area = arch_unmap_area;
-	} else {
-		mm->mmap_base = mmap_base(random_factor);
-		mm->get_unmapped_area = arch_get_unmapped_area_topdown;
-		mm->unmap_area = arch_unmap_area_topdown;
-	}
-}
 
 /*
  * You really shouldn't be using read() or write() on /dev/mem.  This
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
index bb0025c..1b85949 100644
--- a/drivers/base/dma-coherent.c
+++ b/drivers/base/dma-coherent.c
@@ -10,6 +10,7 @@
 struct dma_coherent_mem {
 	void		*virt_base;
 	dma_addr_t	device_base;
+	phys_addr_t	pfn_base;
 	int		size;
 	int		flags;
 	unsigned long	*bitmap;
@@ -44,6 +45,7 @@
 
 	dev->dma_mem->virt_base = mem_base;
 	dev->dma_mem->device_base = device_addr;
+	dev->dma_mem->pfn_base = PFN_DOWN(bus_addr);
 	dev->dma_mem->size = pages;
 	dev->dma_mem->flags = flags;
 
@@ -176,3 +178,43 @@
 	return 0;
 }
 EXPORT_SYMBOL(dma_release_from_coherent);
+
+/**
+ * dma_mmap_from_coherent() - try to mmap the memory allocated from
+ * per-device coherent memory pool to userspace
+ * @dev:	device from which the memory was allocated
+ * @vma:	vm_area for the userspace memory
+ * @vaddr:	cpu address returned by dma_alloc_from_coherent
+ * @size:	size of the memory buffer allocated by dma_alloc_from_coherent
+ *
+ * This checks whether the memory was allocated from the per-device
+ * coherent memory pool and if so, maps that memory to the provided vma.
+ *
+ * Returns 1 if we correctly mapped the memory, or 0 if
+ * dma_release_coherent() should proceed with mapping memory from
+ * generic pools.
+ */
+int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
+			   void *vaddr, size_t size, int *ret)
+{
+	struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
+
+	if (mem && vaddr >= mem->virt_base && vaddr + size <=
+		   (mem->virt_base + (mem->size << PAGE_SHIFT))) {
+		unsigned long off = vma->vm_pgoff;
+		int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+		int user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+		int count = size >> PAGE_SHIFT;
+
+		*ret = -ENXIO;
+		if (off < count && user_count <= count - off) {
+			unsigned pfn = mem->pfn_base + start + off;
+			*ret = remap_pfn_range(vma, vma->vm_start, pfn,
+					       user_count << PAGE_SHIFT,
+					       vma->vm_page_prot);
+		}
+		return 1;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(dma_mmap_from_coherent);
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index 6511c95..7bfb208 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -31,6 +31,10 @@
 		((q_spec)->offset + reg_index)
 
 #define Q_REG_STATUS1			0x8
+#define Q_REG_STATUS1_VAL_MASK		0x1
+#define Q_REG_STATUS1_GPIO_EN_MASK	0x2
+#define Q_REG_STATUS1_MPP_EN_MASK	0x80
+
 #define Q_NUM_CTL_REGS			0xD
 
 /* type registers base address offsets */
@@ -418,39 +422,41 @@
 }
 
 static int qpnp_pin_read_regs(struct qpnp_pin_chip *q_chip,
-			       struct qpnp_pin_spec *q_spec, u16 addr, u8 *buf)
+			      struct qpnp_pin_spec *q_spec)
 {
 	int bytes_left = q_spec->num_ctl_regs;
 	int rc;
-	char *reg_p = &q_spec->regs[0];
+	char *buf_p = &q_spec->regs[0];
+	u16 reg_addr = Q_REG_ADDR(q_spec, Q_REG_MODE_CTL);
 
 	while (bytes_left > 0) {
 		rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
-					Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
-					reg_p, bytes_left < 8 ? bytes_left : 8);
+			  reg_addr, buf_p, bytes_left < 8 ? bytes_left : 8);
 		if (rc)
 			return rc;
 		bytes_left -= 8;
-		reg_p += 8;
+		buf_p += 8;
+		reg_addr += 8;
 	}
 	return 0;
 }
 
 static int qpnp_pin_write_regs(struct qpnp_pin_chip *q_chip,
-				struct qpnp_pin_spec *q_spec, u16 addr, u8 *buf)
+			       struct qpnp_pin_spec *q_spec)
 {
 	int bytes_left = q_spec->num_ctl_regs;
 	int rc;
-	char *reg_p = &q_spec->regs[0];
+	char *buf_p = &q_spec->regs[0];
+	u16 reg_addr = Q_REG_ADDR(q_spec, Q_REG_MODE_CTL);
 
 	while (bytes_left > 0) {
 		rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
-					Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
-					reg_p, bytes_left < 8 ? bytes_left : 8);
+			  reg_addr, buf_p, bytes_left < 8 ? bytes_left : 8);
 		if (rc)
 			return rc;
 		bytes_left -= 8;
-		reg_p += 8;
+		buf_p += 8;
+		reg_addr += 8;
 	}
 	return 0;
 }
@@ -461,9 +467,7 @@
 	int rc;
 	struct device *dev = &q_chip->spmi->dev;
 
-	rc = qpnp_pin_read_regs(q_chip, q_spec,
-				 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
-				 &q_spec->regs[Q_REG_I_MODE_CTL]);
+	rc = qpnp_pin_read_regs(q_chip, q_spec);
 	if (rc)
 		dev_err(dev, "%s: unable to read control regs\n", __func__);
 
@@ -536,9 +540,7 @@
 			  Q_REG_CS_OUT_SHIFT, Q_REG_CS_OUT_MASK,
 			  param->cs_out);
 
-	rc = qpnp_pin_write_regs(q_chip, q_spec,
-				 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
-				 &q_spec->regs[Q_REG_I_MODE_CTL]);
+	rc = qpnp_pin_write_regs(q_chip, q_spec);
 	if (rc) {
 		dev_err(&q_chip->spmi->dev, "%s: unable to write master enable\n",
 								__func__);
@@ -628,7 +630,7 @@
 	int rc, ret_val;
 	struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
 	struct qpnp_pin_spec *q_spec = NULL;
-	u8 buf[1];
+	u8 buf[1], en_mask;
 
 	if (WARN_ON(!q_chip))
 		return -ENODEV;
@@ -640,11 +642,17 @@
 	/* gpio val is from RT status iff input is enabled */
 	if ((q_spec->regs[Q_REG_I_MODE_CTL] & Q_REG_MODE_SEL_MASK)
 						== QPNP_PIN_MODE_DIG_IN) {
-		/* INT_RT_STS */
 		rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
 				Q_REG_ADDR(q_spec, Q_REG_STATUS1),
 				&buf[0], 1);
-		return buf[0];
+
+		en_mask = q_spec->type == Q_GPIO_TYPE ?
+				Q_REG_STATUS1_GPIO_EN_MASK :
+				Q_REG_STATUS1_MPP_EN_MASK;
+		if (!(buf[0] & en_mask))
+			return -EPERM;
+
+		return buf[0] & Q_REG_STATUS1_VAL_MASK;
 
 	} else {
 		ret_val = (q_spec->regs[Q_REG_I_MODE_CTL] &
@@ -671,7 +679,7 @@
 			  Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 0);
 
 	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
-			      Q_REG_ADDR(q_spec, Q_REG_I_MODE_CTL),
+			      Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
 			      &q_spec->regs[Q_REG_I_MODE_CTL], 1);
 	if (rc)
 		dev_err(&q_chip->spmi->dev, "%s: spmi write failed\n",
@@ -715,7 +723,7 @@
 			mode);
 
 	rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
-			      Q_REG_ADDR(q_spec, Q_REG_I_MODE_CTL),
+			      Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
 			      &q_spec->regs[Q_REG_I_MODE_CTL], 1);
 	return rc;
 }
@@ -799,7 +807,7 @@
 				       Q_REG_OUT_TYPE_SHIFT,
 				       Q_REG_OUT_TYPE_MASK);
 	param.invert	   = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
-				       Q_REG_OUT_INVERT_MASK,
+				       Q_REG_OUT_INVERT_SHIFT,
 				       Q_REG_OUT_INVERT_MASK);
 	param.pull	   = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
 				       Q_REG_PULL_SHIFT, Q_REG_PULL_MASK);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index e4d7141..736fb4e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -17,6 +17,7 @@
 #include <linux/pm_runtime.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_bus.h>
+#include <linux/ktime.h>
 
 #include "kgsl.h"
 #include "kgsl_pwrscale.h"
@@ -60,6 +61,30 @@
 	},
 };
 
+/* Update the elapsed time at a particular clock level
+ * if the device is active(on_time = true).Otherwise
+ * store it as sleep time.
+ */
+static void update_clk_statistics(struct kgsl_device *device,
+				bool on_time)
+{
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	struct kgsl_clk_stats *clkstats = &pwr->clk_stats;
+	ktime_t elapsed;
+	int elapsed_us;
+	if (clkstats->start.tv64 == 0)
+		clkstats->start = ktime_get();
+	clkstats->stop = ktime_get();
+	elapsed = ktime_sub(clkstats->stop, clkstats->start);
+	elapsed_us = ktime_to_us(elapsed);
+	clkstats->elapsed += elapsed_us;
+	if (on_time)
+		clkstats->clock_time[pwr->active_pwrlevel] += elapsed_us;
+	else
+		clkstats->clock_time[pwr->num_pwrlevels - 1] += elapsed_us;
+	clkstats->start = ktime_get();
+}
+
 void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
 				unsigned int new_level)
 {
@@ -71,6 +96,9 @@
 		int diff = new_level - pwr->active_pwrlevel;
 		int d = (diff > 0) ? 1 : -1;
 		int level = pwr->active_pwrlevel;
+		/* Update the clock stats */
+		update_clk_statistics(device, true);
+		/* Finally set active level */
 		pwr->active_pwrlevel = new_level;
 		if ((test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) ||
 			(device->state == KGSL_STATE_NAP)) {
@@ -285,23 +313,51 @@
 {
 	int ret;
 	struct kgsl_device *device = kgsl_device_from_dev(dev);
-	struct kgsl_busy *b = &device->pwrctrl.busy;
-	ret = snprintf(buf, 17, "%7d %7d\n",
-				   b->on_time_old, b->time_old);
+	struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+	ret = snprintf(buf, PAGE_SIZE, "%7d %7d\n",
+			clkstats->on_time_old, clkstats->elapsed_old);
 	if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
-		b->on_time_old = 0;
-		b->time_old = 0;
+		clkstats->on_time_old = 0;
+		clkstats->elapsed_old = 0;
 	}
 	return ret;
 }
 
+static int kgsl_pwrctrl_gputop_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	int ret;
+	struct kgsl_device *device = kgsl_device_from_dev(dev);
+	struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+	int i = 0;
+	char *ptr = buf;
+
+	ret = snprintf(buf, PAGE_SIZE, "%7d %7d ", clkstats->on_time_old,
+					clkstats->elapsed_old);
+	for (i = 0, ptr += ret; i < device->pwrctrl.num_pwrlevels;
+							i++, ptr += ret)
+		ret = snprintf(ptr, PAGE_SIZE, "%7d ",
+						clkstats->old_clock_time[i]);
+
+	if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
+		clkstats->on_time_old = 0;
+		clkstats->elapsed_old = 0;
+		for (i = 0; i < KGSL_MAX_PWRLEVELS ; i++)
+			clkstats->old_clock_time[i] = 0;
+	}
+	return (unsigned int) (ptr - buf);
+}
+
 DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
 DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
 	kgsl_pwrctrl_max_gpuclk_store);
 DEVICE_ATTR(pwrnap, 0664, kgsl_pwrctrl_pwrnap_show, kgsl_pwrctrl_pwrnap_store);
 DEVICE_ATTR(idle_timer, 0644, kgsl_pwrctrl_idle_timer_show,
 	kgsl_pwrctrl_idle_timer_store);
-DEVICE_ATTR(gpubusy, 0644, kgsl_pwrctrl_gpubusy_show,
+DEVICE_ATTR(gpubusy, 0444, kgsl_pwrctrl_gpubusy_show,
+	NULL);
+DEVICE_ATTR(gputop, 0444, kgsl_pwrctrl_gputop_show,
 	NULL);
 
 static const struct device_attribute *pwrctrl_attr_list[] = {
@@ -310,6 +366,7 @@
 	&dev_attr_pwrnap,
 	&dev_attr_idle_timer,
 	&dev_attr_gpubusy,
+	&dev_attr_gputop,
 	NULL
 };
 
@@ -323,29 +380,37 @@
 	kgsl_remove_device_sysfs_files(device->dev, pwrctrl_attr_list);
 }
 
+static void update_statistics(struct kgsl_device *device)
+{
+	struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+	unsigned int on_time = 0;
+	int i;
+	int num_pwrlevels = device->pwrctrl.num_pwrlevels - 1;
+	/*PER CLK TIME*/
+	for (i = 0; i < num_pwrlevels; i++) {
+		clkstats->old_clock_time[i] = clkstats->clock_time[i];
+		on_time += clkstats->clock_time[i];
+		clkstats->clock_time[i] = 0;
+	}
+	clkstats->old_clock_time[num_pwrlevels] =
+				clkstats->clock_time[num_pwrlevels];
+	clkstats->clock_time[num_pwrlevels] = 0;
+	clkstats->on_time_old = on_time;
+	clkstats->elapsed_old = clkstats->elapsed;
+	clkstats->elapsed = 0;
+}
+
 /* Track the amount of time the gpu is on vs the total system time. *
  * Regularly update the percentage of busy time displayed by sysfs. */
 static void kgsl_pwrctrl_busy_time(struct kgsl_device *device, bool on_time)
 {
-	struct kgsl_busy *b = &device->pwrctrl.busy;
-	int elapsed;
-	if (b->start.tv_sec == 0)
-		do_gettimeofday(&(b->start));
-	do_gettimeofday(&(b->stop));
-	elapsed = (b->stop.tv_sec - b->start.tv_sec) * 1000000;
-	elapsed += b->stop.tv_usec - b->start.tv_usec;
-	b->time += elapsed;
-	if (on_time)
-		b->on_time += elapsed;
+	struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+	update_clk_statistics(device, on_time);
 	/* Update the output regularly and reset the counters. */
-	if ((b->time > UPDATE_BUSY_VAL) ||
+	if ((clkstats->elapsed > UPDATE_BUSY_VAL) ||
 		!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
-		b->on_time_old = b->on_time;
-		b->time_old = b->time;
-		b->on_time = 0;
-		b->time = 0;
+		update_statistics(device);
 	}
-	do_gettimeofday(&(b->start));
 }
 
 void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
@@ -648,10 +713,11 @@
 					device->pwrctrl.interval_timeout);
 			/* If the GPU has been too busy to sleep, make sure *
 			 * that is acurately reflected in the % busy numbers. */
-			device->pwrctrl.busy.no_nap_cnt++;
-			if (device->pwrctrl.busy.no_nap_cnt > UPDATE_BUSY) {
+			device->pwrctrl.clk_stats.no_nap_cnt++;
+			if (device->pwrctrl.clk_stats.no_nap_cnt >
+							 UPDATE_BUSY) {
 				kgsl_pwrctrl_busy_time(device, true);
-				device->pwrctrl.busy.no_nap_cnt = 0;
+				device->pwrctrl.clk_stats.no_nap_cnt = 0;
 			}
 		}
 	} else if (device->state & (KGSL_STATE_HUNG |
@@ -753,7 +819,7 @@
 _sleep_accounting(struct kgsl_device *device)
 {
 	kgsl_pwrctrl_busy_time(device, false);
-	device->pwrctrl.busy.start.tv_sec = 0;
+	device->pwrctrl.clk_stats.start = ktime_set(0, 0);
 	device->pwrctrl.time = 0;
 	kgsl_pwrscale_sleep(device);
 }
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index cd44152..c02a9fc 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -27,14 +27,15 @@
 
 struct platform_device;
 
-struct kgsl_busy {
-	struct timeval start;
-	struct timeval stop;
-	int on_time;
-	int time;
-	int on_time_old;
-	int time_old;
+struct kgsl_clk_stats {
+	unsigned int old_clock_time[KGSL_MAX_PWRLEVELS];
+	unsigned int clock_time[KGSL_MAX_PWRLEVELS];
+	unsigned int on_time_old;
+	ktime_t start;
+	ktime_t stop;
 	unsigned int no_nap_cnt;
+	unsigned int elapsed;
+	unsigned int elapsed_old;
 };
 
 struct kgsl_pwrctrl {
@@ -56,8 +57,8 @@
 	unsigned int idle_needed;
 	const char *irq_name;
 	s64 time;
-	struct kgsl_busy busy;
 	unsigned int restore_slumber;
+	struct kgsl_clk_stats clk_stats;
 };
 
 void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
diff --git a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index 7e80145..9549dcc 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -21,7 +21,7 @@
 #include <mach/clk.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
-
+#include <mach/dal_axi.h>
 
 #define MSM_AXI_QOS_PREVIEW 200000
 #define MSM_AXI_QOS_SNAPSHOT 200000
@@ -142,6 +142,7 @@
 		break;
 	case S_PREVIEW:
 		update_axi_qos(MSM_AXI_QOS_PREVIEW);
+		axi_allocate(AXI_FLOW_VIEWFINDER_HI);
 		break;
 	case S_VIDEO:
 		update_axi_qos(MSM_AXI_QOS_RECORDING);
@@ -153,6 +154,7 @@
 		update_axi_qos(PM_QOS_DEFAULT_VALUE);
 		break;
 	case S_EXIT:
+		axi_free(AXI_FLOW_VIEWFINDER_HI);
 		release_axi_qos();
 		break;
 	default:
diff --git a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
index e1d8b48..460eb07 100644
--- a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
@@ -696,7 +696,6 @@
 
 		switch (id) {
 		case MSG_SNAPSHOT:
-			msm_camio_set_perf_lvl(S_PREVIEW);
 			while (vfe2x_ctrl->snap.frame_cnt <
 				vfe2x_ctrl->num_snap) {
 				vfe_7x_ops(driver_data, MSG_OUTPUT_S, len,
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index ff12a5c..76d8068 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -35,6 +35,8 @@
 	if (align < 4096)
 		align = 4096;
 	flags |= UNCACHED;
+	pr_debug("\n In %s  domain: %d, Partition: %d\n",
+		__func__, domain_num, partition_num);
 	rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
 			0, iova, buffer_size, flags, 0);
 	if (rc)
@@ -45,9 +47,9 @@
 }
 
 static void put_device_address(struct ion_client *clnt,
-		struct ion_handle *hndl, int domain_num)
+		struct ion_handle *hndl, int domain_num, int partition_num)
 {
-	ion_unmap_iommu(clnt, hndl, domain_num, 0);
+	ion_unmap_iommu(clnt, hndl, domain_num, partition_num);
 }
 
 static int ion_user_to_kernel(struct smem_client *client,
@@ -91,6 +93,8 @@
 	mem->smem_priv = hndl;
 	mem->device_addr = iova + offset;
 	mem->size = buffer_size;
+	pr_debug("Buffer device address: 0x%lx, size: %d\n",
+		mem->device_addr, mem->size);
 	return rc;
 fail_device_address:
 	ion_unmap_kernel(client->clnt, hndl);
@@ -112,6 +116,8 @@
 	if (align < 4096)
 		align = 4096;
 	size = (size + 4095) & (~4095);
+	pr_debug("\n in %s domain: %d, Partition: %d\n",
+		__func__, domain, partition);
 	hndl = ion_alloc(client->clnt, size, align, flags);
 	if (IS_ERR_OR_NULL(hndl)) {
 		pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
@@ -136,7 +142,7 @@
 		goto fail_device_address;
 	}
 	mem->device_addr = iova;
-	pr_err("device_address = 0x%lx, kvaddr = 0x%p\n",
+	pr_debug("device_address = 0x%lx, kvaddr = 0x%p\n",
 		mem->device_addr, mem->kvaddr);
 	mem->size = size;
 	return rc;
@@ -151,7 +157,7 @@
 static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
 {
 	put_device_address(client->clnt,
-		mem->smem_priv, mem->domain);
+		mem->smem_priv, mem->domain, mem->partition_num);
 	ion_unmap_kernel(client->clnt, mem->smem_priv);
 	ion_free(client->clnt, mem->smem_priv);
 }
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index cf1ebbb..12b4c76 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -31,6 +31,7 @@
 
 #define BASE_DEVICE_NUMBER 32
 #define MAX_EVENTS 30
+#define SHARED_QSIZE 0x1000000
 
 
 static struct msm_bus_vectors ocmem_init_vectors[]  = {
@@ -505,6 +506,13 @@
 	return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
 }
 
+static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
+				struct v4l2_encoder_cmd *enc)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	return msm_vidc_encoder_cmd((void *)vidc_inst, enc);
+}
+
 static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
 	.vidioc_querycap = msm_v4l2_querycap,
 	.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
@@ -524,6 +532,7 @@
 	.vidioc_subscribe_event = msm_v4l2_subscribe_event,
 	.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
 	.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
+	.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
 };
 
 static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
@@ -583,7 +592,7 @@
 	struct msm_vidc_core *core)
 {
 	size_t len;
-	struct msm_iova_partition partition;
+	struct msm_iova_partition partition[2];
 	struct msm_iova_layout layout;
 	int rc = 0;
 	int i;
@@ -606,14 +615,28 @@
 			rc = -EINVAL;
 			break;
 		}
-		partition.start = io_map[i].addr_range[0];
-		partition.size = io_map[i].addr_range[1];
-		layout.partitions = &partition;
-		layout.npartitions = 1;
+		partition[0].start = io_map[i].addr_range[0];
+		if (i == NS_MAP) {
+			partition[0].size =
+				io_map[i].addr_range[1] - SHARED_QSIZE;
+			partition[1].start =
+				partition[0].start + io_map[i].addr_range[1]
+					- SHARED_QSIZE;
+			partition[1].size = SHARED_QSIZE;
+			layout.npartitions = 2;
+		} else {
+			partition[0].size = io_map[i].addr_range[1];
+			layout.npartitions = 1;
+		}
+		layout.partitions = &partition[0];
 		layout.client_name = io_map[i].name;
 		layout.domain_flags = 0;
-		pr_debug("Registering domain with: %lx, %lx, %s\n",
-			partition.start, partition.size, layout.client_name);
+		pr_debug("Registering domain 1 with: %lx, %lx, %s\n",
+			partition[0].start, partition[0].size,
+			layout.client_name);
+		pr_debug("Registering domain 2 with: %lx, %lx, %s\n",
+			partition[1].start, partition[1].size,
+			layout.client_name);
 		io_map[i].domain = msm_register_domain(&layout);
 		if (io_map[i].domain < 0) {
 			pr_err("Failed to register cp domain\n");
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index d47bdb0..a838a12 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -722,11 +722,13 @@
 	switch (q->type) {
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
-			rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+			rc = msm_comm_try_state(inst,
+				MSM_VIDC_RELEASE_RESOURCES_DONE);
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
-			rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+			rc = msm_comm_try_state(inst,
+				MSM_VIDC_RELEASE_RESOURCES_DONE);
 		break;
 	default:
 		pr_err("Q-type is not supported: %d\n", q->type);
@@ -735,7 +737,7 @@
 	}
 	if (rc)
 		pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
-				inst, q->type, MSM_VIDC_CLOSE_DONE);
+				inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
 	return rc;
 }
 
@@ -747,6 +749,74 @@
 		pr_err("Failed to queue buffer: %d\n", rc);
 }
 
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec)
+{
+	int rc = 0;
+	bool ip_flush = false,
+	     op_flush = false;
+
+	switch (dec->cmd) {
+	case V4L2_DEC_QCOM_CMD_FLUSH:
+		mutex_lock(&inst->sync_lock);
+		ip_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
+		op_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
+		/* Only support flush on decoder (for now)*/
+		if (inst->session_type == MSM_VIDC_ENCODER) {
+			pr_err("Buffer flushing not supported for encoder\n");
+			rc = -ENOTSUPP;
+			mutex_unlock(&inst->sync_lock);
+			break;
+		}
+
+		/* Certain types of flushes aren't supported such as: */
+		/* 1) Input only flush */
+		if (ip_flush && !op_flush) {
+			pr_err("Input only flush not supported\n");
+			rc = -ENOTSUPP;
+			mutex_unlock(&inst->sync_lock);
+			break;
+		}
+
+		/* 2) Output only flush when in reconfig */
+		if (!ip_flush && op_flush && !inst->in_reconfig) {
+			pr_err("Output only flush only supported when reconfiguring\n");
+			rc = -ENOTSUPP;
+			mutex_unlock(&inst->sync_lock);
+			break;
+		}
+
+		/* Finally flush */
+		if (op_flush && ip_flush)
+			rc = vidc_hal_session_flush(inst->session,
+					HAL_FLUSH_ALL);
+		else if (ip_flush)
+			rc = vidc_hal_session_flush(inst->session,
+					HAL_FLUSH_INPUT);
+		else if (op_flush)
+			rc = vidc_hal_session_flush(inst->session,
+					HAL_FLUSH_OUTPUT);
+		mutex_unlock(&inst->sync_lock);
+		break;
+	case V4L2_DEC_CMD_STOP:
+		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		if (rc)
+			pr_err("Failed to close instance\n");
+		break;
+	default:
+		pr_err("Unknown Decoder Command\n");
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+
+	if (rc) {
+		pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
+		goto exit;
+	}
+exit:
+	return rc;
+}
+
+
 static const struct vb2_ops msm_vdec_vb2q_ops = {
 	.queue_setup = msm_vdec_queue_setup,
 	.start_streaming = msm_vdec_start_streaming,
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index 1242fb4..b8326d8 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -31,6 +31,7 @@
 int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
 int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec);
 struct vb2_ops *msm_vdec_get_vb2q_ops(void);
 
 #endif
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 282da64..2e51daa 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -22,13 +22,13 @@
 #define DEFAULT_WIDTH 1280
 #define MIN_NUM_OUTPUT_BUFFERS 2
 #define MAX_NUM_OUTPUT_BUFFERS 8
-#define MIN_BIT_RATE 64
-#define MAX_BIT_RATE 160000
-#define DEFAULT_BIT_RATE 64
-#define BIT_RATE_STEP 1
-#define MIN_FRAME_RATE 1
-#define MAX_FRAME_RATE 240
-#define DEFAULT_FRAME_RATE 30
+#define MIN_BIT_RATE 64000
+#define MAX_BIT_RATE 160000000
+#define DEFAULT_BIT_RATE 64000
+#define BIT_RATE_STEP 100
+#define MIN_FRAME_RATE 65536
+#define MAX_FRAME_RATE 15728640
+#define DEFAULT_FRAME_RATE 1966080
 #define DEFAULT_IR_MBS 30
 #define MAX_SLICE_BYTE_SIZE 1024
 #define MIN_SLICE_BYTE_SIZE 1024
@@ -706,7 +706,7 @@
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		break;
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+		rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
 		break;
 	default:
 		pr_err("Q-type is not supported: %d\n", q->type);
@@ -1230,6 +1230,15 @@
 	return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
 }
 
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc)
+{
+	int rc = 0;
+	rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+	if (rc)
+		pr_err("Failed to close instance\n");
+	return rc;
+}
+
 int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
 {
 	if (!inst || !cap) {
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
index 4a156dd..83610b3 100644
--- a/drivers/media/video/msm_vidc/msm_venc.h
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -30,6 +30,7 @@
 int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
 int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
 int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc);
 struct vb2_ops *msm_venc_get_vb2q_ops(void);
 
 #endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 72f30ea..7c9b6db 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -29,11 +29,6 @@
 	struct vb2_buffer *out_vb = NULL;
 	struct vb2_buffer *cap_vb = NULL;
 	unsigned long flags;
-	if (!outq->streaming && !capq->streaming) {
-		pr_err("Returning POLLERR from here: %d, %d\n",
-			outq->streaming, capq->streaming);
-		return POLLERR;
-	}
 	poll_wait(filp, &inst->event_handler.wait, wait);
 	poll_wait(filp, &capq->done_wq, wait);
 	poll_wait(filp, &outq->done_wq, wait);
@@ -140,6 +135,22 @@
 	return -EINVAL;
 }
 
+int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_cmd(instance, enc);
+	return -EINVAL;
+}
+
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
+{
+	struct msm_vidc_inst *inst = instance;
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_cmd(instance, dec);
+	return -EINVAL;
+}
+
 int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
 {
 	struct msm_vidc_inst *inst = instance;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 763477a..50f98da 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -22,7 +22,7 @@
 #include "vidc_hal_api.h"
 #include "msm_smem.h"
 
-#define HW_RESPONSE_TIMEOUT 5000
+#define HW_RESPONSE_TIMEOUT (5 * 60 * 1000)
 
 #define IS_ALREADY_IN_STATE(__p, __d) ({\
 	int __rc = (__p >= __d);\
@@ -1421,67 +1421,6 @@
 	return rc;
 }
 
-int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
-{
-	int rc = 0;
-	struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
-	bool ip_flush = false,
-	     op_flush = false;
-
-	mutex_lock(&inst->sync_lock);
-
-	switch (dec->cmd) {
-	case V4L2_DEC_QCOM_CMD_FLUSH:
-		ip_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
-		op_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
-		/* Only support flush on decoder (for now)*/
-		if (inst->session_type == MSM_VIDC_ENCODER) {
-			pr_err("Buffer flushing not supported for encoder\n");
-			rc = -ENOTSUPP;
-			break;
-		}
-
-		/* Certain types of flushes aren't supported such as: */
-		/* 1) Input only flush */
-		if (ip_flush && !op_flush) {
-			pr_err("Input only flush not supported\n");
-			rc = -ENOTSUPP;
-			break;
-		}
-
-		/* 2) Output only flush when in reconfig */
-		if (!ip_flush && op_flush && !inst->in_reconfig) {
-			pr_err("Output only flush only supported when reconfiguring\n");
-			rc = -ENOTSUPP;
-			break;
-		}
-
-		/* Finally flush */
-		if (op_flush && ip_flush)
-			rc = vidc_hal_session_flush(inst->session,
-					HAL_FLUSH_ALL);
-		else if (ip_flush)
-			rc = vidc_hal_session_flush(inst->session,
-					HAL_FLUSH_INPUT);
-		else if (op_flush)
-			rc = vidc_hal_session_flush(inst->session,
-					HAL_FLUSH_OUTPUT);
-
-		break;
-	default:
-		rc = -ENOTSUPP;
-		goto exit;
-	}
-
-	if (rc) {
-		pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
-		goto exit;
-	}
-exit:
-	mutex_unlock(&inst->sync_lock);
-	return rc;
-}
-
 int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 16a3ecd..cf540d8 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -316,7 +316,7 @@
 	vmem = (struct vidc_mem_addr *)mem;
 	HAL_MSG_HIGH("start to alloc: size:%d, Flags: %d", size, flags);
 
-	alloc  = msm_smem_alloc(clnt, size, align, flags, domain, 0);
+	alloc  = msm_smem_alloc(clnt, size, align, flags, domain, 1);
 	HAL_MSG_LOW("Alloc done");
 	if (!alloc) {
 		HAL_MSG_HIGH("Alloc fail in %s", __func__);
@@ -1201,9 +1201,11 @@
 	}
 	case HAL_PARAM_VENC_RATE_CONTROL:
 	{
+		u32 *rc_mode;
 		pkt->rg_property_data[0] =
 			HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
-		switch ((enum hal_rate_control)pdata) {
+		rc_mode = (u32 *)pdata;
+		switch ((enum hal_rate_control) *rc_mode) {
 		case HAL_RATE_CONTROL_OFF:
 		pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF;
 			break;
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 2bc0938..a7d13a8 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -1330,12 +1330,14 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(&q->q_lock);
 	ret = __vb2_get_done_vb(q, &vb, nonblocking);
 	if (ret < 0) {
 		dprintk(1, "dqbuf: error getting next done buffer\n");
+		mutex_unlock(&q->q_lock);
 		return ret;
 	}
-
+	mutex_unlock(&q->q_lock);
 	ret = call_qop(q, buf_finish, vb);
 	if (ret) {
 		dprintk(1, "dqbuf: buffer finish failed\n");
@@ -1447,15 +1449,17 @@
 	/*
 	 * Let driver notice that streaming state has been enabled.
 	 */
+	mutex_lock(&q->q_lock);
 	ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
 	if (ret) {
 		dprintk(1, "streamon: driver refused to start streaming\n");
 		__vb2_queue_cancel(q);
+		mutex_unlock(&q->q_lock);
 		return ret;
 	}
 
 	q->streaming = 1;
-
+	mutex_unlock(&q->q_lock);
 	dprintk(3, "Streamon successful\n");
 	return 0;
 }
@@ -1729,6 +1733,7 @@
 	INIT_LIST_HEAD(&q->queued_list);
 	INIT_LIST_HEAD(&q->done_list);
 	spin_lock_init(&q->done_lock);
+	mutex_init(&q->q_lock);
 	init_waitqueue_head(&q->done_wq);
 
 	if (q->buf_struct_size == 0)
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 8354aa8..696f16d 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -522,7 +522,6 @@
 	return 0;
 }
 
-
 static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
 {
 	int ret;
@@ -771,21 +770,20 @@
 	int ret = 0;
 	struct qseecom_command_scm_resp resp;
 	struct qseecom_registered_app_list *ptr_app;
-	uint32_t unload = 0;
+	bool unload = false;
+	bool found_app = false;
 
 	if (qseecom.qseos_version == QSEOS_VERSION_14) {
 		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
 		list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
 								list) {
 			if (ptr_app->app_id == data->client.app_id) {
+				found_app = true;
 				if (ptr_app->ref_cnt == 1) {
-					unload = __qseecom_cleanup_app(data);
-					list_del(&ptr_app->list);
-					kzfree(ptr_app);
+					unload = true;
 					break;
 				} else {
 					ptr_app->ref_cnt--;
-					data->released = true;
 					pr_warn("Can't unload app with id %d (it is inuse)\n",
 							ptr_app->app_id);
 					break;
@@ -795,14 +793,20 @@
 		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
 								flags);
 	}
-	if (!IS_ERR_OR_NULL(data->client.ihandle)) {
-		ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
-		ion_free(qseecom.ion_clnt, data->client.ihandle);
+	if (found_app == false)  {
+		pr_err("Cannot find app with id = %d\n", data->client.app_id);
+		return -EINVAL;
 	}
 
 	if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
 		struct qseecom_unload_app_ireq req;
 
+		__qseecom_cleanup_app(data);
+		spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+		list_del(&ptr_app->list);
+		kzfree(ptr_app);
+		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+								flags);
 		/* Populate the structure for sending scm call to load image */
 		req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
 		req.app_id = data->client.app_id;
@@ -840,6 +844,11 @@
 			}
 		}
 	}
+	if (!IS_ERR_OR_NULL(data->client.ihandle)) {
+		ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
+		ion_free(qseecom.ion_clnt, data->client.ihandle);
+		data->client.ihandle = NULL;
+	}
 	data->released = true;
 	return ret;
 }
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index d75cac4..34e1d40 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -67,4 +67,13 @@
 	  This driver supports the power-on functionality on Qualcomm
 	  PNP PMIC. It currently supports reporting the change in status of
 	  the KPDPWR_N line (connected to the power-key).
+
+config QPNP_CLKDIV
+	tristate "QPNP PMIC clkdiv driver"
+	depends on OF_SPMI && SPMI
+	help
+	  This driver supports the clkdiv functionality on the Qualcomm
+	  PNP PMIC. It configures the frequency of clkdiv outputs on the
+	  PMIC. These clocks are typically wired through alternate functions
+	  on gpio pins.
 endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 2b6b806..35efd91 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -6,3 +6,4 @@
 obj-$(CONFIG_SPS) += sps/
 obj-$(CONFIG_QPNP_PWM) += qpnp-pwm.o
 obj-$(CONFIG_QPNP_POWER_ON) += qpnp-power-on.o
+obj-$(CONFIG_QPNP_CLKDIV) += qpnp-clkdiv.o
diff --git a/drivers/platform/msm/qpnp-clkdiv.c b/drivers/platform/msm/qpnp-clkdiv.c
new file mode 100644
index 0000000..2a9ba90
--- /dev/null
+++ b/drivers/platform/msm/qpnp-clkdiv.c
@@ -0,0 +1,287 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/types.h>
+#include <linux/spmi.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/time.h>
+#include <linux/qpnp/clkdiv.h>
+
+#define Q_MAX_DT_PROP_SIZE 32
+
+#define Q_REG_ADDR(q_clkdiv, reg_offset)	\
+		((q_clkdiv)->offset + reg_offset)
+
+#define Q_REG_DIV_CTL1			   0x43
+#define Q_REG_EN_CTL			   0x46
+
+#define Q_SET_EN			   BIT(7)
+
+#define Q_CXO_PERIOD_NS(_cxo_clk)	   (NSEC_PER_SEC / _cxo_clk)
+#define Q_DIV_PERIOD_NS(_cxo_clk, _div)	   (NSEC_PER_SEC / (_cxo_clk / _div))
+#define Q_ENABLE_DELAY_NS(_cxo_clk, _div)  (2 * Q_CXO_PERIOD_NS(_cxo_clk) + \
+					    3 * Q_DIV_PERIOD_NS(_cxo_clk, _div))
+#define Q_DISABLE_DELAY_NS(_cxo_clk, _div) (3 * Q_DIV_PERIOD_NS(_cxo_clk, _div))
+
+struct q_clkdiv {
+	uint32_t cxo_hz;
+	enum q_clkdiv_cfg cxo_div;
+	struct device_node *node;
+	uint16_t offset;
+	struct spmi_controller *ctrl;
+	bool enabled;
+	struct mutex lock;
+	struct list_head list;
+	uint8_t slave;
+};
+
+static LIST_HEAD(qpnp_clkdiv_devs);
+
+/**
+ * qpnp_clkdiv_get - get a clkdiv handle
+ * @dev: client device pointer.
+ * @name: client specific name for the clock in question.
+ *
+ * Return a clkdiv handle given a client specific name. This name be a prefix
+ * for a property naming that takes a phandle to the actual clkdiv device.
+ */
+struct q_clkdiv *qpnp_clkdiv_get(struct device *dev, const char *name)
+{
+	struct q_clkdiv *q_clkdiv;
+	struct device_node *divclk_node;
+	char prop_name[Q_MAX_DT_PROP_SIZE];
+	int n;
+
+	n = snprintf(prop_name, Q_MAX_DT_PROP_SIZE, "%s-clk", name);
+	if (n == Q_MAX_DT_PROP_SIZE)
+		return ERR_PTR(-EINVAL);
+
+	divclk_node = of_parse_phandle(dev->of_node, prop_name, 0);
+	if (divclk_node == NULL)
+		return ERR_PTR(-ENODEV);
+
+	list_for_each_entry(q_clkdiv, &qpnp_clkdiv_devs, list)
+		if (q_clkdiv->node == divclk_node)
+			return q_clkdiv;
+	return ERR_PTR(-EPROBE_DEFER);
+}
+EXPORT_SYMBOL(qpnp_clkdiv_get);
+
+static int __clkdiv_enable(struct q_clkdiv *q_clkdiv, bool enable)
+{
+	int rc;
+	char buf[1];
+
+	buf[0] = enable ? Q_SET_EN : 0;
+
+	mutex_lock(&q_clkdiv->lock);
+	rc = spmi_ext_register_writel(q_clkdiv->ctrl, q_clkdiv->slave,
+			      Q_REG_ADDR(q_clkdiv, Q_REG_EN_CTL),
+			      &buf[0], 1);
+	if (!rc)
+		q_clkdiv->enabled = enable;
+
+	mutex_unlock(&q_clkdiv->lock);
+
+	if (enable)
+		ndelay(Q_ENABLE_DELAY_NS(q_clkdiv->cxo_hz, q_clkdiv->cxo_div));
+	else
+		ndelay(Q_DISABLE_DELAY_NS(q_clkdiv->cxo_hz, q_clkdiv->cxo_div));
+
+	return rc;
+}
+
+/**
+ * qpnp_clkdiv_enable - enable a clkdiv
+ * @q_clkdiv: pointer to clkdiv handle
+ */
+int qpnp_clkdiv_enable(struct q_clkdiv *q_clkdiv)
+{
+	return __clkdiv_enable(q_clkdiv, true);
+}
+EXPORT_SYMBOL(qpnp_clkdiv_enable);
+
+/**
+ * qpnp_clkdiv_disable - disable a clkdiv
+ * @q_clkdiv: pointer to clkdiv handle
+ */
+int qpnp_clkdiv_disable(struct q_clkdiv *q_clkdiv)
+{
+	return __clkdiv_enable(q_clkdiv, false);
+}
+EXPORT_SYMBOL(qpnp_clkdiv_disable);
+
+/**
+ * @q_clkdiv: pointer to clkdiv handle
+ * @cfg: setting used to configure the output frequency
+ *
+ * Given a q_clkdiv_cfg setting, configure the corresponding clkdiv device
+ * for the desired output frequency.
+ */
+int qpnp_clkdiv_config(struct q_clkdiv *q_clkdiv, enum q_clkdiv_cfg cfg)
+{
+	int rc;
+	char buf[1];
+
+	if (cfg < 0 || cfg >= Q_CLKDIV_INVALID)
+		return -EINVAL;
+
+	buf[0] = cfg;
+
+	mutex_lock(&q_clkdiv->lock);
+
+	if (q_clkdiv->enabled) {
+		rc = __clkdiv_enable(q_clkdiv, false);
+		if (rc) {
+			pr_err("unable to disable clock\n");
+			goto cfg_err;
+		}
+	}
+
+	rc = spmi_ext_register_writel(q_clkdiv->ctrl, q_clkdiv->slave,
+			      Q_REG_ADDR(q_clkdiv, Q_REG_DIV_CTL1), &buf[0], 1);
+	if (rc) {
+		pr_err("enable to write config\n");
+		q_clkdiv->enabled = 0;
+		goto cfg_err;
+	}
+
+	q_clkdiv->cxo_div = cfg;
+
+	if (q_clkdiv->enabled) {
+		rc = __clkdiv_enable(q_clkdiv, true);
+		if (rc) {
+			pr_err("unable to re-enable clock\n");
+			goto cfg_err;
+		}
+	}
+
+cfg_err:
+	mutex_unlock(&q_clkdiv->lock);
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_clkdiv_config);
+
+static int __devinit qpnp_clkdiv_probe(struct spmi_device *spmi)
+{
+	struct q_clkdiv *q_clkdiv;
+	struct device_node *node = spmi->dev.of_node;
+	int rc;
+	uint32_t en;
+	struct resource *res;
+
+	q_clkdiv = devm_kzalloc(&spmi->dev, sizeof(*q_clkdiv), GFP_ATOMIC);
+	if (!q_clkdiv)
+		return -ENOMEM;
+
+	rc = of_property_read_u32(node, "qcom,cxo-freq",
+					&q_clkdiv->cxo_hz);
+	if (rc) {
+		dev_err(&spmi->dev,
+			"%s: unable to get qcom,cxo-freq property\n", __func__);
+		return rc;
+	}
+
+	res = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&spmi->dev, "%s: unable to get device reg resource\n",
+					__func__);
+	}
+
+	q_clkdiv->slave = spmi->sid;
+	q_clkdiv->offset = res->start;
+	q_clkdiv->ctrl = spmi->ctrl;
+	q_clkdiv->node = node;
+	mutex_init(&q_clkdiv->lock);
+
+	rc = of_property_read_u32(node, "qcom,cxo-div",
+					&q_clkdiv->cxo_div);
+	if (rc && rc != -EINVAL) {
+		dev_err(&spmi->dev,
+			"%s: error getting qcom,cxo-div property\n",
+								__func__);
+		return rc;
+	}
+
+	if (!rc) {
+		rc = qpnp_clkdiv_config(q_clkdiv, q_clkdiv->cxo_div);
+		if (rc) {
+			dev_err(&spmi->dev,
+				"%s: unable to set default divide config\n",
+								    __func__);
+			return rc;
+		}
+	}
+
+	rc = of_property_read_u32(node, "qcom,enable", &en);
+	if (rc && rc != -EINVAL) {
+		dev_err(&spmi->dev,
+			"%s: error getting qcom,enable property\n", __func__);
+		return rc;
+	}
+	if (!rc) {
+		rc = __clkdiv_enable(q_clkdiv, en);
+		dev_err(&spmi->dev,
+				"%s: unable to set default config\n", __func__);
+		return rc;
+	}
+
+	dev_set_drvdata(&spmi->dev, q_clkdiv);
+	list_add(&q_clkdiv->list, &qpnp_clkdiv_devs);
+
+	return 0;
+}
+
+static int __devexit qpnp_clkdiv_remove(struct spmi_device *spmi)
+{
+	struct q_clkdiv *q_clkdiv = dev_get_drvdata(&spmi->dev);
+	list_del(&q_clkdiv->list);
+	return 0;
+}
+
+static struct of_device_id spmi_match_table[] = {
+	{	.compatible = "qcom,qpnp-clkdiv",
+	},
+	{}
+};
+
+static struct spmi_driver qpnp_clkdiv_driver = {
+	.driver		= {
+		.name	= "qcom,qpnp-clkdiv",
+		.of_match_table = spmi_match_table,
+	},
+	.probe		= qpnp_clkdiv_probe,
+	.remove		= __devexit_p(qpnp_clkdiv_remove),
+};
+
+static int __init qpnp_clkdiv_init(void)
+{
+	return spmi_driver_register(&qpnp_clkdiv_driver);
+}
+
+static void __exit qpnp_clkdiv_exit(void)
+{
+	return spmi_driver_unregister(&qpnp_clkdiv_driver);
+}
+
+MODULE_DESCRIPTION("QPNP PMIC clkdiv driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(qpnp_clkdiv_init);
+module_exit(qpnp_clkdiv_exit);
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index d8bb884..0119ebe 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -16,141 +16,635 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/spmi.h>
+#include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
+#include <linux/log2.h>
 
+/* PON common register addresses */
 #define QPNP_PON_RT_STS(base)		(base + 0x10)
 #define QPNP_PON_PULL_CTL(base)		(base + 0x70)
 #define QPNP_PON_DBC_CTL(base)		(base + 0x71)
 
-#define QPNP_PON_CNTL_PULL_UP		BIT(1)
-#define QPNP_PON_CNTL_TRIG_DELAY_MASK	(0x7)
+/* PON/RESET sources register addresses */
+#define QPNP_PON_KPDPWR_S1_TIMER(base)	(base + 0x40)
+#define QPNP_PON_KPDPWR_S2_TIMER(base)	(base + 0x41)
+#define QPNP_PON_KPDPWR_S2_CNTL(base)	(base + 0x42)
+#define QPNP_PON_RESIN_S1_TIMER(base)	(base + 0x44)
+#define QPNP_PON_RESIN_S2_TIMER(base)	(base + 0x45)
+#define QPNP_PON_RESIN_S2_CNTL(base)	(base + 0x46)
+
+#define QPNP_PON_RESIN_PULL_UP		BIT(0)
+#define QPNP_PON_KPDPWR_PULL_UP		BIT(1)
+#define QPNP_PON_S2_CNTL_EN		BIT(7)
+#define QPNP_PON_S2_RESET_ENABLE	BIT(7)
+
+#define QPNP_PON_S1_TIMER_MASK		(0xF)
+#define QPNP_PON_S2_TIMER_MASK		(0x7)
+#define QPNP_PON_S2_CNTL_TYPE_MASK	(0xF)
+
+#define QPNP_PON_DBC_DELAY_MASK		(0x7)
 #define QPNP_PON_KPDPWR_N_SET		BIT(0)
+#define QPNP_PON_RESIN_N_SET		BIT(1)
+#define QPNP_PON_RESIN_BARK_N_SET	BIT(4)
+
+/* Ranges */
+#define QPNP_PON_S1_TIMER_MAX		10256
+#define QPNP_PON_S2_TIMER_MAX		2000
+#define QPNP_PON_RESET_TYPE_MAX		0xF
+#define PON_S1_COUNT_MAX		0xF
+
+#define QPNP_KEY_STATUS_DELAY		msecs_to_jiffies(500)
+
+enum pon_type {
+	PON_KPDPWR,
+	PON_RESIN,
+};
+
+struct qpnp_pon_config {
+	u32 pon_type;
+	u32 support_reset;
+	u32 key_code;
+	u32 s1_timer;
+	u32 s2_timer;
+	u32 s2_type;
+	u32 pull_up;
+	u32 state_irq;
+	u32 bark_irq;
+};
 
 struct qpnp_pon {
 	struct spmi_device *spmi;
 	struct input_dev *pon_input;
-	u32 key_status_irq;
+	struct qpnp_pon_config *pon_cfg;
+	int num_pon_config;
 	u16 base;
+	struct delayed_work bark_work;
 };
 
-static irqreturn_t qpnp_pon_key_irq(int irq, void *_pon)
-{
-	u8 pon_rt_sts;
-	int rc;
-	struct qpnp_pon *pon = _pon;
+static u32 s1_delay[PON_S1_COUNT_MAX + 1] = {
+	0 , 32, 56, 80, 138, 184, 272, 408, 608, 904, 1352, 2048,
+	3072, 4480, 6720, 10256
+};
 
+static int
+qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val)
+{
+	int rc;
+	u8 reg;
+
+	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+							addr, &reg, 1);
+	if (rc) {
+		dev_err(&pon->spmi->dev,
+			"Unable to read from addr=%x, rc(%d)\n", addr, rc);
+		return rc;
+	}
+
+	reg &= ~mask;
+	reg |= val & mask;
+	rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
+							addr, &reg, 1);
+	if (rc)
+		dev_err(&pon->spmi->dev,
+			"Unable to write to addr=%x, rc(%d)\n", addr, rc);
+	return rc;
+}
+
+static struct qpnp_pon_config *
+qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
+{
+	int i;
+
+	for (i = 0; i < pon->num_pon_config; i++) {
+		if (pon_type == pon->pon_cfg[i].pon_type)
+			return  &pon->pon_cfg[i];
+	}
+
+	return NULL;
+}
+
+static int
+qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type)
+{
+	int rc;
+	struct qpnp_pon_config *cfg = NULL;
+	u8 pon_rt_sts = 0, pon_rt_bit = 0;
+
+	cfg = qpnp_get_cfg(pon, pon_type);
+	if (!cfg)
+		return -EINVAL;
+
+	/* Check if key reporting is supported */
+	if (!cfg->key_code)
+		return 0;
+
+	/* check the RT status to get the current status of the line */
 	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
 				QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
 	if (rc) {
 		dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
-		return IRQ_HANDLED;
+		return rc;
 	}
 
-	input_report_key(pon->pon_input, KEY_POWER,
-				!(pon_rt_sts & QPNP_PON_KPDPWR_N_SET));
+	switch (cfg->pon_type) {
+	case PON_KPDPWR:
+		pon_rt_bit = QPNP_PON_KPDPWR_N_SET;
+		break;
+	case PON_RESIN:
+		pon_rt_bit = QPNP_PON_RESIN_N_SET;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	input_report_key(pon->pon_input, cfg->key_code,
+					(pon_rt_sts & pon_rt_bit));
 	input_sync(pon->pon_input);
 
+	return 0;
+}
+
+static irqreturn_t qpnp_kpdpwr_irq(int irq, void *_pon)
+{
+	int rc;
+	struct qpnp_pon *pon = _pon;
+
+	rc = qpnp_pon_input_dispatch(pon, PON_KPDPWR);
+	if (rc)
+		dev_err(&pon->spmi->dev, "Unable to send input event\n");
+
 	return IRQ_HANDLED;
 }
 
-static int __devinit qpnp_pon_key_init(struct qpnp_pon *pon)
+static irqreturn_t qpnp_kpdpwr_bark_irq(int irq, void *_pon)
+{
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t qpnp_resin_irq(int irq, void *_pon)
+{
+	int rc;
+	struct qpnp_pon *pon = _pon;
+
+	rc = qpnp_pon_input_dispatch(pon, PON_RESIN);
+	if (rc)
+		dev_err(&pon->spmi->dev, "Unable to send input event\n");
+	return IRQ_HANDLED;
+}
+
+static void bark_work_func(struct work_struct *work)
+{
+	int rc;
+	u8 pon_rt_sts = 0;
+	struct qpnp_pon_config *cfg;
+	struct qpnp_pon *pon =
+		container_of(work, struct qpnp_pon, bark_work.work);
+
+	/* enable reset */
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
+				QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+		goto err_return;
+	}
+	/* bark RT status update delay */
+	msleep(100);
+	/* read the bark RT status */
+	rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+				QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
+		goto err_return;
+	}
+
+	if (!(pon_rt_sts & QPNP_PON_RESIN_BARK_N_SET)) {
+		cfg = qpnp_get_cfg(pon, PON_RESIN);
+		if (!cfg) {
+			dev_err(&pon->spmi->dev, "Invalid config pointer\n");
+			goto err_return;
+		}
+		/* report the key event and enable the bark IRQ */
+		input_report_key(pon->pon_input, cfg->key_code, 0);
+		input_sync(pon->pon_input);
+		enable_irq(cfg->bark_irq);
+	} else {
+		/* disable reset */
+		rc = qpnp_pon_masked_write(pon,
+				QPNP_PON_RESIN_S2_CNTL(pon->base),
+				QPNP_PON_S2_CNTL_EN, 0);
+		if (rc) {
+			dev_err(&pon->spmi->dev,
+				"Unable to configure S2 enable\n");
+			goto err_return;
+		}
+		/* re-arm the work */
+		schedule_delayed_work(&pon->bark_work, QPNP_KEY_STATUS_DELAY);
+	}
+
+err_return:
+	return;
+}
+
+static irqreturn_t qpnp_resin_bark_irq(int irq, void *_pon)
+{
+	int rc;
+	struct qpnp_pon *pon = _pon;
+	struct qpnp_pon_config *cfg;
+
+	/* disable the bark interrupt */
+	disable_irq_nosync(irq);
+
+	/* disable reset */
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
+						QPNP_PON_S2_CNTL_EN, 0);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+		goto err_exit;
+	}
+
+	cfg = qpnp_get_cfg(pon, PON_RESIN);
+	if (!cfg) {
+		dev_err(&pon->spmi->dev, "Invalid config pointer\n");
+		goto err_exit;
+	}
+
+	/* report the key event */
+	input_report_key(pon->pon_input, cfg->key_code, 1);
+	input_sync(pon->pon_input);
+	/* schedule work to check the bark status for key-release */
+	schedule_delayed_work(&pon->bark_work, QPNP_KEY_STATUS_DELAY);
+err_exit:
+	return IRQ_HANDLED;
+}
+
+static int __devinit
+qpnp_config_pull(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+	int rc;
+	u8 pull_bit;
+
+	switch (cfg->pon_type) {
+	case PON_KPDPWR:
+		pull_bit = QPNP_PON_KPDPWR_PULL_UP;
+		break;
+	case PON_RESIN:
+		pull_bit = QPNP_PON_RESIN_PULL_UP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rc = qpnp_pon_masked_write(pon, QPNP_PON_PULL_CTL(pon->base),
+				pull_bit, cfg->pull_up ? pull_bit : 0);
+	if (rc)
+		dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
+
+	return rc;
+}
+
+static int __devinit
+qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+	int rc;
+	u8 i;
+	u16 s1_timer_addr, s2_cntl_addr, s2_timer_addr;
+
+	switch (cfg->pon_type) {
+	case PON_KPDPWR:
+		s1_timer_addr = QPNP_PON_KPDPWR_S1_TIMER(pon->base);
+		s2_timer_addr = QPNP_PON_KPDPWR_S2_TIMER(pon->base);
+		s2_cntl_addr = QPNP_PON_KPDPWR_S2_CNTL(pon->base);
+		break;
+	case PON_RESIN:
+		s1_timer_addr = QPNP_PON_RESIN_S1_TIMER(pon->base);
+		s2_timer_addr = QPNP_PON_RESIN_S2_TIMER(pon->base);
+		s2_cntl_addr = QPNP_PON_RESIN_S2_CNTL(pon->base);
+		break;
+	default:
+		return -EINVAL;
+	}
+	/* disable S2 reset */
+	rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+				QPNP_PON_S2_CNTL_EN, 0);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+		return rc;
+	}
+
+	usleep(100);
+
+	/* configure s1 timer, s2 timer and reset type */
+	for (i = 0; i < PON_S1_COUNT_MAX + 1; i++) {
+		if (cfg->s1_timer <= s1_delay[i])
+			break;
+	}
+	rc = qpnp_pon_masked_write(pon, s1_timer_addr,
+				QPNP_PON_S1_TIMER_MASK, i);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S1 timer\n");
+		return rc;
+	}
+
+	i = 0;
+	if (cfg->s2_timer) {
+		i = cfg->s2_timer / 10;
+		i = ilog2(i + 1);
+	}
+
+	rc = qpnp_pon_masked_write(pon, s2_timer_addr,
+				QPNP_PON_S2_TIMER_MASK, i);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 timer\n");
+		return rc;
+	}
+
+	rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+				QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 reset type\n");
+		return rc;
+	}
+
+	/* enable S2 reset */
+	rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+				QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
+	if (rc) {
+		dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int __devinit
+qpnp_pon_request_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
 {
 	int rc = 0;
-	u32 pullup, delay;
-	u8 pon_cntl;
 
-	pon->key_status_irq = spmi_get_irq_byname(pon->spmi,
-						NULL, "power-key");
-	if (pon->key_status_irq < 0) {
-		dev_err(&pon->spmi->dev, "Unable to get pon key irq\n");
-		return -ENXIO;
-	}
-
-	rc = of_property_read_u32(pon->spmi->dev.of_node,
-					"qcom,pon-key-dbc-delay", &delay);
-	if (rc) {
-		delay = (delay << 6) / USEC_PER_SEC;
-		delay = ilog2(delay);
-
-		rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
-				QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
-		if (rc) {
-			dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
-						QPNP_PON_DBC_CTL(pon->base));
-			return rc;
-		}
-		pon_cntl &= ~QPNP_PON_CNTL_TRIG_DELAY_MASK;
-		pon_cntl |= (delay & QPNP_PON_CNTL_TRIG_DELAY_MASK);
-		rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
-				QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
-		if (rc) {
-			dev_err(&pon->spmi->dev, "spmi write addre=%x failed\n",
-						QPNP_PON_DBC_CTL(pon->base));
-			return rc;
-		}
-	}
-
-	rc = of_property_read_u32(pon->spmi->dev.of_node,
-				"qcom,pon-key-pull-up", &pullup);
-	if (!rc) {
-		rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
-				QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
-		if (rc) {
-			dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
-						QPNP_PON_PULL_CTL(pon->base));
-			return rc;
-		}
-		if (pullup)
-			pon_cntl |= QPNP_PON_CNTL_PULL_UP;
-		else
-			pon_cntl &= ~QPNP_PON_CNTL_PULL_UP;
-
-		rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
-				QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
-		if (rc) {
-			dev_err(&pon->spmi->dev, "spmi write addr=%x failed\n",
-						QPNP_PON_PULL_CTL(pon->base));
-			return rc;
-		}
-	}
-
-	pon->pon_input = input_allocate_device();
-	if (!pon->pon_input) {
-		dev_err(&pon->spmi->dev, "Can't allocate pon button\n");
-		return -ENOMEM;
-	}
-
-	input_set_capability(pon->pon_input, EV_KEY, KEY_POWER);
-	pon->pon_input->name = "qpnp_pon_key";
-	pon->pon_input->phys = "qpnp_pon_key/input0";
-
-	rc = input_register_device(pon->pon_input);
-	if (rc) {
-		dev_err(&pon->spmi->dev, "Can't register pon key: %d\n", rc);
-		goto free_input_dev;
-	}
-
-	rc = request_any_context_irq(pon->key_status_irq, qpnp_pon_key_irq,
+	switch (cfg->pon_type) {
+	case PON_KPDPWR:
+		rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+							qpnp_kpdpwr_irq,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-						"qpnp_pon_key_status", pon);
-	if (rc < 0) {
-		dev_err(&pon->spmi->dev, "Can't request %d IRQ for pon: %d\n",
-						pon->key_status_irq, rc);
-		goto unreg_input_dev;
+						"qpnp_kpdpwr_status", pon);
+		if (rc < 0) {
+			dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+							cfg->state_irq);
+			return rc;
+		}
+		if (cfg->support_reset) {
+			rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
+						qpnp_kpdpwr_bark_irq,
+						IRQF_TRIGGER_RISING,
+						"qpnp_kpdpwr_bark", pon);
+			if (rc < 0) {
+				dev_err(&pon->spmi->dev,
+					"Can't request %d IRQ\n",
+						cfg->bark_irq);
+				return rc;
+			}
+		}
+		break;
+	case PON_RESIN:
+		rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+							qpnp_resin_irq,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+						"qpnp_resin_status", pon);
+		if (rc < 0) {
+			dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+							cfg->state_irq);
+			return rc;
+		}
+		if (cfg->support_reset) {
+			rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
+						qpnp_resin_bark_irq,
+						IRQF_TRIGGER_RISING,
+						"qpnp_resin_bark", pon);
+			if (rc < 0) {
+				dev_err(&pon->spmi->dev,
+					"Can't request %d IRQ\n",
+						cfg->bark_irq);
+				return rc;
+			}
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __devinit
+qpnp_pon_config_input(struct qpnp_pon *pon,  struct qpnp_pon_config *cfg)
+{
+	if (!pon->pon_input) {
+		pon->pon_input = input_allocate_device();
+		if (!pon->pon_input) {
+			dev_err(&pon->spmi->dev,
+				"Can't allocate pon input device\n");
+			return -ENOMEM;
+		}
+		pon->pon_input->name = "qpnp_pon";
+		pon->pon_input->phys = "qpnp_pon/input0";
+	}
+
+	input_set_capability(pon->pon_input, EV_KEY, cfg->key_code);
+
+	return 0;
+}
+
+static int __devinit qpnp_pon_config_init(struct qpnp_pon *pon)
+{
+	int rc = 0, i = 0;
+	struct device_node *pp = NULL;
+	struct qpnp_pon_config *cfg;
+
+	/* iterate through the list of pon configs */
+	while ((pp = of_get_next_child(pon->spmi->dev.of_node, pp))) {
+
+		cfg = &pon->pon_cfg[i++];
+
+		rc = of_property_read_u32(pp, "qcom,pon-type", &cfg->pon_type);
+		if (rc) {
+			dev_err(&pon->spmi->dev, "PON type not specified\n");
+			return rc;
+		}
+
+		switch (cfg->pon_type) {
+		case PON_KPDPWR:
+			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+							NULL, "kpdpwr");
+			if (cfg->state_irq < 0) {
+				dev_err(&pon->spmi->dev,
+					"Unable to get kpdpwr irq\n");
+				return cfg->state_irq;
+			}
+
+			rc = of_property_read_u32(pp, "qcom,support-reset",
+							&cfg->support_reset);
+			if (rc && rc != -EINVAL) {
+				dev_err(&pon->spmi->dev,
+					"Unable to read 'support-reset'\n");
+				return rc;
+			}
+
+			if (cfg->support_reset) {
+				cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
+							NULL, "kpdpwr-bark");
+				if (cfg->bark_irq < 0) {
+					dev_err(&pon->spmi->dev,
+					"Unable to get kpdpwr-bark irq\n");
+					return cfg->bark_irq;
+				}
+			}
+			break;
+		case PON_RESIN:
+			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+							NULL, "resin");
+			if (cfg->state_irq < 0) {
+				dev_err(&pon->spmi->dev,
+					"Unable to get resin irq\n");
+				return cfg->bark_irq;
+			}
+
+			rc = of_property_read_u32(pp, "qcom,support-reset",
+							&cfg->support_reset);
+			if (rc && rc != -EINVAL) {
+				dev_err(&pon->spmi->dev,
+					"Unable to read 'support-reset'\n");
+				return rc;
+			}
+
+			if (cfg->support_reset) {
+				cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
+							NULL, "resin-bark");
+				if (cfg->bark_irq < 0) {
+					dev_err(&pon->spmi->dev,
+					"Unable to get resin-bark irq\n");
+					return cfg->bark_irq;
+				}
+			}
+			break;
+		default:
+			dev_err(&pon->spmi->dev, "PON RESET %d not supported",
+								cfg->pon_type);
+			return -EINVAL;
+		}
+
+		if (cfg->support_reset) {
+			/*
+			 * Get the reset parameters (bark debounce time and
+			 * reset debounce time) for the reset line.
+			 */
+			rc = of_property_read_u32(pp, "qcom,s1-timer",
+							&cfg->s1_timer);
+			if (rc) {
+				dev_err(&pon->spmi->dev,
+					"Unable to read s1-timer\n");
+				return rc;
+			}
+			if (cfg->s1_timer > QPNP_PON_S1_TIMER_MAX) {
+				dev_err(&pon->spmi->dev,
+					"Incorrect S1 debounce time\n");
+				return -EINVAL;
+			}
+			rc = of_property_read_u32(pp, "qcom,s2-timer",
+							&cfg->s2_timer);
+			if (rc) {
+				dev_err(&pon->spmi->dev,
+					"Unable to read s2-timer\n");
+				return rc;
+			}
+			if (cfg->s2_timer > QPNP_PON_S2_TIMER_MAX) {
+				dev_err(&pon->spmi->dev,
+					"Incorrect S2 debounce time\n");
+				return -EINVAL;
+			}
+			rc = of_property_read_u32(pp, "qcom,s2-type",
+							&cfg->s2_type);
+			if (rc) {
+				dev_err(&pon->spmi->dev,
+					"Unable to read s2-type\n");
+				return rc;
+			}
+			if (cfg->s2_type > QPNP_PON_RESET_TYPE_MAX) {
+				dev_err(&pon->spmi->dev,
+					"Incorrect reset type specified\n");
+				return -EINVAL;
+			}
+		}
+		/*
+		 * Get the standard-key parameters. This might not be
+		 * specified if there is no key mapping on the reset line.
+		 */
+		rc = of_property_read_u32(pp, "linux,code", &cfg->key_code);
+		if (rc && rc == -EINVAL) {
+			dev_err(&pon->spmi->dev,
+				"Unable to read key-code\n");
+			return rc;
+		}
+		/* Register key configuration */
+		if (cfg->key_code) {
+			rc = qpnp_pon_config_input(pon, cfg);
+			if (rc < 0)
+				return rc;
+		}
+		/* get the pull-up configuration */
+		rc = of_property_read_u32(pp, "qcom,pull-up", &cfg->pull_up);
+		if (rc && rc != -EINVAL) {
+			dev_err(&pon->spmi->dev, "Unable to read pull-up\n");
+			return rc;
+		}
+	}
+
+	/* register the input device */
+	if (pon->pon_input) {
+		rc = input_register_device(pon->pon_input);
+		if (rc) {
+			dev_err(&pon->spmi->dev,
+				"Can't register pon key: %d\n", rc);
+			goto free_input_dev;
+		}
+	}
+
+	for (i = 0; i < pon->num_pon_config; i++) {
+		cfg = &pon->pon_cfg[i];
+		/* Configure the pull-up */
+		rc = qpnp_config_pull(pon, cfg);
+		if (rc) {
+			dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
+			goto unreg_input_dev;
+		}
+		/* Configure the reset-configuration */
+		if (cfg->support_reset) {
+			rc = qpnp_config_reset(pon, cfg);
+			if (rc) {
+				dev_err(&pon->spmi->dev,
+					"Unable to config pon reset\n");
+				goto unreg_input_dev;
+			}
+		}
+		rc = qpnp_pon_request_irqs(pon, cfg);
+		if (rc) {
+			dev_err(&pon->spmi->dev, "Unable to request-irq's\n");
+			goto unreg_input_dev;
+		}
 	}
 
 	device_init_wakeup(&pon->spmi->dev, 1);
-	enable_irq_wake(pon->key_status_irq);
 
 	return rc;
 
 unreg_input_dev:
-	input_unregister_device(pon->pon_input);
+	if (pon->pon_input)
+		input_unregister_device(pon->pon_input);
 free_input_dev:
-	input_free_device(pon->pon_input);
+	if (pon->pon_input)
+		input_free_device(pon->pon_input);
 	return rc;
 }
 
@@ -158,7 +652,8 @@
 {
 	struct qpnp_pon *pon;
 	struct resource *pon_resource;
-	u32 pon_key_enable = 0;
+	struct device_node *itr = NULL;
+	u32 delay = 0;
 	int rc = 0;
 
 	pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
@@ -170,6 +665,20 @@
 
 	pon->spmi = spmi;
 
+	/* get the total number of pon configurations */
+	while ((itr = of_get_next_child(spmi->dev.of_node, itr)))
+		pon->num_pon_config++;
+
+	if (!pon->num_pon_config) {
+		/* No PON config., do not register the driver */
+		dev_err(&spmi->dev, "No PON config. specified\n");
+		return -EINVAL;
+	}
+
+	pon->pon_cfg = devm_kzalloc(&spmi->dev,
+			sizeof(struct qpnp_pon_config) * pon->num_pon_config,
+								GFP_KERNEL);
+
 	pon_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
 	if (!pon_resource) {
 		dev_err(&spmi->dev, "Unable to get PON base address\n");
@@ -177,36 +686,45 @@
 	}
 	pon->base = pon_resource->start;
 
-	dev_set_drvdata(&spmi->dev, pon);
-
-	/* pon-key-enable property must be set to register pon key */
-	rc = of_property_read_u32(spmi->dev.of_node, "qcom,pon-key-enable",
-							&pon_key_enable);
+	rc = of_property_read_u32(pon->spmi->dev.of_node,
+				"qcom,pon-dbc-delay", &delay);
 	if (rc && rc != -EINVAL) {
-		dev_err(&spmi->dev,
-			"Error reading 'pon-key-enable' property (%d)", rc);
+		dev_err(&spmi->dev, "Unable to read debounce delay\n");
 		return rc;
-	}
-
-	if (pon_key_enable) {
-		rc = qpnp_pon_key_init(pon);
-		if (rc < 0) {
-			dev_err(&spmi->dev, "Failed to register pon-key\n");
+	} else {
+		delay = (delay << 6) / USEC_PER_SEC;
+		delay = ilog2(delay);
+		rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
+						QPNP_PON_DBC_DELAY_MASK, delay);
+		if (rc) {
+			dev_err(&spmi->dev, "Unable to set PON debounce\n");
 			return rc;
 		}
 	}
 
-	return 0;
+	dev_set_drvdata(&spmi->dev, pon);
+
+	INIT_DELAYED_WORK(&pon->bark_work, bark_work_func);
+
+	/* register the PON configurations */
+	rc = qpnp_pon_config_init(pon);
+	if (rc) {
+		dev_err(&spmi->dev,
+			"Unable to intialize PON configurations\n");
+		return rc;
+	}
+
+	return rc;
 }
 
 static int qpnp_pon_remove(struct spmi_device *spmi)
 {
 	struct qpnp_pon *pon = dev_get_drvdata(&spmi->dev);
 
-	if (pon->pon_input) {
-		free_irq(pon->key_status_irq, pon);
+	cancel_delayed_work_sync(&pon->bark_work);
+
+	if (pon->pon_input)
 		input_unregister_device(pon->pon_input);
-	}
 
 	return 0;
 }
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 88e0948..5e1b77a 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -122,6 +122,7 @@
 	int			cc_reading_at_100;
 	int			max_voltage_uv;
 
+	int			chg_term_ua;
 	int			default_rbatt_mohm;
 	int			amux_2_trim_delta;
 	uint16_t		prev_last_good_ocv_raw;
@@ -134,8 +135,6 @@
 	int			enable_fcc_learning;
 	int			shutdown_soc;
 	int			shutdown_iavg_ua;
-	int			shutdown_soc_timer_expired;
-	struct delayed_work	shutdown_soc_work;
 	struct delayed_work	calculate_soc_delayed_work;
 	struct timespec		t_soc_queried;
 	int			shutdown_soc_valid_limit;
@@ -144,6 +143,10 @@
 	int			prev_uuc_iavg_ma;
 	int			prev_pc_unusable;
 	int			adjust_soc_low_threshold;
+
+	int			ibat_at_cv_ua;
+	int			soc_at_cv;
+	int			prev_chg_soc;
 };
 
 /*
@@ -1503,6 +1506,75 @@
 }
 EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
 
+static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
+			int batt_temp,
+			int chargecycles,
+			int fcc_uah,
+			int uuc_uah,
+			int cc_uah,
+			int shutdown_soc,
+			int *rc_uah,
+			int *ocv_uv)
+{
+	s64 rc;
+	int pc, new_pc;
+	int batt_temp_degc = batt_temp / 10;
+	int ocv;
+
+	rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
+	rc = div_s64(rc, 100) + cc_uah + uuc_uah;
+	pc = DIV_ROUND_CLOSEST((int)rc * 100, fcc_uah);
+	pc = clamp(pc, 0, 100);
+
+	ocv = interpolate_ocv(chip, batt_temp_degc, pc);
+
+	pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
+			shutdown_soc, fcc_uah, uuc_uah, (int)rc, pc, ocv);
+	new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+
+	while (abs(new_pc - pc) > 1) {
+		int delta_mv = 5;
+
+		if (new_pc > pc)
+			delta_mv = -1 * delta_mv;
+
+		ocv = ocv + delta_mv;
+		new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+		pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+	}
+
+	*ocv_uv = ocv * 1000;
+	*rc_uah = (int)rc;
+}
+
+static void adjust_rc_and_uuc_for_specific_soc(
+						struct pm8921_bms_chip *chip,
+						int batt_temp,
+						int chargecycles,
+						int soc,
+						int fcc_uah,
+						int uuc_uah,
+						int cc_uah,
+						int rc_uah,
+						int rbatt,
+						int *ret_ocv,
+						int *ret_rc,
+						int *ret_uuc,
+						int *ret_rbatt)
+{
+	int ocv_uv;
+
+	find_ocv_for_soc(chip, batt_temp, chargecycles,
+					fcc_uah, uuc_uah, cc_uah,
+					soc,
+					&rc_uah, &ocv_uv);
+
+	*ret_ocv = ocv_uv;
+	*ret_rbatt = rbatt;
+	*ret_rc = rc_uah;
+	*ret_uuc = uuc_uah;
+}
 static int bound_soc(int soc)
 {
 	soc = max(0, soc);
@@ -1510,9 +1582,73 @@
 	return soc;
 }
 
+static int charging_adjustments(struct pm8921_bms_chip *chip,
+				int soc, int vbat_uv, int ibat_ua,
+				int batt_temp, int chargecycles,
+				int fcc_uah, int cc_uah, int uuc_uah)
+{
+	int chg_soc;
+
+	if (chip->soc_at_cv == -EINVAL) {
+		/* In constant current charging return the calc soc */
+		if (vbat_uv <= chip->max_voltage_uv)
+			pr_debug("CC CHG SOC %d\n", soc);
+
+		/* Note the CC to CV point */
+		if (vbat_uv >= chip->max_voltage_uv) {
+			chip->soc_at_cv = soc;
+			chip->prev_chg_soc = soc;
+			chip->ibat_at_cv_ua = ibat_ua;
+			pr_debug("CC_TO_CV ibat_ua = %d CHG SOC %d\n",
+					ibat_ua, soc);
+		}
+		return soc;
+	}
+
+	/*
+	 * battery is in CV phase - begin liner inerpolation of soc based on
+	 * battery charge current
+	 */
+
+	/*
+	 * if voltage lessened (possibly because of a system load)
+	 * keep reporting the prev chg soc
+	 */
+	if (vbat_uv <= chip->max_voltage_uv) {
+		pr_debug("vbat %d < max = %d CC CHG SOC %d\n",
+			vbat_uv, chip->max_voltage_uv, chip->prev_chg_soc);
+		return chip->prev_chg_soc;
+	}
+
+	chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua,
+					100, -100000,
+					ibat_ua);
+
+	/* always report a higher soc */
+	if (chg_soc > chip->prev_chg_soc) {
+		int new_ocv_uv;
+		int new_rc;
+
+		chip->prev_chg_soc = chg_soc;
+
+		find_ocv_for_soc(chip, batt_temp, chargecycles,
+				fcc_uah, uuc_uah, cc_uah,
+				chg_soc,
+				&new_rc, &new_ocv_uv);
+		the_chip->last_ocv_uv = new_ocv_uv;
+		pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n",
+				new_ocv_uv,
+				chip->prev_chg_soc);
+	}
+
+	pr_debug("Reporting CHG SOC %d\n", chip->prev_chg_soc);
+	return chip->prev_chg_soc;
+}
+
 static int last_soc_est = -EINVAL;
-static int adjust_soc(struct pm8921_bms_chip *chip, int soc, int batt_temp,
-		int rbatt , int fcc_uah, int uuc_uah, int cc_uah)
+static int adjust_soc(struct pm8921_bms_chip *chip, int soc,
+		int batt_temp, int chargecycles,
+		int rbatt, int fcc_uah, int uuc_uah, int cc_uah)
 {
 	int ibat_ua = 0, vbat_uv = 0;
 	int ocv_est_uv = 0, soc_est = 0, pc_est = 0, pc = 0;
@@ -1534,9 +1670,6 @@
 	}
 
 
-	if (ibat_ua < 0)
-		goto out;
-
 	delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
 
 	ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000;
@@ -1545,6 +1678,13 @@
 						(s64)fcc_uah - uuc_uah);
 	soc_est = bound_soc(soc_est);
 
+	if (ibat_ua < 0) {
+		soc = charging_adjustments(chip, soc, vbat_uv, ibat_ua,
+				batt_temp, chargecycles,
+				fcc_uah, cc_uah, uuc_uah);
+		goto out;
+	}
+
 	/*
 	 * do not adjust
 	 * if soc is same as what bms calculated
@@ -1628,10 +1768,10 @@
 out:
 	pr_debug("ibat_ua = %d, vbat_uv = %d, ocv_est_uv = %d, pc_est = %d, "
 		"soc_est = %d, n = %d, delta_ocv_uv = %d, last_ocv_uv = %d, "
-		"pc_new = %d, soc_new = %d\n",
+		"pc_new = %d, soc_new = %d, rbatt = %d, m = %d\n",
 		ibat_ua, vbat_uv, ocv_est_uv, pc_est,
 		soc_est, n, delta_ocv_uv, chip->last_ocv_uv,
-		pc_new, soc_new);
+		pc_new, soc_new, rbatt, m);
 
 	return soc;
 }
@@ -1713,76 +1853,6 @@
 			shutdown_soc_invalid);
 }
 
-static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
-			int batt_temp,
-			int chargecycles,
-			int fcc_uah,
-			int uuc_uah,
-			int cc_uah,
-			int shutdown_soc,
-			int *rc_uah,
-			int *ocv_uv)
-{
-	s64 rc;
-	int pc, new_pc;
-	int batt_temp_degc = batt_temp / 10;
-	int ocv;
-
-	rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
-	rc = div_s64(rc, 100) + cc_uah + uuc_uah;
-	pc = DIV_ROUND_CLOSEST((int)rc * 100, fcc_uah);
-	pc = clamp(pc, 0, 100);
-
-	ocv = interpolate_ocv(chip, batt_temp_degc, pc);
-
-	pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
-			shutdown_soc, fcc_uah, uuc_uah, (int)rc, pc, ocv);
-	new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
-	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
-
-	while (abs(new_pc - pc) > 1) {
-		int delta_mv = 5;
-
-		if (new_pc > pc)
-			delta_mv = -1 * delta_mv;
-
-		ocv = ocv + delta_mv;
-		new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
-		pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
-	}
-
-	*ocv_uv = ocv * 1000;
-	*rc_uah = (int)rc;
-}
-
-static void adjust_rc_and_uuc_for_specific_soc(
-						struct pm8921_bms_chip *chip,
-						int batt_temp,
-						int chargecycles,
-						int soc,
-						int fcc_uah,
-						int uuc_uah,
-						int cc_uah,
-						int rc_uah,
-						int rbatt,
-						int *ret_ocv,
-						int *ret_rc,
-						int *ret_uuc,
-						int *ret_rbatt)
-{
-	int ocv_uv;
-
-	find_ocv_for_soc(chip, batt_temp, chargecycles,
-					fcc_uah, uuc_uah, cc_uah,
-					soc,
-					&rc_uah, &ocv_uv);
-
-	*ret_ocv = ocv_uv;
-	*ret_rbatt = rbatt;
-	*ret_rc = rc_uah;
-	*ret_uuc = uuc_uah;
-}
-
 #define SOC_CATCHUP_SEC_MAX		600
 #define SOC_CATCHUP_SEC_PER_PERCENT	60
 #define MAX_CATCHUP_SOC	(SOC_CATCHUP_SEC_MAX/SOC_CATCHUP_SEC_PER_PERCENT)
@@ -1831,17 +1901,6 @@
 	return scaled_soc;
 }
 
-#define SHOW_SHUTDOWN_SOC_MS	30000
-static void shutdown_soc_work(struct work_struct *work)
-{
-	struct pm8921_bms_chip *chip = container_of(work,
-				struct pm8921_bms_chip, shutdown_soc_work.work);
-
-	pr_debug("not forcing shutdown soc anymore\n");
-	/* it has been  30 seconds since init, no need to show shutdown soc */
-	chip->shutdown_soc_timer_expired = 1;
-}
-
 static bool is_shutdown_soc_within_limits(struct pm8921_bms_chip *chip, int soc)
 {
 	if (shutdown_soc_invalid) {
@@ -2001,7 +2060,8 @@
 	}
 	mutex_unlock(&soc_invalidation_mutex);
 
-	calculated_soc = adjust_soc(chip, soc, batt_temp,
+	pr_debug("SOC before adjustment = %d\n", soc);
+	calculated_soc = adjust_soc(chip, soc, batt_temp, chargecycles,
 			rbatt, fcc_uah, unusable_charge_uah, cc_uah);
 
 	pr_debug("calculated SOC = %d\n", calculated_soc);
@@ -2107,18 +2167,6 @@
 	if (last_soc != -EINVAL && last_soc < soc && soc != 100)
 		soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
 
-	if (chip->shutdown_soc != 0
-			&& !shutdown_soc_invalid
-			&& !chip->shutdown_soc_timer_expired) {
-		/*
-		 * force shutdown soc if it is valid and the shutdown soc show
-		 * timer has not expired
-		 */
-		soc = chip->shutdown_soc;
-
-		pr_debug("Forcing SHUTDOWN_SOC = %d\n", soc);
-	}
-
 	last_soc = soc;
 	backup_soc_and_iavg(chip, batt_temp, last_soc);
 	pr_debug("Reported SOC = %d\n", last_soc);
@@ -2402,6 +2450,9 @@
 			IBAT_TOL_MASK, IBAT_TOL_DEFAULT);
 	the_chip->charge_time_us = 0;
 	the_chip->catch_up_time_us = 0;
+
+	the_chip->soc_at_cv = -EINVAL;
+	the_chip->prev_chg_soc = -EINVAL;
 	pr_debug("start_percent = %u%%\n", the_chip->start_percent);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
@@ -2507,6 +2558,8 @@
 	the_chip->end_percent = -EINVAL;
 	the_chip->charge_time_us = 0;
 	the_chip->catch_up_time_us = 0;
+	the_chip->soc_at_cv = -EINVAL;
+	the_chip->prev_chg_soc = -EINVAL;
 	pm_bms_masked_write(the_chip, BMS_TOLERANCES,
 				IBAT_TOL_MASK, IBAT_TOL_NOCHG);
 }
@@ -3107,6 +3160,7 @@
 	chip->r_sense = pdata->r_sense;
 	chip->v_cutoff = pdata->v_cutoff;
 	chip->max_voltage_uv = pdata->max_voltage_uv;
+	chip->chg_term_ua = pdata->chg_term_ua;
 	chip->batt_type = pdata->battery_type;
 	chip->rconn_mohm = pdata->rconn_mohm;
 	chip->start_percent = -EINVAL;
@@ -3117,6 +3171,7 @@
 		chip->adjust_soc_low_threshold = 45;
 
 	chip->prev_pc_unusable = -EINVAL;
+	chip->soc_at_cv = -EINVAL;
 
 	chip->ignore_shutdown_soc = pdata->ignore_shutdown_soc;
 	rc = set_battery_data(chip);
@@ -3190,11 +3245,6 @@
 				pm8921_bms_get_percent_charge(),
 				vbatt, chip->last_ocv_uv);
 
-	INIT_DELAYED_WORK(&chip->shutdown_soc_work, shutdown_soc_work);
-	schedule_delayed_work(&chip->shutdown_soc_work,
-			round_jiffies_relative(msecs_to_jiffies
-			(SHOW_SHUTDOWN_SOC_MS)));
-
 	return 0;
 
 free_irqs:
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index f2c881d..9f3327a 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1818,6 +1818,14 @@
 			goto err_probe_exit;
 		}
 
+		rc = of_property_read_u32(pdev->dev.of_node,
+				"cell-index", &pdev->id);
+		if (rc)
+			dev_warn(&pdev->dev,
+				"using default bus_num %d\n", pdev->id);
+		else
+			master->bus_num = pdev->id;
+
 		for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
 			dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
 								i, &flags);
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 7d0583c..3366bba 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -60,19 +60,40 @@
 #define TSENS2_POINT1_MASK		0x3f00000
 #define TSENS3_POINT1_MASK		0xfc000000
 #define TSENS4_POINT1_MASK		0x3f
-#define TSENS5_POINT1_MASK		0xfc00
+#define TSENS5_POINT1_MASK		0xfc0
 #define TSENS6_POINT1_MASK		0x3f000
 #define TSENS7_POINT1_MASK		0xfc0000
 #define TSENS8_POINT1_MASK		0x3f000000
 #define TSENS9_POINT1_MASK		0x3f
 #define TSENS10_POINT1_MASK		0xfc00
 #define TSENS_CAL_SEL_0_1		0xc0000000
-#define TSENS_CAL_SEL_2			BIT(30)
+#define TSENS_CAL_SEL_2			0x40000000
 #define TSENS_CAL_SEL_SHIFT		30
 #define TSENS_CAL_SEL_SHIFT_2		28
-#define TSENS_ONE_POINT_CALIB		0x3
+#define TSENS_ONE_POINT_CALIB		0x1
 #define TSENS_TWO_POINT_CALIB		0x2
 
+#define TSENS0_POINT1_SHIFT		8
+#define TSENS1_POINT1_SHIFT		14
+#define TSENS2_POINT1_SHIFT		20
+#define TSENS3_POINT1_SHIFT		26
+#define TSENS5_POINT1_SHIFT		6
+#define TSENS6_POINT1_SHIFT		12
+#define TSENS7_POINT1_SHIFT		18
+#define TSENS8_POINT1_SHIFT		24
+#define TSENS10_POINT1_SHIFT		6
+
+#define TSENS_POINT2_BASE_SHIFT		12
+#define TSENS0_POINT2_SHIFT		20
+#define TSENS1_POINT2_SHIFT		26
+#define TSENS3_POINT2_SHIFT		6
+#define TSENS4_POINT2_SHIFT		12
+#define TSENS5_POINT2_SHIFT		18
+#define TSENS6_POINT2_SHIFT		24
+#define TSENS8_POINT2_SHIFT		6
+#define TSENS9_POINT2_SHIFT		12
+#define TSENS10_POINT2_SHIFT		18
+
 #define TSENS_BASE2_MASK		0xff000
 #define TSENS0_POINT2_MASK		0x3f00000
 #define TSENS1_POINT2_MASK		0xfc000000
@@ -148,9 +169,11 @@
 	if (degcbeforefactor == 0)
 		degc = degcbeforefactor;
 	else if (degcbeforefactor > 0)
-		degc = degcbeforefactor;
+		degc = ((degcbeforefactor * tmdev->tsens_factor) +
+				tmdev->tsens_factor/2)/tmdev->tsens_factor;
 	else
-		degc = degcbeforefactor;
+		degc = ((degcbeforefactor * tmdev->tsens_factor) -
+				tmdev->tsens_factor/2)/tmdev->tsens_factor;
 
 	return degc;
 }
@@ -479,20 +502,20 @@
 	int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
 	int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
 	int tsens9_point2 = 0, tsens10_point2 = 0;
-	int tsens_base2_data = 0, tsens_calibration_mode = 0, temp;
+	int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
 	uint32_t calib_data[5];
 
 	for (i = 0; i < 5; i++)
 		calib_data[i] = readl_relaxed(tmdev->tsens_calib_addr
 					+ (i * TSENS_SN_ADDR_OFFSET));
 
-	tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1
-			>> TSENS_CAL_SEL_SHIFT);
-	temp = (calib_data[3] & TSENS_CAL_SEL_2
-			>> TSENS_CAL_SEL_SHIFT_2);
+	tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
+			>> TSENS_CAL_SEL_SHIFT;
+	temp = (calib_data[3] & TSENS_CAL_SEL_2)
+			>> TSENS_CAL_SEL_SHIFT_2;
 	tsens_calibration_mode |= temp;
 
-	if (!tsens_calibration_mode) {
+	if (tsens_calibration_mode == 0) {
 		pr_debug("TSENS is calibrationless mode\n");
 		for (i = 0; i < tmdev->tsens_num_sensor; i++) {
 			tmdev->sensor[i].calib_data_point2 = 780;
@@ -501,38 +524,58 @@
 		goto compute_intercept_slope;
 	} else if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
 				TSENS_TWO_POINT_CALIB) {
-		tsens_base1_data = calib_data[0] & TSENS_BASE1_MASK;
-		tsens0_point1 = calib_data[0] & TSENS0_POINT1_MASK;
-		tsens1_point1 = calib_data[0] & TSENS1_POINT1_MASK;
-		tsens2_point1 = calib_data[0] & TSENS2_POINT1_MASK;
-		tsens3_point1 = calib_data[0] & TSENS3_POINT1_MASK;
-		tsens4_point1 = calib_data[1] & TSENS4_POINT1_MASK;
-		tsens5_point1 = calib_data[1] & TSENS5_POINT1_MASK;
-		tsens6_point1 = calib_data[1] & TSENS6_POINT1_MASK;
-		tsens7_point1 = calib_data[1] & TSENS7_POINT1_MASK;
-		tsens8_point1 = calib_data[1] & TSENS8_POINT1_MASK;
-		tsens9_point1 = calib_data[2] & TSENS9_POINT1_MASK;
-		tsens10_point1 = calib_data[2] & TSENS10_POINT1_MASK;
+		tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
+		tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
+							TSENS0_POINT1_SHIFT;
+		tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
+							TSENS1_POINT1_SHIFT;
+		tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
+							TSENS2_POINT1_SHIFT;
+		tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
+							TSENS3_POINT1_SHIFT;
+		tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
+		tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
+							TSENS5_POINT1_SHIFT;
+		tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
+							TSENS6_POINT1_SHIFT;
+		tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
+							TSENS7_POINT1_SHIFT;
+		tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
+							TSENS8_POINT1_SHIFT;
+		tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
+		tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK) >>
+							TSENS10_POINT1_SHIFT;
 	} else if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
-		tsens_base2_data = calib_data[2] & TSENS_BASE2_MASK;
-		tsens0_point2 = calib_data[2] & TSENS0_POINT2_MASK;
-		tsens1_point2 = calib_data[2] & TSENS1_POINT2_MASK;
-		tsens2_point2 = calib_data[3] & TSENS2_POINT2_MASK;
-		tsens3_point2 = calib_data[3] & TSENS3_POINT2_MASK;
-		tsens4_point2 = calib_data[3] & TSENS4_POINT2_MASK;
-		tsens5_point2 = calib_data[3] & TSENS5_POINT2_MASK;
-		tsens6_point2 = calib_data[3] & TSENS6_POINT2_MASK;
-		tsens7_point2 = calib_data[4] & TSENS7_POINT2_MASK;
-		tsens8_point2 = calib_data[4] & TSENS8_POINT2_MASK;
-		tsens9_point2 = calib_data[4] & TSENS9_POINT2_MASK;
-		tsens10_point2 = calib_data[4] & TSENS10_POINT2_MASK;
+		tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
+						TSENS_POINT2_BASE_SHIFT;
+		tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
+						TSENS0_POINT2_SHIFT;
+		tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
+						TSENS1_POINT2_SHIFT;
+		tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
+		tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
+						TSENS3_POINT2_SHIFT;
+		tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
+						TSENS4_POINT2_SHIFT;
+		tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
+						TSENS5_POINT2_SHIFT;
+		tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
+						TSENS6_POINT2_SHIFT;
+		tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
+		tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
+						TSENS8_POINT2_SHIFT;
+		tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
+						TSENS9_POINT2_SHIFT;
+		tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK) >>
+						TSENS10_POINT2_SHIFT;
 	} else {
 		pr_debug("Calibration mode is unknown: %d\n",
 						tsens_calibration_mode);
 		return -ENODEV;
 	}
 
-	if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
+	if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
+					TSENS_TWO_POINT_CALIB) {
 		tmdev->sensor[0].calib_data_point1 =
 		(((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
 		tmdev->sensor[1].calib_data_point1 =
@@ -577,7 +620,7 @@
 		tmdev->sensor[8].calib_data_point2 =
 		(((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
 		tmdev->sensor[9].calib_data_point2 =
-		(((tsens_base2_data + tsens9_point2) < 2) | TSENS_BIT_APPEND);
+		(((tsens_base2_data + tsens9_point2) << 2) | TSENS_BIT_APPEND);
 		tmdev->sensor[10].calib_data_point2 =
 		(((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
 	}
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index ccbaa6d..3d29607 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -185,25 +185,19 @@
 	/* Should possibly check if this fails for the largest buffer we
 	   have queued and recycle that ? */
 }
-
 /**
- *	tty_buffer_request_room		-	grow tty buffer if needed
+ *	__tty_buffer_request_room		-	grow tty buffer if needed
  *	@tty: tty structure
  *	@size: size desired
  *
  *	Make at least size bytes of linear space available for the tty
  *	buffer. If we fail return the size we managed to find.
- *
- *	Locking: Takes tty->buf.lock
+ *      Locking: Caller must hold tty->buf.lock
  */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
 {
 	struct tty_buffer *b, *n;
 	int left;
-	unsigned long flags;
-
-	spin_lock_irqsave(&tty->buf.lock, flags);
-
 	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
 	   remove this conditional if its worth it. This would be invisible
 	   to the callers */
@@ -225,9 +219,30 @@
 			size = left;
 	}
 
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
 	return size;
 }
+
+
+/**
+ *	tty_buffer_request_room		-	grow tty buffer if needed
+ *	@tty: tty structure
+ *	@size: size desired
+ *
+ *	Make at least size bytes of linear space available for the tty
+ *	buffer. If we fail return the size we managed to find.
+ *
+ *	Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+	unsigned long flags;
+	int length;
+
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	length = __tty_buffer_request_room(tty, size);
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
+	return length;
+}
 EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 
 /**
@@ -249,14 +264,22 @@
 	int copied = 0;
 	do {
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-		int space = tty_buffer_request_room(tty, goal);
-		struct tty_buffer *tb = tty->buf.tail;
+		int space;
+		unsigned long flags;
+		struct tty_buffer *tb;
+
+		spin_lock_irqsave(&tty->buf.lock, flags);
+		space = __tty_buffer_request_room(tty, goal);
+		tb = tty->buf.tail;
 		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
+		if (unlikely(space == 0)) {
+			spin_unlock_irqrestore(&tty->buf.lock, flags);
 			break;
+		}
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memset(tb->flag_buf_ptr + tb->used, flag, space);
 		tb->used += space;
+		spin_unlock_irqrestore(&tty->buf.lock, flags);
 		copied += space;
 		chars += space;
 		/* There is a small chance that we need to split the data over
@@ -286,14 +309,22 @@
 	int copied = 0;
 	do {
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-		int space = tty_buffer_request_room(tty, goal);
-		struct tty_buffer *tb = tty->buf.tail;
+		int space;
+		unsigned long __flags;
+		struct tty_buffer *tb;
+
+		spin_lock_irqsave(&tty->buf.lock, __flags);
+		space = __tty_buffer_request_room(tty, goal);
+		tb = tty->buf.tail;
 		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
+		if (unlikely(space == 0)) {
+			spin_unlock_irqrestore(&tty->buf.lock, __flags);
 			break;
+		}
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memcpy(tb->flag_buf_ptr + tb->used, flags, space);
 		tb->used += space;
+		spin_unlock_irqrestore(&tty->buf.lock, __flags);
 		copied += space;
 		chars += space;
 		flags += space;
@@ -344,13 +375,20 @@
 int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
 								size_t size)
 {
-	int space = tty_buffer_request_room(tty, size);
+	int space;
+	unsigned long flags;
+	struct tty_buffer *tb;
+
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	space = __tty_buffer_request_room(tty, size);
+
+	tb = tty->buf.tail;
 	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
 		*chars = tb->char_buf_ptr + tb->used;
 		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
 		tb->used += space;
 	}
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
 	return space;
 }
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
@@ -374,13 +412,20 @@
 int tty_prepare_flip_string_flags(struct tty_struct *tty,
 			unsigned char **chars, char **flags, size_t size)
 {
-	int space = tty_buffer_request_room(tty, size);
+	int space;
+	unsigned long __flags;
+	struct tty_buffer *tb;
+
+	spin_lock_irqsave(&tty->buf.lock, __flags);
+	space = __tty_buffer_request_room(tty, size);
+
+	tb = tty->buf.tail;
 	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
 		*chars = tb->char_buf_ptr + tb->used;
 		*flags = tb->flag_buf_ptr + tb->used;
 		tb->used += space;
 	}
+	spin_unlock_irqrestore(&tty->buf.lock, __flags);
 	return space;
 }
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index c95f82d..de9a7aa 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -1121,15 +1121,4 @@
        help
 	  Data SMD channel for transferring network data
 
-config USB_ANDROID_RMNET_CTRL_SMD
-       boolean "RmNet(BAM) control over SMD driver"
-       depends on MSM_SMD
-       help
-         Enabling this option adds rmnet control over SMD
-	 support to the android gadget. Rmnet is an
-	 alternative to CDC-ECM and Windows RNDIS.
-	 It uses QUALCOMM MSM Interface for control
-	 transfers. This option enables only control interface.
-	 Data interface used is BAM.
-
 endif # USB_GADGET
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 465e512..eebda9e 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1465,12 +1465,26 @@
 	return ret;
 }
 
+static int msm_hsic_pm_suspend_noirq(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+
+	if (mehci->async_int) {
+		dev_dbg(dev, "suspend_noirq: Aborting due to pending interrupt\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
 static int msm_hsic_pm_resume(struct device *dev)
 {
 	int ret;
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 
+	dev_dbg(dev, "ehci-msm-hsic PM resume\n");
 	dbg_log_event(NULL, "PM Resume", 0);
 
 	if (device_may_wakeup(dev))
@@ -1524,6 +1538,7 @@
 #ifdef CONFIG_PM
 static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
+	.suspend_noirq = msm_hsic_pm_suspend_noirq,
 	SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
 				msm_hsic_runtime_idle)
 };
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 355990a..4217ba0 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -879,6 +879,8 @@
 
 	if (device_may_wakeup(phy->dev)) {
 		enable_irq_wake(motg->irq);
+		if (motg->async_irq)
+			enable_irq_wake(motg->async_irq);
 		if (motg->pdata->pmic_id_irq)
 			enable_irq_wake(motg->pdata->pmic_id_irq);
 		if (pdata->otg_control == OTG_PHY_CONTROL &&
@@ -889,6 +891,9 @@
 		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
 
 	atomic_set(&motg->in_lpm, 1);
+	/* Enable ASYNC IRQ (if present) during LPM */
+	if (motg->async_irq)
+		enable_irq(motg->async_irq);
 	enable_irq(motg->irq);
 	wake_unlock(&motg->wlock);
 
@@ -979,6 +984,8 @@
 skip_phy_resume:
 	if (device_may_wakeup(phy->dev)) {
 		disable_irq_wake(motg->irq);
+		if (motg->async_irq)
+			disable_irq_wake(motg->async_irq);
 		if (motg->pdata->pmic_id_irq)
 			disable_irq_wake(motg->pdata->pmic_id_irq);
 		if (pdata->otg_control == OTG_PHY_CONTROL &&
@@ -991,10 +998,15 @@
 	atomic_set(&motg->in_lpm, 0);
 
 	if (motg->async_int) {
+		/* Match the disable_irq call from ISR */
+		enable_irq(motg->async_int);
 		motg->async_int = 0;
-		enable_irq(motg->irq);
 	}
 
+	/* If ASYNC IRQ is present then keep it enabled only during LPM */
+	if (motg->async_irq)
+		disable_irq(motg->async_irq);
+
 	dev_info(phy->dev, "USB exited from low power mode\n");
 
 	return 0;
@@ -2728,9 +2740,9 @@
 	irqreturn_t ret = IRQ_HANDLED;
 
 	if (atomic_read(&motg->in_lpm)) {
-		pr_debug("OTG IRQ: in LPM\n");
+		pr_debug("OTG IRQ: %d in LPM\n", irq);
 		disable_irq_nosync(irq);
-		motg->async_int = 1;
+		motg->async_int = irq;
 		if (atomic_read(&motg->pm_suspended)) {
 			motg->sm_work_pending = true;
 			if ((otg->phy->state == OTG_STATE_A_SUSPEND) ||
@@ -3397,7 +3409,7 @@
 
 static int __init msm_otg_probe(struct platform_device *pdev)
 {
-	int ret = 0, disable_lpm = 0;
+	int ret = 0;
 	struct resource *res;
 	struct msm_otg *motg;
 	struct usb_phy *phy;
@@ -3415,8 +3427,6 @@
 			dev_err(&pdev->dev, "devices setup failed\n");
 			return ret;
 		}
-		/* LPM not supported on targets using DT */
-		disable_lpm = 1;
 	} else if (!pdev->dev.platform_data) {
 		dev_err(&pdev->dev, "No platform data given. Bailing out\n");
 		return -ENODEV;
@@ -3516,6 +3526,12 @@
 		goto free_regs;
 	}
 
+	motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
+	if (motg->async_irq < 0) {
+		dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
+		motg->async_irq = 0;
+	}
+
 	motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
 	if (IS_ERR(motg->xo_handle)) {
 		dev_err(&pdev->dev, "%s not able to get the handle "
@@ -3602,6 +3618,16 @@
 		goto destroy_wlock;
 	}
 
+	if (motg->async_irq) {
+		ret = request_irq(motg->async_irq, msm_otg_irq, IRQF_SHARED,
+							"msm_otg", motg);
+		if (ret) {
+			dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
+			goto free_irq;
+		}
+		disable_irq(motg->async_irq);
+	}
+
 	if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
 		msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
 
@@ -3620,7 +3646,7 @@
 	ret = usb_set_transceiver(&motg->phy);
 	if (ret) {
 		dev_err(&pdev->dev, "usb_set_transceiver failed\n");
-		goto free_irq;
+		goto free_async_irq;
 	}
 
 	if (motg->pdata->mode == USB_OTG &&
@@ -3672,8 +3698,7 @@
 
 	wake_lock(&motg->wlock);
 	pm_runtime_set_active(&pdev->dev);
-	if (!disable_lpm)
-		pm_runtime_enable(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
 
 	if (motg->pdata->bus_scale_table) {
 		motg->bus_perf_client =
@@ -3689,6 +3714,9 @@
 
 remove_phy:
 	usb_set_transceiver(NULL);
+free_async_irq:
+	if (motg->async_irq)
+		free_irq(motg->async_irq, motg);
 free_irq:
 	free_irq(motg->irq, motg);
 destroy_wlock:
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index f0a3639..89ae254 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -3218,6 +3218,7 @@
 
 	if (pipe->pipe_type == OVERLAY_TYPE_BF) {
 		mdp4_overlay_borderfill_stage_up(pipe);
+		mdp4_mixer_stage_commit(pipe->mixer_num);
 		return 0;
 	}
 
@@ -3583,7 +3584,7 @@
 		mdp4_overlay_reg_flush(pipe, 1);
 
 	mdp4_mixer_stage_up(pipe);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 #ifdef V4L2_VSYNC
 	/*
 	 * TODO: incorporate v4l2 into vsycn driven mechanism
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index 3fe00ed..c133831 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -116,7 +116,7 @@
 
 	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	if (ret == 0)
 		mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
@@ -187,7 +187,7 @@
 	mdp4_overlay_rgb_setup(pipe);
 	mdp4_overlay_reg_flush(pipe, 0);
 	mdp4_mixer_stage_up(pipe);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n",
 					(int)pipe, pipe->pipe_ndx);
 
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 05a89b8..36a6b2a 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -879,6 +879,7 @@
 
 	mdp4_overlay_dmap_cfg(mfd, 0);
 
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	/* MDP cmd block disable */
 	mdp_clk_ctrl(0);
 }
@@ -956,6 +957,7 @@
 
 	mdp4_overlay_dmap_cfg(mfd, 0);
 
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index a8b906a..40ffac4 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -553,8 +553,7 @@
 
 	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
-
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	/*
 	 * DSI timing setting
 	 */
@@ -774,6 +773,8 @@
 
 	mdp4_mixer_stage_up(pipe);
 
+	mdp4_mixer_stage_commit(pipe->mixer_num);
+
 	mb();
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index d22de54..128a3c6 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -724,7 +724,7 @@
 
 	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	vctrl->base_pipe = pipe; /* keep it */
 }
 
@@ -898,6 +898,7 @@
 	MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
 	mdp4_overlay_reg_flush(vctrl->base_pipe, 1);
 	mdp4_mixer_stage_up(vctrl->base_pipe);
+	mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index d10e669..e6ff9ef 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -243,7 +243,7 @@
 	mdp4_overlay_dmap_xy(pipe);
 
 	mdp4_overlay_dmap_cfg(mfd, 0);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	mdp4_mddi_vsync_enable(mfd, pipe, 0);
 
 	/* MDP cmd block disable */
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index d8e4be4..940aea8 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -184,7 +184,7 @@
 	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
-
+	mdp4_mixer_stage_commit(pipe->mixer_num);
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ee086ad..7efca07 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -276,9 +276,8 @@
 	if ((!mfd) || (mfd->key != MFD_KEY))
 		return 0;
 
-	/*
-	 * suspend this channel
-	 */
+	pr_debug("mdss_fb suspend index=%d\n", mfd->index);
+
 	mfd->suspend.op_enable = mfd->op_enable;
 	mfd->suspend.panel_power_on = mfd->panel_power_on;
 
@@ -295,7 +294,6 @@
 	return 0;
 }
 
-#if defined(CONFIG_PM)
 static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd)
 {
 	int ret = 0;
@@ -303,6 +301,8 @@
 	if ((!mfd) || (mfd->key != MFD_KEY))
 		return 0;
 
+	pr_debug("mdss_fb resume index=%d\n", mfd->index);
+
 	/* resume state var recover */
 	mfd->op_enable = mfd->suspend.op_enable;
 
@@ -316,59 +316,43 @@
 	return ret;
 }
 
-static int mdss_fb_suspend(struct platform_device *pdev, pm_message_t state)
+int mdss_fb_suspend_all(void)
 {
-	struct msm_fb_data_type *mfd;
-	int ret = 0;
-
-	pr_debug("mdss_fb_suspend\n");
-
-	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-
-	if ((!mfd) || (mfd->key != MFD_KEY))
-		return 0;
-
+	struct fb_info *fbi;
+	int ret, i;
+	int result = 0;
 	console_lock();
-	fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED);
+	for (i = 0; i < fbi_list_index; i++) {
+		fbi = fbi_list[i];
+		fb_set_suspend(fbi, FBINFO_STATE_SUSPENDED);
 
-	ret = mdss_fb_suspend_sub(mfd);
-	if (ret != 0) {
-		pr_err("failed to suspend! %d\n", ret);
-		fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
-	} else {
-		pdev->dev.power.power_state = state;
+		ret = mdss_fb_suspend_sub(fbi->par);
+		if (ret != 0) {
+			fb_set_suspend(fbi, FBINFO_STATE_RUNNING);
+			result = ret;
+		}
 	}
-
 	console_unlock();
-	return ret;
+	return result;
 }
 
-static int mdss_fb_resume(struct platform_device *pdev)
+int mdss_fb_resume_all(void)
 {
-	/* This resume function is called when interrupt is enabled.
-	 */
-	int ret = 0;
-	struct msm_fb_data_type *mfd;
-
-	pr_debug("mdss_fb_resume\n");
-
-	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-
-	if ((!mfd) || (mfd->key != MFD_KEY))
-		return 0;
+	struct fb_info *fbi;
+	int ret, i;
+	int result = 0;
 
 	console_lock();
-	ret = mdss_fb_resume_sub(mfd);
-	pdev->dev.power.power_state = PMSG_ON;
-	fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
-	console_unlock();
+	for (i = 0; i < fbi_list_index; i++) {
+		fbi = fbi_list[i];
 
-	return ret;
+		ret = mdss_fb_resume_sub(fbi->par);
+		if (ret == 0)
+			fb_set_suspend(fbi, FBINFO_STATE_RUNNING);
+	}
+	console_unlock();
+	return result;
 }
-#else
-#define mdss_fb_suspend NULL
-#define mdss_fb_resume NULL
-#endif
 
 #if defined(CONFIG_PM) && defined(CONFIG_SUSPEND)
 static int mdss_fb_ext_suspend(struct device *dev)
@@ -413,9 +397,6 @@
 static struct platform_driver mdss_fb_driver = {
 	.probe = mdss_fb_probe,
 	.remove = mdss_fb_remove,
-	.suspend = mdss_fb_suspend,
-	.resume = mdss_fb_resume,
-	.shutdown = NULL,
 	.driver = {
 		.name = "mdss_fb",
 		.pm = &mdss_fb_dev_pm_ops,
@@ -611,11 +592,27 @@
 	size *= mfd->fb_page;
 
 	if (mfd->index == 0) {
-		virt = dma_alloc_coherent(NULL, size, (dma_addr_t *) &phys,
-				GFP_KERNEL);
-		if (!virt) {
-			pr_err("unable to alloc fb memory size=%u\n", size);
-			return -ENOMEM;
+		struct ion_client *iclient = mfd->iclient;
+
+		if (iclient) {
+			mfd->ihdl = ion_alloc(iclient, size, SZ_4K,
+					 ION_HEAP(ION_CP_MM_HEAP_ID) |
+					 ION_HEAP(ION_SF_HEAP_ID));
+			if (IS_ERR_OR_NULL(mfd->ihdl)) {
+				pr_err("unable to alloc fbmem from ion (%p)\n",
+					mfd->ihdl);
+				return -ENOMEM;
+			}
+
+			virt = ion_map_kernel(iclient, mfd->ihdl, 0);
+			ion_phys(iclient, mfd->ihdl, &phys, &size);
+		} else {
+			virt = dma_alloc_coherent(NULL, size,
+					(dma_addr_t *) &phys, GFP_KERNEL);
+			if (!virt) {
+				pr_err("unable to alloc fbmem size=%u\n", size);
+				return -ENOMEM;
+			}
 		}
 
 		pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index ac6c213..3ea0ab3 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -75,6 +75,8 @@
 			   struct fb_cmap *cmap);
 	int (*do_histogram) (struct fb_info *info,
 			     struct mdp_histogram *hist);
+
+	struct ion_handle *ihdl;
 	void *cursor_buf;
 	void *cursor_buf_phys;
 
@@ -97,4 +99,6 @@
 int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
 void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
 void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
+int mdss_fb_suspend_all(void);
+int mdss_fb_resume_all(void);
 #endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 46e49da..c267a78 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -74,30 +74,18 @@
 	MDSS_MDP_MIXER_TYPE_WRITEBACK,
 };
 
-#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
-	{ \
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
+	{						\
 		.src = MSM_BUS_MASTER_MDP_PORT0,	\
 		.dst = MSM_BUS_SLAVE_EBI_CH0,		\
 		.ab = (ab_val),				\
 		.ib = (ib_val),				\
 	}
 
-#define MDP_BUS_VECTOR_ENTRY_NDX(n) \
-		MDP_BUS_VECTOR_ENTRY((n) * 100000000, (n) * 200000000)
-
 static struct msm_bus_vectors mdp_bus_vectors[] = {
-	MDP_BUS_VECTOR_ENTRY_NDX(0),
-	MDP_BUS_VECTOR_ENTRY_NDX(1),
-	MDP_BUS_VECTOR_ENTRY_NDX(2),
-	MDP_BUS_VECTOR_ENTRY_NDX(3),
-	MDP_BUS_VECTOR_ENTRY_NDX(4),
-	MDP_BUS_VECTOR_ENTRY_NDX(5),
-	MDP_BUS_VECTOR_ENTRY_NDX(6),
-	MDP_BUS_VECTOR_ENTRY_NDX(7),
-	MDP_BUS_VECTOR_ENTRY_NDX(8),
-	MDP_BUS_VECTOR_ENTRY_NDX(9),
-	MDP_BUS_VECTOR_ENTRY_NDX(10),
-	MDP_BUS_VECTOR_ENTRY(200000000, 200000000)
+	MDP_BUS_VECTOR_ENTRY(0, 0),
+	MDP_BUS_VECTOR_ENTRY(SZ_128M, SZ_256M),
+	MDP_BUS_VECTOR_ENTRY(SZ_256M, SZ_512M),
 };
 static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
 static struct msm_bus_scale_pdata mdp_bus_scale_table = {
@@ -270,34 +258,39 @@
 		msm_bus_scale_unregister_client(mdss_res->bus_hdl);
 }
 
-int mdss_mdp_bus_scale_set_min_quota(u32 quota)
+int mdss_mdp_bus_scale_set_quota(u32 ab_quota, u32 ib_quota)
 {
-	struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
-	struct msm_bus_vectors *vect = NULL;
-	int lvl;
+	static int current_bus_idx;
+	int bus_idx;
 
 	if (mdss_res->bus_hdl < 1) {
 		pr_err("invalid bus handle %d\n", mdss_res->bus_hdl);
 		return -EINVAL;
 	}
 
-	for (lvl = 0; lvl < bus_pdata->num_usecases; lvl++) {
-		if (bus_pdata->usecase[lvl].num_paths) {
-			vect = &bus_pdata->usecase[lvl].vectors[0];
-			if (vect->ab >= quota) {
-				pr_debug("lvl=%d quota=%u ab=%u\n", lvl, quota,
-						vect->ab);
-				break;
-			}
+	if ((ab_quota | ib_quota) == 0) {
+		bus_idx = 0;
+	} else {
+		int num_cases = mdp_bus_scale_table.num_usecases;
+		struct msm_bus_vectors *vect = NULL;
+
+		bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
+
+		vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
+		if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
+			pr_debug("skip bus scaling, no change in vectors\n");
+			return 0;
 		}
-	}
 
-	if (lvl == bus_pdata->num_usecases) {
-		pr_warn("cannot match quota=%u try with max level\n", quota);
-		lvl--;
-	}
+		vect = mdp_bus_scale_table.usecase[bus_idx].vectors;
+		vect->ab = ab_quota;
+		vect->ib = ib_quota;
 
-	return msm_bus_scale_client_update_request(mdss_res->bus_hdl, lvl);
+		pr_debug("bus scale idx=%d ab=%u ib=%u\n", bus_idx,
+				vect->ab, vect->ib);
+	}
+	current_bus_idx = bus_idx;
+	return msm_bus_scale_client_update_request(mdss_res->bus_hdl, bus_idx);
 }
 
 static inline u32 mdss_mdp_irq_mask(u32 intr_type, u32 intf_num)
@@ -427,6 +420,8 @@
 				pr_debug("mdp clk rate=%lu\n", clk_rate);
 		}
 		mutex_unlock(&mdp_clk_lock);
+	} else {
+		pr_err("mdp src clk not setup properly\n");
 	}
 }
 
@@ -466,7 +461,7 @@
 
 static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
 {
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
 }
 
 void mdss_mdp_clk_ctrl(int enable, int isr)
@@ -485,13 +480,19 @@
 	 */
 	WARN_ON(isr == true && enable);
 
-	if (enable) {
+	if (enable == MDP_BLOCK_POWER_ON) {
 		atomic_inc(&clk_ref);
 	} else if (!atomic_add_unless(&clk_ref, -1, 0)) {
-		pr_debug("master power-off req\n");
-		force_off = 1;
+		if (enable == MDP_BLOCK_MASTER_OFF) {
+			pr_debug("master power-off req\n");
+			force_off = 1;
+		} else {
+			WARN(1, "too many mdp clock off call\n");
+		}
 	}
 
+	WARN_ON(enable == MDP_BLOCK_MASTER_OFF && !force_off);
+
 	if (isr) {
 		/* if it's power off send workqueue to turn off clocks */
 		if (mdss_res->clk_ena && !atomic_read(&clk_ref))
@@ -561,6 +562,7 @@
 		goto error;
 	}
 	regulator_enable(mdss_res->fs);
+	mdss_res->fs_ena = true;
 
 	if (mdss_mdp_irq_clk_register(pdev, "bus_clk", MDSS_CLK_AXI) ||
 	    mdss_mdp_irq_clk_register(pdev, "iface_clk", MDSS_CLK_AHB) ||
@@ -736,7 +738,7 @@
 
 	flush_workqueue(mdss_res->clk_ctrl_wq);
 
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
 
 	mutex_lock(&mdp_suspend_mutex);
 	mdss_res->suspend = true;
@@ -745,24 +747,38 @@
 
 static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	if (pdev->id == 0) {
-		mdss_mdp_suspend_sub();
-		if (mdss_res->clk_ena) {
-			pr_err("MDP suspend failed\n");
-			return -EBUSY;
-		}
-		mdss_mdp_footswitch_ctrl(false);
+	int ret;
+	pr_debug("display suspend");
+
+	ret = mdss_fb_suspend_all();
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("Unable to suspend all fb panels (%d)\n", ret);
+		return ret;
 	}
+	mdss_mdp_suspend_sub();
+	if (mdss_res->clk_ena) {
+		pr_err("MDP suspend failed\n");
+		return -EBUSY;
+	}
+	mdss_mdp_footswitch_ctrl(false);
+
 	return 0;
 }
 
 static int mdss_mdp_resume(struct platform_device *pdev)
 {
+	int ret = 0;
+
+	pr_debug("resume display");
+
 	mdss_mdp_footswitch_ctrl(true);
 	mutex_lock(&mdp_suspend_mutex);
 	mdss_res->suspend = false;
 	mutex_unlock(&mdp_suspend_mutex);
-	return 0;
+	ret = mdss_fb_resume_all();
+	if (IS_ERR_VALUE(ret))
+		pr_err("Unable to resume all fb panels (%d)\n", ret);
+	return ret;
 }
 #else
 #define mdss_mdp_suspend NULL
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 4489fbb..776bf8b 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -61,8 +61,9 @@
 #endif
 
 enum mdss_mdp_block_power_state {
-	MDP_BLOCK_POWER_OFF,
-	MDP_BLOCK_POWER_ON
+	MDP_BLOCK_MASTER_OFF = -1,
+	MDP_BLOCK_POWER_OFF = 0,
+	MDP_BLOCK_POWER_ON = 1,
 };
 
 enum mdss_mdp_mixer_type {
@@ -118,7 +119,10 @@
 	u16 height;
 	u32 dst_format;
 
+	u32 bus_ab_quota;
+	u32 bus_ib_quota;
 	u32 bus_quota;
+	u32 clk_rate;
 
 	struct msm_fb_data_type *mfd;
 	struct mdss_mdp_mixer *mixer_left;
@@ -144,8 +148,6 @@
 	u8 cursor_enabled;
 	u8 rotator_mode;
 
-	u32 bus_quota;
-
 	struct mdss_mdp_ctl *ctl;
 	struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
 };
@@ -231,7 +233,6 @@
 	struct mdss_mdp_format_params *src_fmt;
 	struct mdss_mdp_plane_sizes src_planes;
 
-	u32 bus_quota;
 	u8 mixer_stage;
 	u8 is_fg;
 	u8 alpha;
@@ -273,7 +274,7 @@
 int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
 			       void (*fnc_ptr)(void *), void *arg);
 
-int mdss_mdp_bus_scale_set_min_quota(u32 quota);
+int mdss_mdp_bus_scale_set_quota(u32 ab_quota, u32 ib_quota);
 void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
 unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
 int mdss_mdp_vsync_clk_enable(int enable);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index c80527d..d29ecd6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -20,122 +20,177 @@
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 
+/* 1.10 bus fudge factor */
+#define MDSS_MDP_BUS_FUDGE_FACTOR(val) ALIGN((((val) * 11) / 10), SZ_16M)
+/* 1.25 clock fudge factor */
+#define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
+
 enum {
-	MDSS_MDP_BUS_UPDATE_SKIP,
-	MDSS_MDP_BUS_UPDATE_EARLY,
-	MDSS_MDP_BUS_UPDATE_LATE,
+	MDSS_MDP_PERF_UPDATE_SKIP,
+	MDSS_MDP_PERF_UPDATE_EARLY,
+	MDSS_MDP_PERF_UPDATE_LATE,
 };
 
+#define MDSS_MDP_PERF_UPDATE_CLK BIT(0)
+#define MDSS_MDP_PERF_UPDATE_BUS BIT(1)
+#define MDSS_MDP_PERF_UPDATE_ALL -1
+
 static DEFINE_MUTEX(mdss_mdp_ctl_lock);
 static struct mdss_mdp_ctl mdss_mdp_ctl_list[MDSS_MDP_MAX_CTL];
 static struct mdss_mdp_mixer mdss_mdp_mixer_list[MDSS_MDP_MAX_LAYERMIXER];
 
-static int mdss_mdp_ctl_update_clk_rate(void)
+static int mdss_mdp_ctl_perf_commit(u32 flags)
 {
 	struct mdss_mdp_ctl *ctl;
 	int cnum;
-	unsigned long clk_rate = MDP_CLK_DEFAULT_RATE;
+	unsigned long clk_rate = 0;
+	u32 bus_ab_quota = 0, bus_ib_quota = 0;
+
+	if (!flags) {
+		pr_err("nothing to update\n");
+		return -EINVAL;
+	}
 
 	mutex_lock(&mdss_mdp_ctl_lock);
 	for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
 		ctl = &mdss_mdp_ctl_list[cnum];
-		if (ctl->power_on && ctl->mfd) {
-			unsigned long tmp;
-			pr_debug("ctl=%d pclk_rate=%u\n", ctl->num,
-					ctl->mfd->panel_info.clk_rate);
-			tmp = (ctl->mfd->panel_info.clk_rate * 23) / 20;
-			if (tmp > clk_rate)
-				clk_rate = tmp;
+		if (ctl->power_on) {
+			bus_ab_quota += ctl->bus_ab_quota;
+			bus_ib_quota += ctl->bus_ib_quota;
+
+			if (ctl->clk_rate > clk_rate)
+				clk_rate = ctl->clk_rate;
 		}
 	}
-	mdss_mdp_set_clk_rate(clk_rate);
-	mutex_unlock(&mdss_mdp_ctl_lock);
-
-	return 0;
-}
-
-static int mdss_mdp_ctl_update_bus_scale(void)
-{
-	struct mdss_mdp_ctl *ctl;
-	int cnum;
-	u32 bus_quota = 0;
-
-	mutex_lock(&mdss_mdp_ctl_lock);
-	for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
-		ctl = &mdss_mdp_ctl_list[cnum];
-		if (ctl->power_on)
-			bus_quota += ctl->bus_quota;
+	if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
+		bus_ab_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ab_quota);
+		bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ib_quota);
+		mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
 	}
-	mdss_mdp_bus_scale_set_min_quota(bus_quota);
+	if (flags & MDSS_MDP_PERF_UPDATE_CLK) {
+		clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(clk_rate);
+		pr_debug("update clk rate = %lu\n", clk_rate);
+		mdss_mdp_set_clk_rate(clk_rate);
+	}
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return 0;
 }
 
-static void mdss_mdp_bus_update_pipe_quota(struct mdss_mdp_pipe *pipe)
-{
-	u32 quota;
-
-	quota = pipe->img_width * pipe->img_height * 60 * pipe->src_fmt->bpp;
-	quota *= 5 / 4; /* 1.25 factor */
-
-	pr_debug("pipe=%d quota old=%u new=%u\n", pipe->num,
-		   pipe->bus_quota, quota);
-	pipe->bus_quota = quota;
-}
-
-static int mdss_mdp_bus_update_mixer_quota(struct mdss_mdp_mixer *mixer)
+static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer,
+				       u32 *bus_ab_quota, u32 *bus_ib_quota,
+				       u32 *clk_rate)
 {
 	struct mdss_mdp_pipe *pipe;
-	u32 quota, stage;
+	const int fps = 60;
+	u32 quota, rate;
+	u32 v_total, v_active;
+	int i;
 
-	if (!mixer)
-		return 0;
+	*bus_ab_quota = 0;
+	*bus_ib_quota = 0;
+	*clk_rate = 0;
 
-	quota = 0;
-	for (stage = 0; stage < MDSS_MDP_MAX_STAGE; stage++) {
-		pipe = mixer->stage_pipe[stage];
+	if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+		struct mdss_panel_info *pinfo = &mixer->ctl->mfd->panel_info;
+		v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
+			pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width);
+		v_active = pinfo->yres;
+	} else if (mixer->rotator_mode) {
+		pipe = mixer->stage_pipe[0]; /* rotator pipe */
+		v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
+		v_active = v_total;
+	} else {
+		v_total = mixer->height;
+		v_active = v_total;
+	}
+
+	for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
+		u32 ib_quota;
+		pipe = mixer->stage_pipe[i];
 		if (pipe == NULL)
 			continue;
 
-		quota += pipe->bus_quota;
+		quota = fps * pipe->src.w * pipe->src.h;
+		if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
+			quota = (quota * 3) / 2;
+		else
+			quota *= pipe->src_fmt->bpp;
+
+		if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+			quota = (quota / v_active) * v_total;
+		else
+			quota *= 2; /* bus read + write */
+
+		rate = pipe->dst.w;
+		if (pipe->src.h > pipe->dst.h) {
+			rate = (rate * pipe->src.h) / pipe->dst.h;
+			ib_quota = (quota / pipe->dst.h) * pipe->src.h;
+		} else {
+			ib_quota = quota;
+		}
+		rate *= v_total * fps;
+		if (mixer->rotator_mode)
+			rate /= 4; /* block mode fetch at 4 pix/clk */
+
+		*bus_ab_quota += quota;
+		*bus_ib_quota += ib_quota;
+		if (rate > *clk_rate)
+			*clk_rate = rate;
+
+		pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
+			 mixer->num, pipe->num, rate, quota, ib_quota);
 	}
 
-	pr_debug("mixer=%d quota old=%u new=%u\n", mixer->num,
-		   mixer->bus_quota, quota);
-
-	if (quota != mixer->bus_quota) {
-		mixer->bus_quota = quota;
-		return 1;
-	}
-
-	return 0;
+	pr_debug("final mixer=%d clk_rate=%u bus ab=%u ib=%u\n", mixer->num,
+		 *clk_rate, *bus_ab_quota, *bus_ib_quota);
 }
 
-static int mdss_mdp_bus_update_ctl_quota(struct mdss_mdp_ctl *ctl)
+static int mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, u32 *flags)
 {
-	int ret = MDSS_MDP_BUS_UPDATE_SKIP;
+	int ret = MDSS_MDP_PERF_UPDATE_SKIP;
+	u32 clk_rate, ab_quota, ib_quota;
+	u32 max_clk_rate = 0, total_ab_quota = 0, total_ib_quota = 0;
 
-	if (mdss_mdp_bus_update_mixer_quota(ctl->mixer_left) ||
-			mdss_mdp_bus_update_mixer_quota(ctl->mixer_right)) {
-		u32 quota = 0;
+	if (ctl->mixer_left) {
+		mdss_mdp_perf_mixer_update(ctl->mixer_left, &ab_quota,
+					   &ib_quota, &clk_rate);
+		total_ab_quota += ab_quota;
+		total_ib_quota += ib_quota;
+		max_clk_rate = clk_rate;
+	}
 
-		if (ctl->mixer_left)
-			quota += ctl->mixer_left->bus_quota;
-		if (ctl->mixer_right)
-			quota += ctl->mixer_right->bus_quota;
+	if (ctl->mixer_right) {
+		mdss_mdp_perf_mixer_update(ctl->mixer_right, &ab_quota,
+					   &ib_quota, &clk_rate);
+		total_ab_quota += ab_quota;
+		total_ib_quota += ib_quota;
+		if (clk_rate > max_clk_rate)
+			max_clk_rate = clk_rate;
+	}
 
-		pr_debug("ctl=%d quota old=%u new=%u\n",
-			   ctl->num, ctl->bus_quota, quota);
+	*flags = 0;
 
-		if (quota != ctl->bus_quota) {
-			if (quota > ctl->bus_quota)
-				ret = MDSS_MDP_BUS_UPDATE_EARLY;
+	if (max_clk_rate != ctl->clk_rate) {
+		if (max_clk_rate > ctl->clk_rate)
+			ret = MDSS_MDP_PERF_UPDATE_EARLY;
+		else
+			ret = MDSS_MDP_PERF_UPDATE_LATE;
+		ctl->clk_rate = max_clk_rate;
+		*flags |= MDSS_MDP_PERF_UPDATE_CLK;
+	}
+
+	if ((total_ab_quota != ctl->bus_ab_quota) ||
+			(total_ib_quota != ctl->bus_ib_quota)) {
+		if (ret == MDSS_MDP_PERF_UPDATE_SKIP) {
+			if (total_ib_quota > ctl->bus_ib_quota)
+				ret = MDSS_MDP_PERF_UPDATE_EARLY;
 			else
-				ret = MDSS_MDP_BUS_UPDATE_LATE;
-
-			ctl->bus_quota = quota;
+				ret = MDSS_MDP_PERF_UPDATE_LATE;
 		}
+		ctl->bus_ab_quota = total_ab_quota;
+		ctl->bus_ib_quota = total_ib_quota;
+		*flags |= MDSS_MDP_PERF_UPDATE_BUS;
 	}
 
 	return ret;
@@ -261,6 +316,7 @@
 	mixer->ctl = ctl;
 
 	ctl->start_fnc = mdss_mdp_writeback_start;
+	ctl->power_on = true;
 
 	if (ctl->start_fnc)
 		ctl->start_fnc(ctl);
@@ -442,7 +498,6 @@
 	mutex_lock(&ctl->lock);
 
 	ctl->power_on = true;
-	mdss_mdp_ctl_update_clk_rate();
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (ctl->start_fnc)
@@ -531,8 +586,7 @@
 
 	ctl->play_cnt = 0;
 
-	mdss_mdp_ctl_update_bus_scale();
-	mdss_mdp_ctl_update_clk_rate();
+	mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
 
 	mutex_unlock(&ctl->lock);
 
@@ -705,7 +759,6 @@
 	if (params_changed) {
 		mixer->params_changed++;
 		mixer->stage_pipe[pipe->mixer_stage] = pipe;
-		mdss_mdp_bus_update_pipe_quota(pipe);
 	}
 
 	if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
@@ -764,14 +817,18 @@
 {
 	int mixer1_changed, mixer2_changed;
 	int ret = 0;
-	int bus_update = MDSS_MDP_BUS_UPDATE_SKIP;
+	int perf_update = MDSS_MDP_PERF_UPDATE_SKIP;
+	u32 update_flags = 0;
 
 	if (!ctl) {
 		pr_err("display function not set\n");
 		return -ENODEV;
 	}
 
-	pr_debug("commit ctl=%d\n", ctl->num);
+	if (!ctl->power_on)
+		return 0;
+
+	pr_debug("commit ctl=%d play_cnt=%d\n", ctl->num, ctl->play_cnt);
 
 	if (mutex_lock_interruptible(&ctl->lock))
 		return -EINTR;
@@ -781,7 +838,7 @@
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (mixer1_changed || mixer2_changed) {
-		bus_update = mdss_mdp_bus_update_ctl_quota(ctl);
+		perf_update = mdss_mdp_ctl_perf_update(ctl, &update_flags);
 
 		if (ctl->prepare_fnc)
 			ret = ctl->prepare_fnc(ctl, arg);
@@ -790,8 +847,8 @@
 			goto done;
 		}
 
-		if (bus_update == MDSS_MDP_BUS_UPDATE_EARLY)
-			mdss_mdp_ctl_update_bus_scale();
+		if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY)
+			mdss_mdp_ctl_perf_commit(update_flags);
 
 		if (mixer1_changed)
 			mdss_mdp_mixer_update(ctl->mixer_left);
@@ -813,8 +870,8 @@
 
 	ctl->play_cnt++;
 
-	if (bus_update == MDSS_MDP_BUS_UPDATE_LATE)
-		mdss_mdp_ctl_update_bus_scale();
+	if (perf_update == MDSS_MDP_PERF_UPDATE_LATE)
+		mdss_mdp_ctl_perf_commit(update_flags);
 
 done:
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index d9a148e..9a8260f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -630,7 +630,8 @@
 		return -ENODEV;
 	}
 
-	pr_debug("pnum=%x mixer=%d\n", pipe->num, pipe->mixer->num);
+	pr_debug("pnum=%x mixer=%d play_cnt=%u\n", pipe->num,
+		 pipe->mixer->num, pipe->play_cnt);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
diff --git a/include/asm-generic/dma-coherent.h b/include/asm-generic/dma-coherent.h
index 85a3ffa..abfb268 100644
--- a/include/asm-generic/dma-coherent.h
+++ b/include/asm-generic/dma-coherent.h
@@ -3,13 +3,15 @@
 
 #ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
 /*
- * These two functions are only for dma allocator.
+ * These three functions are only for dma allocator.
  * Don't use them in device drivers.
  */
 int dma_alloc_from_coherent(struct device *dev, ssize_t size,
 				       dma_addr_t *dma_handle, void **ret);
 int dma_release_from_coherent(struct device *dev, int order, void *vaddr);
 
+int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
+			    void *cpu_addr, size_t size, int *ret);
 /*
  * Standard interface
  */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 277fdf1..31a152d 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -427,6 +427,7 @@
 header-y += msm_vidc_enc.h
 header-y += msm_audio.h
 header-y += msm_audio_aac.h
+header-y += msm_audio_ac3.h
 header-y += msm_audio_acdb.h
 header-y += android_pmem.h
 header-y += msm_audio_wma.h
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index d1438d1..a73a284 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -133,6 +133,7 @@
 	int				shutdown_soc_valid_limit;
 	int				ignore_shutdown_soc;
 	int				adjust_soc_low_threshold;
+	int				chg_term_ua;
 };
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/msm_audio_ac3.h b/include/linux/msm_audio_ac3.h
new file mode 100644
index 0000000..fc50c30
--- /dev/null
+++ b/include/linux/msm_audio_ac3.h
@@ -0,0 +1,41 @@
+#ifndef __MSM_AUDIO_AC3_H
+#define __MSM_AUDIO_AC3_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_SET_AC3_CONFIG  _IOW(AUDIO_IOCTL_MAGIC, \
+	(AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned)
+#define AUDIO_GET_AC3_CONFIG  _IOR(AUDIO_IOCTL_MAGIC, \
+	(AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned)
+
+#define AUDAC3_DEF_WORDSIZE 0
+#define AUDAC3_DEF_USER_DOWNMIX_FLAG 0x0
+#define AUDAC3_DEF_USER_KARAOKE_FLAG 0x0
+#define AUDAC3_DEF_ERROR_CONCEALMENT 0
+#define AUDAC3_DEF_MAX_REPEAT_COUNT  0
+
+struct msm_audio_ac3_config {
+	unsigned short		numChans;
+	unsigned short		wordSize;
+	unsigned short		kCapableMode;
+	unsigned short		compMode;
+	unsigned short		outLfeOn;
+	unsigned short		outputMode;
+	unsigned short		stereoMode;
+	unsigned short		dualMonoMode;
+	unsigned short		fsCod;
+	unsigned short		pcmScaleFac;
+	unsigned short		dynRngScaleHi;
+	unsigned short		dynRngScaleLow;
+	unsigned short		user_downmix_flag;
+	unsigned short		user_karaoke_flag;
+	unsigned short		dm_address_high;
+	unsigned short		dm_address_low;
+	unsigned short		ko_address_high;
+	unsigned short		ko_address_low;
+	unsigned short		error_concealment;
+	unsigned short		max_rep_count;
+	unsigned short		channel_routing_mode[6];
+};
+
+#endif /* __MSM_AUDIO_AC3_H */
diff --git a/include/linux/qpnp/clkdiv.h b/include/linux/qpnp/clkdiv.h
new file mode 100644
index 0000000..c75a922
--- /dev/null
+++ b/include/linux/qpnp/clkdiv.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef QPNP_CLKDIV_H
+#define QPNP_CLKDIV_H
+
+enum q_clkdiv_cfg {
+	Q_CLKDIV_NO_CLK = 0,
+	Q_CLKDIV_XO_DIV_1,
+	Q_CLKDIV_XO_DIV_2,
+	Q_CLKDIV_XO_DIV_4,
+	Q_CLKDIV_XO_DIV_8,
+	Q_CLKDIV_XO_DIV_16,
+	Q_CLKDIV_XO_DIV_32,
+	Q_CLKDIV_XO_DIV_64,
+	Q_CLKDIV_INVALID,
+};
+
+struct q_clkdiv;
+
+struct q_clkdiv *qpnp_clkdiv_get(struct device *dev, const char *name);
+int qpnp_clkdiv_enable(struct q_clkdiv *q_clkdiv);
+int qpnp_clkdiv_disable(struct q_clkdiv *q_clkdiv);
+int qpnp_clkdiv_config(struct q_clkdiv *q_clkdiv,
+				enum q_clkdiv_cfg cfg);
+#endif
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index e731f97..ffa542f 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -268,6 +268,7 @@
  * @otg: USB OTG Transceiver structure.
  * @pdata: otg device platform data.
  * @irq: IRQ number assigned for HSUSB controller.
+ * @async_irq: IRQ number used by some controllers during low power state
  * @clk: clock struct of alt_core_clk.
  * @pclk: clock struct of iface_clk.
  * @phy_reset_clk: clock struct of phy_clk.
@@ -276,7 +277,7 @@
  * @inputs: OTG state machine inputs(Id, SessValid etc).
  * @sm_work: OTG state machine work.
  * @in_lpm: indicates low power mode (LPM) state.
- * @async_int: Async interrupt arrived.
+ * @async_int: IRQ line on which ASYNC interrupt arrived in LPM.
  * @cur_power: The amount of mA available from downstream port.
  * @chg_work: Charger detection work.
  * @chg_state: The state of charger detection process.
@@ -298,6 +299,7 @@
 	struct usb_phy phy;
 	struct msm_otg_platform_data *pdata;
 	int irq;
+	int async_irq;
 	struct clk *clk;
 	struct clk *pclk;
 	struct clk *phy_reset_clk;
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index baa6a28..2efe31c 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -44,6 +44,7 @@
 int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
 int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
 int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec);
+int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc);
 int msm_vidc_poll(void *instance, struct file *filp,
 		struct poll_table_struct *pt);
 #endif
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index a15d1f1..2918b94 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -289,6 +289,7 @@
 	atomic_t			queued_count;
 	struct list_head		done_list;
 	spinlock_t			done_lock;
+	struct mutex		q_lock;
 	wait_queue_head_t		done_wq;
 
 	void				*alloc_ctx[VIDEO_MAX_PLANES];
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 979db58..b7ddb08 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -561,6 +561,7 @@
 #define ADM_CMD_COPP_CLOSE                               0x00010305
 
 #define ADM_CMD_MULTI_CHANNEL_COPP_OPEN                  0x00010310
+#define ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3               0x00010333
 struct adm_multi_ch_copp_open_command {
 	struct apr_hdr hdr;
 	u16 flags;
@@ -573,7 +574,6 @@
 	u32 rate;
 	u8 dev_channel_mapping[8];
 } __packed;
-
 #define ADM_CMD_MEMORY_MAP				0x00010C30
 struct adm_cmd_memory_map{
 	struct apr_hdr	hdr;
@@ -618,6 +618,14 @@
 #define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY			0x00010F72
 #define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY		0x00010F75
 
+#define LOWLATENCY_POPP_TOPOLOGY			0x00010C68
+#define LOWLATENCY_COPP_TOPOLOGY			0x00010312
+#define PCM_BITS_PER_SAMPLE				16
+
+#define ASM_OPEN_WRITE_PERF_MODE_BIT			(1<<28)
+#define ASM_OPEN_READ_PERF_MODE_BIT			(1<<29)
+#define ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT		(1<<13)
+
 /* SRS TRUMEDIA GUIDS */
 /* topology */
 #define SRS_TRUMEDIA_TOPOLOGY_ID			0x00010D90
@@ -741,6 +749,7 @@
 } __attribute__ ((packed));
 
 #define ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN               0x00010311
+#define ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3            0x00010334
 
 
 #define ASM_STREAM_PRIORITY_NORMAL	0
@@ -1102,6 +1111,7 @@
 
 /* Stream level commands */
 #define ASM_STREAM_CMD_OPEN_READ                         0x00010BCB
+#define ASM_STREAM_CMD_OPEN_READ_V2_1                    0x00010DB2
 struct asm_stream_cmd_open_read {
 	struct apr_hdr hdr;
 	u32            uMode;
@@ -1110,6 +1120,16 @@
 	u32            format;
 } __attribute__((packed));
 
+struct asm_stream_cmd_open_read_v2_1 {
+	struct apr_hdr hdr;
+	u32            uMode;
+	u32            src_endpoint;
+	u32            pre_proc_top;
+	u32            format;
+	u16            bits_per_sample;
+	u16            reserved;
+} __packed;
+
 /* Supported formats */
 #define LINEAR_PCM   0x00010BE5
 #define DTMF         0x00010BE6
@@ -1158,6 +1178,7 @@
 } __packed;
 
 #define ASM_STREAM_CMD_OPEN_WRITE                        0x00010BCA
+#define ASM_STREAM_CMD_OPEN_WRITE_V2_1                   0x00010DB1
 struct asm_stream_cmd_open_write {
 	struct apr_hdr hdr;
 	u32            uMode;
diff --git a/include/sound/q6adm.h b/include/sound/q6adm.h
index 8e15955..676c4cb 100644
--- a/include/sound/q6adm.h
+++ b/include/sound/q6adm.h
@@ -27,7 +27,7 @@
 int adm_open(int port, int path, int rate, int mode, int topology);
 
 int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
-				int topology);
+				int topology, int perfmode);
 
 int adm_memory_map_regions(uint32_t *buf_add, uint32_t mempool_id,
 				uint32_t *bufsz, uint32_t bufcnt);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index ea77974..01f2fac 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -160,6 +160,7 @@
 	uint32_t         io_mode;
 	uint64_t         time_stamp;
 	atomic_t         cmd_response;
+	bool             perf_mode;
 };
 
 void q6asm_audio_client_free(struct audio_client *ac);
@@ -182,6 +183,7 @@
 			struct audio_client *ac);
 
 int q6asm_open_read(struct audio_client *ac, uint32_t format);
+int q6asm_open_read_v2_1(struct audio_client *ac, uint32_t format);
 
 int q6asm_open_read_compressed(struct audio_client *ac,
 			 uint32_t frames_per_buffer, uint32_t meta_data_mode);
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 5c5ee30..32565bc 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -38,6 +38,8 @@
 
 #define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
 			SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
+#define ADC_DMIC_SEL_ADC	0
+#define	ADC_DMIC_SEL_DMIC	1
 
 #define NUM_DECIMATORS 4
 #define NUM_INTERPOLATORS 3
@@ -812,17 +814,106 @@
 static const struct snd_kcontrol_new sb_tx1_mux =
 	SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
 
+static int wcd9304_put_dec_enum(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+	{
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
+	struct snd_soc_codec *codec = w->codec;
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int dec_mux, decimator;
+	char *dec_name = NULL;
+	char *widget_name = NULL;
+	char *temp;
+	u16 tx_mux_ctl_reg;
+	u8 adc_dmic_sel = 0x0;
+	int ret = 0;
+
+	if (ucontrol->value.enumerated.item[0] > e->max - 1)
+		return -EINVAL;
+
+	dec_mux = ucontrol->value.enumerated.item[0];
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+	temp = widget_name;
+
+	dec_name = strsep(&widget_name, " ");
+	widget_name = temp;
+	if (!dec_name) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
+	if (ret < 0) {
+		pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"\
+		"dec_mux = %u\n", __func__, w->name, dec_name, decimator,
+		dec_mux);
+
+
+	switch (decimator) {
+	case 1:
+	case 2:
+		if ((dec_mux == 1) || (dec_mux == 6))
+			adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+		else
+			adc_dmic_sel = ADC_DMIC_SEL_ADC;
+		break;
+	case 3:
+		if ((dec_mux == 1) || (dec_mux == 6) || (dec_mux == 7))
+			adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+		else
+			adc_dmic_sel = ADC_DMIC_SEL_ADC;
+		break;
+	case 4:
+		if ((dec_mux == 1) || (dec_mux == 5)
+			|| (dec_mux == 6) || (dec_mux == 7))
+			adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+		else
+			adc_dmic_sel = ADC_DMIC_SEL_ADC;
+		break;
+	default:
+		pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
+
+	snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
+
+	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+out:
+	kfree(widget_name);
+	return ret;
+}
+
+#define WCD9304_DEC_ENUM(xname, xenum) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_enum_double, \
+	.get = snd_soc_dapm_get_enum_double, \
+	.put = wcd9304_put_dec_enum, \
+	.private_value = (unsigned long)&xenum }
+
 static const struct snd_kcontrol_new dec1_mux =
-	SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+	WCD9304_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
 
 static const struct snd_kcontrol_new dec2_mux =
-	SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+	WCD9304_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
 
 static const struct snd_kcontrol_new dec3_mux =
-	SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+	WCD9304_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
 
 static const struct snd_kcontrol_new dec4_mux =
-	SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+	WCD9304_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
 
 static const struct snd_kcontrol_new iir1_inp1_mux =
 	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
@@ -970,7 +1061,7 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
-	u16 tx_dmic_ctl_reg, tx_mux_ctl_reg;
+	u16 tx_dmic_ctl_reg;
 	u8 dmic_clk_sel, dmic_clk_en;
 	unsigned int dmic;
 	int ret;
@@ -1000,15 +1091,12 @@
 		return -EINVAL;
 	}
 
-	tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
 	tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
 
 	pr_debug("%s %d\n", __func__, event);
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x01);
-
 		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
 				dmic_clk_sel, dmic_clk_sel);
 
@@ -1020,8 +1108,6 @@
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
 				dmic_clk_en, 0);
-
-		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x00);
 		break;
 	}
 	return 0;
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 43c678d..390c314 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -56,7 +56,7 @@
 
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
 
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
 obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
 obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o
 snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 81bde3f..2959fe0 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -1678,6 +1678,37 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{
+		.name = "VoLTE",
+		.stream_name = "VoLTE",
+		.cpu_dai_name   = "VoLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOLTE,
+	},
+	{
+		.name = "MSM8960 LowLatency",
+		.stream_name = "MultiMedia5",
+		.cpu_dai_name   = "MultiMedia5",
+		.platform_name  = "msm-lowlatency-pcm-dsp",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+	},
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 35cbb5b..1dbd698 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -548,6 +548,7 @@
 	}
 	prtd = &compr->prtd;
 	prtd->substream = substream;
+	prtd->audio_client->perf_mode = false;
 	prtd->audio_client = q6asm_audio_client_alloc(
 				(app_cb)compr_event_handler, compr);
 	if (!prtd->audio_client) {
@@ -768,7 +769,9 @@
 			}
 			msm_pcm_routing_reg_phy_stream(
 				soc_prtd->dai_link->be_id,
-				prtd->session_id, substream->stream);
+				prtd->audio_client->perf_mode,
+				prtd->session_id,
+				substream->stream);
 
 			break;
 		}
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 4cd4a2c..011ff29 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -203,6 +203,17 @@
 			.rate_min =	8000,
 			.rate_max = 48000,
 		},
+		.capture = {
+			.stream_name = "MultiMedia5 Capture",
+			.aif_name = "MM_UL5",
+			.rates = (SNDRV_PCM_RATE_8000_48000|
+					SNDRV_PCM_RATE_KNOT),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 8,
+			.rate_min =     8000,
+			.rate_max =	48000,
+		},
 		.ops = &msm_fe_Multimedia_dai_ops,
 		.name = "MultiMedia5",
 	},
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
new file mode 100644
index 0000000..129f69f
--- /dev/null
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -0,0 +1,756 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#include "msm-pcm-q6.h"
+#include "msm-pcm-routing.h"
+
+static struct audio_locks the_locks;
+
+struct snd_msm {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+};
+
+struct snd_msm_volume {
+	struct msm_audio *prtd;
+	unsigned volume;
+};
+
+#define PLAYBACK_NUM_PERIODS		4
+#define PLAYBACK_MAX_PERIOD_SIZE	1024
+#define PLAYBACK_MIN_PERIOD_SIZE	512
+#define CAPTURE_NUM_PERIODS		4
+#define CAPTURE_MIN_PERIOD_SIZE		128
+#define CAPTURE_MAX_PERIOD_SIZE		1024
+
+static struct snd_pcm_hardware msm_pcm_hardware_capture = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         8,
+	.buffer_bytes_max =     CAPTURE_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
+	.period_bytes_min =	CAPTURE_MIN_PERIOD_SIZE,
+	.period_bytes_max =     CAPTURE_MAX_PERIOD_SIZE,
+	.periods_min =          CAPTURE_NUM_PERIODS,
+	.periods_max =          CAPTURE_NUM_PERIODS,
+	.fifo_size =            0,
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware_playback = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				SNDRV_PCM_INFO_MMAP_VALID |
+				SNDRV_PCM_INFO_INTERLEAVED |
+				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =                SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
+	.rate_min =             8000,
+	.rate_max =             48000,
+	.channels_min =         1,
+	.channels_max =         6,
+	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+	.period_bytes_min =     PLAYBACK_MIN_PERIOD_SIZE,
+	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
+	.periods_min =          PLAYBACK_NUM_PERIODS,
+	.periods_max =          PLAYBACK_NUM_PERIODS,
+	.fifo_size =            0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+	.count = ARRAY_SIZE(supported_sample_rates),
+	.list = supported_sample_rates,
+	.mask = 0,
+};
+
+static void event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+	struct msm_audio *prtd = priv;
+	struct snd_pcm_substream *substream = prtd->substream;
+	uint32_t *ptrmem = (uint32_t *)payload;
+	int i = 0;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	pr_debug("%s\n", __func__);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE: {
+		pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+		prtd->pcm_irq_pos += prtd->pcm_count;
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		atomic_inc(&prtd->out_count);
+		wake_up(&the_locks.write_wait);
+		if (!atomic_read(&prtd->start))
+			break;
+		if (!prtd->mmap_flag)
+			break;
+		if (q6asm_is_cpu_buf_avail_nolock(IN,
+				prtd->audio_client,
+				&size, &idx)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+					__func__, prtd->pcm_count);
+			q6asm_write_nolock(prtd->audio_client,
+				prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+		}
+		break;
+	}
+	case ASM_DATA_CMDRSP_EOS:
+		pr_debug("ASM_DATA_CMDRSP_EOS\n");
+		prtd->cmd_ack = 1;
+		wake_up(&the_locks.eos_wait);
+		break;
+	case ASM_DATA_EVENT_READ_DONE: {
+		pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+		pr_debug("token = 0x%08x\n", token);
+		for (i = 0; i < 8; i++, ++ptrmem)
+			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+		in_frame_info[token][0] = payload[2];
+		in_frame_info[token][1] = payload[3];
+		prtd->pcm_irq_pos += in_frame_info[token][0];
+		pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+		if (atomic_read(&prtd->start))
+			snd_pcm_period_elapsed(substream);
+		if (atomic_read(&prtd->in_count) <= prtd->periods)
+			atomic_inc(&prtd->in_count);
+		wake_up(&the_locks.read_wait);
+		if (prtd->mmap_flag
+			&& q6asm_is_cpu_buf_avail_nolock(OUT,
+				prtd->audio_client,
+				&size, &idx))
+			q6asm_read_nolock(prtd->audio_client);
+		break;
+	}
+	case APR_BASIC_RSP_RESULT: {
+		switch (payload[0]) {
+		case ASM_SESSION_CMD_RUN:
+			if (substream->stream
+				!= SNDRV_PCM_STREAM_PLAYBACK) {
+				atomic_set(&prtd->start, 1);
+				break;
+			}
+			if (prtd->mmap_flag) {
+				pr_debug("%s:writing %d bytes buffer to dsp\n",
+					__func__, prtd->pcm_count);
+				q6asm_write_nolock(prtd->audio_client,
+					prtd->pcm_count,
+					0, 0, NO_TIMESTAMP);
+			} else {
+				while (atomic_read(&prtd->out_needed)) {
+					pr_debug("%s:writing %d bytesto dsp\n",
+						__func__, prtd->pcm_count);
+					q6asm_write_nolock(prtd->audio_client,
+						prtd->pcm_count,
+						0, 0, NO_TIMESTAMP);
+					atomic_dec(&prtd->out_needed);
+					wake_up(&the_locks.write_wait);
+				};
+			}
+			atomic_set(&prtd->start, 1);
+			break;
+		default:
+			break;
+		}
+	}
+	break;
+	default:
+		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+		break;
+	}
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret;
+
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+	if (prtd->enabled)
+		return 0;
+
+	ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
+			runtime->rate, runtime->channels);
+	if (ret < 0)
+		pr_info("%s: CMD Format block failed\n", __func__);
+
+	atomic_set(&prtd->out_count, runtime->periods);
+
+	prtd->enabled = 1;
+	prtd->cmd_ack = 0;
+
+	return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	int ret = 0;
+	int i = 0;
+	pr_debug("%s\n", __func__);
+	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_irq_pos = 0;
+
+	/* rate and channels are sent to audio driver */
+	prtd->samp_rate = runtime->rate;
+	prtd->channel_mode = runtime->channels;
+
+	if (prtd->enabled)
+		return 0;
+
+	pr_debug("Samp_rate = %d\n", prtd->samp_rate);
+	pr_debug("Channel = %d\n", prtd->channel_mode);
+	ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
+					prtd->channel_mode);
+	if (ret < 0)
+		pr_debug("%s: cmd cfg pcm was block failed", __func__);
+
+	for (i = 0; i < runtime->periods; i++)
+		q6asm_read(prtd->audio_client);
+	prtd->periods = runtime->periods;
+
+	prtd->enabled = 1;
+
+	return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pr_debug("%s: Trigger start\n", __func__);
+		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		atomic_set(&prtd->start, 0);
+		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+			break;
+		prtd->cmd_ack = 0;
+		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+		atomic_set(&prtd->start, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd;
+	int ret = 0;
+	pr_debug("%s lowlatency\n", __func__);
+	prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+	if (prtd == NULL) {
+		pr_err("Failed to allocate memory for msm_audio\n");
+		return -ENOMEM;
+	}
+	prtd->substream = substream;
+	prtd->audio_client = q6asm_audio_client_alloc(
+				(app_cb)event_handler, prtd);
+	if (!prtd->audio_client) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
+	prtd->audio_client->perf_mode = true;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		runtime->hw = msm_pcm_hardware_playback;
+		ret = q6asm_open_write(prtd->audio_client,
+				FORMAT_MULTI_CHANNEL_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm out open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+	/* Capture path */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		runtime->hw = msm_pcm_hardware_capture;
+		ret = q6asm_open_read_v2_1(prtd->audio_client,
+					FORMAT_LINEAR_PCM);
+		if (ret < 0) {
+			pr_err("%s: pcm in open failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+
+	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+
+	prtd->session_id = prtd->audio_client->session;
+	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->audio_client->perf_mode,
+			prtd->session_id, substream->stream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prtd->cmd_ack = 1;
+
+	ret = snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&constraints_sample_rates);
+	if (ret < 0)
+		pr_err("snd_pcm_hw_constraint_list failed\n");
+	/* Ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		pr_err("snd_pcm_hw_constraint_integer failed\n");
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			PLAYBACK_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
+			PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
+		if (ret < 0) {
+			pr_err("constraint for buffer bytes min max ret = %d\n",
+									ret);
+		}
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		ret = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			CAPTURE_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
+			CAPTURE_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
+		if (ret < 0) {
+			pr_err("constraint for buffer bytes min max ret = %d\n",
+									ret);
+		}
+	}
+
+	prtd->dsp_cnt = 0;
+	runtime->private_data = prtd;
+	pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
+	pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
+	return 0;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer = 0;
+	char *bufptr = NULL;
+	void *data = NULL;
+	uint32_t idx = 0;
+	uint32_t size = 0;
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	fbytes = frames_to_bytes(runtime, frames);
+	pr_debug("%s: prtd->out_count = %d\n",
+				__func__, atomic_read(&prtd->out_count));
+	ret = wait_event_timeout(the_locks.write_wait,
+			(atomic_read(&prtd->out_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_err("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+
+	if (!atomic_read(&prtd->out_count)) {
+		pr_err("%s: pcm stopped out_count 0\n", __func__);
+		return 0;
+	}
+
+	data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	if (bufptr) {
+		pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
+					__func__, fbytes, xfer, size);
+		xfer = fbytes;
+		if (copy_from_user(bufptr, buf, xfer)) {
+			ret = -EFAULT;
+			goto fail;
+		}
+		buf += xfer;
+		fbytes -= xfer;
+		pr_debug("%s:fbytes = %d: xfer=%d\n", __func__, fbytes, xfer);
+		if (atomic_read(&prtd->start)) {
+			pr_debug("%s:writing %d bytes of buffer to dsp\n",
+					__func__, xfer);
+			ret = q6asm_write(prtd->audio_client, xfer,
+						0, 0, NO_TIMESTAMP);
+			if (ret < 0) {
+				ret = -EFAULT;
+				goto fail;
+			}
+		} else
+			atomic_inc(&prtd->out_needed);
+		atomic_dec(&prtd->out_count);
+	}
+fail:
+	return  ret;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = 0;
+	int ret = 0;
+
+	pr_debug("%s\n", __func__);
+
+	dir = IN;
+	ret = wait_event_timeout(the_locks.eos_wait,
+				prtd->cmd_ack, 5 * HZ);
+	if (ret < 0)
+		pr_err("%s: CMD_EOS failed\n", __func__);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+			SNDRV_PCM_STREAM_PLAYBACK);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+	return 0;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+		 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+						 snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+	int fbytes = 0;
+	int xfer;
+	char *bufptr;
+	void *data = NULL;
+	static uint32_t idx;
+	static uint32_t size;
+	uint32_t offset = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = substream->runtime->private_data;
+
+
+	pr_debug("%s\n", __func__);
+	fbytes = frames_to_bytes(runtime, frames);
+
+	pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
+	pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
+	pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+
+	ret = wait_event_timeout(the_locks.read_wait,
+			(atomic_read(&prtd->in_count)), 5 * HZ);
+	if (ret < 0) {
+		pr_debug("%s: wait_event_timeout failed\n", __func__);
+		goto fail;
+	}
+	if (!atomic_read(&prtd->in_count)) {
+		pr_debug("%s: pcm stopped in_count 0\n", __func__);
+		return 0;
+	}
+	pr_debug("Checking if valid buffer is available...%08x\n",
+						(unsigned int) data);
+	data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
+	bufptr = data;
+	pr_debug("Size = %d\n", size);
+	pr_debug("fbytes = %d\n", fbytes);
+	pr_debug("idx = %d\n", idx);
+	if (bufptr) {
+		xfer = fbytes;
+		if (xfer > size)
+			xfer = size;
+		offset = in_frame_info[idx][1];
+		pr_debug("Offset value = %d\n", offset);
+		if (copy_to_user(buf, bufptr+offset, xfer)) {
+			pr_err("Failed to copy buf to user\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+		fbytes -= xfer;
+		size -= xfer;
+		in_frame_info[idx][1] += xfer;
+		pr_debug("%s:fbytes = %d: size=%d: xfer=%d\n",
+					__func__, fbytes, size, xfer);
+		pr_debug(" Sending next buffer to dsp\n");
+		memset(&in_frame_info[idx], 0,
+			sizeof(uint32_t) * 2);
+		atomic_dec(&prtd->in_count);
+		ret = q6asm_read(prtd->audio_client);
+		if (ret < 0) {
+			pr_err("q6asm read failed\n");
+			ret = -EFAULT;
+			goto fail;
+		}
+	} else
+		pr_err("No valid buffer\n");
+
+	pr_debug("Returning from capture_copy... %d\n", ret);
+fail:
+	return ret;
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+	struct msm_audio *prtd = runtime->private_data;
+	int dir = OUT;
+
+	pr_debug("%s\n", __func__);
+	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
+	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+			SNDRV_PCM_STREAM_CAPTURE);
+	q6asm_audio_client_free(prtd->audio_client);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+	 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_close(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_close(substream);
+	return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = msm_pcm_playback_prepare(substream);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_prepare(substream);
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	if (prtd->pcm_irq_pos >= prtd->pcm_size)
+		prtd->pcm_irq_pos = 0;
+
+	pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+				struct vm_area_struct *vma)
+{
+	int result = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+
+	pr_debug("%s\n", __func__);
+	prtd->mmap_flag = 1;
+
+	if (runtime->dma_addr && runtime->dma_bytes) {
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		result = remap_pfn_range(vma, vma->vm_start,
+				runtime->dma_addr >> PAGE_SHIFT,
+				runtime->dma_bytes,
+				vma->vm_page_prot);
+	} else {
+		pr_err("Physical address or size of buf is NULL");
+		return -EINVAL;
+	}
+
+	return result;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct msm_audio *prtd = runtime->private_data;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct audio_buffer *buf;
+	int dir, ret;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+
+	/*
+	 *TODO : Need to Add Async IO changes. All period
+	 * size might not be supported.
+	 */
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+		prtd->audio_client,
+		(params_buffer_bytes(params) / params_periods(params)),
+		params_periods(params));
+
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
+		return -ENOMEM;
+	}
+	buf = prtd->audio_client->port[dir].buf;
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
+	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	dma_buf->dev.dev = substream->pcm->card->dev;
+	dma_buf->private_data = NULL;
+	dma_buf->area = buf[0].data;
+	dma_buf->addr =  buf[0].phys;
+	dma_buf->bytes = params_buffer_bytes(params);
+	if (!dma_buf->area)
+		return -ENOMEM;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+	.open           = msm_pcm_open,
+	.copy		= msm_pcm_copy,
+	.hw_params	= msm_pcm_hw_params,
+	.close          = msm_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+	.mmap		= msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret = 0;
+
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+	.ops		= &msm_pcm_ops,
+	.pcm_new	= msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+	pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+	return snd_soc_register_platform(&pdev->dev,
+				   &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+	.driver = {
+		.name = "msm-lowlatency-pcm-dsp",
+		.owner = THIS_MODULE,
+	},
+	.probe = msm_pcm_probe,
+	.remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+	init_waitqueue_head(&the_locks.enable_wait);
+	init_waitqueue_head(&the_locks.eos_wait);
+	init_waitqueue_head(&the_locks.write_wait);
+	init_waitqueue_head(&the_locks.read_wait);
+
+	return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+	platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("Multi channel PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index ef58dd1..2d23b48 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -330,6 +330,7 @@
 		return -ENOMEM;
 	}
 	prtd->substream = substream;
+	prtd->audio_client->perf_mode = false;
 	prtd->audio_client = q6asm_audio_client_alloc(
 				(app_cb)event_handler, prtd);
 	if (!prtd->audio_client) {
@@ -364,8 +365,8 @@
 
 	prtd->session_id = prtd->audio_client->session;
 	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->audio_client->perf_mode,
 			prtd->session_id, substream->stream);
-
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		prtd->cmd_ack = 1;
 
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 269b49b..116ce3e 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -282,6 +282,7 @@
 	}
 	runtime->hw = msm_pcm_hardware;
 	prtd->substream = substream;
+	prtd->audio_client->perf_mode = false;
 	prtd->audio_client = q6asm_audio_client_alloc(
 				(app_cb)event_handler, prtd);
 	if (!prtd->audio_client) {
@@ -311,6 +312,7 @@
 	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
 	prtd->session_id = prtd->audio_client->session;
 	msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+		prtd->audio_client->perf_mode,
 		prtd->session_id, substream->stream);
 
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 942c3ea..74136dc 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -324,6 +324,7 @@
 		kfree(prtd);
 		return -ENOMEM;
 	}
+	prtd->audio_client->perf_mode = false;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		runtime->hw = msm_pcm_hardware_playback;
 		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
@@ -338,6 +339,7 @@
 			prtd->audio_client->session);
 		prtd->session_id = prtd->audio_client->session;
 		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->audio_client->perf_mode,
 			prtd->session_id, substream->stream);
 		prtd->cmd_ack = 1;
 
@@ -443,7 +445,7 @@
 				prtd->audio_client);
 
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
-	SNDRV_PCM_STREAM_PLAYBACK);
+			SNDRV_PCM_STREAM_PLAYBACK);
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 	return 0;
@@ -649,8 +651,9 @@
 			prtd->audio_client->session);
 		prtd->session_id = prtd->audio_client->session;
 		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+			prtd->audio_client->perf_mode,
 			prtd->session_id, substream->stream);
-	}
+		}
 
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 26dbb21..374357d 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -38,6 +38,7 @@
 	unsigned long port_sessions; /* track Tx BE ports -> Rx BE */
 	unsigned int  sample_rate;
 	unsigned int  channel;
+	bool perf_mode;
 };
 
 #define INVALID_SESSION -1
@@ -291,7 +292,8 @@
 	mutex_unlock(&routing_lock);
 }
 
-void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id, int stream_type)
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
+							int stream_type)
 {
 	int i, session_type, path_type, port_type;
 	struct route_payload payload;
@@ -321,6 +323,8 @@
 	if (eq_data[fedai_id].enable)
 		msm_send_eq_values(fedai_id);
 	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+		if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+			msm_bedais[i].perf_mode = perf_mode;
 		if (!is_be_dai_extproc(i) &&
 		   (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
 		   (msm_bedais[i].active) &&
@@ -329,12 +333,22 @@
 			channels = msm_bedais[i].channel;
 
 			if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
+				((channels == 1) || (channels == 2)) &&
+				msm_bedais[i].perf_mode) {
+				pr_debug("%s configure COPP to lowlatency mode",
+								__func__);
+				adm_multi_ch_copp_open(msm_bedais[i].port_id,
+				path_type,
+				msm_bedais[i].sample_rate,
+				msm_bedais[i].channel,
+				DEFAULT_COPP_TOPOLOGY, msm_bedais[i].perf_mode);
+			} else if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
 				(channels > 2))
 				adm_multi_ch_copp_open(msm_bedais[i].port_id,
 				path_type,
 				msm_bedais[i].sample_rate,
 				msm_bedais[i].channel,
-				DEFAULT_COPP_TOPOLOGY);
+				DEFAULT_COPP_TOPOLOGY, msm_bedais[i].perf_mode);
 			else
 				adm_open(msm_bedais[i].port_id,
 				path_type,
@@ -440,18 +454,32 @@
 
 			channels = msm_bedais[reg].channel;
 
-			if ((session_type == SESSION_TYPE_RX) && (channels > 2))
+			if ((session_type == SESSION_TYPE_RX) &&
+				((channels == 1) || (channels == 2))
+				&& msm_bedais[reg].perf_mode) {
 				adm_multi_ch_copp_open(msm_bedais[reg].port_id,
 				path_type,
 				msm_bedais[reg].sample_rate,
 				channels,
-				DEFAULT_COPP_TOPOLOGY);
+				DEFAULT_COPP_TOPOLOGY,
+				msm_bedais[reg].perf_mode);
+				pr_debug("%s:configure COPP to lowlatency mode",
+								 __func__);
+			} else if ((session_type == SESSION_TYPE_RX)
+					&& (channels > 2))
+				adm_multi_ch_copp_open(msm_bedais[reg].port_id,
+				path_type,
+				msm_bedais[reg].sample_rate,
+				channels,
+				DEFAULT_COPP_TOPOLOGY,
+				msm_bedais[reg].perf_mode);
 			else
 				adm_open(msm_bedais[reg].port_id,
 				path_type,
 				msm_bedais[reg].sample_rate, channels,
 				DEFAULT_COPP_TOPOLOGY);
 
+
 			msm_pcm_routing_build_matrix(val,
 				fe_dai_map[val][session_type], path_type);
 			srs_port_id = msm_bedais[reg].port_id;
@@ -1375,6 +1403,12 @@
 	msm_routing_put_audio_mixer),
 };
 
+static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
+	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
+
 
 static const struct snd_kcontrol_new mmul4_mixer_controls[] = {
 	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
@@ -2023,6 +2057,7 @@
 	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2122,6 +2157,8 @@
 	mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
 	SND_SOC_DAPM_MIXER("MultiMedia4 Mixer", SND_SOC_NOPM, 0, 0,
 	mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
+	mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2280,6 +2317,7 @@
 	{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
 	{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
 	{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
+	{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
 	{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -2320,6 +2358,7 @@
 	{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
 	{"MM_UL2", NULL, "MultiMedia2 Mixer"},
 	{"MM_UL4", NULL, "MultiMedia4 Mixer"},
+	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
 
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
 	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2553,6 +2592,7 @@
 	bedai->active = 0;
 	bedai->sample_rate = 0;
 	bedai->channel = 0;
+	bedai->perf_mode = false;
 	mutex_unlock(&routing_lock);
 
 	return 0;
@@ -2565,6 +2605,7 @@
 	int i, path_type, session_type;
 	struct msm_pcm_routing_bdai_data *bedai;
 	u32 channels;
+	bool playback, capture;
 
 	if (be_id >= MSM_BACKEND_DAI_MAX) {
 		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -2592,18 +2633,29 @@
 	* is started.
 	*/
 	bedai->active = 1;
+	playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	capture  = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
+
 	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
 		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
-
 			channels = bedai->channel;
-			if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-				substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			if ((playback || capture)
+				&& ((channels == 2) || (channels == 1)) &&
+				bedai->perf_mode) {
+				adm_multi_ch_copp_open(bedai->port_id,
+				path_type,
+				bedai->sample_rate,
+				channels,
+				DEFAULT_COPP_TOPOLOGY, bedai->perf_mode);
+				pr_debug("%s:configure COPP to lowlatency mode",
+								__func__);
+			} else if ((playback || capture)
 				&& (channels > 2))
 				adm_multi_ch_copp_open(bedai->port_id,
 				path_type,
 				bedai->sample_rate,
 				channels,
-				DEFAULT_COPP_TOPOLOGY);
+				DEFAULT_COPP_TOPOLOGY, bedai->perf_mode);
 			else
 				adm_open(bedai->port_id,
 				path_type,
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 45dbf40..6b87475 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -111,8 +111,8 @@
  * dspst_id:  DSP audio stream ID
  * stream_type: playback or capture
  */
-void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id,
-	int stream_type);
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+				int dspst_id, int stream_type);
 void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
 		int stream_type, int enable);
 
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index e86db10..a577b6a 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1015,6 +1015,53 @@
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 	},
+	{
+		.name = "VoLTE",
+		.stream_name = "VoLTE",
+		.cpu_dai_name   = "VoLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_VOLTE,
+	},
+	{
+		.name = "SGLTE",
+		.stream_name = "SGLTE",
+		.cpu_dai_name   = "SGLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_SGLTE,
+	},
+	{
+		.name = "MSM8960 LowLatency",
+		.stream_name = "MultiMedia5",
+		.cpu_dai_name	= "MultiMedia5",
+		.platform_name  = "msm-lowlatency-pcm-dsp",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+	},
 	/* Backend DAI Links */
 	{
 		.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index b10a7ea..040bbe0 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1348,6 +1348,21 @@
 		.codec_name = "snd-soc-dummy",
 		.be_id = MSM_FRONTEND_DAI_SGLTE,
 	},
+	{
+		.name = "MSM8960 LowLatency",
+		.stream_name = "MultiMedia5",
+		.cpu_dai_name	= "MultiMedia5",
+		.platform_name  = "msm-lowlatency-pcm-dsp",
+		.dynamic = 1,
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+					SND_SOC_DPCM_TRIGGER_POST},
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
+		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1746,6 +1761,7 @@
 		msm8960_headset_gpios_configured = 1;
 
 	mutex_init(&cdc_mclk_mutex);
+
 	return ret;
 
 }
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 0327e4a..6724c545 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -294,7 +294,8 @@
 
 		switch (data->opcode) {
 		case ADM_CMDRSP_COPP_OPEN:
-		case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN: {
+		case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN:
+		case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3: {
 			struct adm_copp_open_respond *open = data->payload;
 			if (open->copp_id == INVALID_COPP_ID) {
 				pr_err("%s: invalid coppid rxed %d\n",
@@ -707,7 +708,7 @@
 
 
 int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
-				int topology)
+				int topology, int perfmode)
 {
 	struct adm_multi_ch_copp_open_command open;
 	int ret = 0;
@@ -745,7 +746,17 @@
 
 		open.hdr.pkt_size =
 			sizeof(struct adm_multi_ch_copp_open_command);
-		open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN;
+
+		if (perfmode) {
+			pr_debug("%s Performance mode", __func__);
+			open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3;
+			open.flags = ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT;
+			open.reserved = PCM_BITS_PER_SAMPLE;
+		} else {
+			open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN;
+			open.reserved = 0;
+		}
+
 		memset(open.dev_channel_mapping, 0, 8);
 
 		if (channel_mode == 1)	{
@@ -779,8 +790,6 @@
 					channel_mode);
 			return -EINVAL;
 		}
-
-
 		open.hdr.src_svc = APR_SVC_ADM;
 		open.hdr.src_domain = APR_DOMAIN_APPS;
 		open.hdr.src_port = port_id;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 06be186..76940ee 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -209,6 +209,7 @@
 	session[ac->session] = 0;
 	mutex_unlock(&session_lock);
 	ac->session = 0;
+	ac->perf_mode = false;
 	return;
 }
 
@@ -412,6 +413,7 @@
 	ac->cb = cb;
 	ac->priv = priv;
 	ac->io_mode = SYNC_IO_MODE;
+	ac->perf_mode = false;
 	ac->apr = apr_register("ADSP", "ASM", \
 				(apr_fn)q6asm_callback,\
 				((ac->session) << 8 | 0x0001),\
@@ -844,6 +846,7 @@
 
 	if (data->opcode == APR_BASIC_RSP_RESULT) {
 		token = data->token;
+		pr_debug("%s payload[0]:%x", __func__, payload[0]);
 		switch (payload[0]) {
 		case ASM_STREAM_CMD_SET_PP_PARAMS:
 			if (rtac_make_asm_callback(ac->session, payload,
@@ -863,7 +866,9 @@
 			return -EINVAL;
 		}
 		case ASM_STREAM_CMD_OPEN_READ:
+		case ASM_STREAM_CMD_OPEN_READ_V2_1:
 		case ASM_STREAM_CMD_OPEN_WRITE:
+		case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
 		case ASM_STREAM_CMD_OPEN_READWRITE:
 		case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
 		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
@@ -871,8 +876,11 @@
 		case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
 			if (atomic_read(&ac->cmd_state) && wakeup_flag) {
 				atomic_set(&ac->cmd_state, 0);
-				if (payload[1] == ADSP_EUNSUPPORTED)
+				if (payload[1] == ADSP_EUNSUPPORTED) {
+					pr_debug("paload[1]:%d unsupported",
+								payload[1]);
 					atomic_set(&ac->cmd_response, 1);
+				}
 				else
 					atomic_set(&ac->cmd_response, 0);
 				wake_up(&ac->cmd_wait);
@@ -1276,6 +1284,82 @@
 	return -EINVAL;
 }
 
+int q6asm_open_read_v2_1(struct audio_client *ac,
+		uint32_t format)
+{
+	int rc = 0x00;
+	struct asm_stream_cmd_open_read_v2_1 open;
+#ifdef CONFIG_DEBUG_FS
+	in_cont_index = 0;
+#endif
+	if ((ac == NULL) || (ac->apr == NULL)) {
+		pr_err("%s: APR handle NULL\n", __func__);
+		return -EINVAL;
+	}
+	pr_debug("%s:session[%d]", __func__, ac->session);
+
+	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V2_1;
+	open.src_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+	open.pre_proc_top = get_asm_topology();
+	if (open.pre_proc_top == 0)
+		open.pre_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+	switch (format) {
+	case FORMAT_LINEAR_PCM:
+		open.uMode = STREAM_PRIORITY_HIGH;
+		open.format = LINEAR_PCM;
+		break;
+	case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+		open.uMode = STREAM_PRIORITY_HIGH;
+		open.format = MULTI_CHANNEL_PCM;
+		break;
+	case FORMAT_MPEG4_AAC:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = MPEG4_AAC;
+		break;
+	case FORMAT_V13K:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = V13K_FS;
+		break;
+	case FORMAT_EVRC:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = EVRC_FS;
+		break;
+	case FORMAT_AMRNB:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = AMRNB_FS;
+		break;
+	case FORMAT_AMRWB:
+		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+		open.format = AMRWB_FS;
+		break;
+	default:
+		pr_err("Invalid format[%d]\n", format);
+		goto fail_cmd;
+	}
+	open.uMode = ASM_OPEN_READ_PERF_MODE_BIT;
+	open.bits_per_sample = PCM_BITS_PER_SAMPLE;
+	open.reserved = 0;
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+	if (rc < 0) {
+		pr_err("open failed op[0x%x]rc[%d]\n", \
+						open.hdr.opcode, rc);
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+			rc);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
+
 int q6asm_open_read_compressed(struct audio_client *ac,
 			 uint32_t frames_per_buffer, uint32_t meta_data_mode)
 {
@@ -1396,12 +1480,20 @@
 
 	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
 
-	open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE;
-	open.uMode = STREAM_PRIORITY_HIGH;
-	/* source endpoint : matrix */
-	open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
-	open.stream_handle = 0x00;
-
+	if (ac->perf_mode) {
+		pr_debug("%s In Performance/lowlatency mode", __func__);
+		open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V2_1;
+		open.uMode = ASM_OPEN_WRITE_PERF_MODE_BIT;
+		/* source endpoint : matrix */
+		open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+		open.stream_handle = PCM_BITS_PER_SAMPLE;
+	} else {
+		open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE;
+		open.uMode = STREAM_PRIORITY_HIGH;
+		/* source endpoint : matrix */
+		open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+		open.stream_handle = 0x00;
+	}
 	open.post_proc_top = get_asm_topology();
 	if (open.post_proc_top == 0)
 		open.post_proc_top = DEFAULT_POPP_TOPOLOGY;