Merge "mmc: sdhci: remove too large timeout warning"
diff --git a/Documentation/devicetree/bindings/arm/msm/smem.txt b/Documentation/devicetree/bindings/arm/msm/smem.txt
new file mode 100644
index 0000000..a38984c
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/smem.txt
@@ -0,0 +1,107 @@
+Qualcomm Shared Memory
+
+[Root level node]
+Required properties:
+-compatible : should be "qcom,smem"
+-reg : the location and size of smem, the irq register base memory, and
+	optionally any auxiliary smem areas
+-reg-names : "smem" - string to identify the shared memory region
+	     "irq-reg-base" - string to identify the irq register region
+	     "aux-mem1", "aux-mem2", "aux-mem3", ... - optional strings to
+			identify any auxiliary shared memory regions
+
+[Second level nodes]
+
+qcom,smd
+Required properties:
+-compatible : should be "qcom,smd"
+-qcom,smd-edge : the smd edge
+-qcom,smd-irq-offset : the offset into the irq register base memory for sending
+	interrupts
+-qcom,smd-irq-bitmask : the sending irq bitmask
+-interrupts : the receiving interrupt line
+
+Optional properties:
+-qcom,pil-string : the name to use when loading this edge
+-qcom,irq-no-suspend: configure the incoming irq line as active during suspend
+
+qcom,smsm
+Required properties:
+-compatible : should be "qcom,smsm"
+-qcom,smsm-edge : the smsm edge
+-qcom,smsm-irq-offset : the offset into the irq register base memory for sending
+	interrupts
+-qcom,smsm-irq-bitmask : the sending irq bitmask
+-interrupts : the receiving interrupt line
+
+
+Example:
+
+	qcom,smem@fa00000 {
+		compatible = "qcom,smem";
+		reg = <0xfa00000 0x200000>,
+			<0xfa006000 0x1000>,
+			<0xfc428000 0x4000>;
+		reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+		qcom,smd-modem {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <0>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1000>;
+			qcom,pil-string = "modem";
+			interrupts = <0 25 1>;
+		};
+
+		qcom,smsm-modem {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <0>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x2000>;
+			interrupts = <0 26 1>;
+		};
+
+		qcom,smd-adsp {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <1>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x100>;
+			qcom,pil-string = "adsp";
+			interrupts = <0 156 1>;
+		};
+
+		qcom,smsm-adsp {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <1>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x200>;
+			interrupts = <0 157 1>;
+		};
+
+		qcom,smd-wcnss {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <6>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x20000>;
+			qcom,pil-string = "wcnss";
+			interrupts = <0 142 1>;
+		};
+
+		qcom,smsm-wcnss {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <6>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x80000>;
+			interrupts = <0 144 1>;
+		};
+
+		qcom,smd-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			qcom,irq-no-syspend;
+		};
+	};
+
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index d7290e0..10732cf 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -24,14 +24,14 @@
 
 Optional properties for WLED:
 - qcom,num-strings: number of wled strings supported
-- qcom,ovp_val: over voltage protection threshold,
+- qcom,ovp-val: over voltage protection threshold,
 		follows enum wled_ovp_threshold
-- qcom,boost_curr_lim: boot currnet limit, follows enum wled_current_bost_limit
-- qcom,ctrl_delay_us: delay in activation of led
-- qcom,dig_mod_gen_en: digital module generator
-- qcom,cs_out_en: current sink output enable
-- qcom,op_fdbck: selection of output as feedback for the boost
-- qcom,cp_select: high pole capacitance
+- qcom,boost-curr-lim: boot currnet limit, follows enum wled_current_bost_limit
+- qcom,ctrl-delay-us: delay in activation of led
+- qcom,dig-mod-gen-en: digital module generator
+- qcom,cs-out-en: current sink output enable
+- qcom,op-fdbck: selection of output as feedback for the boost
+- qcom,cp-select: high pole capacitance
 - linux,default-trigger: trigger the led from external modules such as display
 - qcom,default-state:  default state of the led, should be "on" or "off"
 
diff --git a/Documentation/devicetree/bindings/misc/ti_drv2667.txt b/Documentation/devicetree/bindings/misc/ti_drv2667.txt
new file mode 100644
index 0000000..3a8f4b3
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/ti_drv2667.txt
@@ -0,0 +1,44 @@
+TI DRV2667 is a haptic controller chip. It can drive piezo haptics
+and can operate in two modes - analog and digital.
+
+Required properties:
+
+-compatible	: should be "ti,drv2667".
+-reg		: i2c address to be used.
+-vdd-supply	: regulator to power the chip.
+-vdd-i2c-supply	: regulator to power i2c bus.
+
+Optional properties:
+
+-ti,label		: Name to be registered with timedoutput class.
+-ti,mode		: Mode to be supported, 0 to 3 - FIFO, RAM, WAVE and ANALOG.
+-ti,wav-seq		: Wave Sequence composed of 11 bytes - wave form id,
+				Header size, start upper byte, start lower byte,
+				stop upper byte, stop lower byte, repeat count,
+				amplitude, frequency, duration and envelope
+-ti,gain		: Gain to be programmed for the chip.
+-ti,idle-timeout-ms	: Idle timeout in ms to be programmed for the chip to go into
+				low power mode after finishing its operation.
+-ti,max-runtime-ms	: Maximum time in ms for which chip can drive haptics.
+
+Example:
+	i2c@f9967000 {
+		ti-drv2667@59 {
+			compatible = "ti,drv2667";
+			reg = <0x59>;
+			vdd-supply = <&drv2667_vreg>;
+			vdd-i2c-supply = <&pm8941_s3>;
+			ti,label = "vibrator";
+			ti,gain = <3>;
+			ti,idle-timeout-ms = <20>;
+			ti,max-runtime-ms = <15000>;
+			ti,mode = <2>;
+			ti,wav-seq = [
+				/* wave form id */
+				01
+				/* header size, start and stop bytes */
+				05 80 06 00 09
+				/* repeat, amp, freq, duration, envelope */
+				01 ff 19 02 00];
+		};
+	};
diff --git a/Documentation/devicetree/bindings/net/wireless/ath/ath6kl.txt b/Documentation/devicetree/bindings/net/wireless/ath/ath6kl.txt
new file mode 100644
index 0000000..7b9feae
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/ath/ath6kl.txt
@@ -0,0 +1,24 @@
+* Qualcomm Atheros mobile chipsets
+
+Required properties:
+    - compatible: Can be "qca,ar6004-sdio" for SDIO device and
+    "qca,ar6004-hsic" for HSIC devcie.
+    - qca,chip-pwd-l-gpios: specify GPIO for CHIP_PWD_L.
+
+Optional Properties:
+    - cell-index: WLAN Hardware index.
+    - qca,pm-enable-gpios: Specify this GPIO if internal PMU needs to be used.
+    - qca,ar6004-vbatt-supply: Specify this if VBATT is provided through a
+    regulator.
+    - qca,ar6004-vdd-io-supply: Specify this if VDD-IO is provided through a
+    regulator.
+
+Example:
+
+	wlan0: qca,wlan {
+		cell-index = <0>;
+		compatible = "qca,ar6004-sdio";
+		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+	};
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 1d3c2db..4d571eb 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -36,12 +36,34 @@
 - qcom,bms-adjust-soc-low-threshold : The low threshold for the "flat portion"
 			of the charging curve. The BMS will not adjust SoC
 			based on voltage during this time.
-- qcom,bms-adjust-soc-high-threshold :  The high threshold for the "flat
+- qcom,bms-adjust-soc-high-threshold : The high threshold for the "flat
 			portion" of the charging curve. The BMS will not
 			adjust SoC based on voltage during this time.
+- qcom,bms-low-soc-calculate-soc-threshold : The SoC threshold for when
+			the period calculate_soc work speeds up. This ensures
+			SoC is updated in userspace constantly when we are near
+			shutdown.
+- qcom,bms-low-soc-calculate-soc-ms : The time period between subsequent
+			SoC recalculations when the current SoC is below
+			qcom,bms-low-soc-calculate-soc-threshold.
+- qcom,bms-soc-calculate-soc-ms : The time period between subsequent SoC
+			recalculations when the current SoC is above or equal
+			qcom,bms-low-soc-calculate-soc-threshold.
 - qcom,bms-chg-term-ua : current in micro-amps when charging is considered done.
 			As soon as current passes this point, charging is
 			stopped.
+- qcom,bms-batt-type: Type of battery used. This is an integer that corresponds
+			to the enum defined in
+			include/linux/mfd/pm8xxx/batterydata-lib.h
+
+Optional properties:
+- qcom,bms-ignore-shutdown-soc: A boolean that controls whether BMS will
+			try to force the startup SoC to be the same as the
+			shutdown SoC. Defining it will make BMS ignore the
+			shutdown SoC.
+- qcom,bms-use-voltage-soc : A boolean that controls whether BMS will use
+			voltage-based SoC instead of a coulomb counter based
+			one. Voltage-based SoC will not guarantee linearity.
 
 Example:
 	bms@4000 {
@@ -76,5 +98,10 @@
 		qcom,bms-shutdown-soc-valid-limit = <20>;
 		qcom,bms-adjust-soc-low-threshold = <25>;
 		qcom,bms-adjust-soc-high-threshold = <45>;
+		qcom,bms-low-soc-calculate-soc-threshold = <15>;
+		qcom,bms-low-soc-calculate-soc-ms = <5000>;
+		qcom,bms-calculate-soc-ms = <20000>;
 		qcom,bms-chg-term-ua = <100000>;
+		qcom,bms-batt-type = <0>;
+		qcom,bms-ignore-shutdown-soc;
 	};
diff --git a/Documentation/devicetree/bindings/prng/msm-rng.txt b/Documentation/devicetree/bindings/prng/msm-rng.txt
index 3d55808..28dfe50 100644
--- a/Documentation/devicetree/bindings/prng/msm-rng.txt
+++ b/Documentation/devicetree/bindings/prng/msm-rng.txt
@@ -4,9 +4,13 @@
 - compatible : Should be "qcom,msm-rng"
 - reg        : Offset and length of the register set for the device
 
+Optional property:
+- qcom,msm-rng-iface-clk : If the device uses iface-clk.
+
 Example:
 
-        qcom,msm-rng@f9bff000 {
-                              compatible = "qcom,msm-rng";
-                              reg = <0xf9bff000 0x200>;
-        };
+	qcom,msm-rng@f9bff000 {
+		compatible = "qcom,msm-rng";
+		reg = <0xf9bff000 0x200>;
+		qcom,msm-rng-iface-clk;
+	};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index bf605ec..2c74415 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -381,3 +381,48 @@
 	taiko-mclk-clk = <&pm8941_clkdiv1>;
 	qcom,taiko-mclk-clk-freq = <9600000>;
 };
+
+* msm-dai-mi2s
+
+[First Level Nodes]
+
+Required properties:
+
+ - compatible : "msm-dai-mi2s"
+
+ [Second Level Nodes]
+
+Required properties:
+
+ - compatible : "qcom,msm-dai-q6-mi2s"
+ - qcom,msm-dai-q6-mi2s-dev-id: MSM or MDM can use Slimbus or I2S interface to transfer data
+								to (WCD9XXX) codec. If slimbus interface is used then
+								"msm-dai-q6" needs to be filled with correct data for slimbus
+								interface. The sections "msm-dai-mi2s" is used by MDM or MSM
+								to use I2S interface with codec. This section is used by CPU
+								driver in ASOC MSM to configure MI2S interface. MSM internally
+								has multiple MI2S namely Primary, Secondary, Tertiary and
+								Quaternary MI2S. They are represented with id 0, 1, 2, 3
+								respectively. The field "qcom,msm-dai-q6-mi2s-dev-id" represents
+								which of the MI2S block is used. These MI2S are connected to I2S
+								interface.
+
+ - qcom,msm-mi2s-rx-lines:		Each MI2S interface in MSM has one or more SD lines. These lines
+								are used for data transfer between codec and MSM. This element in
+								indicates which output RX lines are used in the MI2S interface.
+
+ - qcom,msm-mi2s-tx-lines:  	Each MI2S interface in MSM has one or more SD lines. These lines
+								are used for data transfer between codec and MSM. This element in
+								indicates which input TX lines are used in the MI2S interface.
+
+Example:
+
+qcom,msm-dai-mi2s {
+		compatible = "qcom,msm-dai-mi2s";
+		qcom,msm-dai-q6-mi2s-prim {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <0>;
+			qcom,msm-mi2s-rx-lines = <2>;
+			qcom,msm-mi2s-tx-lines = <1>;
+		};
+};
\ No newline at end of file
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 5d5f9de..89c7417 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -264,6 +264,29 @@
 	def_bool y
 	depends on BUG
 
+config GENERIC_TIME_VSYSCALL
+	bool "Enable gettimeofday updates"
+	depends on CPU_V7
+	help
+	  Enables updating the kernel user helper area with the xtime struct
+	  data for gettimeofday via kernel user helpers.
+
+config ARM_USE_USER_ACCESSIBLE_TIMERS
+	bool "Enables mapping a timer counter page to user space"
+	depends on USE_USER_ACCESSIBLE_TIMERS && GENERIC_TIME_VSYSCALL
+	help
+	 Enables ARM-specific user-accessible timers via a shared
+	 memory page containing the cycle counter.
+
+config ARM_USER_ACCESSIBLE_TIMER_BASE
+	hex "Base address of user-accessible timer counter page"
+	default 0xfffef000
+	depends on ARM_USE_USER_ACCESSIBLE_TIMERS
+	help
+	 Specify the base user-space virtual address where the user-accessible
+	 timer counter page should be mapped by the kernel.  User-space apps
+	 will read directly from the page at this address.
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 4ec5684..bf1c971 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -90,7 +90,12 @@
 			qcom,bms-shutdown-soc-valid-limit = <20>;
 			qcom,bms-adjust-soc-low-threshold = <25>;
 			qcom,bms-adjust-soc-high-threshold = <45>;
+			qcom,bms-low-soc-calculate-soc-threshold = <15>;
+			qcom,bms-low-soc-calculate-soc-ms = <5000>;
+			qcom,bms-calculate-soc-ms = <20000>;
 			qcom,bms-chg-term-ua = <100000>;
+			qcom,bms-batt-type = <0>;
+			qcom,bms-use-voltage-soc;
 		};
 
 		clkdiv@5b00 {
diff --git a/arch/arm/boot/dts/msm8910.dtsi b/arch/arm/boot/dts/msm8910.dtsi
index 1f3c1d8..2a2e764 100644
--- a/arch/arm/boot/dts/msm8910.dtsi
+++ b/arch/arm/boot/dts/msm8910.dtsi
@@ -73,13 +73,25 @@
 		interrupts = <0 123 0>;
 		interrupt-names = "core_irq";
 
+		vdd-supply = <&pm8110_l17>;
+		qcom,vdd-always-on;
+		qcom,vdd-lpm-sup;
+		qcom,vdd-voltage-level = <2900000 2900000>;
+		qcom,vdd-current-level = <9000 400000>;
+
+		vdd-io-supply = <&pm8110_l6>;
+		qcom,vdd-io-always-on;
+		qcom,vdd-io-lpm-sup;
+		qcom,vdd-io-voltage-level = <1800000 1800000>;
+		qcom,vdd-io-current-level = <9000 60000>;
+
 		qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 		qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 		qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
 		qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
 
 		qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-		qcom,sup-voltages = <2950 2950>;
+		qcom,sup-voltages = <2900 2900>;
 		qcom,bus-width = <8>;
 		qcom,nonremovable;
 		qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
@@ -93,6 +105,14 @@
 		interrupts = <0 125 0>;
 		interrupt-names = "core_irq";
 
+		vdd-supply = <&pm8110_l18>;
+		qcom,vdd-voltage-level = <2950000 2950000>;
+		qcom,vdd-current-level = <9000 400000>;
+
+		vdd-io-supply = <&pm8110_l21>;
+		qcom,vdd-io-voltage-level = <1800000 2950000>;
+		qcom,vdd-io-current-level = <9000 50000>;
+
 		qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 		qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
 		qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
new file mode 100644
index 0000000..25f79f8
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -0,0 +1,98 @@
+
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&cci {
+
+	qcom,camera@6e {
+		compatible = "qcom,s5k3l1yx";
+		reg = <0x6e 0x0>;
+		qcom,csi-if = <1>;
+		qcom,csid-core = <0>;
+		qcom,flash-type = <0>;
+		qcom,mount-angle = <0>;
+		qcom,sensor-name = "s5k3l1yx";
+		cam_vdig-supply = <&pm8941_l3>;
+		cam_vana-supply = <&pm8941_l17>;
+		cam_vio-supply = <&pm8941_lvs3>;
+		cam_vaf-supply = <&pm8941_l23>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio",
+				     "cam_vaf";
+		qcom,cam-vreg-type = <0 0 1 0>;
+		qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
+		qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
+		qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 15 0>,
+			<&msmgpio 19 0>,
+			<&msmgpio 20 0>,
+			<&msmgpio 90 0>;
+		qcom,gpio-common-tbl-num = <0 1 2>;
+		qcom,gpio-common-tbl-flags = <1 1 1>;
+		qcom,gpio-common-tbl-label = "CAMIF_MCLK",
+					     "CAMIF_I2C_DATA",
+					     "CAMIF_I2C_CLK";
+		qcom,gpio-req-tbl-num = <3>;
+		qcom,gpio-req-tbl-flags = <0>;
+		qcom,gpio-req-tbl-label = "CAM_RESET1";
+		qcom,gpio-set-tbl-num = <3 3>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 30000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,csi-phy-sel = <0>;
+		qcom,camera-type = <0>;
+		qcom,sensor-type = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@6c {
+		compatible = "qcom,ov2720";
+		reg = <0x6c 0x0>;
+		qcom,csi-if = <1>;
+		qcom,csid-core = <0>;
+		qcom,flash-type = <0>;
+		qcom,mount-angle = <180>;
+		qcom,sensor-name = "ov2720";
+		cam_vdig-supply = <&pm8941_l3>;
+		cam_vana-supply = <&pm8941_l17>;
+		cam_vio-supply = <&pm8941_lvs2>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+		qcom,cam-vreg-type = <0 0 1>;
+		qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+		qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+		qcom,cam-vreg-op-mode = <105000 80000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 17 0>,
+			<&msmgpio 19 0>,
+			<&msmgpio 20 0>,
+			<&msmgpio 18 0>;
+		qcom,gpio-common-tbl-num = <0 1 2>;
+		qcom,gpio-common-tbl-flags = <1 1 1>;
+		qcom,gpio-common-tbl-label = "CAMIF_MCLK",
+					     "CAMIF_I2C_DATA",
+					     "CAMIF_I2C_CLK";
+		qcom,gpio-req-tbl-num = <3>;
+		qcom,gpio-req-tbl-flags = <0>;
+		qcom,gpio-req-tbl-label = "CAM_RESET1";
+		qcom,gpio-set-tbl-num = <3 3>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 4000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x7>;
+		qcom,csi-phy-sel = <2>;
+		qcom,camera-type = <1>;
+		qcom,sensor-type = <0>;
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
new file mode 100644
index 0000000..d804355
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&cci {
+
+	qcom,camera@6e {
+		compatible = "qcom,s5k3l1yx";
+		reg = <0x6e 0x0>;
+		qcom,csi-if = <1>;
+		qcom,csid-core = <0>;
+		qcom,flash-type = <0>;
+		qcom,mount-angle = <90>;
+		qcom,sensor-name = "s5k3l1yx";
+		cam_vdig-supply = <&pm8941_l3>;
+		cam_vana-supply = <&pm8941_l17>;
+		cam_vio-supply = <&pm8941_lvs3>;
+		cam_vaf-supply = <&pm8941_l23>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio",
+				     "cam_vaf";
+		qcom,cam-vreg-type = <0 0 1 0>;
+		qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
+		qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
+		qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 15 0>,
+			<&msmgpio 19 0>,
+			<&msmgpio 20 0>,
+			<&msmgpio 90 0>;
+		qcom,gpio-common-tbl-num = <0 1 2>;
+		qcom,gpio-common-tbl-flags = <1 1 1>;
+		qcom,gpio-common-tbl-label = "CAMIF_MCLK",
+					     "CAMIF_I2C_DATA",
+					     "CAMIF_I2C_CLK";
+		qcom,gpio-req-tbl-num = <3>;
+		qcom,gpio-req-tbl-flags = <0>;
+		qcom,gpio-req-tbl-label = "CAM_RESET1";
+		qcom,gpio-set-tbl-num = <3 3>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 30000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x1F>;
+		qcom,csi-phy-sel = <0>;
+		qcom,camera-type = <0>;
+		qcom,sensor-type = <0>;
+		status = "ok";
+	};
+
+	qcom,camera@6c {
+		compatible = "qcom,ov2720";
+		reg = <0x6c 0x0>;
+		qcom,csi-if = <1>;
+		qcom,csid-core = <0>;
+		qcom,flash-type = <0>;
+		qcom,mount-angle = <180>;
+		qcom,sensor-name = "ov2720";
+		cam_vdig-supply = <&pm8941_l3>;
+		cam_vana-supply = <&pm8941_l17>;
+		cam_vio-supply = <&pm8941_lvs3>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+		qcom,cam-vreg-type = <0 0 1>;
+		qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+		qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+		qcom,cam-vreg-op-mode = <105000 80000 0>;
+		qcom,gpio-no-mux = <0>;
+		gpios = <&msmgpio 17 0>,
+			<&msmgpio 19 0>,
+			<&msmgpio 20 0>,
+			<&msmgpio 18 0>;
+		qcom,gpio-common-tbl-num = <0 1 2>;
+		qcom,gpio-common-tbl-flags = <1 1 1>;
+		qcom,gpio-common-tbl-label = "CAMIF_MCLK",
+					     "CAMIF_I2C_DATA",
+					     "CAMIF_I2C_CLK";
+		qcom,gpio-req-tbl-num = <3>;
+		qcom,gpio-req-tbl-flags = <0>;
+		qcom,gpio-req-tbl-label = "CAM_RESET1";
+		qcom,gpio-set-tbl-num = <3 3>;
+		qcom,gpio-set-tbl-flags = <0 2>;
+		qcom,gpio-set-tbl-delay = <1000 4000>;
+		qcom,csi-lane-assign = <0x4320>;
+		qcom,csi-lane-mask = <0x7>;
+		qcom,csi-phy-sel = <2>;
+		qcom,camera-type = <1>;
+		qcom,sensor-type = <0>;
+		status = "ok";
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index fd652a0..4b96811 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -165,7 +165,7 @@
 		vdd-supply = <&gdsc_vfe>;
 	};
 
-	qcom,cci@fda0C000 {
+	cci: qcom,cci@fda0C000 {
 		cell-index = <0>;
 		compatible = "qcom,cci";
 		reg = <0xfda0C000 0x1000>;
@@ -177,83 +177,11 @@
 		interrupt-names = "cci";
 
 		qcom,camera@6e {
-			compatible = "qcom,s5k3l1yx";
-			reg = <0x6e 0x0>;
-			qcom,csi-if = <1>;
-			qcom,csid-core = <0>;
-			qcom,flash-type = <0>;
-			qcom,mount-angle = <90>;
-			qcom,sensor-name = "s5k3l1yx";
-			cam_vdig-supply = <&pm8941_l3>;
-			cam_vana-supply = <&pm8941_l17>;
-			cam_vio-supply = <&pm8941_lvs3>;
-			cam_vaf-supply = <&pm8941_l23>;
-			qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio",
-					     "cam_vaf";
-			qcom,cam-vreg-type = <0 0 1 0>;
-			qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
-			qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
-			qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
-			qcom,gpio-no-mux = <0>;
-			gpios = <&msmgpio 15 0>,
-				<&msmgpio 19 0>,
-				<&msmgpio 20 0>,
-				<&msmgpio 90 0>;
-			qcom,gpio-common-tbl-num = <0 1 2>;
-			qcom,gpio-common-tbl-flags = <1 1 1>;
-			qcom,gpio-common-tbl-label = "CAMIF_MCLK",
-						     "CAMIF_I2C_DATA",
-						     "CAMIF_I2C_CLK";
-			qcom,gpio-req-tbl-num = <3>;
-			qcom,gpio-req-tbl-flags = <0>;
-			qcom,gpio-req-tbl-label = "CAM_RESET1";
-			qcom,gpio-set-tbl-num = <3 3>;
-			qcom,gpio-set-tbl-flags = <0 2>;
-			qcom,gpio-set-tbl-delay = <1000 30000>;
-			qcom,csi-lane-assign = <0x4320>;
-			qcom,csi-lane-mask = <0x1F>;
-			qcom,csi-phy-sel = <0>;
-			qcom,camera-type = <0>;
-			qcom,sensor-type = <0>;
+			status = "disable";
 		};
 
 		qcom,camera@6c {
-			compatible = "qcom,ov2720";
-			reg = <0x6c 0x0>;
-			qcom,csi-if = <1>;
-			qcom,csid-core = <0>;
-			qcom,flash-type = <0>;
-			qcom,mount-angle = <0>;
-			qcom,sensor-name = "ov2720";
-			cam_vdig-supply = <&pm8941_l3>;
-			cam_vana-supply = <&pm8941_l17>;
-			cam_vio-supply = <&pm8941_lvs3>;
-			qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
-			qcom,cam-vreg-type = <0 0 1>;
-			qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
-			qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
-			qcom,cam-vreg-op-mode = <105000 80000 0>;
-			qcom,gpio-no-mux = <0>;
-			gpios = <&msmgpio 16 0>,
-				<&msmgpio 19 0>,
-				<&msmgpio 20 0>,
-				<&msmgpio 92 0>;
-			qcom,gpio-common-tbl-num = <0 1 2>;
-			qcom,gpio-common-tbl-flags = <1 1 1>;
-			qcom,gpio-common-tbl-label = "CAMIF_MCLK",
-						     "CAMIF_I2C_DATA",
-						     "CAMIF_I2C_CLK";
-			qcom,gpio-req-tbl-num = <3>;
-			qcom,gpio-req-tbl-flags = <0>;
-			qcom,gpio-req-tbl-label = "CAM_RESET1";
-			qcom,gpio-set-tbl-num = <3 3>;
-			qcom,gpio-set-tbl-flags = <0 2>;
-			qcom,gpio-set-tbl-delay = <1000 4000>;
-			qcom,csi-lane-assign = <0x4320>;
-			qcom,csi-lane-mask = <0x7>;
-			qcom,csi-phy-sel = <1>;
-			qcom,camera-type = <1>;
-			qcom,sensor-type = <0>;
+			status = "disable";
 		};
 
 		qcom,camera@90 {
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 6004d15..e1b2863 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -11,6 +11,7 @@
  */
 
 /include/ "dsi-panel-toshiba-720p-video.dtsi"
+/include/ "msm8974-camera-sensor.dtsi"
 
 / {
 	serial@f991e000 {
@@ -152,6 +153,43 @@
 			vdd-phy-supply = <&spi_eth_vreg>;
 		};
 	};
+
+	sound {
+		compatible = "qcom,msm8974-audio-taiko";
+		qcom,model = "msm8974-taiko-cdp-snd-card";
+
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"Ext Spk Bottom Pos", "LINEOUT1",
+			"Ext Spk Bottom Neg", "LINEOUT3",
+			"Ext Spk Top Pos", "LINEOUT2",
+			"Ext Spk Top Neg", "LINEOUT4",
+			"AMIC1", "MIC BIAS1 Internal1",
+			"MIC BIAS1 Internal1", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCLeft Headset Mic",
+			"DMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic1",
+			"DMIC2", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic2",
+			"DMIC3", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic3",
+			"DMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic4",
+			"DMIC5", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic5",
+			"DMIC6", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic6";
+
+		qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
+		taiko-mclk-clk = <&pm8941_clkdiv1>;
+		qcom,taiko-mclk-clk-freq = <9600000>;
+	};
 };
 
 &sdcc2 {
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 938bc22..15fb799 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -11,6 +11,7 @@
  */
 
 /include/ "dsi-panel-toshiba-720p-video.dtsi"
+/include/ "msm8974-camera-sensor.dtsi"
 
 / {
 	serial@f991e000 {
@@ -152,6 +153,43 @@
 			vdd-phy-supply = <&spi_eth_vreg>;
 		};
 	};
+
+	sound {
+		compatible = "qcom,msm8974-audio-taiko";
+		qcom,model = "msm8974-taiko-fluid-snd-card";
+
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"Ext Spk Bottom Pos", "LINEOUT1",
+			"Ext Spk Bottom Neg", "LINEOUT3",
+			"Ext Spk Top Pos", "LINEOUT2",
+			"Ext Spk Top Neg", "LINEOUT4",
+			"AMIC1", "MIC BIAS1 Internal1",
+			"MIC BIAS1 Internal1", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCLeft Headset Mic",
+			"DMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic1",
+			"DMIC2", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic2",
+			"DMIC3", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic3",
+			"DMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic4",
+			"DMIC5", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic5",
+			"DMIC6", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic6";
+
+		qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
+		taiko-mclk-clk = <&pm8941_clkdiv1>;
+		qcom,taiko-mclk-clk-freq = <9600000>;
+	};
 };
 
 &sdcc1 {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 68207af..f391621 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -10,6 +10,8 @@
  * GNU General Public License for more details.
  */
 
+/include/ "msm8974-camera-sensor-liquid.dtsi"
+
 / {
 	serial@f991e000 {
 		status = "ok";
@@ -76,6 +78,32 @@
 		status = "ok";
 	};
 
+	drv2667_vreg: drv2667_vdd_vreg {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_drv2667";
+	};
+
+	i2c@f9967000 {
+		ti-drv2667@59 {
+			compatible = "ti,drv2667";
+			reg = <0x59>;
+			vdd-supply = <&drv2667_vreg>;
+			vdd-i2c-supply = <&pm8941_s3>;
+			ti,label = "vibrator";
+			ti,gain = <2>;
+			ti,idle-timeout-ms = <20>;
+			ti,max-runtime-ms = <15000>;
+			ti,mode = <2>;
+			ti,wav-seq = [
+				/* wave form id */
+				01
+				/* header size, start and stop bytes */
+				05 80 06 00 09
+				/* repeat, amp, freq, duration, envelope */
+				01 ff 19 02 00];
+		};
+	};
+
 	i2c@f9924000 {
 		atmel_mxt_ts@4a {
 			compatible = "atmel,mxt-ts";
@@ -176,6 +204,7 @@
 		compatible = "regulator-fixed";
 		regulator-name = "ext_5v";
 		gpio = <&pm8941_mpps 2 0>;
+		startup-delay-us = <12000>;
 		enable-active-high;
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index 6553fc0..e2c80c2 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -11,6 +11,7 @@
  */
 
 /include/ "dsi-panel-toshiba-720p-video.dtsi"
+/include/ "msm8974-camera-sensor.dtsi"
 
 / {
 	serial@f991e000 {
@@ -152,6 +153,43 @@
 			vdd-phy-supply = <&spi_eth_vreg>;
 		};
 	};
+
+	sound {
+		compatible = "qcom,msm8974-audio-taiko";
+		qcom,model = "msm8974-taiko-mtp-snd-card";
+
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"Ext Spk Bottom Pos", "LINEOUT1",
+			"Ext Spk Bottom Neg", "LINEOUT3",
+			"Ext Spk Top Pos", "LINEOUT2",
+			"Ext Spk Top Neg", "LINEOUT4",
+			"AMIC1", "MIC BIAS1 Internal1",
+			"MIC BIAS1 Internal1", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS2 External",
+			"MIC BIAS2 External", "ANCLeft Headset Mic",
+			"DMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic1",
+			"DMIC2", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic2",
+			"DMIC3", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic3",
+			"DMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic4",
+			"DMIC5", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic5",
+			"DMIC6", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic6";
+
+		qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
+		taiko-mclk-clk = <&pm8941_clkdiv1>;
+		qcom,taiko-mclk-clk-freq = <9600000>;
+	};
 };
 
 &sdcc2 {
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index 5a16be7..33656cd 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -10,6 +10,8 @@
  * GNU General Public License for more details.
  */
 
+/include/ "msm8974-camera-sensor.dtsi"
+
 / {
 	timer {
 		clock-frequency = <5000000>;
diff --git a/arch/arm/boot/dts/msm8974-sim.dtsi b/arch/arm/boot/dts/msm8974-sim.dtsi
index 41e37de..8e8b3c3 100644
--- a/arch/arm/boot/dts/msm8974-sim.dtsi
+++ b/arch/arm/boot/dts/msm8974-sim.dtsi
@@ -11,6 +11,7 @@
  */
 
 /include/ "dsi-panel-sim-video.dtsi"
+/include/ "msm8974-camera-sensor.dtsi"
 
 / {
 	qcom,mdss_dsi@fd922800 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 0e30129..20249be 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1216,6 +1216,74 @@
                 compatible = "qcom,msm-mem-hole";
                 qcom,memblock-remove = <0x8400000 0x7b00000>; /* Address and Size of Hole */
         };
+
+	qcom,smem@fa00000 {
+		compatible = "qcom,smem";
+		reg = <0xfa00000 0x200000>,
+			<0xfa006000 0x1000>,
+			<0xfc428000 0x4000>;
+		reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+		qcom,smd-modem {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <0>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1000>;
+			qcom,pil-string = "modem";
+			interrupts = <0 25 1>;
+		};
+
+		qcom,smsm-modem {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <0>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x2000>;
+			interrupts = <0 26 1>;
+		};
+
+		qcom,smd-adsp {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <1>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x100>;
+			qcom,pil-string = "adsp";
+			interrupts = <0 156 1>;
+		};
+
+		qcom,smsm-adsp {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <1>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x200>;
+			interrupts = <0 157 1>;
+		};
+
+		qcom,smd-wcnss {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <6>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x20000>;
+			qcom,pil-string = "wcnss";
+			interrupts = <0 142 1>;
+		};
+
+		qcom,smsm-wcnss {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <6>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x80000>;
+			interrupts = <0 144 1>;
+		};
+
+		qcom,smd-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			qcom,irq-no-suspend;
+		};
+	};
 };
 
 /include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm9625-cdp.dts b/arch/arm/boot/dts/msm9625-cdp.dts
index ba5bbcf..232fba7 100644
--- a/arch/arm/boot/dts/msm9625-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-cdp.dts
@@ -37,6 +37,14 @@
 			summit,temperature-max = <3>; /* 45 C */
 		};
 	};
+
+	wlan0: qca,wlan {
+		cell-index = <0>;
+		compatible = "qca,ar6004-sdio";
+		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+	};
 };
 
 /* PM8019 GPIO and MPP configuration */
diff --git a/arch/arm/boot/dts/msm9625-mtp.dts b/arch/arm/boot/dts/msm9625-mtp.dts
index 7780686..faf86d4 100644
--- a/arch/arm/boot/dts/msm9625-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-mtp.dts
@@ -37,6 +37,14 @@
 			summit,temperature-max = <3>; /* 45 C */
 		};
 	};
+
+	wlan0: qca,wlan {
+		cell-index = <0>;
+		compatible = "qca,ar6004-sdio";
+		qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+		qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+		qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+	};
 };
 
 /* PM8019 GPIO and MPP configuration */
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 26f8ab7..b79f370 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -98,25 +98,26 @@
 		interrupt-names = "bam_irq";
 	};
 
-	spi@f9928000 {
+	spi@f9924000 {
+		cell-index = <0>;
 		compatible = "qcom,spi-qup-v2";
-		reg = <0xf9928000 0x1000>;
-		interrupts = <0 100 0>;
-		spi-max-frequency = <24000000>;
+		reg = <0xf9924000 0x1000>;
+		interrupts = <0 96 0>;
+		spi-max-frequency = <25000000>;
 		#address-cells = <1>;
 		#size-cells = <0>;
-		gpios = <&msmgpio 23 0>, /* CLK  */
-			<&msmgpio 21 0>, /* MISO */
-			<&msmgpio 20 0>; /* MOSI */
+		gpios = <&msmgpio 7 0>, /* CLK  */
+			<&msmgpio 5 0>, /* MISO */
+			<&msmgpio 4 0>; /* MOSI */
 
-		cs-gpios = <&msmgpio 69 0>;
+		cs-gpios = <&msmgpio 6 0>;
 
 		ethernet-switch@0 {
 			compatible = "simtec,ks8851";
 			reg = <0>;
 			interrupt-parent = <&msmgpio>;
 			interrupts = <75 0>;
-			spi-max-frequency = <5000000>;
+			spi-max-frequency = <4800000>;
 		};
 	};
 
@@ -268,6 +269,177 @@
 		qcom,sensors = <5>;
 		qcom,slope = <3200 3200 3200 3200 3200>;
 	};
+
+	qcom,msm-rng@f9bff000 {
+                compatible = "qcom,msm-rng";
+                reg = <0xf9bff000 0x200>;
+                qcom,msm-rng-iface-clk;
+	};
+
+	wcd9xxx_intc: wcd9xxx-irq {
+		compatible = "qcom,wcd9xxx-irq";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupt-parent = <&msmgpio>;
+		interrupts = <20 0>;
+		interrupt-names = "cdc-int";
+	};
+
+	i2c@f9925000 {
+		cell-index = <3>;
+		compatible = "qcom,i2c-qup";
+		reg = <0xf9925000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		interrupts = <0 97 0>;
+		interrupt-names = "qup_err_intr";
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <24000000>;
+
+		wcd9xxx_codec@0d{
+			compatible = "qcom,wcd9xxx-i2c";
+			reg = <0x0d>;
+			qcom,cdc-reset-gpio = <&msmgpio 22 0>;
+			interrupt-parent = <&wcd9xxx_intc>;
+			interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28>;
+			cdc-vdd-buck-supply = <&pm8019_l11>;
+			qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+			qcom,cdc-vdd-buck-current = <25000>;
+
+			cdc-vdd-tx-h-supply = <&pm8019_l11>;
+			qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+			qcom,cdc-vdd-tx-h-current = <25000>;
+
+			cdc-vdd-rx-h-supply = <&pm8019_l11>;
+			qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+			qcom,cdc-vdd-rx-h-current = <25000>;
+
+			cdc-vddpx-1-supply = <&pm8019_l11>;
+			qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+			qcom,cdc-vddpx-1-current = <10000>;
+
+			cdc-vdd-a-1p2v-supply = <&pm8019_l9>;
+			qcom,cdc-vdd-a-1p2v-voltage = <1200000 1200000>;
+			qcom,cdc-vdd-a-1p2v-current = <10000>;
+
+			cdc-vddcx-1-supply = <&pm8019_l9>;
+			qcom,cdc-vddcx-1-voltage = <1200000 1200000>;
+			qcom,cdc-vddcx-1-current = <10000>;
+
+			cdc-vddcx-2-supply = <&pm8019_l9>;
+			qcom,cdc-vddcx-2-voltage = <1200000 1200000>;
+			qcom,cdc-vddcx-2-current = <10000>;
+
+			qcom,cdc-micbias-ldoh-v = <0x3>;
+			qcom,cdc-micbias-cfilt1-mv = <1800>;
+			qcom,cdc-micbias-cfilt2-mv = <2700>;
+			qcom,cdc-micbias-cfilt3-mv = <1800>;
+			qcom,cdc-micbias1-cfilt-sel = <0x0>;
+			qcom,cdc-micbias2-cfilt-sel = <0x1>;
+			qcom,cdc-micbias3-cfilt-sel = <0x2>;
+			qcom,cdc-micbias4-cfilt-sel = <0x2>;
+		};
+
+		wcd9xxx_codec@77{
+			compatible = "qcom,wcd9xxx-i2c";
+			reg = <0x77>;
+		};
+
+		wcd9xxx_codec@66{
+			compatible = "qcom,wcd9xxx-i2c";
+			reg = <0x66>;
+		};
+
+		wcd9xxx_codec@55{
+			compatible = "qcom,wcd9xxx-i2c";
+			reg = <0x55>;
+		};
+	};
+
+	sound {
+		compatible = "qcom,mdm9625-audio-taiko";
+		qcom,model = "mdm9625-taiko-i2s-snd-card";
+
+		qcom,audio-routing =
+			"RX_BIAS", "MCLK",
+			"LDO_H", "MCLK",
+			"Ext Spk Bottom Pos", "LINEOUT1",
+			"Ext Spk Bottom Neg", "LINEOUT3",
+			"Ext Spk Top Pos", "LINEOUT2",
+			"Ext Spk Top Neg", "LINEOUT4",
+			"AMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Handset Mic",
+			"AMIC2", "MIC BIAS2 External",
+			"MIC BIAS2 External", "Headset Mic",
+			"AMIC3", "MIC BIAS3 Internal1",
+			"MIC BIAS3 Internal1", "ANCRight Headset Mic",
+			"AMIC4", "MIC BIAS1 Internal2",
+			"MIC BIAS1 Internal2", "ANCLeft Headset Mic",
+			"DMIC1", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic1",
+			"DMIC2", "MIC BIAS1 External",
+			"MIC BIAS1 External", "Digital Mic2",
+			"DMIC3", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic3",
+			"DMIC4", "MIC BIAS3 External",
+			"MIC BIAS3 External", "Digital Mic4",
+			"DMIC5", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic5",
+			"DMIC6", "MIC BIAS4 External",
+			"MIC BIAS4 External", "Digital Mic6";
+			qcom,taiko-mclk-clk-freq = <12288000>;
+	};
+
+	qcom,msm-adsp-loader {
+		compatible = "qcom,adsp-loader";
+	};
+
+	qcom,msm-pcm {
+		compatible = "qcom,msm-pcm-dsp";
+	};
+
+	qcom,msm-pcm-routing {
+		compatible = "qcom,msm-pcm-routing";
+	};
+
+	qcom,msm-compr-dsp {
+		compatible = "qcom,msm-compr-dsp";
+	};
+
+	qcom,msm-voip-dsp {
+		compatible = "qcom,msm-voip-dsp";
+	};
+
+	qcom,msm-pcm-voice {
+		compatible = "qcom,msm-pcm-voice";
+	};
+
+	qcom,msm-dai-fe {
+		compatible = "qcom,msm-dai-fe";
+	};
+
+	qcom,msm-pcm-afe {
+		compatible = "qcom,msm-pcm-afe";
+	};
+
+	qcom,msm-pcm-hostless {
+		compatible = "qcom,msm-pcm-hostless";
+	};
+
+	qcom,msm-dai-mi2s {
+		compatible = "qcom,msm-dai-mi2s";
+		qcom,msm-dai-q6-mi2s-prim {
+			compatible = "qcom,msm-dai-q6-mi2s";
+			qcom,msm-dai-q6-mi2s-dev-id = <0>;
+			qcom,msm-mi2s-rx-lines = <2>;
+			qcom,msm-mi2s-tx-lines = <1>;
+		};
+	};
+
+	qcom,msm-dai-q6 {
+		compatible = "qcom,msm-dai-q6";
+	};
 };
 
 /include/ "msm-pm8019-rpm-regulator.dtsi"
@@ -329,10 +501,4 @@
 		qcom,hw-settle-time = <0>;
 		qcom,fast-avg-setup = <0>;
 	};
-
-	qcom,msm-rng@f9bff000 {
-		compatible = "qcom,msm-rng";
-		reg = <0xf9bff000 0x200>;
-		qcom,msm-rng-iface-clk;
-	};
 };
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 4b84923..b9add04 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -121,6 +121,7 @@
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
@@ -203,3 +204,50 @@
 CONFIG_LIBCRC32C=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
 CONFIG_MSM_QDSS=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER_XT_MARK=y
+CONFIG_NETFILTER_XT_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_IP_SET=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP_NF_TARGET_ULOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_ECN=y
+CONFIG_IP_NF_TARGET_TTL=y
+CONFIG_IP_NF_RAW=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_AH=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_HL=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+CONFIG_IP6_NF_MATCH_RT=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index cd5be28..f705388 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -37,6 +37,7 @@
 #define MT_MEMORY_RW		16
 #define MT_MEMORY_RX		17
 #define MT_MEMORY_DMA_READY	18
+#define MT_DEVICE_USER_ACCESSIBLE	19
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
diff --git a/arch/arm/include/asm/user_accessible_timer.h b/arch/arm/include/asm/user_accessible_timer.h
new file mode 100644
index 0000000..c6d7bd4
--- /dev/null
+++ b/arch/arm/include/asm/user_accessible_timer.h
@@ -0,0 +1,49 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ARM_KERNEL_USER_ACCESSIBLE_TIMER_H_
+#define _ARM_KERNEL_USER_ACCESSIBLE_TIMER_H_
+
+#define ARM_USER_ACCESSIBLE_TIMERS_INVALID_PAGE -1
+
+extern unsigned long zero_pfn;
+
+#ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
+#ifndef CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE
+#define CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE 0xfffef000
+#endif
+extern void setup_user_timer_offset(unsigned long addr);
+extern int get_timer_page_address(void);
+static inline int get_user_accessible_timers_base(void)
+{
+	return CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE;
+}
+extern void set_user_accessible_timer_flag(bool flag);
+#else
+#define CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE 0
+static inline void setup_user_timer_offset(unsigned long addr)
+{
+}
+static inline int get_timer_page_address(void)
+{
+	return ARM_USER_ACCESSIBLE_TIMERS_INVALID_PAGE;
+}
+static inline int get_user_accessible_timers_base(void)
+{
+	return 0;
+}
+static inline void set_user_accessible_timer_flag(bool flag)
+{
+}
+#endif
+
+#endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 22b0f1e..fc00a23 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -63,6 +63,7 @@
 obj-$(CONFIG_SWP_EMULATE)	+= swp_emulate.o
 CFLAGS_swp_emulate.o		:= -Wa,-march=armv7-a
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
+obj-$(CONFIG_GENERIC_TIME_VSYSCALL)	+= update_vsyscall_arm.o
 
 obj-$(CONFIG_CPU_XSCALE)	+= xscale-cp0.o
 obj-$(CONFIG_CPU_XSC3)		+= xscale-cp0.o
@@ -73,6 +74,7 @@
 obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
+obj-$(CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS)	+= user_accessible_timer.o
 
 ifneq ($(CONFIG_ARCH_EBSA110),y)
   obj-y		+= io.o
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 7a8c2d6..ddd421c 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -764,6 +764,97 @@
 	.align	5
 	.globl	__kuser_helper_start
 __kuser_helper_start:
+#ifdef GENERIC_TIME_VSYSCALL
+/*
+ * Reference declaration:
+ *
+ *      extern struct timezone __kernel_helper_gtod_timezone
+ *      extern unsigned int __kernel_helper_gtod_seqnum
+ *
+ *  Definition and user space usage example:
+ *
+ *      #define __kernel_helper_gtod_timezone (*(unsigned int*)0xffff0f20)
+ *      #define __kernel_helper_gtod_seqnum   (*(unsigned int*)0xffff0f28)
+ *
+ *      unsigned int prelock, postlock ;
+ *      do {
+ *          prelock = __kernel_helper_gtod_seqnum;
+ *          memcpy(&tz, (void*)&(__kernel_helper_gtod_timezone),
+ *                     sizeof(struct timezone)) ;
+ *          postlock = __kernel_helper_gtod_seqnum;
+ *      } while (prelock != postlock);
+ *
+ * 0xffff0f20-3: tz_minuteswest
+ * 0xffff0f24-7: tz_dsttime
+ * 0xffff0f28-b: sequence #.
+ * 0xffff0f30-3: offset into CONFIG_USER_ACCESSIBLE_TIMER_BASE to get the timer.
+ * 0xffff0f34-7: Feature flag
+ * 0xffff0f38-b: wall-to-mononic: tv_sec
+ * 0xffff0f3c-f: wall-to-mononic: tv_nsec
+ */
+	.globl  __kuser_gtod_timezone
+__kuser_gtod_timezone: @0xffff0f20
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	/* This offset is where the flag to enable the
+	 * user accessible timers is located.
+	 */
+	.word	0
+	.word	0
+	.word	0
+	.align	5
+
+/*
+ * Reference declaration:
+ *
+ *      extern struct timeval __kernel_helper_gtod_timeval
+ *      extern unsigned int __kernel_helper_gtod_seqnum
+ *
+ *  Definition and user space usage example:
+ *
+ *      #define __kernel_helper_gtod_timeval (*(unsigned int*)0xffff0f40)
+ *      #define __kernel_helper_gtod_seqnum   (*(unsigned int*)0xffff0f48)
+ *
+ *      unsigned int prelock, postlock ;
+ *      struct gtod {
+ *          uint64_t  cycle_last;
+ *          uint64_t  mask;
+ *          uint32_t  mult;
+ *          uint32_t  shift;
+ *          uint32_t  tv_sec;
+ *          uint32_t  tv_nsec;
+ *      };
+ *      struct gtod gdtod;
+ *
+ *      do {
+ *          prelock = __kernel_helper_gtod_seqnum;
+ *          memcpy(&gdtod, (void*)&(__kernel_helper_gtod_timeval),
+ *                     sizeof(struct gtod)) ;
+ *          postlock = __kernel_helper_gtod_seqnum;
+ *      } while (prelock != postlock);
+ *
+ * 0xffff0f40-7: cycle_last
+ * 0xffff0f48-f: mask
+ * 0xffff0f50-3: mult
+ * 0xffff0f54-7: shift
+ * 0xffff0f58-b: tv_sec
+ * 0xffff0f5c-f: tv_nsec
+ */
+	.globl  __kuser_gtod_timeval
+__kuser_gtod_timeval:  @0xffff0f40
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.word	0
+	.align	5
+#endif
 
 /*
  * Due to the length of some sequences, __kuser_cmpxchg64 spans 2 regular
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index af21496..ac17480 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -680,6 +680,11 @@
 
 const char *arch_vma_name(struct vm_area_struct *vma)
 {
-	return (vma == &gate_vma) ? "[vectors]" : NULL;
+	if (vma == &gate_vma)
+		return "[vectors]";
+	else if (vma == get_user_timers_vma(NULL))
+		return "[timers]";
+	else
+		return NULL;
 }
 #endif
diff --git a/arch/arm/kernel/update_vsyscall_arm.c b/arch/arm/kernel/update_vsyscall_arm.c
new file mode 100644
index 0000000..51f47ae
--- /dev/null
+++ b/arch/arm/kernel/update_vsyscall_arm.c
@@ -0,0 +1,100 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/clocksource.h>
+#include <linux/time.h>
+#include "update_vsyscall_arm.h"
+/*
+ * See entry-armv.S for the offsets into the kernel user helper for
+ * these fields.
+ */
+#define ARM_VSYSCALL_TIMER_TZ			0xf20
+#define ARM_VSYSCALL_TIMER_SEQ			0xf28
+#define ARM_VSYSCALL_TIMER_OFFSET		0xf30
+#define ARM_VSYSCALL_TIMER_WTM_TV_SEC		0xf38
+#define ARM_VSYSCALL_TIMER_WTM_TV_NSEC		0xf3c
+#define ARM_VSYSCALL_TIMER_CYCLE_LAST		0xf40
+#define ARM_VSYSCALL_TIMER_MASK			0xf48
+#define ARM_VSYSCALL_TIMER_MULT			0xf50
+#define ARM_VSYSCALL_TIMER_SHIFT		0xf54
+#define ARM_VSYSCALL_TIMER_TV_SEC		0xf58
+#define ARM_VSYSCALL_TIMER_TV_NSEC		0xf5c
+
+struct kernel_gtod_t {
+	u64  cycle_last;
+	u64  mask;
+	u32  mult;
+	u32  shift;
+	u32  tv_sec;
+	u32  tv_nsec;
+};
+
+struct kernel_tz_t {
+	u32  tz_minuteswest;
+	u32  tz_dsttime;
+};
+
+struct kernel_wtm_t {
+	u32  tv_sec;
+	u32  tv_nsec;
+};
+
+/*
+ * Updates the kernel user helper area with the current timespec
+ * data, as well as additional fields needed to calculate
+ * gettimeofday, clock_gettime, etc.
+ */
+void
+update_vsyscall(struct timespec *ts, struct timespec *wtm,
+	struct clocksource *c, u32 mult)
+{
+	unsigned long vectors = (unsigned long)vectors_page;
+	unsigned long flags;
+	unsigned *seqnum = (unsigned *)(vectors + ARM_VSYSCALL_TIMER_SEQ);
+	struct kernel_gtod_t *dgtod = (struct kernel_gtod_t *)(vectors +
+		ARM_VSYSCALL_TIMER_CYCLE_LAST);
+	struct kernel_wtm_t *dgwtm = (struct kernel_wtm_t *)(vectors +
+		ARM_VSYSCALL_TIMER_WTM_TV_SEC);
+
+	write_seqlock_irqsave(&kuh_time_lock, flags);
+	*seqnum = kuh_time_lock.sequence;
+	dgtod->cycle_last = c->cycle_last;
+	dgtod->mask = c->mask;
+	dgtod->mult = c->mult;
+	dgtod->shift = c->shift;
+	dgtod->tv_sec = ts->tv_sec;
+	dgtod->tv_nsec = ts->tv_nsec;
+	dgwtm->tv_sec = wtm->tv_sec;
+	dgwtm->tv_nsec = wtm->tv_nsec;
+	*seqnum = kuh_time_lock.sequence + 1;
+	write_sequnlock_irqrestore(&kuh_time_lock, flags);
+}
+EXPORT_SYMBOL(update_vsyscall);
+
+void
+update_vsyscall_tz(void)
+{
+	unsigned long vectors = (unsigned long)vectors_page;
+	unsigned long flags;
+	unsigned *seqnum = (unsigned *)(vectors + ARM_VSYSCALL_TIMER_SEQ);
+	struct kernel_tz_t *dgtod = (struct kernel_tz_t *)(vectors +
+		ARM_VSYSCALL_TIMER_TZ);
+
+	write_seqlock_irqsave(&kuh_time_lock, flags);
+	*seqnum = kuh_time_lock.sequence;
+	dgtod->tz_minuteswest = sys_tz.tz_minuteswest;
+	dgtod->tz_dsttime = sys_tz.tz_dsttime;
+	*seqnum = kuh_time_lock.sequence + 1;
+	write_sequnlock_irqrestore(&kuh_time_lock, flags);
+}
+EXPORT_SYMBOL(update_vsyscall_tz);
diff --git a/arch/arm/kernel/update_vsyscall_arm.h b/arch/arm/kernel/update_vsyscall_arm.h
new file mode 100644
index 0000000..d06ca56
--- /dev/null
+++ b/arch/arm/kernel/update_vsyscall_arm.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/export.h>
+#include <linux/clocksource.h>
+#include <linux/time.h>
+
+extern void *vectors_page;
+extern struct timezone sys_tz;
+
+/*
+ * This read-write spinlock protects us from races in SMP while
+ * updating the kernel user helper-embedded time.
+ */
+__cacheline_aligned_in_smp DEFINE_SEQLOCK(kuh_time_lock);
diff --git a/arch/arm/kernel/user_accessible_timer.c b/arch/arm/kernel/user_accessible_timer.c
new file mode 100644
index 0000000..c550c03
--- /dev/null
+++ b/arch/arm/kernel/user_accessible_timer.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/user_accessible_timer.h>
+#include <asm/traps.h>
+
+#define USER_ACCESS_TIMER_OFFSET	0xf30
+#define USER_ACCESS_FEATURE_OFFSET	0xf34
+#define USER_ACCESS_FEATURE_FLAG	0xffff0f20
+
+static struct vm_area_struct user_timers_vma;
+static int __init user_timers_vma_init(void)
+{
+	user_timers_vma.vm_start        = CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE;
+	user_timers_vma.vm_end          = CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE
+						+ PAGE_SIZE;
+	user_timers_vma.vm_page_prot    = PAGE_READONLY;
+	user_timers_vma.vm_flags        = VM_READ | VM_MAYREAD;
+	return 0;
+}
+arch_initcall(user_timers_vma_init);
+
+int in_user_timers_area(struct mm_struct *mm, unsigned long addr)
+{
+	return (addr >= user_timers_vma.vm_start) &&
+		(addr < user_timers_vma.vm_end);
+}
+EXPORT_SYMBOL(in_user_timers_area);
+
+struct vm_area_struct *get_user_timers_vma(struct mm_struct *mm)
+{
+	return &user_timers_vma;
+}
+EXPORT_SYMBOL(get_user_timers_vma);
+
+int get_user_timer_page(struct vm_area_struct *vma,
+	struct mm_struct *mm, unsigned long start, unsigned int gup_flags,
+	struct page **pages, int idx, int *goto_next_page)
+{
+	/* Replicates the earlier work done in mm/memory.c */
+	unsigned long pg = start & PAGE_MASK;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	/* Unset this flag -- this only gets activated if the
+	 * caller should go straight to the next_page label on
+	 * return.
+	 */
+	*goto_next_page = 0;
+
+	/* user gate pages are read-only */
+	if (gup_flags & FOLL_WRITE)
+		return idx ? : -EFAULT;
+	if (pg > TASK_SIZE)
+		pgd = pgd_offset_k(pg);
+	else
+		pgd = pgd_offset_gate(mm, pg);
+	BUG_ON(pgd_none(*pgd));
+	pud = pud_offset(pgd, pg);
+	BUG_ON(pud_none(*pud));
+	pmd = pmd_offset(pud, pg);
+	if (pmd_none(*pmd))
+		return idx ? : -EFAULT;
+	VM_BUG_ON(pmd_trans_huge(*pmd));
+	pte = pte_offset_map(pmd, pg);
+	if (pte_none(*pte)) {
+		pte_unmap(pte);
+		return idx ? : -EFAULT;
+	}
+	vma = get_user_timers_vma(mm);
+	if (pages) {
+		struct page *page;
+
+		page = vm_normal_page(vma, start, *pte);
+		if (!page) {
+			if (!(gup_flags & FOLL_DUMP) &&
+				zero_pfn == pte_pfn(*pte))
+				page = pte_page(*pte);
+			else {
+				pte_unmap(pte);
+				return idx ? : -EFAULT;
+			}
+		}
+		pages[idx] = page;
+		get_page(page);
+	}
+	pte_unmap(pte);
+	/* In this case, set the next page */
+	*goto_next_page = 1;
+	return 0;
+}
+EXPORT_SYMBOL(get_user_timer_page);
+
+void setup_user_timer_offset(unsigned long addr)
+{
+#if defined(CONFIG_CPU_USE_DOMAINS)
+	unsigned long vectors = CONFIG_VECTORS_BASE;
+#else
+	unsigned long vectors = (unsigned long)vectors_page;
+#endif
+	unsigned long *timer_offset = (unsigned long *)(vectors +
+		USER_ACCESS_TIMER_OFFSET);
+	*timer_offset = addr;
+}
+EXPORT_SYMBOL(setup_user_timer_offset);
+
+void set_user_accessible_timer_flag(bool flag)
+{
+#if defined(CONFIG_CPU_USE_DOMAINS)
+	unsigned long vectors = CONFIG_VECTORS_BASE;
+#else
+	unsigned long vectors = (unsigned long)vectors_page;
+#endif
+	unsigned long *timer_offset = (unsigned long *)(vectors +
+		USER_ACCESS_FEATURE_OFFSET);
+	*timer_offset = (flag ? USER_ACCESS_FEATURE_FLAG : 0);
+}
+EXPORT_SYMBOL(set_user_accessible_timer_flag);
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index dbb4328..a0868c7 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -177,6 +177,10 @@
 	select ARM_HAS_SG_CHAIN
 	select MSM_KRAIT_WFE_FIXUP
 	select MSM_ULTRASOUND_A
+	select GENERIC_TIME_VSYSCALL
+	select USE_USER_ACCESSIBLE_TIMERS
+	select ARM_USE_USER_ACCESSIBLE_TIMERS
+	select MSM_USE_USER_ACCESSIBLE_TIMERS
 
 config ARCH_MSM8930
 	bool "MSM8930"
@@ -209,6 +213,10 @@
 	select HOLES_IN_ZONE if SPARSEMEM
 	select ARM_HAS_SG_CHAIN
 	select MSM_KRAIT_WFE_FIXUP
+	select GENERIC_TIME_VSYSCALL
+	select USE_USER_ACCESSIBLE_TIMERS
+	select ARM_USE_USER_ACCESSIBLE_TIMERS
+	select MSM_USE_USER_ACCESSIBLE_TIMERS
 
 config ARCH_APQ8064
 	bool "APQ8064"
@@ -237,6 +245,10 @@
 	select ARM_HAS_SG_CHAIN
 	select MSM_KRAIT_WFE_FIXUP
 	select MSM_ULTRASOUND_A
+	select GENERIC_TIME_VSYSCALL
+	select USE_USER_ACCESSIBLE_TIMERS
+	select ARM_USE_USER_ACCESSIBLE_TIMERS
+	select MSM_USE_USER_ACCESSIBLE_TIMERS
 
 config ARCH_MSM8974
 	bool "MSM8974"
@@ -349,6 +361,9 @@
 	select SPARSE_IRQ
 	select MSM_MULTIMEDIA_USE_ION
 	select MSM_RPM_STATS_LOG
+	select MSM_QDSP6_APRV2
+	select MSM_QDSP6V2_CODECS
+	select MSM_AUDIO_QDSP6V2 if SND_SOC
 
 config ARCH_MSM8910
 	bool "MSM8910"
@@ -2661,4 +2676,12 @@
 	  if apps is not responding and holding lock with irqs disabled.
 	  Modem will then generate an raise a FIQ on this line before sending
 	  SMSM reset.
+
+config MSM_USE_USER_ACCESSIBLE_TIMERS
+	bool "Enables mapping an MSM timer counter page to user space."
+	depends on ARM_USE_USER_ACCESSIBLE_TIMERS
+	help
+	  Enables MSM-specific user accessible timers via a shared
+	  memory page containing the cycle counter.
+
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 88ed433..8690df8 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -282,6 +282,7 @@
 obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
 obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
 obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
+obj-$(CONFIG_QPNP_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
 obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_LIQUID) += board-8064-all.o board-8064-regulator.o
@@ -397,6 +398,8 @@
 
 obj-$(CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL) += wdog_debug.o
 
+obj-$(CONFIG_MSM_USE_USER_ACCESSIBLE_TIMERS) += timer_page.o
+
 ifdef CONFIG_MSM_CPR
 obj-$(CONFIG_DEBUG_FS) += msm_cpr-debug.o
 endif
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index bf57eab..b9d0527 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -33,6 +33,7 @@
 #include <mach/rpm-regulator.h>
 #include <mach/rpm-regulator-smd.h>
 #include <mach/msm_bus.h>
+#include <mach/msm_dcvs.h>
 
 #include "acpuclock.h"
 #include "acpuclock-krait.h"
@@ -951,6 +952,17 @@
 static void __init cpufreq_table_init(void) {}
 #endif
 
+static void __init dcvs_freq_init(void)
+{
+	int i;
+
+	for (i = 0; drv.acpu_freq_tbl[i].speed.khz != 0; i++)
+		if (drv.acpu_freq_tbl[i].use_for_scaling)
+			msm_dcvs_register_cpu_freq(
+				drv.acpu_freq_tbl[i].speed.khz,
+				drv.acpu_freq_tbl[i].vdd_core / 1000);
+}
+
 static int __cpuinit acpuclk_cpu_callback(struct notifier_block *nfb,
 					    unsigned long action, void *hcpu)
 {
@@ -1156,6 +1168,7 @@
 	hw_init();
 
 	cpufreq_table_init();
+	dcvs_freq_init();
 	acpuclk_register(&acpuclk_krait_data);
 	register_hotcpu_notifier(&acpuclk_cpu_notifier);
 
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index a358bba..fe2d2d2 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -419,14 +419,14 @@
 
 static struct pm8xxx_ccadc_platform_data
 apq8064_pm8xxx_ccadc_pdata = {
-	.r_sense		= 10,
+	.r_sense_uohm		= 10000,
 	.calib_delay_ms		= 600000,
 };
 
 static struct pm8921_bms_platform_data
 apq8064_pm8921_bms_pdata __devinitdata = {
 	.battery_type			= BATT_UNKNOWN,
-	.r_sense			= 10,
+	.r_sense_uohm			= 10000,
 	.v_cutoff			= 3400,
 	.max_voltage_uv			= MAX_VOLTAGE_MV * 1000,
 	.rconn_mohm			= 18,
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 314bfd0..95246a7 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -693,12 +693,6 @@
 static struct msm_bus_vectors hsic_init_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_SPS,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 0,
-		.ib = 0,
-	},
-	{
-		.src = MSM_BUS_MASTER_SPS,
 		.dst = MSM_BUS_SLAVE_SPS,
 		.ab = 0,
 		.ib = 0,
@@ -709,15 +703,9 @@
 static struct msm_bus_vectors hsic_max_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_SPS,
-		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab = 60000000,		/* At least 480Mbps on bus. */
-		.ib = 960000000,	/* MAX bursts rate */
-	},
-	{
-		.src = MSM_BUS_MASTER_SPS,
 		.dst = MSM_BUS_SLAVE_SPS,
 		.ab = 0,
-		.ib = 512000000, /*vote for 64Mhz dfab clk rate*/
+		.ib = 256000000, /*vote for 32Mhz dfab clk rate*/
 	},
 };
 
@@ -2551,6 +2539,7 @@
 	&msm_pil_vidc,
 	&msm_gss,
 	&apq8064_rtb_device,
+	&apq8064_dcvs_device,
 	&apq8064_msm_gov_device,
 	&apq8064_device_cache_erp,
 	&msm8960_device_ebi1_ch0_erp,
@@ -3406,6 +3395,7 @@
 static void __init apq8064_common_init(void)
 {
 	u32 platform_version = socinfo_get_platform_version();
+	struct msm_rpmrs_level rpmrs_level;
 
 	if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
 		apq8064_pm8917_pdata_fixup();
@@ -3482,8 +3472,12 @@
 	}
 
 	enable_ddr3_regulator();
-	msm_hsic_pdata.swfi_latency =
-		msm_rpmrs_levels[0].latency_us;
+	rpmrs_level =
+		msm_rpmrs_levels[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT];
+	msm_hsic_pdata.swfi_latency = rpmrs_level.latency_us;
+	rpmrs_level =
+		msm_rpmrs_levels[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE];
+	msm_hsic_pdata.standalone_latency = rpmrs_level.latency_us;
 	if (machine_is_apq8064_mtp()) {
 		msm_hsic_pdata.log2_irq_thresh = 5,
 		apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 083d5ab..be55031 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -244,7 +244,7 @@
 		.src = MSM_BUS_MASTER_VFE,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab  = 27648000,
-		.ib  = 110592000,
+		.ib  = 2656000000UL,
 	},
 	{
 		.src = MSM_BUS_MASTER_VPE,
@@ -265,7 +265,7 @@
 		.src = MSM_BUS_MASTER_VFE,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab  = 274406400,
-		.ib  = 561807360,
+		.ib  = 2656000000UL,
 	},
 	{
 		.src = MSM_BUS_MASTER_VPE,
@@ -285,8 +285,8 @@
 	{
 		.src = MSM_BUS_MASTER_VFE,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = 274423680,
-		.ib  = 1097694720,
+		.ab  = 600000000,
+		.ib  = 2656000000UL,
 	},
 	{
 		.src = MSM_BUS_MASTER_VPE,
@@ -306,8 +306,8 @@
 	{
 		.src = MSM_BUS_MASTER_VFE,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = 302071680,
-		.ib  = 1208286720,
+		.ab  = 600000000,
+		.ib  = 2656000000UL,
 	},
 	{
 		.src = MSM_BUS_MASTER_VPE,
@@ -327,8 +327,8 @@
 	{
 		.src = MSM_BUS_MASTER_VFE,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
-		.ab  = 348192000,
-		.ib  = 617103360,
+		.ab  = 600000000,
+		.ib  = 4264000000UL,
 	},
 	{
 		.src = MSM_BUS_MASTER_VPE,
@@ -349,7 +349,7 @@
 		.src = MSM_BUS_MASTER_VFE,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
 		.ab  = 302071680,
-		.ib  = 1208286720,
+		.ib  = 2656000000UL,
 	},
 	{
 		.src = MSM_BUS_MASTER_VPE,
@@ -365,6 +365,27 @@
 	},
 };
 
+static struct msm_bus_vectors cam_adv_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 274406400,
+		.ib  = 2656000000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 206807040,
+		.ib  = 488816640,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
 
 static struct msm_bus_paths cam_bus_client_config[] = {
 	{
@@ -395,6 +416,11 @@
 		ARRAY_SIZE(cam_dual_vectors),
 		cam_dual_vectors,
 	},
+	{
+		ARRAY_SIZE(cam_adv_video_vectors),
+		cam_adv_video_vectors,
+	},
+
 };
 
 static struct msm_bus_scale_pdata cam_bus_client_pdata = {
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index a0bfabf..7e477b1 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -740,11 +740,29 @@
 		return 0;
 
 	if (on) {
+		if (!(hdmi_msm_data.is_mhl_enabled)) {
+			rc = gpio_request(HDMI_MHL_MUX_GPIO, "MHL_HDMI_MUX");
+			if (rc < 0) {
+				pr_err("gpio hdmi_mhl mux req failed:%d\n",
+					rc);
+				return rc;
+			}
+			rc = gpio_direction_output(HDMI_MHL_MUX_GPIO, 1);
+			if (rc < 0) {
+				pr_err("set gpio hdmi_mhl dir failed:%d\n",
+					rc);
+				goto error0;
+			}
+			gpio_set_value(HDMI_MHL_MUX_GPIO, 1);
+			pr_debug("set gpio hdmi mhl mux %d to 1\n",
+				HDMI_MHL_MUX_GPIO);
+		}
+
 		rc = gpio_request(100, "HDMI_DDC_CLK");
 		if (rc) {
 			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
 				"HDMI_DDC_CLK", 100, rc);
-			return rc;
+			goto error0;
 		}
 		rc = gpio_request(101, "HDMI_DDC_DATA");
 		if (rc) {
@@ -760,6 +778,8 @@
 		}
 		pr_debug("%s(on): success\n", __func__);
 	} else {
+		if (!(hdmi_msm_data.is_mhl_enabled))
+			gpio_free(HDMI_MHL_MUX_GPIO);
 		gpio_free(100);
 		gpio_free(101);
 		gpio_free(102);
@@ -773,6 +793,9 @@
 	gpio_free(101);
 error1:
 	gpio_free(100);
+error0:
+	if (!(hdmi_msm_data.is_mhl_enabled))
+		gpio_free(HDMI_MHL_MUX_GPIO);
 	return rc;
 }
 
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index d35a907..618f83b 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -437,7 +437,7 @@
 };
 
 static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
-	.r_sense		= 10,
+	.r_sense_uohm		= 10000,
 	.calib_delay_ms		= 600000,
 };
 
@@ -465,7 +465,7 @@
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
 	.battery_type			= BATT_UNKNOWN,
-	.r_sense			= 10,
+	.r_sense_uohm			= 10000,
 	.v_cutoff			= 3400,
 	.max_voltage_uv			= MAX_VOLTAGE_MV * 1000,
 	.shutdown_soc_valid_limit	= 20,
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index 727c4c6..c74dc26 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -490,7 +490,7 @@
 	/*	ID a_on pd ss min_uV   max_uV  supply sys_uA  freq  fm  ss_fm */
 	RPM_SMPS(S1, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
 	RPM_SMPS(S2, 1, 1, 1, 1400000, 1400000, NULL, 100000, 1p60, AUTO, LPM),
-	RPM_SMPS(S3, 0, 1, 1, 1150000, 1150000, NULL, 100000, 3p20, AUTO, LPM),
+	RPM_SMPS(S3, 0, 1, 1, 1150000, 1150000, NULL, 100000, 3p20, AUTO, AUTO),
 	RPM_SMPS(S4, 1, 1, 1, 1950000, 2200000, NULL, 100000, 1p60, AUTO, LPM),
 
 	/*	ID     a_on pd ss min_uV   max_uV  supply  sys_uA init_ip */
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 1b487fa..ece65d6 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -112,7 +112,6 @@
 #define KS8851_IRQ_GPIO		90
 #define HAP_SHIFT_LVL_OE_GPIO	47
 
-#define HDMI_MHL_MUX_GPIO       73
 #define MHL_GPIO_INT            72
 #define MHL_GPIO_RESET          71
 #define MHL_GPIO_PWR_EN         5
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index 055576f..dbcfa9d 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -164,5 +164,7 @@
 #define MSM_8930_GSBI10_QUP_I2C_BUS_ID 10
 #define MSM_8930_GSBI12_QUP_I2C_BUS_ID 12
 
+#define HDMI_MHL_MUX_GPIO       73
+
 extern struct msm_rtb_platform_data msm8930_rtb_pdata;
 extern struct msm_cache_dump_platform_data msm8930_cache_dump_pdata;
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 1a3d90d..2071a55 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -424,7 +424,7 @@
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
 	.battery_type			= BATT_UNKNOWN,
-	.r_sense			= 10,
+	.r_sense_uohm			= 10000,
 	.v_cutoff			= 3400,
 	.max_voltage_uv			= MAX_VOLTAGE_MV * 1000,
 	.rconn_mohm			= 18,
@@ -552,7 +552,7 @@
 };
 
 static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
-	.r_sense		= 10,
+	.r_sense_uohm		= 10000,
 	.calib_delay_ms		= 600000,
 };
 
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 50b59e1..89ad4ef 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -152,6 +152,26 @@
 
 };
 
+static struct gpiomux_setting mhl_suspend_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting mhl_active_1_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+	.dir = GPIOMUX_OUT_HIGH,
+};
+
+static struct gpiomux_setting mhl_active_2_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+
 static struct gpiomux_setting hdmi_suspend_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
@@ -170,6 +190,34 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+static struct msm_gpiomux_config msm_mhl_configs[] __initdata = {
+	{
+		/* mhl-sii8334 pwr */
+		.gpio = 12,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mhl_suspend_config,
+			[GPIOMUX_ACTIVE]    = &mhl_active_1_cfg,
+		},
+	},
+	{
+		/* mhl-sii8334 intr */
+		.gpio = 82,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mhl_suspend_config,
+			[GPIOMUX_ACTIVE]    = &mhl_active_1_cfg,
+		},
+	},
+	{
+		/* mhl-sii8334 reset */
+		.gpio = 8,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mhl_suspend_config,
+			[GPIOMUX_ACTIVE]    = &mhl_active_2_cfg,
+		},
+	},
+};
+
+
 static struct msm_gpiomux_config msm_hdmi_configs[] __initdata = {
 	{
 		.gpio = 31,
@@ -575,4 +623,5 @@
 	msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
 
 	msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs));
+	msm_gpiomux_install(msm_mhl_configs, ARRAY_SIZE(msm_mhl_configs));
 }
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 98a82b1..b092a53 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -66,168 +66,6 @@
 	return MEMTYPE_EBI1;
 }
 
-static struct resource smd_resource[] = {
-	{
-		.name	= "modem_smd_in",
-		.start	= 32 + 25,		/* mss_sw_to_kpss_ipc_irq0  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "modem_smsm_in",
-		.start	= 32 + 26,		/* mss_sw_to_kpss_ipc_irq1  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "adsp_smd_in",
-		.start	= 32 + 156,		/* lpass_to_kpss_ipc_irq0  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "adsp_smsm_in",
-		.start	= 32 + 157,		/* lpass_to_kpss_ipc_irq1  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "wcnss_smd_in",
-		.start	= 32 + 142,		/* WcnssAppsSmdMedIrq  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "wcnss_smsm_in",
-		.start	= 32 + 144,		/* RivaAppsWlanSmsmIrq  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "rpm_smd_in",
-		.start	= 32 + 168,		/* rpm_to_kpss_ipc_irq4  */
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct smd_subsystem_config smd_config_list[] = {
-	{
-		.irq_config_id = SMD_MODEM,
-		.subsys_name = "modem",
-		.edge = SMD_APPS_MODEM,
-
-		.smd_int.irq_name = "modem_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 12,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = "modem_smsm_in",
-		.smsm_int.flags = IRQF_TRIGGER_RISING,
-		.smsm_int.irq_id = -1,
-		.smsm_int.device_name = "smsm_dev",
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 1 << 13,
-		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smsm_int.out_offset = 0x8,
-	},
-	{
-		.irq_config_id = SMD_Q6,
-		.subsys_name = "adsp",
-		.edge = SMD_APPS_QDSP,
-
-		.smd_int.irq_name = "adsp_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 8,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = "adsp_smsm_in",
-		.smsm_int.flags = IRQF_TRIGGER_RISING,
-		.smsm_int.irq_id = -1,
-		.smsm_int.device_name = "smsm_dev",
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 1 << 9,
-		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smsm_int.out_offset = 0x8,
-	},
-	{
-		.irq_config_id = SMD_WCNSS,
-		.subsys_name = "wcnss",
-		.edge = SMD_APPS_WCNSS,
-
-		.smd_int.irq_name = "wcnss_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 17,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = "wcnss_smsm_in",
-		.smsm_int.flags = IRQF_TRIGGER_RISING,
-		.smsm_int.irq_id = -1,
-		.smsm_int.device_name = "smsm_dev",
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 1 << 19,
-		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smsm_int.out_offset = 0x8,
-	},
-	{
-		.irq_config_id = SMD_RPM,
-		.subsys_name = NULL, /* do not use PIL to load RPM */
-		.edge = SMD_APPS_RPM,
-
-		.smd_int.irq_name = "rpm_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 0,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = NULL, /* RPM does not support SMSM */
-		.smsm_int.flags = 0,
-		.smsm_int.irq_id = 0,
-		.smsm_int.device_name = NULL,
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 0,
-		.smsm_int.out_base = NULL,
-		.smsm_int.out_offset = 0,
-	},
-};
-
-static struct smd_smem_regions aux_smem_areas[] = {
-	{
-		.phys_addr = (void *)(0xfc428000),
-		.size = 0x4000,
-	},
-};
-
-static struct smd_subsystem_restart_config smd_ssr_cfg = {
-	.disable_smsm_reset_handshake = 1,
-};
-
-static struct smd_platform smd_platform_data = {
-	.num_ss_configs = ARRAY_SIZE(smd_config_list),
-	.smd_ss_configs = smd_config_list,
-	.smd_ssr_config = &smd_ssr_cfg,
-	.num_smem_areas = ARRAY_SIZE(aux_smem_areas),
-	.smd_smem_areas = aux_smem_areas,
-};
-
-struct platform_device msm_device_smd_8974 = {
-	.name	= "msm_smd",
-	.id	= -1,
-	.resource = smd_resource,
-	.num_resources = ARRAY_SIZE(smd_resource),
-	.dev = {
-		.platform_data = &smd_platform_data,
-	}
-};
-
 static struct reserve_info msm8974_reserve_info __initdata = {
 	.memtype_reserve_table = msm8974_reserve_table,
 	.paddr_to_memtype = msm8974_paddr_to_memtype,
@@ -426,11 +264,6 @@
 				ARRAY_SIZE(msm_bus_8974_devices));
 };
 
-void __init msm8974_add_devices(void)
-{
-	platform_device_register(&msm_device_smd_8974);
-}
-
 /*
  * Used to satisfy dependencies for devices that need to be
  * run early or in a particular order. Most likely your device doesn't fall
@@ -536,7 +369,6 @@
 	regulator_has_full_constraints();
 	of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
 
-	msm8974_add_devices();
 	msm8974_add_drivers();
 }
 
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index e0a6b4d..35b68b1 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -924,6 +924,7 @@
 	&msm_cpudai_auxpcm_tx,
 	&msm_cpudai_sec_auxpcm_rx,
 	&msm_cpudai_sec_auxpcm_tx,
+	&msm_cpudai_stub,
 
 #if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
 		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index 6f36ef2..9102875 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -25,13 +25,13 @@
 };
 
 static struct gpiomux_setting gpio_spi_cs_config = {
-	.func = GPIOMUX_FUNC_9,
+	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
 
 static struct gpiomux_setting gpio_spi_config = {
-	.func = GPIOMUX_FUNC_2,
+	.func = GPIOMUX_FUNC_1,
 	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
@@ -44,6 +44,30 @@
 
 static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
 	{
+		.gpio      = 4,		/* BLSP1 QUP2 SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 5,		/* BLSP1 QUP2 SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
+		.gpio      = 6,		/* BLSP1 QUP2 SPI_CS_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+		},
+	},
+	{
+		.gpio      = 7,		/* BLSP1 QUP2 SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+		},
+	},
+	{
 		.gpio      = 8,	       /* BLSP1 UART TX */
 		.settings = {
 			[GPIOMUX_SUSPENDED] = &gpio_uart_config,
@@ -67,31 +91,72 @@
 			[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
 		},
 	},
-	{
-		.gpio      = 69,		/* BLSP6 QUP SPI_CS_N */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
-		},
-	},
-	{
-		.gpio      = 20,		/* BLSP6 QUP SPI_DATA_MOSI */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
-		},
-	},
-	{
-		.gpio      = 21,		/* BLSP6 QUP SPI_DATA_MISO */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
-		},
-	},
-	{
-		.gpio      = 23,		/* BLSP6 QUP SPI_CLK */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
-		},
-	},
+};
 
+static struct gpiomux_setting  mi2s_active_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting  mi2s_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting codec_reset = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static struct msm_gpiomux_config mdm9625_mi2s_configs[] __initdata = {
+	{
+		.gpio	= 12,		/* mi2s ws */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
+			[GPIOMUX_ACTIVE] = &mi2s_active_cfg,
+		},
+	},
+	{
+		.gpio	= 15,		/* mi2s sclk */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
+			[GPIOMUX_ACTIVE] = &mi2s_active_cfg,
+		},
+	},
+	{
+		.gpio	= 14,		/* mi2s dout */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
+			[GPIOMUX_ACTIVE] = &mi2s_active_cfg,
+		},
+	},
+	{
+		.gpio	= 13,		/* mi2s din */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
+			[GPIOMUX_ACTIVE] = &mi2s_active_cfg,
+		},
+	},
+	{
+		.gpio	= 71,		/* mi2s mclk */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
+			[GPIOMUX_ACTIVE] = &mi2s_active_cfg,
+		},
+	},
+};
+
+static struct msm_gpiomux_config mdm9625_cdc_reset_config[] __initdata = {
+	{
+		.gpio   = 22,           /* SYS_RST_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &codec_reset,
+		},
+	}
 };
 
 static struct gpiomux_setting sdc3_clk_active_cfg = {
@@ -208,4 +273,8 @@
 	msm_gpiomux_install(sdc3_configs, ARRAY_SIZE(sdc3_configs));
 	msm_gpiomux_install(wlan_ath6kl_configs,
 		ARRAY_SIZE(wlan_ath6kl_configs));
+	msm_gpiomux_install(mdm9625_mi2s_configs,
+			ARRAY_SIZE(mdm9625_mi2s_configs));
+	msm_gpiomux_install(mdm9625_cdc_reset_config,
+			ARRAY_SIZE(mdm9625_cdc_reset_config));
 }
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 3e5fc9d..8e8d3e7 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -101,8 +101,6 @@
 static struct of_dev_auxdata msm9625_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
 			"msm_serial_hsl.0", NULL),
-	OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9928000, \
-			"spi_qsd.1", NULL),
 	OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
 			"spmi-pmic-arb.0", NULL),
 	OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 5e5e274..ca47ea1 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -6328,12 +6328,12 @@
 	 */
 	/*
 	 * Initialize MM AHB registers: Enable the FPB clock and disable HW
-	 * gating on 8627 and 8960 for all clocks. Also set VFE_AHB's
+	 * gating on 8627, 8960 and 8930ab for all clocks. Also set VFE_AHB's
 	 * FORCE_CORE_ON bit to prevent its memory from being collapsed when
 	 * the clock is halted. The sleep and wake-up delays are set to safe
 	 * values.
 	 */
-	if (cpu_is_msm8627() || cpu_is_msm8960ab()) {
+	if (cpu_is_msm8627() || cpu_is_msm8960ab() || cpu_is_msm8930ab()) {
 		rmwreg(0x00000003, AHB_EN_REG,  0x6C000103);
 		writel_relaxed(0x000007F9, AHB_EN2_REG);
 	} else {
@@ -6353,7 +6353,7 @@
 	 * delays to safe values. */
 	if (cpu_is_msm8960ab() || (cpu_is_msm8960() &&
 			SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) ||
-			cpu_is_msm8627()) {
+			cpu_is_msm8627() || cpu_is_msm8930ab()) {
 		rmwreg(0x000007F9, MAXI_EN_REG,  0x0803FFFF);
 		rmwreg(0x3027FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
 	} else {
@@ -6366,12 +6366,13 @@
 
 	if (cpu_is_apq8064() || cpu_is_apq8064ab())
 		rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
-	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627())
+	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627() ||
+	    cpu_is_msm8930ab())
 		rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
 	if (cpu_is_msm8960ab())
 		rmwreg(0x009FE000, MAXI_EN5_REG, 0x01FFE000);
 
-	if (cpu_is_msm8627())
+	if (cpu_is_msm8627() || cpu_is_msm8930ab())
 		rmwreg(0x000003C7, SAXI_EN_REG,  0x00003FFF);
 	else if (cpu_is_msm8960ab())
 		rmwreg(0x000001C6, SAXI_EN_REG,  0x00001DF6);
@@ -6412,7 +6413,7 @@
 		rmwreg(0x00000001, DSI2_PIXEL_CC2_REG, 0x00000001);
 
 	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
-	    cpu_is_msm8627())
+	    cpu_is_msm8627() || cpu_is_msm8930ab())
 		rmwreg(0x80FF0000, TV_CC_REG,        0xE1FFC010);
 	if (cpu_is_msm8960ab())
 		rmwreg(0x00000000, TV_CC_REG,        0x00004010);
@@ -6674,7 +6675,7 @@
 	}
 	clk_set_rate(&usb_fs1_src_clk.c, 60000000);
 	if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_msm8930() ||
-		cpu_is_msm8930aa() || cpu_is_msm8627())
+		cpu_is_msm8930aa() || cpu_is_msm8627() || cpu_is_msm8930ab())
 		clk_set_rate(&usb_fs2_src_clk.c, 60000000);
 	clk_set_rate(&usb_hsic_xcvr_fs_clk.c, 60000000);
 	clk_set_rate(&usb_hsic_hsic_src_clk.c, 480000000);
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 777e0bf..1395f05 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -5159,10 +5159,10 @@
 
 	/* MM sensor clocks */
 	CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_src_clk", mclk2_clk_src.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
-	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "6c.qcom,camera"),
+	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, "6c.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
 	CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
 	CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 0b8919b..9f6a00c 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -2027,13 +2027,13 @@
 
 	CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "msm_serial_hsl.0"),
-	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "spi_qsd.1"),
+	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9924000.spi"),
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
 	CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "spi_qsd.1"),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, "f9924000.spi"),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
@@ -2058,6 +2058,7 @@
 	CLK_LOOKUP("core_clk", gcc_gp2_clk.c, ""),
 	CLK_LOOKUP("core_clk", gcc_gp3_clk.c, ""),
 
+	CLK_LOOKUP("iface_clk", gcc_prng_ahb_clk.c, "f9bff000.qcom,msm-rng"),
 	CLK_LOOKUP("core_src_clk", ipa_clk_src.c, "fd4c0000.qcom,ipa"),
 	CLK_LOOKUP("core_clk", gcc_ipa_clk.c, "fd4c0000.qcom,ipa"),
 	CLK_LOOKUP("bus_clk",  gcc_sys_noc_ipa_axi_clk.c, "fd4c0000.qcom,ipa"),
@@ -2085,10 +2086,15 @@
 	/* LPASS clocks */
 	CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
 	CLK_LOOKUP("iface_clk", audio_core_slimbus_lfabif_clk.c, ""),
-	CLK_LOOKUP("core_clk", audio_core_lpaif_pri_clk_src.c, ""),
-	CLK_LOOKUP("osr_clk", audio_core_lpaif_pri_osr_clk.c, ""),
-	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pri_ebit_clk.c, ""),
-	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pri_ibit_clk.c, ""),
+
+	CLK_LOOKUP("core_clk", audio_core_lpaif_pri_clk_src.c,
+		   "msm-dai-q6-mi2s.0"),
+	CLK_LOOKUP("osr_clk", audio_core_lpaif_pri_osr_clk.c,
+		   "msm-dai-q6-mi2s.0"),
+	CLK_LOOKUP("ebit_clk", audio_core_lpaif_pri_ebit_clk.c,
+		   "msm-dai-q6-mi2s.0"),
+	CLK_LOOKUP("ibit_clk", audio_core_lpaif_pri_ibit_clk.c,
+		   "msm-dai-q6-mi2s.0"),
 	CLK_LOOKUP("core_clk", audio_core_lpaif_sec_clk_src.c, ""),
 	CLK_LOOKUP("osr_clk", audio_core_lpaif_sec_osr_clk.c, ""),
 	CLK_LOOKUP("ebit_clk", audio_core_lpaif_sec_ebit_clk.c, ""),
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index abc0e6a..14edbcf 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2726,18 +2726,26 @@
 	.resource	= i2s_mdm_resources,
 };
 
-static struct msm_dcvs_freq_entry apq8064_freq[] = {
-	{ 384000, 900,  0, 0, 0},
-	{ 594000, 950,  0, 0, 0},
-	{ 702000, 975,  0, 0, 0},
-	{1026000, 1075, 0, 0, 0},
-	{1242000, 1150, 0, 100, 100},
-	{1458000, 1188, 0, 100, 100},
-	{1512000, 1200, 1, 100, 100},
+static struct msm_dcvs_sync_rule apq8064_dcvs_sync_rules[] = {
+	{1026000,	400000},
+	{384000,	200000},
+	{0,		128000},
+};
+
+static struct msm_dcvs_platform_data apq8064_dcvs_data = {
+	.sync_rules	= apq8064_dcvs_sync_rules,
+	.num_sync_rules = ARRAY_SIZE(apq8064_dcvs_sync_rules),
+};
+
+struct platform_device apq8064_dcvs_device = {
+	.name		= "dcvs",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &apq8064_dcvs_data,
+	},
 };
 
 static struct msm_dcvs_core_info apq8064_core_info = {
-	.freq_tbl		= &apq8064_freq[0],
 	.num_cores		= 4,
 	.sensors		= (int[]){7, 8, 9, 10},
 	.thermal_poll_ms	= 60000,
@@ -2772,7 +2780,7 @@
 	},
 	.power_param		= {
 		.current_temp	= 25,
-		.num_freq	= ARRAY_SIZE(apq8064_freq),
+		.num_freq	= 0, /* set at runtime */
 	}
 };
 
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 1ba408f..3888a4e 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -584,6 +584,10 @@
 	.name	= "msm-voip-dsp",
 	.id	= -1,
 };
+struct platform_device msm_cpudai_stub = {
+	.name = "msm-dai-stub",
+	.id = -1,
+};
 struct platform_device msm_dtmf = {
 	.name	= "msm-pcm-dtmf",
 	.id	= -1,
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index 091a8e8..983b13e 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -360,25 +360,25 @@
 static struct msm_iommu_dev gfx3d_iommu = {
 	.name = "gfx3d",
 	.ncb = 3,
-	.ttbr_split = 1,
+	.ttbr_split = 0,
 };
 
 static struct msm_iommu_dev gfx3d1_iommu = {
 	.name = "gfx3d1",
 	.ncb = 3,
-	.ttbr_split = 1,
+	.ttbr_split = 0,
 };
 
 static struct msm_iommu_dev gfx2d0_iommu = {
 	.name = "gfx2d0",
 	.ncb = 2,
-	.ttbr_split = 1,
+	.ttbr_split = 0,
 };
 
 static struct msm_iommu_dev gfx2d1_iommu = {
 	.name = "gfx2d1",
 	.ncb = 2,
-	.ttbr_split = 1,
+	.ttbr_split = 0,
 };
 
 static struct msm_iommu_dev vcap_iommu = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index cd99628..eae01aa 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -250,6 +250,8 @@
 extern struct platform_device msm_i2s_cpudai1;
 extern struct platform_device msm_i2s_cpudai4;
 extern struct platform_device msm_i2s_cpudai5;
+extern struct platform_device msm_cpudai_stub;
+
 extern struct platform_device msm_pil_q6v3;
 extern struct platform_device msm_pil_modem;
 extern struct platform_device msm_pil_tzapps;
@@ -408,6 +410,7 @@
 extern struct platform_device *msm_8974_stub_regulator_devices[];
 extern int msm_8974_stub_regulator_devices_len;
 
+extern struct platform_device apq8064_dcvs_device;
 extern struct platform_device apq8064_msm_gov_device;
 
 extern struct platform_device msm_bus_8930_apps_fabric;
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 14fd092..3dfa659c 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -605,6 +605,7 @@
 	S_DEFAULT,
 	S_LIVESHOT,
 	S_DUAL,
+	S_ADV_VIDEO,
 	S_EXIT
 };
 
diff --git a/arch/arm/mach-msm/include/mach/irqs-9625.h b/arch/arm/mach-msm/include/mach/irqs-9625.h
index f50606d..abafc23 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9625.h
@@ -28,7 +28,7 @@
 #define TLMM_MSM_SUMMARY_IRQ		(GIC_SPI_START + 208)
 
 #define NR_MSM_IRQS 288
-#define NR_GPIO_IRQS 88
+#define NR_GPIO_IRQS 76
 #define NR_BOARD_IRQS 0
 #define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
 #define NR_MSM_GPIOS NR_GPIO_IRQS
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
index e81cee4..c29b57a 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -36,12 +36,36 @@
 	MSM_DCVS_DISABLE_HIGH_LATENCY_MODES,
 };
 
+struct msm_dcvs_sync_rule {
+	unsigned long cpu_khz;
+	unsigned long gpu_floor_khz;
+};
+
+struct msm_dcvs_platform_data {
+	struct msm_dcvs_sync_rule *sync_rules;
+	unsigned num_sync_rules;
+};
+
 struct msm_gov_platform_data {
 	struct msm_dcvs_core_info *info;
 	int latency;
 };
 
 /**
+ * msm_dcvs_register_cpu_freq
+ * @freq: the frequency value to register
+ * @voltage: the operating voltage (in mV) associated with the above frequency
+ *
+ * Register a cpu frequency and its operating voltage with dcvs.
+ */
+#ifdef CONFIG_MSM_DCVS
+void msm_dcvs_register_cpu_freq(uint32_t freq, uint32_t voltage);
+#else
+static inline void msm_dcvs_register_cpu_freq(uint32_t freq, uint32_t voltage)
+{}
+#endif
+
+/**
  * msm_dcvs_idle
  * @dcvs_core_id: The id returned by msm_dcvs_register_core
  * @state: The enter/exit idle state the core is in
@@ -98,6 +122,7 @@
 	unsigned int (*get_frequency)(int type_core_num),
 	int (*idle_enable)(int type_core_num,
 				enum msm_core_control_event event),
+	int (*set_floor_frequency)(int type_core_num, unsigned int freq),
 	int sensor);
 
 /**
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
index d34536d..88cb94a 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
@@ -14,7 +14,7 @@
 #define _AUDIO_ACDB_H
 
 #include <linux/msm_audio_acdb.h>
-#ifdef CONFIG_ARCH_MSM8974
+#if defined CONFIG_ARCH_MSM8974 || defined CONFIG_ARCH_MSM9625
 #include <sound/q6adm-v2.h>
 #else
 #include <sound/q6adm.h>
diff --git a/arch/arm/mach-msm/mpm-8625.c b/arch/arm/mach-msm/mpm-8625.c
index c70ff5c..aaac476 100644
--- a/arch/arm/mach-msm/mpm-8625.c
+++ b/arch/arm/mach-msm/mpm-8625.c
@@ -101,6 +101,7 @@
 
 static uint16_t msm_bypassed_apps_irqs[] = {
 	MSM8625_INT_CPR_IRQ0,
+	MSM8625_INT_L2CC_INTR,
 };
 
 /* Check IRQ falls into bypassed list are not */
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index c1c05af..2736870 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -23,6 +23,7 @@
 #include <linux/stringify.h>
 #include <linux/debugfs.h>
 #include <linux/msm_tsens.h>
+#include <linux/platform_device.h>
 #include <asm/atomic.h>
 #include <asm/page.h>
 #include <mach/msm_dcvs.h>
@@ -33,6 +34,8 @@
 #define __info(f, ...) pr_info("MSM_DCVS: %s: " f, __func__, __VA_ARGS__)
 #define MAX_PENDING	(5)
 
+#define CORE_FLAG_TEMP_UPDATE		0x1
+
 struct core_attribs {
 	struct kobj_attribute freq_change_us;
 
@@ -123,12 +126,14 @@
 	unsigned int (*get_frequency)(int type_core_num);
 	int (*idle_enable)(int type_core_num,
 			enum msm_core_control_event event);
+	int (*set_floor_frequency)(int type_core_num, unsigned int freq);
 
 	spinlock_t	pending_freq_lock;
 	int pending_freq;
 
 	struct hrtimer	slack_timer;
 	struct delayed_work	temperature_work;
+	int flags;
 };
 
 static int msm_dcvs_enabled = 1;
@@ -140,6 +145,11 @@
 
 static struct kobject *cores_kobj;
 
+#define DCVS_MAX_NUM_FREQS 15
+static struct msm_dcvs_freq_entry cpu_freq_tbl[DCVS_MAX_NUM_FREQS];
+static unsigned num_cpu_freqs;
+static struct msm_dcvs_platform_data *dcvs_pdata;
+
 static void force_stop_slack_timer(struct dcvs_core *core)
 {
 	unsigned long flags;
@@ -246,6 +256,35 @@
 	spin_unlock_irqrestore(&core->idle_state_change_lock, flags2);
 }
 
+static void apply_gpu_floor(int cpu_freq)
+{
+	int i;
+	int gpu_floor_freq = 0;
+	struct dcvs_core *gpu;
+
+	if (!dcvs_pdata)
+		return;
+
+	for (i = 0; i < dcvs_pdata->num_sync_rules; i++)
+		if (cpu_freq > dcvs_pdata->sync_rules[i].cpu_khz) {
+			gpu_floor_freq =
+				dcvs_pdata->sync_rules[i].gpu_floor_khz;
+			break;
+		}
+
+	if (!gpu_floor_freq)
+		return;
+
+	for (i = GPU_OFFSET; i < CORES_MAX; i++) {
+		gpu = &core_list[i];
+		if (gpu->dcvs_core_id == -1)
+			continue;
+		if (gpu->set_floor_frequency)
+			gpu->set_floor_frequency(gpu->type_core_num,
+						 gpu_floor_freq);
+	}
+}
+
 static int __msm_dcvs_change_freq(struct dcvs_core *core)
 {
 	int ret = 0;
@@ -277,6 +316,10 @@
 
 	spin_unlock_irqrestore(&core->pending_freq_lock, flags);
 
+	if (core->type == MSM_DCVS_CORE_TYPE_CPU &&
+	    core->type_core_num == 0)
+		apply_gpu_floor(requested_freq);
+
 	/**
 	 * Call the frequency sink driver to change the frequency
 	 * We will need to get back the actual frequency in KHz and
@@ -353,6 +396,9 @@
 	unsigned long temp = 0;
 	int interval_ms;
 
+	if (!(core->flags & CORE_FLAG_TEMP_UPDATE))
+		return;
+
 	tsens_dev.sensor_num = core->sensor;
 	ret = tsens_get_temp(&tsens_dev, &temp);
 	if (!temp) {
@@ -825,6 +871,37 @@
 	return &core_list[offset];
 }
 
+void msm_dcvs_register_cpu_freq(uint32_t freq, uint32_t voltage)
+{
+	BUG_ON(freq == 0 || voltage == 0 ||
+	       num_cpu_freqs == DCVS_MAX_NUM_FREQS);
+
+	cpu_freq_tbl[num_cpu_freqs].freq = freq;
+	cpu_freq_tbl[num_cpu_freqs].voltage = voltage;
+
+	num_cpu_freqs++;
+}
+
+static void update_cpu_dcvs_params(struct msm_dcvs_core_info *info)
+{
+	int i;
+
+	BUG_ON(num_cpu_freqs == 0);
+
+	info->freq_tbl = cpu_freq_tbl;
+	info->power_param.num_freq = num_cpu_freqs;
+
+	if (!dcvs_pdata || dcvs_pdata->num_sync_rules == 0)
+		return;
+
+	/* the first sync rule shows what the turbo frequencies are -
+	 * these frequencies need energy offsets set */
+	for (i = 0; i < DCVS_MAX_NUM_FREQS && cpu_freq_tbl[i].freq != 0; i++)
+		if (cpu_freq_tbl[i].freq > dcvs_pdata->sync_rules[0].cpu_khz) {
+			cpu_freq_tbl[i].active_energy_offset = 100;
+			cpu_freq_tbl[i].leakage_energy_offset = 100;
+		}
+}
 
 int msm_dcvs_register_core(
 	enum msm_dcvs_core_type type,
@@ -834,6 +911,7 @@
 	unsigned int (*get_frequency)(int type_core_num),
 	int (*idle_enable)(int type_core_num,
 					enum msm_core_control_event event),
+	int (*set_floor_frequency)(int type_core_num, unsigned int freq),
 	int sensor)
 {
 	int ret = -EINVAL;
@@ -857,9 +935,13 @@
 	core->set_frequency = set_frequency;
 	core->get_frequency = get_frequency;
 	core->idle_enable = idle_enable;
+	core->set_floor_frequency = set_floor_frequency;
 	core->pending_freq = STOP_FREQ_CHANGE;
 
 	core->info = info;
+	if (type == MSM_DCVS_CORE_TYPE_CPU)
+		update_cpu_dcvs_params(info);
+
 	memcpy(&core->algo_param, &info->algo_param,
 			sizeof(struct msm_dcvs_algo_param));
 
@@ -913,10 +995,6 @@
 	core->task = kthread_run(msm_dcvs_do_freq, (void *)core,
 			"msm_dcvs/%d", core->dcvs_core_id);
 	ret = core->dcvs_core_id;
-
-	INIT_DELAYED_WORK(&core->temperature_work, msm_dcvs_report_temp_work);
-	schedule_delayed_work(&core->temperature_work,
-			msecs_to_jiffies(info->thermal_poll_ms));
 	return ret;
 bail:
 	core->dcvs_core_id = -1;
@@ -985,6 +1063,10 @@
 	}
 	force_start_slack_timer(core, timer_interval_us);
 
+	core->flags |= CORE_FLAG_TEMP_UPDATE;
+	INIT_DELAYED_WORK(&core->temperature_work, msm_dcvs_report_temp_work);
+	schedule_delayed_work(&core->temperature_work,
+			      msecs_to_jiffies(core->info->thermal_poll_ms));
 
 	core->idle_enable(core->type_core_num, MSM_DCVS_ENABLE_IDLE_PULSE);
 	return 0;
@@ -1011,6 +1093,9 @@
 		return ret;
 	}
 
+	core->flags &= ~CORE_FLAG_TEMP_UPDATE;
+	cancel_delayed_work(&core->temperature_work);
+
 	core->idle_enable(core->type_core_num, MSM_DCVS_DISABLE_IDLE_PULSE);
 	/* Notify TZ to stop receiving idle info for the core */
 	ret = msm_dcvs_scm_event(core->dcvs_core_id, MSM_DCVS_SCM_DCVS_ENABLE,
@@ -1109,11 +1194,29 @@
 }
 late_initcall(msm_dcvs_late_init);
 
+static int __devinit dcvs_probe(struct platform_device *pdev)
+{
+	if (pdev->dev.platform_data)
+		dcvs_pdata = pdev->dev.platform_data;
+
+	return 0;
+}
+
+static struct platform_driver dcvs_driver = {
+	.probe = dcvs_probe,
+	.driver = {
+		.name = "dcvs",
+		.owner = THIS_MODULE,
+	},
+};
+
 static int __init msm_dcvs_early_init(void)
 {
 	int ret = 0;
 	int i;
 
+	platform_driver_register(&dcvs_driver);
+
 	if (!msm_dcvs_enabled) {
 		__info("Not enabled (%d)\n", msm_dcvs_enabled);
 		return 0;
diff --git a/arch/arm/mach-msm/msm_mpdecision.c b/arch/arm/mach-msm/msm_mpdecision.c
index a65b3ee..407be6a 100644
--- a/arch/arm/mach-msm/msm_mpdecision.c
+++ b/arch/arm/mach-msm/msm_mpdecision.c
@@ -123,6 +123,7 @@
 
 static unsigned long last_nr;
 static int num_present_hundreds;
+static ktime_t last_down_time;
 
 #define RQ_AVG_INSIGNIFICANT_BITS	3
 static bool ok_to_update_tz(int nr, int last_nr)
@@ -380,14 +381,15 @@
 			}
 		}
 
-		for_each_possible_cpu(cpu) {
-			if (!(atomic_read(&msm_mpd.algo_cpu_mask) & (1 << cpu))
-				&& cpu_online(cpu)) {
-				bring_down_cpu(cpu);
-				if (!cpu_online(cpu))
-					goto restart;
-			}
-		}
+		if (ktime_to_ns(ktime_sub(ktime_get(), last_down_time)) >
+		    100 * NSEC_PER_MSEC)
+			for_each_possible_cpu(cpu)
+				if (!(atomic_read(&msm_mpd.algo_cpu_mask) &
+				      (1 << cpu)) && cpu_online(cpu)) {
+					bring_down_cpu(cpu);
+					last_down_time = ktime_get();
+					break;
+				}
 		msm_mpd.hpupdate = HPUPDATE_WAITING;
 	}
 
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index d38b416..d460c70 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,13 +12,15 @@
  */
 
 #include <linux/module.h>
-
+#include <asm/proc-fns.h>
 #include <mach/cpuidle.h>
 #include "idle.h"
 #include "pm.h"
 
 void arch_idle(void)
-{ }
+{
+	cpu_do_idle();
+}
 
 void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count)
 { }
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 49fe182..6ae7544 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -31,6 +31,7 @@
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
+#include "ramdump.h"
 
 #define PRONTO_PMU_COMMON_GDSCR				0x24
 #define PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE		BIT(0)
@@ -81,6 +82,7 @@
 	bool crash;
 	struct delayed_work cancel_vote_work;
 	int irq;
+	struct ramdump_device *ramdump_dev;
 };
 
 static int pil_pronto_make_proxy_vote(struct pil_desc *pil)
@@ -359,9 +361,19 @@
 		smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
 }
 
-static int wcnss_ramdump(int enable, const struct subsys_desc *crashed_subsys)
+static struct ramdump_segment pronto_segments[] = {
+	{ 0x0D200000, 0x0D980000 - 0x0D200000 }
+};
+
+static int wcnss_ramdump(int enable, const struct subsys_desc *subsys)
 {
-	return 0;
+	struct pronto_data *drv = subsys_to_drv(subsys);
+
+	if (enable)
+		return do_ramdump(drv->ramdump_dev, pronto_segments,
+				ARRAY_SIZE(pronto_segments));
+	else
+		return 0;
 }
 
 static int __devinit pil_pronto_probe(struct platform_device *pdev)
@@ -464,6 +476,12 @@
 	if (ret < 0)
 		goto err_irq;
 
+	drv->ramdump_dev = create_ramdump_device("pronto", &pdev->dev);
+	if (!drv->ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_irq;
+	}
+
 	/* Initialize common_ss GDSCR to wait 4 cycles between states */
 	regval = readl_relaxed(drv->base + PRONTO_PMU_COMMON_GDSCR)
 		& PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
@@ -489,6 +507,7 @@
 	smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
 					smsm_state_cb_hdlr, drv);
 	pil_desc_release(&drv->desc);
+	destroy_ramdump_device(drv->ramdump_dev);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/qdsp5/audio_acdb.c b/arch/arm/mach-msm/qdsp5/audio_acdb.c
index 16f23f4..d7a4607 100644
--- a/arch/arm/mach-msm/qdsp5/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_acdb.c
@@ -2575,6 +2575,7 @@
 
 	memset(&acdb_data, 0, sizeof(acdb_data));
 	spin_lock_init(&acdb_data.dsp_lock);
+	init_waitqueue_head(&acdb_data.wait);
 	acdb_data.cb_thread_task = kthread_run(acdb_calibrate_device,
 		NULL, "acdb_cb_thread");
 
@@ -2590,7 +2591,6 @@
 		MM_ERR("RTC ACDB=>INIT Failure\n");
 
 #endif
-	init_waitqueue_head(&acdb_data.wait);
 
 	return misc_register(&acdb_misc);
 err:
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
index e4291e7..3bc8454 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
@@ -15,7 +15,7 @@
 #ifndef __Q6_AUDIO_COMMON_H__
 #define __Q6_AUDIO_COMMON_H__
 
-#ifdef CONFIG_ARCH_MSM8974
+#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM9625)
 #include <sound/apr_audio-v2.h>
 #include <sound/q6asm-v2.h>
 #else
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index b1dd1db..7427899 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -36,6 +36,8 @@
 #include <linux/notifier.h>
 #include <linux/sort.h>
 #include <linux/suspend.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
 #include <mach/system.h>
@@ -3502,6 +3504,295 @@
 	return err_ret;
 }
 
+static int __devinit parse_smd_devicetree(struct device_node *node,
+						void *irq_out_base)
+{
+	uint32_t edge;
+	char *key;
+	int ret;
+	uint32_t irq_offset;
+	uint32_t irq_bitmask;
+	uint32_t irq_line;
+	unsigned long irq_flags = IRQF_TRIGGER_RISING;
+	const char *pilstr;
+	struct interrupt_config_item *private_irq;
+
+	key = "qcom,smd-edge";
+	ret = of_property_read_u32(node, key, &edge);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, edge);
+
+	key = "qcom,smd-irq-offset";
+	ret = of_property_read_u32(node, key, &irq_offset);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_offset);
+
+	key = "qcom,smd-irq-bitmask";
+	ret = of_property_read_u32(node, key, &irq_bitmask);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);
+
+	key = "interrupts";
+	irq_line = irq_of_parse_and_map(node, 0);
+	if (!irq_line)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, irq_line);
+
+	key = "qcom,pil-string";
+	pilstr = of_get_property(node, key, NULL);
+	if (pilstr)
+		SMD_DBG("%s: %s = %s", __func__, key, pilstr);
+
+	key = "qcom,irq-no-suspend";
+	ret = of_property_read_bool(node, key);
+	if (ret)
+		irq_flags |= IRQF_NO_SUSPEND;
+
+	private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smd;
+	private_irq->out_bit_pos = irq_bitmask;
+	private_irq->out_offset = irq_offset;
+	private_irq->out_base = irq_out_base;
+	private_irq->irq_id = irq_line;
+
+	ret = request_irq(irq_line,
+				private_irq->irq_handler,
+				irq_flags,
+				"smd_dev",
+				NULL);
+	if (ret < 0) {
+		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
+		return ret;
+	} else {
+		ret = enable_irq_wake(irq_line);
+		if (ret < 0)
+			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
+					irq_line);
+	}
+
+	if (pilstr)
+		strlcpy(edge_to_pids[edge].subsys_name, pilstr,
+						SMD_MAX_CH_NAME_LEN);
+
+	return 0;
+
+missing_key:
+	pr_err("%s: missing key: %s", __func__, key);
+	return -ENODEV;
+}
+
+static int __devinit parse_smsm_devicetree(struct device_node *node,
+						void *irq_out_base)
+{
+	uint32_t edge;
+	char *key;
+	int ret;
+	uint32_t irq_offset;
+	uint32_t irq_bitmask;
+	uint32_t irq_line;
+	struct interrupt_config_item *private_irq;
+
+	key = "qcom,smsm-edge";
+	ret = of_property_read_u32(node, key, &edge);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, edge);
+
+	key = "qcom,smsm-irq-offset";
+	ret = of_property_read_u32(node, key, &irq_offset);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_offset);
+
+	key = "qcom,smsm-irq-bitmask";
+	ret = of_property_read_u32(node, key, &irq_bitmask);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);
+
+	key = "interrupts";
+	irq_line = irq_of_parse_and_map(node, 0);
+	if (!irq_line)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, irq_line);
+
+	private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smsm;
+	private_irq->out_bit_pos = irq_bitmask;
+	private_irq->out_offset = irq_offset;
+	private_irq->out_base = irq_out_base;
+	private_irq->irq_id = irq_line;
+
+	ret = request_irq(irq_line,
+				private_irq->irq_handler,
+				IRQF_TRIGGER_RISING,
+				"smsm_dev",
+				NULL);
+	if (ret < 0) {
+		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
+		return ret;
+	} else {
+		ret = enable_irq_wake(irq_line);
+		if (ret < 0)
+			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
+					irq_line);
+	}
+
+	return 0;
+
+missing_key:
+	pr_err("%s: missing key: %s", __func__, key);
+	return -ENODEV;
+}
+
+static void __devinit unparse_smd_devicetree(struct device_node *node)
+{
+	uint32_t irq_line;
+
+	irq_line = irq_of_parse_and_map(node, 0);
+
+	free_irq(irq_line, NULL);
+}
+
+static void __devinit unparse_smsm_devicetree(struct device_node *node)
+{
+	uint32_t irq_line;
+
+	irq_line = irq_of_parse_and_map(node, 0);
+
+	free_irq(irq_line, NULL);
+}
+
+static int __devinit smd_core_devicetree_init(struct platform_device *pdev)
+{
+	char *key;
+	struct resource *r;
+	void *irq_out_base;
+	void *aux_mem_base;
+	uint32_t aux_mem_size;
+	int temp_string_size = 11; /* max 3 digit count */
+	char temp_string[temp_string_size];
+	int count;
+	struct device_node *node;
+	int ret;
+	const char *compatible;
+	int subnode_num = 0;
+
+	disable_smsm_reset_handshake = 1;
+
+	key = "irq-reg-base";
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+	if (!r) {
+		pr_err("%s: missing '%s'\n", __func__, key);
+		return -ENODEV;
+	}
+	irq_out_base = (void *)(r->start);
+	SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
+
+	count = 1;
+	while (1) {
+		scnprintf(temp_string, temp_string_size, "aux-mem%d", count);
+		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+								temp_string);
+		if (!r)
+			break;
+
+		++num_smem_areas;
+		++count;
+		if (count > 999) {
+			pr_err("%s: max num aux mem regions reached\n",
+								__func__);
+			break;
+		}
+	}
+
+	if (num_smem_areas) {
+		smem_areas = kmalloc(sizeof(struct smem_area) * num_smem_areas,
+					GFP_KERNEL);
+		if (!smem_areas) {
+			pr_err("%s: smem areas kmalloc failed\n", __func__);
+			num_smem_areas = 0;
+			return -ENOMEM;
+		}
+		count = 1;
+		while (1) {
+			scnprintf(temp_string, temp_string_size, "aux-mem%d",
+									count);
+			r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+								temp_string);
+			if (!r)
+				break;
+			aux_mem_base = (void *)(r->start);
+			aux_mem_size = (uint32_t)(resource_size(r));
+			SMD_DBG("%s: %s = %p %x", __func__, temp_string,
+					aux_mem_base, aux_mem_size);
+			smem_areas[count - 1].phys_addr = aux_mem_base;
+			smem_areas[count - 1].size = aux_mem_size;
+			smem_areas[count - 1].virt_addr = ioremap_nocache(
+				(unsigned long)(smem_areas[count-1].phys_addr),
+				smem_areas[count - 1].size);
+			if (!smem_areas[count - 1].virt_addr) {
+				pr_err("%s: ioremap_nocache() of addr:%p size: %x\n",
+					__func__,
+					smem_areas[count - 1].phys_addr,
+					smem_areas[count - 1].size);
+				ret = -ENOMEM;
+				goto free_smem_areas;
+			}
+
+			++count;
+			if (count > 999) {
+				pr_err("%s: max num aux mem regions reached\n",
+								__func__);
+				break;
+			}
+		}
+		sort(smem_areas, num_smem_areas,
+				sizeof(struct smem_area),
+				sort_cmp_func, NULL);
+	}
+
+	for_each_child_of_node(pdev->dev.of_node, node) {
+		compatible = of_get_property(node, "compatible", NULL);
+		if (!strcmp(compatible, "qcom,smd")) {
+			ret = parse_smd_devicetree(node, irq_out_base);
+			if (ret)
+				goto rollback_subnodes;
+		} else if (!strcmp(compatible, "qcom,smsm")) {
+			ret = parse_smsm_devicetree(node, irq_out_base);
+			if (ret)
+				goto rollback_subnodes;
+		} else {
+			pr_err("%s: invalid child node named: %s\n", __func__,
+							compatible);
+			ret = -ENODEV;
+			goto rollback_subnodes;
+		}
+		++subnode_num;
+	}
+
+	return 0;
+
+rollback_subnodes:
+	count = 0;
+	for_each_child_of_node(pdev->dev.of_node, node) {
+		if (count >= subnode_num)
+			break;
+		++count;
+		compatible = of_get_property(node, "compatible", NULL);
+		if (!strcmp(compatible, "qcom,smd"))
+			unparse_smd_devicetree(node);
+		else
+			unparse_smsm_devicetree(node);
+	}
+free_smem_areas:
+	num_smem_areas = 0;
+	kfree(smem_areas);
+	smem_areas = NULL;
+	return ret;
+}
+
 static int __devinit msm_smd_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -3522,8 +3813,12 @@
 
 	if (pdev) {
 		if (pdev->dev.of_node) {
-			pr_err("SMD: Device tree not currently supported\n");
-			return -ENODEV;
+			ret = smd_core_devicetree_init(pdev);
+			if (ret) {
+				pr_err("%s: device tree init failed\n",
+								__func__);
+				return ret;
+			}
 		} else if (pdev->dev.platform_data) {
 			ret = smd_core_platform_init(pdev);
 			if (ret) {
@@ -3600,11 +3895,17 @@
 }
 late_initcall(modem_restart_late_init);
 
+static struct of_device_id msm_smem_match_table[] = {
+	{ .compatible = "qcom,smem" },
+	{},
+};
+
 static struct platform_driver msm_smd_driver = {
 	.probe = msm_smd_probe,
 	.driver = {
 		.name = MODULE_NAME,
 		.owner = THIS_MODULE,
+		.of_match_table = msm_smem_match_table,
 	},
 };
 
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index b61604a..3af066d 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -23,12 +23,14 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/percpu.h>
+#include <linux/mm.h>
 
 #include <asm/localtimer.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/gic.h>
 #include <asm/sched_clock.h>
 #include <asm/smp_plat.h>
+#include <asm/user_accessible_timer.h>
 #include <mach/msm_iomap.h>
 #include <mach/irqs.h>
 #include <mach/socinfo.h>
@@ -1161,6 +1163,16 @@
 	}
 	msm_sched_clock_init();
 
+	if (use_user_accessible_timers()) {
+		if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064()) {
+			struct msm_clock *gtclock = &msm_clocks[MSM_CLOCK_GPT];
+			void __iomem *addr = gtclock->regbase +
+				TIMER_COUNT_VAL + global_timer_offset;
+			setup_user_timer_offset(virt_to_phys(addr)&0xfff);
+			set_user_accessible_timer_flag(true);
+		}
+	}
+
 #ifdef ARCH_HAS_READ_CURRENT_TIMER
 	if (is_smp()) {
 		__raw_writel(1,
diff --git a/arch/arm/mach-msm/timer_page.c b/arch/arm/mach-msm/timer_page.c
new file mode 100644
index 0000000..24d2a35
--- /dev/null
+++ b/arch/arm/mach-msm/timer_page.c
@@ -0,0 +1,36 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/export.h>
+#include <asm/user_accessible_timer.h>
+#include "mach/socinfo.h"
+#include "mach/msm_iomap.h"
+
+#include "timer.h"
+
+inline int get_timer_page_address(void)
+{
+	if (!use_user_accessible_timers())
+		return ARM_USER_ACCESSIBLE_TIMERS_INVALID_PAGE;
+
+	if (cpu_is_msm8960())
+		return MSM8960_TMR0_PHYS;
+	else if (cpu_is_msm8930())
+		return MSM8930_TMR0_PHYS;
+	else if (cpu_is_apq8064())
+		return APQ8064_TMR0_PHYS;
+	else
+		return ARM_USER_ACCESSIBLE_TIMERS_INVALID_PAGE;
+}
+EXPORT_SYMBOL(get_timer_page_address);
+
diff --git a/arch/arm/mm/cache-pl310-erp.c b/arch/arm/mm/cache-pl310-erp.c
index ad75143..191060f 100644
--- a/arch/arm/mm/cache-pl310-erp.c
+++ b/arch/arm/mm/cache-pl310-erp.c
@@ -34,6 +34,7 @@
 	unsigned int slverr;
 	unsigned int decerr;
 	void __iomem *base;
+	unsigned int intr_mask_reg;
 };
 
 #define ECNTR	BIT(0)
@@ -128,19 +129,20 @@
 
 static void pl310_mask_int(struct pl310_drv_data *p, bool enable)
 {
-	uint16_t mask;
-
+	/* L2CC register contents needs to be saved
+	 * as it's power rail will be removed during suspend
+	 */
 	if (enable)
-		mask = 0x1FF;
+		p->intr_mask_reg = 0x1FF;
 	else
-		mask = 0x0;
+		p->intr_mask_reg = 0x0;
 
-	writel_relaxed(mask, p->base + L2X0_INTR_MASK);
+	writel_relaxed(p->intr_mask_reg, p->base + L2X0_INTR_MASK);
 
 	/* Make sure Mask is updated */
 	mb();
 
-	pr_debug("Mask interrupt %x\n",
+	pr_debug("Mask interrupt 0%x\n",
 			readl_relaxed(p->base + L2X0_INTR_MASK));
 }
 
@@ -258,12 +260,42 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int pl310_suspend(struct device *dev)
+{
+	struct pl310_drv_data *p = dev_get_drvdata(dev);
+
+	disable_irq(p->irq);
+
+	return 0;
+}
+
+static int pl310_resume_early(struct device *dev)
+{
+	struct pl310_drv_data *p = dev_get_drvdata(dev);
+
+	pl310_mask_int(p, true);
+
+	enable_irq(p->irq);
+
+	return 0;
+}
+
+static const struct dev_pm_ops pl310_cache_pm_ops = {
+	.suspend = pl310_suspend,
+	.resume_early = pl310_resume_early,
+};
+#endif
+
 static struct platform_driver pl310_cache_erp_driver = {
 	.probe = pl310_cache_erp_probe,
 	.remove = __devexit_p(pl310_cache_erp_remove),
 	.driver = {
 		.name = MODULE_NAME,
 		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &pl310_cache_pm_ops,
+#endif
 	},
 };
 
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 57f41ca..e2cd0120 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -771,6 +771,9 @@
 
 	printk(KERN_NOTICE "Virtual kernel memory layout:\n"
 			"    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
+#ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
+			"    timers  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
+#endif
 #ifdef CONFIG_HAVE_TCM
 			"    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 			"    ITCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
@@ -791,6 +794,11 @@
 
 			MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
 				(PAGE_SIZE)),
+#ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
+			MLK(UL(CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE),
+				UL(CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE)
+					+ (PAGE_SIZE)),
+#endif
 #ifdef CONFIG_HAVE_TCM
 			MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
 			MLK(ITCM_OFFSET, (unsigned long) itcm_end),
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index bae23b0..1cb6cba 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -33,6 +33,8 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
+#include <asm/user_accessible_timer.h>
+
 #include "mm.h"
 
 /*
@@ -309,6 +311,13 @@
 		.prot_l1   = PMD_TYPE_TABLE,
 		.domain    = DOMAIN_KERNEL,
 	},
+	[MT_DEVICE_USER_ACCESSIBLE] = {
+		.prot_pte  = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED |
+				L_PTE_SHARED | L_PTE_USER | L_PTE_RDONLY,
+		.prot_l1   = PMD_TYPE_TABLE,
+		.prot_sect = PROT_SECT_DEVICE | PMD_SECT_S,
+		.domain    = DOMAIN_IO,
+	},
 };
 
 const struct mem_type *get_mem_type(unsigned int type)
@@ -764,7 +773,9 @@
 	const struct mem_type *type;
 	pgd_t *pgd;
 
-	if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
+	if ((md->virtual != vectors_base() &&
+		md->virtual != get_user_accessible_timers_base()) &&
+			md->virtual < TASK_SIZE) {
 		printk(KERN_WARNING "BUG: not creating mapping for 0x%08llx"
 		       " at 0x%08lx in user region\n",
 		       (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
@@ -1203,6 +1214,20 @@
 		mdesc->map_io();
 	fill_pmd_gaps();
 
+	if (use_user_accessible_timers()) {
+		/*
+		 * Generate a mapping for the timer page.
+		 */
+		int page_addr = get_timer_page_address();
+		if (page_addr != ARM_USER_ACCESSIBLE_TIMERS_INVALID_PAGE) {
+			map.pfn = __phys_to_pfn(page_addr);
+			map.virtual = CONFIG_ARM_USER_ACCESSIBLE_TIMER_BASE;
+			map.length = PAGE_SIZE;
+			map.type = MT_DEVICE_USER_ACCESSIBLE;
+			create_mapping(&map, false);
+		}
+	}
+
 	/*
 	 * Finally flush the caches and tlb to ensure that we're in a
 	 * consistent state wrt the writebuffer.  This also ensures that
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 28d0565..de3cf52 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -29,6 +29,7 @@
 #define IN_BUF_SIZE		16384
 #define MAX_IN_BUF_SIZE	32768
 #define MAX_SYNC_OBJ_NAME_SIZE	32
+#define UINT32_MAX	UINT_MAX
 /* Size of the buffer used for deframing a packet
   reveived from the PC tool*/
 #define HDLC_MAX 4096
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index fe61d2d..7b17ce4 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -358,7 +358,7 @@
 }
 
 void diag_add_reg(int j, struct bindpkt_params *params,
-					  int *success, int *count_entries)
+				  int *success, unsigned int *count_entries)
 {
 	*success = 1;
 	driver->table[j].cmd_code = params->cmd_code;
@@ -380,82 +380,172 @@
 	(*count_entries)++;
 }
 
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+uint16_t diag_get_remote_device_mask(void)
+{
+	uint16_t remote_dev = 0;
+
+	if (driver->hsic_inited)
+		remote_dev |= (1 << 0);
+	if (driver->diag_smux_enabled)
+		remote_dev |= (1 << 1);
+
+	return remote_dev;
+}
+#else
+inline uint16_t diag_get_remote_device_mask(void) { return 0; }
+#endif
+
 long diagchar_ioctl(struct file *filp,
 			   unsigned int iocmd, unsigned long ioarg)
 {
-	int i, j, count_entries = 0, temp;
-	int success = -1;
+	int i, j, temp, success = -1, status;
+	unsigned int count_entries = 0, interim_count = 0;
 	void *temp_buf;
 	uint16_t support_list = 0;
-	struct diag_dci_client_tbl *params =
-		kzalloc(sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
+	struct diag_dci_client_tbl *dci_params;
 	struct diag_dci_health_stats stats;
-	int status;
 
 	if (iocmd == DIAG_IOCTL_COMMAND_REG) {
-		struct bindpkt_params_per_process *pkt_params =
-			 (struct bindpkt_params_per_process *) ioarg;
+		struct bindpkt_params_per_process pkt_params;
+		struct bindpkt_params *params;
+		struct bindpkt_params *head_params;
+		if (copy_from_user(&pkt_params, (void *)ioarg,
+			   sizeof(struct bindpkt_params_per_process))) {
+			return -EFAULT;
+		}
+		if ((UINT32_MAX/sizeof(struct bindpkt_params)) <
+							 pkt_params.count) {
+			pr_warning("diag: integer overflow while multiply\n");
+			return -EFAULT;
+		}
+		params = kzalloc(pkt_params.count*sizeof(
+			struct bindpkt_params), GFP_KERNEL);
+		if (!params) {
+			pr_err("diag: unable to alloc memory\n");
+			return -ENOMEM;
+		} else
+			head_params = params;
+
+		if (copy_from_user(params, pkt_params.params,
+			   pkt_params.count*sizeof(struct bindpkt_params))) {
+			kfree(head_params);
+			return -EFAULT;
+		}
 		mutex_lock(&driver->diagchar_mutex);
 		for (i = 0; i < diag_max_reg; i++) {
 			if (driver->table[i].process_id == 0) {
-				diag_add_reg(i, pkt_params->params,
-						&success, &count_entries);
-				if (pkt_params->count > count_entries) {
-					pkt_params->params++;
+				diag_add_reg(i, params, &success,
+							 &count_entries);
+				if (pkt_params.count > count_entries) {
+					params++;
 				} else {
 					mutex_unlock(&driver->diagchar_mutex);
+					kfree(head_params);
 					return success;
 				}
 			}
 		}
 		if (i < diag_threshold_reg) {
 			/* Increase table size by amount required */
-			diag_max_reg += pkt_params->count -
+			if (pkt_params.count >= count_entries) {
+				interim_count = pkt_params.count -
 							 count_entries;
+			} else {
+				pr_warning("diag: error in params count\n");
+				kfree(head_params);
+				mutex_unlock(&driver->diagchar_mutex);
+				return -EFAULT;
+			}
+			if (UINT32_MAX - diag_max_reg >=
+							interim_count) {
+				diag_max_reg += interim_count;
+			} else {
+				pr_warning("diag: Integer overflow\n");
+				kfree(head_params);
+				mutex_unlock(&driver->diagchar_mutex);
+				return -EFAULT;
+			}
 			/* Make sure size doesnt go beyond threshold */
 			if (diag_max_reg > diag_threshold_reg) {
 				diag_max_reg = diag_threshold_reg;
 				pr_info("diag: best case memory allocation\n");
 			}
+			if (UINT32_MAX/sizeof(struct diag_master_table) <
+								 diag_max_reg) {
+				pr_warning("diag: integer overflow\n");
+				kfree(head_params);
+				mutex_unlock(&driver->diagchar_mutex);
+				return -EFAULT;
+			}
 			temp_buf = krealloc(driver->table,
 					 diag_max_reg*sizeof(struct
 					 diag_master_table), GFP_KERNEL);
 			if (!temp_buf) {
-				diag_max_reg -= pkt_params->count -
-							 count_entries;
-				pr_alert("diag: Insufficient memory for reg.");
+				pr_alert("diag: Insufficient memory for reg.\n");
 				mutex_unlock(&driver->diagchar_mutex);
+
+				if (pkt_params.count >= count_entries) {
+					interim_count = pkt_params.count -
+								 count_entries;
+				} else {
+					pr_warning("diag: params count error\n");
+					mutex_unlock(&driver->diagchar_mutex);
+					kfree(head_params);
+					return -EFAULT;
+				}
+				if (diag_max_reg >= interim_count) {
+					diag_max_reg -= interim_count;
+				} else {
+					pr_warning("diag: Integer underflow\n");
+					mutex_unlock(&driver->diagchar_mutex);
+					kfree(head_params);
+					return -EFAULT;
+				}
+				kfree(head_params);
 				return 0;
 			} else {
 				driver->table = temp_buf;
 			}
 			for (j = i; j < diag_max_reg; j++) {
-				diag_add_reg(j, pkt_params->params,
-						&success, &count_entries);
-				if (pkt_params->count > count_entries) {
-					pkt_params->params++;
+				diag_add_reg(j, params, &success,
+							 &count_entries);
+				if (pkt_params.count > count_entries) {
+					params++;
 				} else {
 					mutex_unlock(&driver->diagchar_mutex);
+					kfree(head_params);
 					return success;
 				}
 			}
+			kfree(head_params);
 			mutex_unlock(&driver->diagchar_mutex);
 		} else {
 			mutex_unlock(&driver->diagchar_mutex);
+			kfree(head_params);
 			pr_err("Max size reached, Pkt Registration failed for"
 						" Process %d", current->tgid);
 		}
 		success = 0;
 	} else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) {
-		struct diagpkt_delay_params *delay_params =
-					(struct diagpkt_delay_params *) ioarg;
-
-		if ((delay_params->rsp_ptr) &&
-		 (delay_params->size == sizeof(delayed_rsp_id)) &&
-				 (delay_params->num_bytes_ptr)) {
-			*((uint16_t *)delay_params->rsp_ptr) =
-				DIAGPKT_NEXT_DELAYED_RSP_ID(delayed_rsp_id);
-			*(delay_params->num_bytes_ptr) = sizeof(delayed_rsp_id);
+		struct diagpkt_delay_params delay_params;
+		uint16_t interim_rsp_id;
+		int interim_size;
+		if (copy_from_user(&delay_params, (void *)ioarg,
+					   sizeof(struct diagpkt_delay_params)))
+			return -EFAULT;
+		if ((delay_params.rsp_ptr) &&
+		 (delay_params.size == sizeof(delayed_rsp_id)) &&
+				 (delay_params.num_bytes_ptr)) {
+			interim_rsp_id = DIAGPKT_NEXT_DELAYED_RSP_ID(
+							delayed_rsp_id);
+			if (copy_to_user((void *)delay_params.rsp_ptr,
+					 &interim_rsp_id, sizeof(uint16_t)))
+				return -EFAULT;
+			interim_size = sizeof(delayed_rsp_id);
+			if (copy_to_user((void *)delay_params.num_bytes_ptr,
+						 &interim_size, sizeof(int)))
+				return -EFAULT;
 			success = 0;
 		}
 	} else if (iocmd == DIAG_IOCTL_DCI_REG) {
@@ -463,7 +553,13 @@
 			return DIAG_DCI_NO_REG;
 		if (driver->num_dci_client >= MAX_DCI_CLIENTS)
 			return DIAG_DCI_NO_REG;
-		if (copy_from_user(params, (void *)ioarg,
+		dci_params = kzalloc(sizeof(struct diag_dci_client_tbl),
+								 GFP_KERNEL);
+		if (dci_params == NULL) {
+			pr_err("diag: unable to alloc memory\n");
+			return -ENOMEM;
+		}
+		if (copy_from_user(dci_params, (void *)ioarg,
 				 sizeof(struct diag_dci_client_tbl)))
 			return -EFAULT;
 		mutex_lock(&driver->dci_mutex);
@@ -476,9 +572,9 @@
 			if (driver->dci_client_tbl[i].client == NULL) {
 				driver->dci_client_tbl[i].client = current;
 				driver->dci_client_tbl[i].list =
-							 params->list;
+							 dci_params->list;
 				driver->dci_client_tbl[i].signal_type =
-					 params->signal_type;
+					 dci_params->signal_type;
 				create_dci_log_mask_tbl(driver->
 					dci_client_tbl[i].dci_log_mask);
 				create_dci_event_mask_tbl(driver->
@@ -496,6 +592,7 @@
 			}
 		}
 		mutex_unlock(&driver->dci_mutex);
+		kfree(dci_params);
 		return driver->dci_client_id;
 	} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
 		success = -1;
@@ -520,25 +617,29 @@
 	} else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
 		if (driver->ch_dci)
 			support_list = support_list | DIAG_CON_MPSS;
-		*(uint16_t *)ioarg = support_list;
+		if (copy_to_user((void *)ioarg, &support_list,
+							 sizeof(uint16_t)))
+			return -EFAULT;
 		return DIAG_DCI_NO_ERROR;
 	} else if (iocmd == DIAG_IOCTL_DCI_HEALTH_STATS) {
 		if (copy_from_user(&stats, (void *)ioarg,
 				 sizeof(struct diag_dci_health_stats)))
 			return -EFAULT;
 		for (i = 0; i < MAX_DCI_CLIENTS; i++) {
-			params = &(driver->dci_client_tbl[i]);
-			if (params->client &&
-				params->client->tgid == current->tgid) {
-				stats.dropped_logs = params->dropped_logs;
-				stats.dropped_events = params->dropped_events;
-				stats.received_logs = params->received_logs;
-				stats.received_events = params->received_events;
+			dci_params = &(driver->dci_client_tbl[i]);
+			if (dci_params->client &&
+				dci_params->client->tgid == current->tgid) {
+				stats.dropped_logs = dci_params->dropped_logs;
+				stats.dropped_events =
+						 dci_params->dropped_events;
+				stats.received_logs = dci_params->received_logs;
+				stats.received_events =
+						 dci_params->received_events;
 				if (stats.reset_status) {
-					params->dropped_logs = 0;
-					params->dropped_events = 0;
-					params->received_logs = 0;
-					params->received_events = 0;
+					dci_params->dropped_logs = 0;
+					dci_params->dropped_events = 0;
+					dci_params->received_logs = 0;
+					dci_params->received_events = 0;
 				}
 				break;
 			}
@@ -551,7 +652,7 @@
 		for (i = 0; i < driver->num_clients; i++)
 			if (driver->client_map[i].pid == current->tgid)
 				break;
-		if (i == -1)
+		if (i == driver->num_clients)
 			return -EINVAL;
 		driver->data_ready[i] |= DEINIT_TYPE;
 		wake_up_interruptible(&driver->wait_q);
@@ -583,6 +684,10 @@
 				}
 			}
 		}
+		if (driver->logging_mode == SOCKET_MODE)
+			driver->socket_process = current;
+		if (driver->logging_mode == CALLBACK_MODE)
+			driver->callback_process = current;
 		if (driver->logging_mode == UART_MODE ||
 			driver->logging_mode == SOCKET_MODE ||
 			driver->logging_mode == CALLBACK_MODE) {
@@ -590,10 +695,6 @@
 			driver->mask_check = 0;
 			driver->logging_mode = MEMORY_DEVICE_MODE;
 		}
-		if (driver->logging_mode == SOCKET_MODE)
-			driver->socket_process = current;
-		if (driver->logging_mode == CALLBACK_MODE)
-			driver->callback_process = current;
 		driver->logging_process_id = current->tgid;
 		mutex_unlock(&driver->diagchar_mutex);
 		if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
@@ -695,6 +796,13 @@
 		}
 #endif /* DIAG over USB */
 		success = 1;
+	} else if (iocmd == DIAG_IOCTL_REMOTE_DEV) {
+		uint16_t remote_dev = diag_get_remote_device_mask();
+
+		if (copy_to_user((void *)ioarg, &remote_dev, sizeof(uint16_t)))
+			success = -EFAULT;
+		else
+			success = 1;
 	}
 
 	return success;
@@ -1045,7 +1153,7 @@
 	struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
 	struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
 	void *buf_copy = NULL;
-	int payload_size;
+	unsigned int payload_size;
 #ifdef CONFIG_DIAG_OVER_USB
 	if (((driver->logging_mode == USB_MODE) && (!driver->usb_connected)) ||
 				(driver->logging_mode == NO_LOGGING_MODE)) {
@@ -1056,8 +1164,17 @@
 	/* Get the packet type F3/log/event/Pkt response */
 	err = copy_from_user((&pkt_type), buf, 4);
 	/* First 4 bytes indicate the type of payload - ignore these */
+	if (count < 4) {
+		pr_err("diag: Client sending short data\n");
+		return -EBADMSG;
+	}
 	payload_size = count - 4;
-
+	if (payload_size > USER_SPACE_DATA) {
+		pr_err("diag: Dropping packet, packet payload size crosses 8KB limit. Current payload size %d\n",
+				payload_size);
+		driver->dropped_count++;
+		return -EBADMSG;
+	}
 	if (pkt_type == DCI_DATA_TYPE) {
 		err = copy_from_user(driver->user_space_data, buf + 4,
 							 payload_size);
@@ -1206,8 +1323,9 @@
 		if (err) {
 			/*Free the buffer right away if write failed */
 			diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
-			diagmem_free(driver, (unsigned char *)driver->
-				 write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
+			if (driver->logging_mode == USB_MODE)
+				diagmem_free(driver, (unsigned char *)driver->
+					write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
 			ret = -EIO;
 			goto fail_free_hdlc;
 		}
@@ -1234,8 +1352,9 @@
 		if (err) {
 			/*Free the buffer right away if write failed */
 			diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
-			diagmem_free(driver, (unsigned char *)driver->
-				 write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
+			if (driver->logging_mode == USB_MODE)
+				diagmem_free(driver, (unsigned char *)driver->
+					write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
 			ret = -EIO;
 			goto fail_free_hdlc;
 		}
@@ -1259,8 +1378,9 @@
 		if (err) {
 			/*Free the buffer right away if write failed */
 			diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
-			diagmem_free(driver, (unsigned char *)driver->
-				 write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
+			if (driver->logging_mode == USB_MODE)
+				diagmem_free(driver, (unsigned char *)driver->
+					write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
 			ret = -EIO;
 			goto fail_free_hdlc;
 		}
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index 56f2fae..7aef01f 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -195,7 +195,7 @@
 	if (actual_size < 0)
 		pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
 
-	if (driver->usb_mdm_connected)
+	if (driver->usb_mdm_connected && (driver->logging_mode == USB_MODE))
 		queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
 }
 
@@ -462,7 +462,7 @@
 	 * If there is no write of the usb mdm data on the
 	 * hsic channel
 	 */
-	if (!driver->in_busy_hsic_write)
+	if (!driver->in_busy_hsic_write && (driver->logging_mode == USB_MODE))
 		queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
 
 	return 0;
@@ -552,9 +552,9 @@
 	 * If for some reason there was no mdm channel read initiated,
 	 * queue up the reading of data from the mdm channel
 	 */
-	if (!driver->in_busy_hsic_read_on_device)
-		queue_work(driver->diag_bridge_wq,
-			 &driver->diag_read_mdm_work);
+	if (!driver->in_busy_hsic_read_on_device &&
+		(driver->logging_mode == USB_MODE))
+		queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
 }
 
 static int diag_hsic_probe(struct platform_device *pdev)
diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
index 60ca44f..f2e5439 100644
--- a/drivers/char/hw_random/msm_rng.c
+++ b/drivers/char/hw_random/msm_rng.c
@@ -181,7 +181,12 @@
 	msm_rng_dev->base = base;
 
 	/* create a handle for clock control */
-	msm_rng_dev->prng_clk = clk_get(&pdev->dev, "core_clk");
+	if ((pdev->dev.of_node) && (of_property_read_bool(pdev->dev.of_node,
+					"qcom,msm-rng-iface-clk")))
+		msm_rng_dev->prng_clk = clk_get(&pdev->dev,
+							"iface_clk");
+	else
+		msm_rng_dev->prng_clk = clk_get(&pdev->dev, "core_clk");
 	if (IS_ERR(msm_rng_dev->prng_clk)) {
 		dev_err(&pdev->dev, "failed to register clock source\n");
 		error = -EPERM;
diff --git a/drivers/cpufreq/cpufreq_gov_msm.c b/drivers/cpufreq/cpufreq_gov_msm.c
index 6ddbf4e..8f086aa 100644
--- a/drivers/cpufreq/cpufreq_gov_msm.c
+++ b/drivers/cpufreq/cpufreq_gov_msm.c
@@ -253,6 +253,7 @@
 						msm_dcvs_freq_set,
 						msm_dcvs_freq_get,
 						msm_dcvs_idle_notifier,
+						NULL,
 						sensor);
 		if (gov->dcvs_core_id < 0) {
 			pr_err("Unable to register core for %d\n", cpu);
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 20f84d6..8699178 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -616,18 +616,15 @@
 	if (end < start)
 		goto out;
 
-	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, start);
 	if (vma && vma->vm_start < end) {
 		if (start < vma->vm_start)
-			goto out_up;
+			goto out;
 		if (end > vma->vm_end)
-			goto out_up;
+			goto out;
 		ret = 0;
 	}
 
-out_up:
-	up_read(&mm->mmap_sem);
 out:
 	return ret;
 }
@@ -645,20 +642,12 @@
 		unsigned long start, end;
 		struct ion_handle *handle = NULL;
 		int ret;
+		struct mm_struct *mm = current->active_mm;
 
 		if (copy_from_user(&data, (void __user *)arg,
 					sizeof(struct ion_flush_data)))
 			return -EFAULT;
 
-		start = (unsigned long) data.vaddr;
-		end = (unsigned long) data.vaddr + data.length;
-
-		if (check_vaddr_bounds(start, end)) {
-			pr_err("%s: virtual address %p is out of bounds\n",
-				__func__, data.vaddr);
-			return -EINVAL;
-		}
-
 		if (!data.handle) {
 			handle = ion_import_dma_buf(client, data.fd);
 			if (IS_ERR(handle)) {
@@ -668,11 +657,27 @@
 			}
 		}
 
+		down_read(&mm->mmap_sem);
+
+		start = (unsigned long) data.vaddr;
+		end = (unsigned long) data.vaddr + data.length;
+
+		if (check_vaddr_bounds(start, end)) {
+			up_read(&mm->mmap_sem);
+			pr_err("%s: virtual address %p is out of bounds\n",
+				__func__, data.vaddr);
+			if (!data.handle)
+				ion_free(client, handle);
+			return -EINVAL;
+		}
+
 		ret = ion_do_cache_op(client,
 				data.handle ? data.handle : handle,
 				data.vaddr, data.offset, data.length,
 				cmd);
 
+		up_read(&mm->mmap_sem);
+
 		if (!data.handle)
 			ion_free(client, handle);
 
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 67cb34a..0109d26 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -253,6 +253,13 @@
 	if (result)
 		goto unmap_memstore_desc;
 
+	/*
+	 * Set the mpu end to the last "normal" global memory we use.
+	 * For the IOMMU, this will be used to restrict access to the
+	 * mapped registers.
+	 */
+	device->mh.mpu_range = device->mmu.setstate_memory.gpuaddr +
+				device->mmu.setstate_memory.size;
 	return result;
 
 unmap_memstore_desc:
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index b8adbe67..c040bf3 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -193,6 +193,52 @@
 }
 EXPORT_SYMBOL(kgsl_cancel_events);
 
+int kgsl_memfree_hist_init(void)
+{
+	void *base;
+
+	base = kzalloc(KGSL_MEMFREE_HIST_SIZE, GFP_KERNEL);
+	kgsl_driver.memfree_hist.base_hist_rb = base;
+	if (base == NULL)
+		return -ENOMEM;
+	kgsl_driver.memfree_hist.size = KGSL_MEMFREE_HIST_SIZE;
+	kgsl_driver.memfree_hist.wptr = base;
+	return 0;
+}
+
+void kgsl_memfree_hist_exit(void)
+{
+	kfree(kgsl_driver.memfree_hist.base_hist_rb);
+	kgsl_driver.memfree_hist.base_hist_rb = NULL;
+}
+
+void kgsl_memfree_hist_set_event(unsigned int pid, unsigned int gpuaddr,
+			unsigned int size, int flags)
+{
+	struct kgsl_memfree_hist_elem *p;
+
+	void *base = kgsl_driver.memfree_hist.base_hist_rb;
+	int rbsize = kgsl_driver.memfree_hist.size;
+
+	if (base == NULL)
+		return;
+
+	mutex_lock(&kgsl_driver.memfree_hist_mutex);
+	p = kgsl_driver.memfree_hist.wptr;
+	p->pid = pid;
+	p->gpuaddr = gpuaddr;
+	p->size = size;
+	p->flags = flags;
+
+	kgsl_driver.memfree_hist.wptr++;
+	if ((void *)kgsl_driver.memfree_hist.wptr >= base+rbsize) {
+		kgsl_driver.memfree_hist.wptr =
+			(struct kgsl_memfree_hist_elem *)base;
+	}
+	mutex_unlock(&kgsl_driver.memfree_hist_mutex);
+}
+
+
 /* kgsl_get_mem_entry - get the mem_entry structure for the specified object
  * @device - Pointer to the device structure
  * @ptbase - the pagetable base of the object
@@ -853,13 +899,6 @@
 	dev_priv->device = device;
 	filep->private_data = dev_priv;
 
-	/* Get file (per process) private struct */
-	dev_priv->process_priv = kgsl_get_process_private(dev_priv);
-	if (dev_priv->process_priv ==  NULL) {
-		result = -ENOMEM;
-		goto err_freedevpriv;
-	}
-
 	mutex_lock(&device->mutex);
 	kgsl_check_suspended(device);
 
@@ -871,21 +910,38 @@
 
 		if (result) {
 			mutex_unlock(&device->mutex);
-			goto err_putprocess;
+			goto err_freedevpriv;
 		}
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
 	}
 	device->open_count++;
 	mutex_unlock(&device->mutex);
 
+	/*
+	 * Get file (per process) private struct. This must be done
+	 * after the first start so that the global pagetable mappings
+	 * are set up before we create the per-process pagetable.
+	 */
+	dev_priv->process_priv = kgsl_get_process_private(dev_priv);
+	if (dev_priv->process_priv ==  NULL) {
+		result = -ENOMEM;
+		goto err_stop;
+	}
+
 	KGSL_DRV_INFO(device, "Initialized %s: mmu=%s pagetable_count=%d\n",
 		device->name, kgsl_mmu_enabled() ? "on" : "off",
 		kgsl_pagetable_count);
 
 	return result;
 
-err_putprocess:
-	kgsl_put_process_private(device, dev_priv->process_priv);
+err_stop:
+	mutex_lock(&device->mutex);
+	device->open_count--;
+	if (device->open_count == 0) {
+		result = device->ftbl->stop(device);
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+	}
+	mutex_unlock(&device->mutex);
 err_freedevpriv:
 	filep->private_data = NULL;
 	kfree(dev_priv);
@@ -1349,6 +1405,13 @@
 
 	if (entry) {
 		trace_kgsl_mem_free(entry);
+
+		kgsl_memfree_hist_set_event(
+			entry->priv->pid,
+			entry->memdesc.gpuaddr,
+			entry->memdesc.size,
+			entry->memdesc.flags);
+
 		kgsl_mem_entry_detach_process(entry);
 	} else {
 		KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
@@ -2328,6 +2391,8 @@
 	.process_mutex = __MUTEX_INITIALIZER(kgsl_driver.process_mutex),
 	.ptlock = __SPIN_LOCK_UNLOCKED(kgsl_driver.ptlock),
 	.devlock = __MUTEX_INITIALIZER(kgsl_driver.devlock),
+	.memfree_hist_mutex =
+		__MUTEX_INITIALIZER(kgsl_driver.memfree_hist_mutex),
 };
 EXPORT_SYMBOL(kgsl_driver);
 
@@ -2658,6 +2723,7 @@
 		kgsl_driver.class = NULL;
 	}
 
+	kgsl_memfree_hist_exit();
 	unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX);
 }
 
@@ -2729,6 +2795,9 @@
 			goto err;
 	}
 
+	if (kgsl_memfree_hist_init())
+		KGSL_CORE_ERR("failed to init memfree_hist");
+
 	return 0;
 
 err:
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 17a5b67..d22cb6d 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -71,6 +71,23 @@
 #define KGSL_STATS_ADD(_size, _stat, _max) \
 	do { _stat += (_size); if (_stat > _max) _max = _stat; } while (0)
 
+
+#define KGSL_MEMFREE_HIST_SIZE	((int)(PAGE_SIZE * 2))
+
+struct kgsl_memfree_hist_elem {
+	unsigned int pid;
+	unsigned int gpuaddr;
+	unsigned int size;
+	unsigned int flags;
+};
+
+struct kgsl_memfree_hist {
+	void *base_hist_rb;
+	unsigned int size;
+	struct kgsl_memfree_hist_elem *wptr;
+};
+
+
 struct kgsl_device;
 
 struct kgsl_driver {
@@ -98,6 +115,9 @@
 
 	void *ptpool;
 
+	struct mutex memfree_hist_mutex;
+	struct kgsl_memfree_hist memfree_hist;
+
 	struct {
 		unsigned int vmalloc;
 		unsigned int vmalloc_max;
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 52097dc..07a5ff4 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -106,6 +106,52 @@
 KGSL_DEBUGFS_LOG(mem_log);
 KGSL_DEBUGFS_LOG(pwr_log);
 
+static int memfree_hist_print(struct seq_file *s, void *unused)
+{
+	void *base = kgsl_driver.memfree_hist.base_hist_rb;
+
+	struct kgsl_memfree_hist_elem *wptr = kgsl_driver.memfree_hist.wptr;
+	struct kgsl_memfree_hist_elem *p;
+	char str[16];
+
+	seq_printf(s, "%8s %8s %8s %11s\n",
+			"pid", "gpuaddr", "size", "flags");
+
+	mutex_lock(&kgsl_driver.memfree_hist_mutex);
+	p = wptr;
+	for (;;) {
+		kgsl_get_memory_usage(str, sizeof(str), p->flags);
+		/*
+		 * if the ring buffer is not filled up yet
+		 * all its empty elems have size==0
+		 * just skip them ...
+		*/
+		if (p->size)
+			seq_printf(s, "%8d %08x %8d %11s\n",
+				p->pid, p->gpuaddr, p->size, str);
+		p++;
+		if ((void *)p >= base + kgsl_driver.memfree_hist.size)
+			p = (struct kgsl_memfree_hist_elem *) base;
+
+		if (p == kgsl_driver.memfree_hist.wptr)
+			break;
+	}
+	mutex_unlock(&kgsl_driver.memfree_hist_mutex);
+	return 0;
+}
+
+static int memfree_hist_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, memfree_hist_print, inode->i_private);
+}
+
+static const struct file_operations memfree_hist_fops = {
+	.open = memfree_hist_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 void kgsl_device_debugfs_init(struct kgsl_device *device)
 {
 	if (kgsl_debugfs_dir && !IS_ERR(kgsl_debugfs_dir))
@@ -131,6 +177,8 @@
 				&mem_log_fops);
 	debugfs_create_file("log_level_pwr", 0644, device->d_debugfs, device,
 				&pwr_log_fops);
+	debugfs_create_file("memfree_history", 0444, device->d_debugfs, device,
+				&memfree_hist_fops);
 
 	/* Create postmortem dump control files */
 
@@ -190,7 +238,7 @@
 		entry = rb_entry(node, struct kgsl_mem_entry, node);
 		m = &entry->memdesc;
 
-		flags[0] = m->priv & KGSL_MEMDESC_GLOBAL ?  'g' : '-';
+		flags[0] = kgsl_memdesc_is_global(m) ?  'g' : '-';
 		flags[1] = m->flags & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
 		flags[2] = get_alignflag(m);
 		flags[3] = '\0';
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 07ea48e..1bccd4d 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -702,6 +702,70 @@
 	}
 }
 
+/*
+ * kgsl_iommu_setup_regs - map iommu registers into a pagetable
+ * @mmu: Pointer to mmu structure
+ * @pt: the pagetable
+ *
+ * To do pagetable switches from the GPU command stream, the IOMMU
+ * registers need to be mapped into the GPU's pagetable. This function
+ * is used differently on different targets. On 8960, the registers
+ * are mapped into every pagetable during kgsl_setup_pt(). On
+ * all other targets, the registers are mapped only into the second
+ * context bank.
+ *
+ * Return - 0 on success else error code
+ */
+static int kgsl_iommu_setup_regs(struct kgsl_mmu *mmu,
+				    struct kgsl_pagetable *pt)
+{
+	int status;
+	int i = 0;
+	struct kgsl_iommu *iommu = mmu->priv;
+
+	if (!msm_soc_version_supports_iommu_v1())
+		return 0;
+
+	for (i = 0; i < iommu->unit_count; i++) {
+		iommu->iommu_units[i].reg_map.priv |= KGSL_MEMDESC_GLOBAL;
+		status = kgsl_mmu_map(pt,
+				&(iommu->iommu_units[i].reg_map),
+				GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+		if (status) {
+			iommu->iommu_units[i].reg_map.priv &=
+				~KGSL_MEMDESC_GLOBAL;
+			goto err;
+		}
+	}
+	return 0;
+err:
+	for (i--; i >= 0; i--) {
+		kgsl_mmu_unmap(pt,
+				&(iommu->iommu_units[i].reg_map));
+		iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMDESC_GLOBAL;
+	}
+	return status;
+}
+
+/*
+ * kgsl_iommu_cleanup_regs - unmap iommu registers from a pagetable
+ * @mmu: Pointer to mmu structure
+ * @pt: the pagetable
+ *
+ * Removes mappings created by kgsl_iommu_setup_regs().
+ *
+ * Return - 0 on success else error code
+ */
+static void kgsl_iommu_cleanup_regs(struct kgsl_mmu *mmu,
+					struct kgsl_pagetable *pt)
+{
+	struct kgsl_iommu *iommu = mmu->priv;
+	int i;
+	for (i = 0; i < iommu->unit_count; i++)
+		kgsl_mmu_unmap(pt, &(iommu->iommu_units[i].reg_map));
+}
+
+
 static int kgsl_iommu_init(struct kgsl_mmu *mmu)
 {
 	/*
@@ -744,6 +808,15 @@
 				KGSL_IOMMU_SETSTATE_NOP_OFFSET,
 				cp_nop_packet(1));
 
+	if (cpu_is_msm8960()) {
+		/*
+		 * 8960 doesn't have a second context bank, so the IOMMU
+		 * registers must be mapped into every pagetable.
+		 */
+		iommu_ops.mmu_setup_pt = kgsl_iommu_setup_regs;
+		iommu_ops.mmu_cleanup_pt = kgsl_iommu_cleanup_regs;
+	}
+
 	dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
 			__func__);
 done:
@@ -766,9 +839,6 @@
 static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
 {
 	int status = 0;
-	int i = 0;
-	struct kgsl_iommu *iommu = mmu->priv;
-	struct kgsl_pagetable *pagetable = NULL;
 
 	/* If chip is not 8960 then we use the 2nd context bank for pagetable
 	 * switching on the 3D side for which a separate table is allocated */
@@ -779,6 +849,9 @@
 			status = -ENOMEM;
 			goto err;
 		}
+		status = kgsl_iommu_setup_regs(mmu, mmu->priv_bank_table);
+		if (status)
+			goto err;
 	}
 	mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
 	/* Return error if the default pagetable doesn't exist */
@@ -786,31 +859,10 @@
 		status = -ENOMEM;
 		goto err;
 	}
-	pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
-				mmu->defaultpagetable;
-	/* Map the IOMMU regsiters to only defaultpagetable */
-	if (msm_soc_version_supports_iommu_v1()) {
-		for (i = 0; i < iommu->unit_count; i++) {
-			iommu->iommu_units[i].reg_map.priv |=
-						KGSL_MEMDESC_GLOBAL;
-			status = kgsl_mmu_map(pagetable,
-				&(iommu->iommu_units[i].reg_map),
-				GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
-			if (status) {
-				iommu->iommu_units[i].reg_map.priv &=
-							~KGSL_MEMDESC_GLOBAL;
-				goto err;
-			}
-		}
-	}
 	return status;
 err:
-	for (i--; i >= 0; i--) {
-		kgsl_mmu_unmap(pagetable,
-				&(iommu->iommu_units[i].reg_map));
-		iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMDESC_GLOBAL;
-	}
 	if (mmu->priv_bank_table) {
+		kgsl_iommu_cleanup_regs(mmu, mmu->priv_bank_table);
 		kgsl_mmu_putpagetable(mmu->priv_bank_table);
 		mmu->priv_bank_table = NULL;
 	}
@@ -839,10 +891,12 @@
 	 * a225, hence we still keep the MMU active on 8960 */
 	if (cpu_is_msm8960()) {
 		struct kgsl_mh *mh = &(mmu->device->mh);
+		BUG_ON(iommu->iommu_units[0].reg_map.gpuaddr != 0 &&
+			mh->mpu_base > iommu->iommu_units[0].reg_map.gpuaddr);
 		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
+
 		kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
-			mh->mpu_base +
-			iommu->iommu_units[0].reg_map.gpuaddr);
+			mh->mpu_base + mh->mpu_range);
 	} else {
 		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
 	}
@@ -915,14 +969,12 @@
 			"with err: %d\n", iommu_pt->domain, gpuaddr,
 			range, ret);
 
-#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
 	/*
 	 * Flushing only required if per process pagetables are used. With
 	 * global case, flushing will happen inside iommu_map function
 	 */
-	if (!ret && msm_soc_version_supports_iommu_v1())
+	if (!ret && kgsl_mmu_is_perprocess())
 		*tlb_flags = UINT_MAX;
-#endif
 	return 0;
 }
 
@@ -1003,22 +1055,23 @@
 {
 	struct kgsl_iommu *iommu = mmu->priv;
 	int i;
-	for (i = 0; i < iommu->unit_count; i++) {
-		struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
-			mmu->priv_bank_table : mmu->defaultpagetable);
-		if (iommu->iommu_units[i].reg_map.gpuaddr)
-			kgsl_mmu_unmap(pagetable,
-			&(iommu->iommu_units[i].reg_map));
-		if (iommu->iommu_units[i].reg_map.hostptr)
-			iounmap(iommu->iommu_units[i].reg_map.hostptr);
-		kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
-				iommu->iommu_units[i].reg_map.sglen);
+
+	if (mmu->priv_bank_table != NULL) {
+		kgsl_iommu_cleanup_regs(mmu, mmu->priv_bank_table);
+		kgsl_mmu_putpagetable(mmu->priv_bank_table);
 	}
 
-	if (mmu->priv_bank_table)
-		kgsl_mmu_putpagetable(mmu->priv_bank_table);
-	if (mmu->defaultpagetable)
+	if (mmu->defaultpagetable != NULL)
 		kgsl_mmu_putpagetable(mmu->defaultpagetable);
+
+	for (i = 0; i < iommu->unit_count; i++) {
+		struct kgsl_memdesc *reg_map = &iommu->iommu_units[i].reg_map;
+
+		if (reg_map->hostptr)
+			iounmap(reg_map->hostptr);
+		kgsl_sg_free(reg_map->sg, reg_map->sglen);
+	}
+
 	kfree(iommu);
 
 	return 0;
@@ -1149,6 +1202,9 @@
 	.mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
 	.mmu_pt_equal = kgsl_iommu_pt_equal,
 	.mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
+	/* These callbacks will be set on some chipsets */
+	.mmu_setup_pt = NULL,
+	.mmu_cleanup_pt = NULL,
 };
 
 struct kgsl_mmu_pt_ops iommu_pt_ops = {
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 68cd167..6fe119d 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -36,17 +36,18 @@
 static int kgsl_cleanup_pt(struct kgsl_pagetable *pt)
 {
 	int i;
-	/* For IOMMU only unmap the global structures to global pt */
-	if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) &&
-		(KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
-		(KGSL_MMU_GLOBAL_PT !=  pt->name) &&
-		(KGSL_MMU_PRIV_BANK_TABLE_NAME !=  pt->name))
-		return 0;
+	struct kgsl_device *device;
+
 	for (i = 0; i < KGSL_DEVICE_MAX; i++) {
-		struct kgsl_device *device = kgsl_driver.devp[i];
+		device = kgsl_driver.devp[i];
 		if (device)
 			device->ftbl->cleanup_pt(device, pt);
 	}
+	/* Only the 3d device needs mmu specific pt entries */
+	device = kgsl_driver.devp[KGSL_DEVICE_3D0];
+	if (device->mmu.mmu_ops->mmu_cleanup_pt != NULL)
+		device->mmu.mmu_ops->mmu_cleanup_pt(&device->mmu, pt);
+
 	return 0;
 }
 
@@ -55,21 +56,23 @@
 {
 	int i = 0;
 	int status = 0;
+	struct kgsl_device *device;
 
-	/* For IOMMU only map the global structures to global pt */
-	if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) &&
-		(KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
-		(KGSL_MMU_GLOBAL_PT !=  pt->name) &&
-		(KGSL_MMU_PRIV_BANK_TABLE_NAME !=  pt->name))
-		return 0;
 	for (i = 0; i < KGSL_DEVICE_MAX; i++) {
-		struct kgsl_device *device = kgsl_driver.devp[i];
+		device = kgsl_driver.devp[i];
 		if (device) {
 			status = device->ftbl->setup_pt(device, pt);
 			if (status)
 				goto error_pt;
 		}
 	}
+	/* Only the 3d device needs mmu specific pt entries */
+	device = kgsl_driver.devp[KGSL_DEVICE_3D0];
+	if (device->mmu.mmu_ops->mmu_setup_pt != NULL) {
+		status = device->mmu.mmu_ops->mmu_setup_pt(&device->mmu, pt);
+		if (status)
+			goto error_pt;
+	}
 	return status;
 error_pt:
 	while (i >= 0) {
@@ -309,22 +312,6 @@
 	return ret;
 }
 
-unsigned int kgsl_mmu_get_ptsize(void)
-{
-	/*
-	 * For IOMMU, we could do up to 4G virtual range if we wanted to, but
-	 * it makes more sense to return a smaller range and leave the rest of
-	 * the virtual range for future improvements
-	 */
-
-	if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
-		return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
-	else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
-		return SZ_2G - KGSL_PAGETABLE_BASE;
-	else
-		return 0;
-}
-
 int
 kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu, unsigned int pt_base)
 {
@@ -480,7 +467,7 @@
 		goto err_kgsl_pool;
 	}
 
-	if (gen_pool_add(pagetable->pool, KGSL_PAGETABLE_BASE,
+	if (gen_pool_add(pagetable->pool, kgsl_mmu_get_base_addr(),
 				ptsize, -1)) {
 		KGSL_CORE_ERR("gen_pool_add failed\n");
 		goto err_pool;
@@ -528,11 +515,7 @@
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
 		return (void *)(-1);
 
-#ifndef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
-	name = KGSL_MMU_GLOBAL_PT;
-#endif
-	/* We presently do not support per-process for IOMMU-v2 */
-	if (!msm_soc_version_supports_iommu_v1())
+	if (!kgsl_mmu_is_perprocess())
 		name = KGSL_MMU_GLOBAL_PT;
 
 	pt = kgsl_get_pagetable(name);
@@ -589,15 +572,6 @@
 	 */
 }
 
-static inline struct gen_pool *
-_get_pool(struct kgsl_pagetable *pagetable, unsigned int flags)
-{
-	if (pagetable->kgsl_pool &&
-		(KGSL_MEMDESC_GLOBAL & flags))
-		return pagetable->kgsl_pool;
-	return pagetable->pool;
-}
-
 int
 kgsl_mmu_map(struct kgsl_pagetable *pagetable,
 				struct kgsl_memdesc *memdesc,
@@ -628,28 +602,48 @@
 
 	size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
 
-	/* Allocate from kgsl pool if it exists for global mappings */
-	pool = _get_pool(pagetable, memdesc->priv);
+	pool = pagetable->pool;
 
-	/* Allocate aligned virtual addresses for iommu. This allows
-	 * more efficient pagetable entries if the physical memory
-	 * is also aligned. Don't do this for GPUMMU, because
-	 * the address space is so small.
-	 */
-	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype() &&
-	    kgsl_memdesc_get_align(memdesc) > 0)
-		page_align = kgsl_memdesc_get_align(memdesc);
-
-	memdesc->gpuaddr = gen_pool_alloc_aligned(pool, size, page_align);
-	if (memdesc->gpuaddr == 0) {
-		KGSL_CORE_ERR("gen_pool_alloc(%d) failed from pool: %s\n",
-			size,
-			(pool == pagetable->kgsl_pool) ?
-			"kgsl_pool" : "general_pool");
-		KGSL_CORE_ERR(" [%d] allocated=%d, entries=%d\n",
-				pagetable->name, pagetable->stats.mapped,
-				pagetable->stats.entries);
-		return -ENOMEM;
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
+		/* Allocate aligned virtual addresses for iommu. This allows
+		 * more efficient pagetable entries if the physical memory
+		 * is also aligned. Don't do this for GPUMMU, because
+		 * the address space is so small.
+		 */
+		if (kgsl_memdesc_get_align(memdesc) > 0)
+			page_align = kgsl_memdesc_get_align(memdesc);
+		if (kgsl_memdesc_is_global(memdesc)) {
+			/*
+			 * Only the default pagetable has a kgsl_pool, and
+			 * it is responsible for creating the mapping for
+			 * each global buffer. The mapping will be reused
+			 * in all other pagetables and it must already exist
+			 * when we're creating other pagetables which do not
+			 * have a kgsl_pool.
+			 */
+			pool = pagetable->kgsl_pool;
+			if (pool == NULL && memdesc->gpuaddr == 0) {
+				KGSL_CORE_ERR(
+				  "No address for global mapping into pt %d\n",
+				  pagetable->name);
+				return -EINVAL;
+			}
+		}
+	}
+	if (pool) {
+		memdesc->gpuaddr = gen_pool_alloc_aligned(pool, size,
+							  page_align);
+		if (memdesc->gpuaddr == 0) {
+			KGSL_CORE_ERR("gen_pool_alloc(%d) failed, pool: %s\n",
+					size,
+					(pool == pagetable->kgsl_pool) ?
+					"kgsl_pool" : "general_pool");
+			KGSL_CORE_ERR(" [%d] allocated=%d, entries=%d\n",
+					pagetable->name,
+					pagetable->stats.mapped,
+					pagetable->stats.entries);
+			return -ENOMEM;
+		}
 	}
 
 	if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype())
@@ -676,7 +670,8 @@
 
 err_free_gpuaddr:
 	spin_unlock(&pagetable->lock);
-	gen_pool_free(pool, memdesc->gpuaddr, size);
+	if (pool)
+		gen_pool_free(pool, memdesc->gpuaddr, size);
 	memdesc->gpuaddr = 0;
 	return ret;
 }
@@ -711,14 +706,20 @@
 
 	spin_unlock(&pagetable->lock);
 
-	pool = _get_pool(pagetable, memdesc->priv);
-	gen_pool_free(pool, memdesc->gpuaddr, size);
+	pool = pagetable->pool;
+
+	if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()
+		&& kgsl_memdesc_is_global(memdesc)) {
+		pool = pagetable->kgsl_pool;
+	}
+	if (pool)
+		gen_pool_free(pool, memdesc->gpuaddr, size);
 
 	/*
 	 * Don't clear the gpuaddr on global mappings because they
 	 * may be in use by other pagetables
 	 */
-	if (!(memdesc->priv & KGSL_MEMDESC_GLOBAL))
+	if (!kgsl_memdesc_is_global(memdesc))
 		memdesc->gpuaddr = 0;
 	return 0;
 }
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index b8b9149..b8eff60 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -13,13 +13,14 @@
 #ifndef __KGSL_MMU_H
 #define __KGSL_MMU_H
 
+#include <mach/iommu.h>
+
 /*
- * These defines control the split between ttbr1 and ttbr0 pagetables of IOMMU
- * and what ranges of memory we map to them
+ * These defines control the address range for allocations that
+ * are mapped into all pagetables.
  */
 #define KGSL_IOMMU_GLOBAL_MEM_BASE	0xC0000000
 #define KGSL_IOMMU_GLOBAL_MEM_SIZE	SZ_4M
-#define KGSL_IOMMU_TTBR1_SPLIT		2
 
 #define KGSL_MMU_ALIGN_SHIFT    13
 #define KGSL_MMU_ALIGN_MASK     (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
@@ -148,6 +149,10 @@
 	unsigned int (*mmu_get_pt_base_addr)
 			(struct kgsl_mmu *mmu,
 			struct kgsl_pagetable *pt);
+	int (*mmu_setup_pt) (struct kgsl_mmu *mmu,
+			struct kgsl_pagetable *pt);
+	void (*mmu_cleanup_pt) (struct kgsl_mmu *mmu,
+			struct kgsl_pagetable *pt);
 };
 
 struct kgsl_mmu_pt_ops {
@@ -209,7 +214,6 @@
 int kgsl_mmu_enabled(void);
 void kgsl_mmu_set_mmutype(char *mmutype);
 enum kgsl_mmutype kgsl_mmu_get_mmutype(void);
-unsigned int kgsl_mmu_get_ptsize(void);
 int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr);
 
 /*
@@ -321,4 +325,58 @@
 		return 0;
 }
 
+/*
+ * kgsl_mmu_is_perprocess() - Runtime check for per-process
+ * pagetables.
+ *
+ * Returns non-zero if per-process pagetables are enabled,
+ * 0 if not.
+ */
+#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
+static inline int kgsl_mmu_is_perprocess(void)
+{
+
+	/* We presently do not support per-process for IOMMU-v2 */
+	return (kgsl_mmu_get_mmutype() != KGSL_MMU_TYPE_IOMMU)
+		|| msm_soc_version_supports_iommu_v1();
+}
+#else
+static inline int kgsl_mmu_is_perprocess(void)
+{
+	return 0;
+}
+#endif
+
+/*
+ * kgsl_mmu_base_addr() - Get gpu virtual address base.
+ *
+ * Returns the start address of the gpu
+ * virtual address space.
+ */
+static inline unsigned int kgsl_mmu_get_base_addr(void)
+{
+	return KGSL_PAGETABLE_BASE;
+}
+
+/*
+ * kgsl_mmu_get_ptsize() - Get gpu pagetable size
+ *
+ * Returns the usable size of the gpu address space.
+ */
+static inline unsigned int kgsl_mmu_get_ptsize(void)
+{
+	/*
+	 * For IOMMU, we could do up to 4G virtual range if we wanted to, but
+	 * it makes more sense to return a smaller range and leave the rest of
+	 * the virtual range for future improvements
+	 */
+	enum kgsl_mmutype mmu_type = kgsl_mmu_get_mmutype();
+
+	if (KGSL_MMU_TYPE_GPU == mmu_type)
+		return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
+	else if (KGSL_MMU_TYPE_IOMMU == mmu_type)
+		return SZ_2G;
+	return 0;
+}
+
 #endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index b302bee..c680d57 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -23,6 +23,8 @@
 	struct kgsl_device		*device;
 	int				enabled;
 	unsigned int			cur_freq;
+	unsigned int			req_level;
+	int				floor_level;
 	struct msm_dcvs_core_info	*core_info;
 	int				gpu_busy;
 	int				dcvs_core_id;
@@ -69,7 +71,39 @@
 		return 0;
 
 	mutex_lock(&device->mutex);
-	kgsl_pwrctrl_pwrlevel_change(device, i);
+	priv->req_level = i;
+	if (priv->req_level <= priv->floor_level) {
+		kgsl_pwrctrl_pwrlevel_change(device, priv->req_level);
+		priv->cur_freq = pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
+	}
+	mutex_unlock(&device->mutex);
+
+	/* return current frequency in kHz */
+	return priv->cur_freq / 1000;
+}
+
+static int msm_set_min_freq(int core_num, unsigned int freq)
+{
+	int i, delta = 5000000;
+	struct msm_priv *priv = the_msm_priv;
+	struct kgsl_device *device = priv->device;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+
+	/* msm_dcvs manager uses frequencies in kHz */
+	freq *= 1000;
+	for (i = 0; i < pwr->num_pwrlevels; i++)
+		if (abs(pwr->pwrlevels[i].gpu_freq - freq) < delta)
+			break;
+	if (i == pwr->num_pwrlevels)
+		return 0;
+
+	mutex_lock(&device->mutex);
+	priv->floor_level = i;
+	if (priv->floor_level <= priv->req_level)
+		kgsl_pwrctrl_pwrlevel_change(device, priv->floor_level);
+	else if (priv->floor_level > priv->req_level)
+		kgsl_pwrctrl_pwrlevel_change(device, priv->req_level);
+
 	priv->cur_freq = pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
 	mutex_unlock(&device->mutex);
 
@@ -170,6 +204,7 @@
 
 		priv->core_info = pdata->core_info;
 		tbl = priv->core_info->freq_tbl;
+		priv->floor_level = pwr->num_pwrlevels - 1;
 		/* Fill in frequency table from low to high, reversing order. */
 		low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
 		for (i = 0; i <= low_level; i++)
@@ -180,6 +215,7 @@
 				0,
 				priv->core_info,
 				msm_set_freq, msm_get_freq, msm_idle_enable,
+				msm_set_min_freq,
 				priv->core_info->sensors[0]);
 		if (priv->dcvs_core_id < 0) {
 			KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 92a6f27..53e88be 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -157,6 +157,17 @@
 	return 0;
 }
 
+/*
+ * kgsl_memdesc_is_global - is this a globally mapped buffer?
+ * @memdesc: the memdesc
+ *
+ * Returns nonzero if this is a global mapping, 0 otherwise
+ */
+static inline int kgsl_memdesc_is_global(const struct kgsl_memdesc *memdesc)
+{
+	return (memdesc->priv & KGSL_MEMDESC_GLOBAL) != 0;
+}
+
 static inline int
 kgsl_allocate(struct kgsl_memdesc *memdesc,
 		struct kgsl_pagetable *pagetable, size_t size)
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 712bc60..258dcfa 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -260,6 +260,13 @@
 				     GSL_PT_PAGE_RV);
 	if (result)
 		goto error_unmap_memstore;
+	/*
+	 * Set the mpu end to the last "normal" global memory we use.
+	 * For the IOMMU, this will be used to restrict access to the
+	 * mapped registers.
+	 */
+	device->mh.mpu_range = z180_dev->ringbuffer.cmdbufdesc.gpuaddr +
+				z180_dev->ringbuffer.cmdbufdesc.size;
 	return result;
 
 error_unmap_dummy:
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 7190af8..b7ace53 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -336,6 +336,8 @@
 	void* priv;                  /* Pointer to private data of the API client */
 	struct data_buffer dvr_input; /* DVR input buffer */
 
+	struct dentry *debugfs_demux_dir; /* debugfs dir */
+
 	int (*open) (struct dmx_demux* demux);
 	int (*close) (struct dmx_demux* demux);
 	int (*write) (struct dmx_demux *demux, const char *buf, size_t count);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 625eb78..71642a5 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -32,6 +32,8 @@
 #include <linux/wait.h>
 #include <linux/mm.h>
 #include <asm/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include "dmxdev.h"
 
 static int debug;
@@ -3164,6 +3166,73 @@
 	.fops = &dvb_dvr_fops
 };
 
+
+/**
+ * debugfs service to print active filters information.
+ */
+static int dvb_dmxdev_dbgfs_print(struct seq_file *s, void *p)
+{
+	int i;
+	struct dmxdev *dmxdev = s->private;
+	struct dmxdev_filter *filter;
+	int active_count = 0;
+	struct dmx_buffer_status buffer_status;
+	const char *pes_feeds[] = {"DEC", "PES", "DVR", "REC"};
+
+	if (!dmxdev)
+		return 0;
+
+	for (i = 0; i < dmxdev->filternum; i++) {
+		filter = &dmxdev->filter[i];
+		if (filter->state >= DMXDEV_STATE_GO) {
+			active_count++;
+
+			seq_printf(s, "filter_%02d - ", i);
+
+		    if (filter->type == DMXDEV_TYPE_SEC) {
+				seq_printf(s, "type: SEC, ");
+				seq_printf(s, "PID %04d ",
+						filter->params.sec.pid);
+		    } else {
+				seq_printf(s, "type: %s, ",
+					pes_feeds[filter->params.pes.output]);
+				seq_printf(s, "PID: %04d ",
+						filter->params.pes.pid);
+		    }
+
+			if (0 == dvb_dmxdev_get_buffer_status(
+						filter, &buffer_status)) {
+				seq_printf(s, "buffer size: %08d, ",
+					buffer_status.size);
+				seq_printf(s, "buffer fullness: %08d\n",
+					buffer_status.fullness);
+				seq_printf(s, "buffer error: %08d\n",
+					buffer_status.error);
+			}
+		}
+	}
+
+	if (!active_count)
+		seq_printf(s, "No active filters\n");
+
+	seq_printf(s, "\n");
+
+	return 0;
+}
+
+static int dvb_dmxdev_dbgfs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dvb_dmxdev_dbgfs_print, inode->i_private);
+}
+
+static const struct file_operations dbgfs_filters_fops = {
+	.open = dvb_dmxdev_dbgfs_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
 int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
 {
 	int i;
@@ -3206,6 +3275,11 @@
 	INIT_WORK(&dmxdev->dvr_input_work,
 			  dvr_input_work_func);
 
+	if (dmxdev->demux->debugfs_demux_dir)
+		debugfs_create_file("filters", S_IRUGO,
+			dmxdev->demux->debugfs_demux_dir, dmxdev,
+			&dbgfs_filters_fops);
+
 	return 0;
 }
 
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index de7b28d..2c5294f 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1732,19 +1732,20 @@
 			"demux%d",
 			dvb_demux_index++);
 
-	dvbdemux->debugfs_demux_dir = debugfs_create_dir(dvbdemux->alias, NULL);
+	dvbdemux->dmx.debugfs_demux_dir =
+		debugfs_create_dir(dvbdemux->alias, NULL);
 
-	if (dvbdemux->debugfs_demux_dir != NULL) {
+	if (dvbdemux->dmx.debugfs_demux_dir != NULL) {
 		debugfs_create_u32(
 			"total_processing_time",
 			S_IRUGO|S_IWUGO,
-			dvbdemux->debugfs_demux_dir,
+			dvbdemux->dmx.debugfs_demux_dir,
 			&dvbdemux->total_process_time);
 
 		debugfs_create_u32(
 			"total_crc_time",
 			S_IRUGO|S_IWUGO,
-			dvbdemux->debugfs_demux_dir,
+			dvbdemux->dmx.debugfs_demux_dir,
 			&dvbdemux->total_crc_time);
 	}
 
@@ -1817,9 +1818,10 @@
 
 void dvb_dmx_release(struct dvb_demux *dvbdemux)
 {
-	if (dvbdemux->debugfs_demux_dir != NULL)
-		debugfs_remove_recursive(dvbdemux->debugfs_demux_dir);
+	if (dvbdemux->dmx.debugfs_demux_dir != NULL)
+		debugfs_remove_recursive(dvbdemux->dmx.debugfs_demux_dir);
 
+	dvb_demux_index--;
 	vfree(dvbdemux->cnt_storage);
 	vfree(dvbdemux->filter);
 	vfree(dvbdemux->feed);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 5a32363..706cd0c 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -174,7 +174,6 @@
 
 	u32 total_process_time;
 	u32 total_crc_time;
-	struct dentry *debugfs_demux_dir;
 };
 
 int dvb_dmx_init(struct dvb_demux *dvbdemux);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index 18c3767..51d66cd 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -477,29 +477,29 @@
 	mpq_demux->hw_notification_size = 0;
 	mpq_demux->decoder_tsp_drop_count = 0;
 
-	if (mpq_demux->demux.debugfs_demux_dir != NULL) {
+	if (mpq_demux->demux.dmx.debugfs_demux_dir != NULL) {
 		debugfs_create_u32(
 			"hw_notification_rate",
 			S_IRUGO|S_IWUGO,
-			mpq_demux->demux.debugfs_demux_dir,
+			mpq_demux->demux.dmx.debugfs_demux_dir,
 			&mpq_demux->hw_notification_rate);
 
 		debugfs_create_u32(
 			"hw_notification_count",
 			S_IRUGO|S_IWUGO,
-			mpq_demux->demux.debugfs_demux_dir,
+			mpq_demux->demux.dmx.debugfs_demux_dir,
 			&mpq_demux->hw_notification_count);
 
 		debugfs_create_u32(
 			"hw_notification_size",
 			S_IRUGO|S_IWUGO,
-			mpq_demux->demux.debugfs_demux_dir,
+			mpq_demux->demux.dmx.debugfs_demux_dir,
 			&mpq_demux->hw_notification_size);
 
 		debugfs_create_u32(
 			"decoder_tsp_drop_count",
 			S_IRUGO|S_IWUGO,
-			mpq_demux->demux.debugfs_demux_dir,
+			mpq_demux->demux.dmx.debugfs_demux_dir,
 			&mpq_demux->decoder_tsp_drop_count);
 	}
 }
diff --git a/drivers/media/video/msm/io/msm_io_8960.c b/drivers/media/video/msm/io/msm_io_8960.c
index 808cc32..1b56578 100644
--- a/drivers/media/video/msm/io/msm_io_8960.c
+++ b/drivers/media/video/msm/io/msm_io_8960.c
@@ -103,6 +103,14 @@
 		} else
 			CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
 		break;
+	case S_ADV_VIDEO:
+		if (bus_perf_client) {
+			rc = msm_bus_scale_client_update_request(
+				bus_perf_client, 7);
+			CDBG("%s: S_ADV_VIDEO rc = %d\n", __func__, rc);
+		} else
+			CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
+		break;
 	case S_DEFAULT:
 		break;
 	default:
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index db0db36..a382d53 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -1464,8 +1464,10 @@
 	CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
 		vfe32_ctrl->share_ctrl->operation_mode,
 		vfe32_ctrl->share_ctrl->outpath.output_mode);
-		msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
-			VFE_CAMIF_COMMAND);
+	msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
+		VFE_CAMIF_COMMAND);
+	msm_camera_io_w_mb(VFE_AXI_CFG_MASK,
+		vfe32_ctrl->share_ctrl->vfebase + VFE_AXI_CFG);
 }
 
 static int vfe32_start_recording(
@@ -5789,7 +5791,7 @@
 void axi_start(struct msm_cam_media_controller *pmctl,
 	struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
 {
-	int rc = 0;
+	int rc = 0, bus_vector_idx = 0;
 	uint32_t reg_update = 0;
 	uint32_t vfe_mode =
 		(axi_ctrl->share_ctrl->current_mode &
@@ -5811,9 +5813,22 @@
 			pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
 		break;
 	case AXI_CMD_RECORD:
+		if (cpu_is_msm8930() || cpu_is_msm8930aa() ||
+			cpu_is_msm8930ab()) {
+			if (axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_PREVIEW_AND_VIDEO
+			|| axi_ctrl->share_ctrl->current_mode &
+				VFE_OUTPUTS_VIDEO_AND_PREVIEW)
+				bus_vector_idx = S_VIDEO;
+			else
+				bus_vector_idx = S_ADV_VIDEO;
+		} else {
+			bus_vector_idx = S_VIDEO;
+		}
 		if (!axi_ctrl->share_ctrl->dual_enabled)
 			msm_camio_bus_scale_cfg(
-			pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+			pmctl->sdata->pdata->cam_bus_scale_table,
+			bus_vector_idx);
 		return;
 	case AXI_CMD_ZSL:
 		if (!axi_ctrl->share_ctrl->dual_enabled)
@@ -6046,6 +6061,8 @@
 	uint32_t vfe_mode =
 	axi_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
 		VFE_OUTPUTS_RDI1);
+	int bus_vector_idx = 0;
+
 	switch (vfe_params.cmd_type) {
 	case AXI_CMD_PREVIEW:
 	case AXI_CMD_CAPTURE:
@@ -6059,9 +6076,17 @@
 			pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 		return;
 	case AXI_CMD_LIVESHOT:
-		if (!axi_ctrl->share_ctrl->dual_enabled)
+		if (!axi_ctrl->share_ctrl->dual_enabled) {
+			bus_vector_idx = S_VIDEO;
+
+			if (cpu_is_msm8930() || cpu_is_msm8930aa() ||
+				cpu_is_msm8930ab())
+				bus_vector_idx = S_ADV_VIDEO;
+
 			msm_camio_bus_scale_cfg(
-			pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+			pmctl->sdata->pdata->cam_bus_scale_table,
+			bus_vector_idx);
+		}
 		return;
 	default:
 		return;
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.h b/drivers/media/video/msm/vfe/msm_vfe32.h
index f985221..169c34e 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.h
+++ b/drivers/media/video/msm/vfe/msm_vfe32.h
@@ -913,6 +913,7 @@
 #define VFE_DMI_ADDR                    0x0000059C
 #define VFE_DMI_DATA_HI                 0x000005A0
 #define VFE_DMI_DATA_LO                 0x000005A4
+#define VFE_AXI_CFG                     0x00000600
 #define VFE_BUS_IO_FORMAT_CFG           0x000006F8
 #define VFE_PIXEL_IF_CFG                0x000006FC
 #define VFE_RDI0_CFG                    0x00000734
@@ -923,6 +924,8 @@
 #define VFE33_DMI_DATA_HI               0x000005A0
 #define VFE33_DMI_DATA_LO               0x000005A4
 
+#define VFE_AXI_CFG_MASK                0xFFFFFFFF
+
 #define VFE32_OUTPUT_MODE_PT			BIT(0)
 #define VFE32_OUTPUT_MODE_S			BIT(1)
 #define VFE32_OUTPUT_MODE_V			BIT(2)
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 22063d4..9e6a593 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -518,6 +518,9 @@
 					fmt->get_frame_size(i,
 						f->fmt.pix_mp.height,
 						f->fmt.pix_mp.width);
+				inst->bufq[OUTPUT_PORT].
+					vb2_bufq.plane_sizes[i] =
+					f->fmt.pix_mp.plane_fmt[i].sizeimage;
 			}
 		} else {
 			f->fmt.pix_mp.plane_fmt[0].sizeimage =
@@ -527,6 +530,11 @@
 				f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
 		inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
 			}
+			for (i = 0; i < fmt->num_planes; ++i)
+				inst->bufq[CAPTURE_PORT].
+					vb2_bufq.plane_sizes[i] =
+					f->fmt.pix_mp.plane_fmt[i].sizeimage;
+
 		}
 	} else {
 		dprintk(VIDC_ERR,
@@ -624,6 +632,10 @@
 			}
 		}
 		f->fmt.pix_mp.num_planes = fmt->num_planes;
+		for (i = 0; i < fmt->num_planes; ++i) {
+			inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+		}
 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		inst->prop.width = f->fmt.pix_mp.width;
 		inst->prop.height = f->fmt.pix_mp.height;
@@ -652,6 +664,10 @@
 			fmt->get_frame_size(0, f->fmt.pix_mp.height,
 					f->fmt.pix_mp.width);
 		f->fmt.pix_mp.num_planes = fmt->num_planes;
+		for (i = 0; i < fmt->num_planes; ++i) {
+			inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+		}
 	}
 err_invalid_fmt:
 	return rc;
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index d53da9e..d01841d 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -23,7 +23,6 @@
 #define DEFAULT_WIDTH 1280
 #define MIN_NUM_OUTPUT_BUFFERS 4
 #define MAX_NUM_OUTPUT_BUFFERS 8
-#define MAX_INPUT_BUFFERS 32
 #define MIN_BIT_RATE 64000
 #define MAX_BIT_RATE 160000000
 #define DEFAULT_BIT_RATE 64000
@@ -594,11 +593,11 @@
 		spin_lock_irqsave(&inst->lock, flags);
 		*num_buffers = inst->buff_req.buffer[0].buffer_count_actual =
 			max(*num_buffers, inst->buff_req.buffer[0].
-			buffer_count_actual);
+				buffer_count_actual);
 		spin_unlock_irqrestore(&inst->lock, flags);
 		property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
 		new_buf_count.buffer_type = HAL_BUFFER_INPUT;
-		new_buf_count.buffer_count_actual = MAX_INPUT_BUFFERS;
+		new_buf_count.buffer_count_actual = *num_buffers;
 		rc = vidc_hal_session_set_property(inst->session,
 					property_id, &new_buf_count);
 		dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 9c81d40..6f74d62 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -953,10 +953,10 @@
 		return;
 	}
 	if (core->resources.fw.cookie) {
-		subsystem_put(core->resources.fw.cookie);
-		core->resources.fw.cookie = NULL;
 		msm_comm_iommu_detach(core);
 		msm_comm_disable_clks(core);
+		subsystem_put(core->resources.fw.cookie);
+		core->resources.fw.cookie = NULL;
 	}
 }
 
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index ba599ec..200f5d3 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -315,16 +315,22 @@
 {
 	struct hfi_buffer_requirements *hfi_buf_req;
 	u32 req_bytes;
-	enum vidc_status rc = VIDC_ERR_NONE;
 
 	dprintk(VIDC_DBG, "Entered ");
+	if (!prop) {
+		dprintk(VIDC_ERR,
+			"hal_process_sess_get_prop_buf_req:bad_prop: %p",
+			prop);
+		return;
+	}
 	req_bytes = prop->size - sizeof(
 	struct hfi_msg_session_property_info_packet);
 
-	if (req_bytes == 0 || (req_bytes % sizeof(
-		struct hfi_buffer_requirements))) {
+	if (!req_bytes || (req_bytes % sizeof(
+		struct hfi_buffer_requirements)) ||
+		(!prop->rg_property_data[1])) {
 		dprintk(VIDC_ERR,
-			"hal_process_sess_get_prop_buf_req:bad_pkt_size: %d",
+			"hal_process_sess_get_prop_buf_req:bad_pkt: %d",
 			req_bytes);
 		return;
 	}
@@ -332,15 +338,14 @@
 	hfi_buf_req = (struct hfi_buffer_requirements *)
 		&prop->rg_property_data[1];
 
-	while (req_bytes != 0) {
-		if ((hfi_buf_req->buffer_count_min > hfi_buf_req->
-			buffer_count_actual)
-			|| (hfi_buf_req->buffer_alignment == 0)
-			|| (hfi_buf_req->buffer_size == 0)) {
-			dprintk(VIDC_ERR, "hal_process_sess_get_prop_buf_req:"
-						"bad_buf_req");
-			rc = VIDC_ERR_FAIL;
-		}
+	while (req_bytes) {
+		if ((hfi_buf_req->buffer_size) &&
+			((hfi_buf_req->buffer_count_min > hfi_buf_req->
+			buffer_count_actual)))
+				dprintk(VIDC_WARN,
+					"hal_process_sess_get_prop_buf_req:"
+					"bad_buf_req");
+
 		dprintk(VIDC_DBG, "got buffer requirements for: %d",
 					hfi_buf_req->buffer_type);
 		switch (hfi_buf_req->buffer_type) {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 6ab3a66..93a3237 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -664,6 +664,17 @@
 	  This adds support for connecting devices like mouse in HSIC
 	  Host mode.
 
+config TI_DRV2667
+	tristate "TI's DRV2667 haptic controller support"
+	depends on I2C
+	help
+	  The DRV2667 is a piezo haptic controller chip. It can drive
+	  piezo haptics either in digital mode or analog mode. This chip
+	  can be used in variety of devices to provide haptic support.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ti_drv2667.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index e92e119..8395ef4 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -72,3 +72,4 @@
 obj-$(CONFIG_PMIC8058_XOADC) += pmic8058-xoadc.o
 obj-$(CONFIG_QSEECOM) += qseecom.o
 obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o
+obj-$(CONFIG_TI_DRV2667) += ti_drv2667.o
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 1972845..46015b0 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -35,6 +35,7 @@
 #include <linux/elf.h>
 #include <linux/firmware.h>
 #include <linux/freezer.h>
+#include <linux/scatterlist.h>
 #include <mach/board.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
@@ -54,6 +55,8 @@
 #define QSEE_CE_CLK_100MHZ		100000000
 #define QSEE_CE_CLK_50MHZ		50000000
 
+#define QSEECOM_MAX_SG_ENTRY	10
+
 enum qseecom_command_scm_resp_type {
 	QSEOS_APP_ID = 0xEE01,
 	QSEOS_LISTENER_ID
@@ -247,6 +250,11 @@
 struct clk *ce_core_src_clk;
 struct clk *ce_bus_clk;
 
+struct qseecom_sg_entry {
+	uint32_t phys_addr;
+	uint32_t len;
+};
+
 /* Function proto types */
 static int qsee_vote_for_clock(int32_t);
 static void qsee_disable_clock_vote(int32_t);
@@ -1093,13 +1101,11 @@
 {
 	struct ion_handle *ihandle;
 	char *field;
-	uint32_t *update;
-	ion_phys_addr_t pa;
 	int ret = 0;
 	int i = 0;
-	uint32_t length;
 
 	for (i = 0; i < MAX_ION_FD; i++) {
+		struct sg_table *sg_ptr = NULL;
 		if (req->ifd_data[i].fd > 0) {
 			/* Get the handle of the shared fd */
 			ihandle = ion_import_dma_buf(qseecom.ion_clnt,
@@ -1110,20 +1116,51 @@
 			}
 			field = (char *) req->cmd_req_buf +
 						req->ifd_data[i].cmd_buf_offset;
-			update = (uint32_t *) field;
 
 			/* Populate the cmd data structure with the phys_addr */
-			ret = ion_phys(qseecom.ion_clnt, ihandle, &pa, &length);
-			if (ret)
-				return -ENOMEM;
-
-			*update = (uint32_t)pa;
+			sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
+			if (sg_ptr == NULL) {
+				pr_err("IOn client could not retrieve sg table\n");
+				goto err;
+			}
+			if (sg_ptr->nents == 0) {
+				pr_err("Num of scattered entries is 0\n");
+				goto err;
+			}
+			if (sg_ptr->nents > QSEECOM_MAX_SG_ENTRY) {
+				pr_err("Num of scattered entries");
+				pr_err(" (%d) is greater than max supported %d\n",
+					sg_ptr->nents, QSEECOM_MAX_SG_ENTRY);
+				goto err;
+			}
+			if (sg_ptr->nents == 1) {
+				uint32_t *update;
+				update = (uint32_t *) field;
+				*update = (uint32_t)sg_dma_address(sg_ptr->sgl);
+			} else {
+				struct qseecom_sg_entry *update;
+				struct scatterlist *sg;
+				int j = 0;
+				update = (struct qseecom_sg_entry *) field;
+				sg = sg_ptr->sgl;
+				for (j = 0; j < sg_ptr->nents; j++) {
+					update->phys_addr = (uint32_t)
+						sg_dma_address(sg);
+					update->len = (uint32_t)sg->length;
+					update++;
+					sg = sg_next(sg);
+				}
+			}
 			/* Deallocate the handle */
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
 		}
 	}
 	return ret;
+err:
+	if (!IS_ERR_OR_NULL(ihandle))
+		ion_free(qseecom.ion_clnt, ihandle);
+	return -ENOMEM;
 }
 
 static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
@@ -1339,12 +1376,10 @@
 	/* Populate the remaining parameters */
 	load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
 	memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
-	mutex_lock(&app_access_lock);
 	ret = qsee_vote_for_clock(CLK_SFPB);
 	if (ret) {
 		kzfree(img_data);
 		pr_warning("Unable to vote for SFPB clock");
-		mutex_unlock(&app_access_lock);
 		return -EIO;
 	}
 
@@ -1356,7 +1391,6 @@
 	if (ret) {
 		pr_err("scm_call to load failed : ret %d\n", ret);
 		qsee_disable_clock_vote(CLK_SFPB);
-		mutex_unlock(&app_access_lock);
 		return -EIO;
 	}
 
@@ -1380,7 +1414,6 @@
 		break;
 	}
 	qsee_disable_clock_vote(CLK_SFPB);
-	mutex_unlock(&app_access_lock);
 
 	return ret;
 }
@@ -1695,6 +1728,21 @@
 }
 EXPORT_SYMBOL(qseecom_send_command);
 
+int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
+{
+	if ((handle == NULL) || (handle->dev == NULL)) {
+		pr_err("No valid kernel client\n");
+		return -EINVAL;
+	}
+	if (high)
+		return qsee_vote_for_clock(CLK_DFAB);
+	else {
+		qsee_disable_clock_vote(CLK_DFAB);
+		return 0;
+	}
+}
+EXPORT_SYMBOL(qseecom_set_bandwidth);
+
 static int qseecom_send_resp(void)
 {
 	qseecom.send_resp_flag = 1;
diff --git a/drivers/misc/qseecom_kernel.h b/drivers/misc/qseecom_kernel.h
index bfa5709..0c93ef2 100644
--- a/drivers/misc/qseecom_kernel.h
+++ b/drivers/misc/qseecom_kernel.h
@@ -31,6 +31,6 @@
 int qseecom_shutdown_app(struct qseecom_handle **handle);
 int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
 			uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len);
-
+int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high);
 
 #endif /* __QSEECOM_KERNEL_H_ */
diff --git a/drivers/misc/ti_drv2667.c b/drivers/misc/ti_drv2667.c
new file mode 100644
index 0000000..554799c
--- /dev/null
+++ b/drivers/misc/ti_drv2667.c
@@ -0,0 +1,679 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/pm.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/i2c/ti_drv2667.h>
+#include "../staging/android/timed_output.h"
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#define DRV2667_SUS_LEVEL	1
+#endif
+
+#define DRV2667_STATUS_REG	0x00
+#define DRV2667_CNTL1_REG	0x01
+#define DRV2667_CNTL2_REG	0x02
+#define DRV2667_WAV_SEQ3_REG	0x03
+#define DRV2667_FIFO_REG	0x0B
+#define DRV2667_PAGE_REG	0xFF
+
+#define DRV2667_STANDBY_MASK	0xBF
+#define DRV2667_INPUT_MUX_MASK	0x04
+#define DRV2667_GAIN_MASK	0xFC
+#define DRV2667_GAIN_SHIFT	0
+#define DRV2667_TIMEOUT_MASK	0xF3
+#define DRV2667_TIMEOUT_SHIFT	2
+#define DRV2667_GO_MASK		0x01
+#define DRV2667_FIFO_SIZE	100
+#define DRV2667_VIB_START_VAL	0x7F
+#define DRV2667_REG_PAGE_ID	0x00
+#define DRV2667_FIFO_CHUNK_MS	10
+#define DRV2667_BYTES_PER_MS	8
+
+#define DRV2667_WAV_SEQ_ID_IDX		1
+#define DRV2667_WAV_SEQ_REP_IDX		6
+#define DRV2667_WAV_SEQ_FREQ_IDX	8
+#define DRV2667_WAV_SEQ_FREQ_MIN	8
+#define DRV2667_WAV_SEQ_DUR_IDX		9
+
+#define DRV2667_MIN_IDLE_TIMEOUT_MS	5
+#define DRV2667_MAX_IDLE_TIMEOUT_MS	20
+
+#define DRV2667_VTG_MIN_UV	3000000
+#define DRV2667_VTG_MAX_UV	5500000
+#define DRV2667_VTG_CURR_UA	24000
+#define DRV2667_I2C_VTG_MIN_UV	1800000
+#define DRV2667_I2C_VTG_MAX_UV	1800000
+#define DRV2667_I2C_CURR_UA	9630
+
+/* supports 3 modes in digital - fifo, ram and wave */
+enum drv2667_modes {
+	FIFO_MODE = 0,
+	RAM_SEQ_MODE,
+	WAV_SEQ_MODE,
+	ANALOG_MODE,
+};
+
+struct drv2667_data {
+	struct i2c_client *client;
+	struct timed_output_dev dev;
+	struct hrtimer timer;
+	struct work_struct work;
+	struct mutex lock;
+	struct regulator *vdd;
+	struct regulator *vdd_i2c;
+	u32 max_runtime_ms;
+	u32 runtime_left;
+	u8 buf[DRV2667_FIFO_SIZE + 1];
+	u8 cntl2_val;
+	enum drv2667_modes mode;
+	u32 time_chunk_ms;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend es;
+#endif
+};
+
+static int drv2667_read_reg(struct i2c_client *client, u32 reg)
+{
+	int rc;
+
+	rc = i2c_smbus_read_byte_data(client, reg);
+	if (rc < 0)
+		dev_err(&client->dev, "i2c reg read for 0x%x failed\n", reg);
+	return rc;
+}
+
+static int drv2667_write_reg(struct i2c_client *client, u32 reg, u8 val)
+{
+	int rc;
+
+	rc = i2c_smbus_write_byte_data(client, reg, val);
+	if (rc < 0)
+		dev_err(&client->dev, "i2c reg write for 0x%xfailed\n", reg);
+
+	return rc;
+}
+
+static void drv2667_dump_regs(struct drv2667_data *data, char *label)
+{
+	dev_dbg(&data->client->dev,
+		"%s: reg0x00 = 0x%x, reg0x01 = 0x%x reg0x02 = 0x%x", label,
+		drv2667_read_reg(data->client, DRV2667_STATUS_REG),
+		drv2667_read_reg(data->client, DRV2667_CNTL1_REG),
+		drv2667_read_reg(data->client, DRV2667_CNTL2_REG));
+}
+
+static void drv2667_worker(struct work_struct *work)
+{
+	struct drv2667_data *data;
+	int rc = 0;
+	u8 val;
+
+	data = container_of(work, struct drv2667_data, work);
+
+	if (data->mode == WAV_SEQ_MODE) {
+		if (data->runtime_left)
+			val = data->cntl2_val | DRV2667_GO_MASK;
+		else
+			val = data->cntl2_val & ~DRV2667_GO_MASK;
+		rc = drv2667_write_reg(data->client, DRV2667_CNTL2_REG, val);
+	} else if (data->mode == FIFO_MODE) {
+		/* data is played at 8khz */
+		if (data->runtime_left < data->time_chunk_ms)
+			val = data->runtime_left * DRV2667_BYTES_PER_MS;
+		else
+			val = data->time_chunk_ms * DRV2667_BYTES_PER_MS;
+
+		rc = i2c_master_send(data->client, data->buf, val + 1);
+	}
+
+	if (rc < 0)
+		dev_err(&data->client->dev, "i2c send message failed\n");
+}
+
+static void drv2667_enable(struct timed_output_dev *dev, int runtime)
+{
+	struct drv2667_data *data = container_of(dev, struct drv2667_data, dev);
+	unsigned long time_ms;
+
+	if (runtime > data->max_runtime_ms) {
+		dev_dbg(&data->client->dev, "Invalid runtime\n");
+		runtime = data->max_runtime_ms;
+	}
+
+	mutex_lock(&data->lock);
+	hrtimer_cancel(&data->timer);
+	data->runtime_left = runtime;
+	if (data->runtime_left < data->time_chunk_ms)
+		time_ms = runtime * NSEC_PER_MSEC;
+	else
+		time_ms = data->time_chunk_ms * NSEC_PER_MSEC;
+	hrtimer_start(&data->timer, ktime_set(0, time_ms), HRTIMER_MODE_REL);
+	schedule_work(&data->work);
+	mutex_unlock(&data->lock);
+}
+
+static int drv2667_get_time(struct timed_output_dev *dev)
+{
+	struct drv2667_data *data = container_of(dev, struct drv2667_data, dev);
+
+	if (hrtimer_active(&data->timer))
+		return	data->runtime_left +
+			ktime_to_ms(hrtimer_get_remaining(&data->timer));
+	return 0;
+}
+
+static enum hrtimer_restart drv2667_timer(struct hrtimer *timer)
+{
+	struct drv2667_data *data;
+	int time_ms;
+
+	data = container_of(timer, struct drv2667_data, timer);
+	if (data->runtime_left <= data->time_chunk_ms) {
+		data->runtime_left = 0;
+		schedule_work(&data->work);
+		return HRTIMER_NORESTART;
+	}
+
+	data->runtime_left -= data->time_chunk_ms;
+	if (data->runtime_left < data->time_chunk_ms)
+		time_ms = data->runtime_left * NSEC_PER_MSEC;
+	else
+		time_ms = data->time_chunk_ms * NSEC_PER_MSEC;
+
+	hrtimer_forward_now(&data->timer, ktime_set(0, time_ms));
+	schedule_work(&data->work);
+	return HRTIMER_RESTART;
+}
+
+static int drv2667_vreg_config(struct drv2667_data *data, bool on)
+{
+	int rc = 0;
+
+	if (!on)
+		goto deconfig_vreg;
+
+	data->vdd = regulator_get(&data->client->dev, "vdd");
+	if (IS_ERR(data->vdd)) {
+		rc = PTR_ERR(data->vdd);
+		dev_err(&data->client->dev, "unable to request vdd\n");
+		return rc;
+	}
+
+	if (regulator_count_voltages(data->vdd) > 0) {
+		rc = regulator_set_voltage(data->vdd,
+				DRV2667_VTG_MIN_UV, DRV2667_VTG_MAX_UV);
+		if (rc < 0) {
+			dev_err(&data->client->dev,
+				"vdd set voltage failed(%d)\n", rc);
+			goto put_vdd;
+		}
+	}
+
+	data->vdd_i2c = regulator_get(&data->client->dev, "vdd-i2c");
+	if (IS_ERR(data->vdd_i2c)) {
+		rc = PTR_ERR(data->vdd_i2c);
+		dev_err(&data->client->dev, "unable to request vdd for i2c\n");
+		goto reset_vdd_volt;
+	}
+
+	if (regulator_count_voltages(data->vdd_i2c) > 0) {
+		rc = regulator_set_voltage(data->vdd_i2c,
+			DRV2667_I2C_VTG_MIN_UV, DRV2667_I2C_VTG_MAX_UV);
+		if (rc < 0) {
+			dev_err(&data->client->dev,
+				"vdd_i2c set voltage failed(%d)\n", rc);
+			goto put_vdd_i2c;
+		}
+	}
+
+	return rc;
+
+deconfig_vreg:
+	if (regulator_count_voltages(data->vdd_i2c) > 0)
+		regulator_set_voltage(data->vdd_i2c, 0, DRV2667_I2C_VTG_MAX_UV);
+put_vdd_i2c:
+	regulator_put(data->vdd_i2c);
+reset_vdd_volt:
+	if (regulator_count_voltages(data->vdd) > 0)
+		regulator_set_voltage(data->vdd, 0, DRV2667_VTG_MAX_UV);
+put_vdd:
+	regulator_put(data->vdd);
+	return rc;
+}
+
+static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
+{
+	return (regulator_count_voltages(reg) > 0) ?
+		regulator_set_optimum_mode(reg, load_uA) : 0;
+}
+
+
+static int drv2667_vreg_on(struct drv2667_data *data, bool on)
+{
+	int rc = 0;
+
+	if (!on)
+		goto vreg_off;
+
+	rc = reg_set_optimum_mode_check(data->vdd, DRV2667_VTG_CURR_UA);
+	if (rc < 0) {
+		dev_err(&data->client->dev,
+			"Regulator vdd set_opt failed rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = regulator_enable(data->vdd);
+	if (rc < 0) {
+		dev_err(&data->client->dev, "enable vdd failed\n");
+		return rc;
+	}
+
+	rc = reg_set_optimum_mode_check(data->vdd_i2c, DRV2667_I2C_CURR_UA);
+	if (rc < 0) {
+		dev_err(&data->client->dev,
+			"Regulator vdd_i2c set_opt failed rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = regulator_enable(data->vdd_i2c);
+	if (rc < 0) {
+		dev_err(&data->client->dev, "enable vdd_i2c failed\n");
+		goto disable_vdd;
+	}
+
+	return rc;
+vreg_off:
+	regulator_disable(data->vdd_i2c);
+disable_vdd:
+	regulator_disable(data->vdd);
+	return rc;
+}
+
+#ifdef CONFIG_PM
+static int drv2667_suspend(struct device *dev)
+{
+	struct drv2667_data *data = dev_get_drvdata(dev);
+	u8 val;
+	int rc;
+
+	hrtimer_cancel(&data->timer);
+	cancel_work_sync(&data->work);
+
+	/* set standby */
+	val = data->cntl2_val | ~DRV2667_STANDBY_MASK;
+	rc = drv2667_write_reg(data->client, DRV2667_CNTL2_REG, val);
+	if (rc < 0)
+		dev_err(dev, "unable to set standby\n");
+
+	/* turn regulators off */
+	drv2667_vreg_on(data, false);
+	return 0;
+}
+
+static int drv2667_resume(struct device *dev)
+{
+	struct drv2667_data *data = dev_get_drvdata(dev);
+	int rc;
+
+	/* turn regulators on */
+	rc = drv2667_vreg_on(data, true);
+	if (rc < 0) {
+		dev_err(dev, "unable to turn regulators on\n");
+		return rc;
+	}
+
+	/* clear standby */
+	rc = drv2667_write_reg(data->client,
+			DRV2667_CNTL2_REG, data->cntl2_val);
+	if (rc < 0) {
+		dev_err(dev, "unable to clear standby\n");
+		goto vreg_off;
+	}
+
+	return 0;
+vreg_off:
+	drv2667_vreg_on(data, false);
+	return rc;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void drv2667_early_suspend(struct early_suspend *es)
+{
+	struct drv2667_data *data = container_of(es, struct drv2667_data, es);
+
+	drv2667_suspend(&data->client->dev);
+}
+
+static void drv2667_late_resume(struct early_suspend *es)
+{
+	struct drv2667_data *data = container_of(es, struct drv2667_data, es);
+
+	drv2667_resume(&data->client->dev);
+}
+#endif
+
+static const struct dev_pm_ops drv2667_pm_ops = {
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend = drv2667_suspend,
+	.resume = drv2667_resume,
+#endif
+};
+#endif
+
+#ifdef CONFIG_OF
+static int drv2667_parse_dt(struct device *dev, struct drv2667_pdata *pdata)
+{
+	struct property *prop;
+	int rc;
+	u32 temp;
+
+	rc = of_property_read_string(dev->of_node, "ti,label", &pdata->name);
+	/* set vibrator as default name */
+	if (rc < 0)
+		pdata->name = "vibrator";
+
+	rc = of_property_read_u32(dev->of_node, "ti,gain", &temp);
+	/* set gain as 0 */
+	if (rc < 0)
+		pdata->gain = 0;
+	else
+		pdata->gain = (u8) temp;
+
+	rc = of_property_read_u32(dev->of_node, "ti,mode", &temp);
+	/* set FIFO mode as default */
+	if (rc < 0)
+		pdata->mode = FIFO_MODE;
+	else
+		pdata->mode = (u8) temp;
+
+	/* read wave sequence */
+	if (pdata->mode == WAV_SEQ_MODE) {
+		prop = of_find_property(dev->of_node, "ti,wav-seq", &temp);
+		if (!prop) {
+			dev_err(dev, "wav seq data not found");
+			return -ENODEV;
+		} else if (temp != DRV2667_WAV_SEQ_LEN) {
+			dev_err(dev, "Invalid length of wav seq data\n");
+			return -EINVAL;
+		}
+		memcpy(pdata->wav_seq, prop->value, DRV2667_WAV_SEQ_LEN);
+	}
+
+	rc = of_property_read_u32(dev->of_node, "ti,idle-timeout-ms", &temp);
+	/* configure minimum idle timeout */
+	if (rc < 0)
+		pdata->idle_timeout_ms = DRV2667_MIN_IDLE_TIMEOUT_MS;
+	else
+		pdata->idle_timeout_ms = (u8) temp;
+
+	rc = of_property_read_u32(dev->of_node, "ti,max-runtime-ms",
+						&pdata->max_runtime_ms);
+	/* configure one sec as default time */
+	if (rc < 0)
+		pdata->max_runtime_ms = MSEC_PER_SEC;
+
+	return 0;
+}
+#else
+static int drv2667_parse_dt(struct device *dev, struct drv2667_pdata *pdata)
+{
+	return -ENODEV;
+}
+#endif
+
+static int __devinit drv2667_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct drv2667_data *data;
+	struct drv2667_pdata *pdata;
+	int rc, i;
+	u8 val, fifo_seq_val, reg;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "i2c is not supported\n");
+		return -EIO;
+	}
+
+	if (client->dev.of_node) {
+		pdata = devm_kzalloc(&client->dev,
+			sizeof(struct drv2667_pdata), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&client->dev, "unable to allocate pdata\n");
+			return -ENOMEM;
+		}
+		/* parse DT */
+		rc = drv2667_parse_dt(&client->dev, pdata);
+		if (rc) {
+			dev_err(&client->dev, "DT parsing failed\n");
+			return rc;
+		}
+	} else {
+		pdata = client->dev.platform_data;
+		if (!pdata) {
+			dev_err(&client->dev, "invalid pdata\n");
+			return -EINVAL;
+		}
+	}
+
+	data = devm_kzalloc(&client->dev, sizeof(struct drv2667_data),
+					GFP_KERNEL);
+	if (!data) {
+		dev_err(&client->dev, "unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	i2c_set_clientdata(client, data);
+
+	data->client = client;
+	data->max_runtime_ms = pdata->max_runtime_ms;
+	mutex_init(&data->lock);
+	INIT_WORK(&data->work, drv2667_worker);
+	hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	data->timer.function = drv2667_timer;
+	data->mode = pdata->mode;
+
+	/* configure voltage regulators */
+	rc = drv2667_vreg_config(data, true);
+	if (rc) {
+		dev_err(&client->dev, "unable to configure regulators\n");
+		goto destroy_mutex;
+	}
+
+	/* turn on voltage regulators */
+	rc = drv2667_vreg_on(data, true);
+	if (rc) {
+		dev_err(&client->dev, "unable to turn on regulators\n");
+		goto deconfig_vreg;
+	}
+
+	rc = drv2667_read_reg(client, DRV2667_CNTL2_REG);
+	if (rc < 0)
+		goto vreg_off;
+
+	/* set timeout, clear standby */
+	val = (u8) rc;
+
+	if (pdata->idle_timeout_ms < DRV2667_MIN_IDLE_TIMEOUT_MS ||
+		pdata->idle_timeout_ms > DRV2667_MAX_IDLE_TIMEOUT_MS ||
+		(pdata->idle_timeout_ms % DRV2667_MIN_IDLE_TIMEOUT_MS)) {
+		dev_err(&client->dev, "Invalid idle timeout\n");
+		goto vreg_off;
+	}
+
+	val = (val & DRV2667_TIMEOUT_MASK) |
+		((pdata->idle_timeout_ms / DRV2667_MIN_IDLE_TIMEOUT_MS - 1) <<
+		DRV2667_TIMEOUT_SHIFT);
+
+	val &= DRV2667_STANDBY_MASK;
+
+	rc = drv2667_write_reg(client, DRV2667_CNTL2_REG, val);
+	if (rc < 0)
+		goto vreg_off;
+
+	/* cache control2 val */
+	data->cntl2_val = val;
+
+	/* program drv2667 registers */
+	rc = drv2667_read_reg(client, DRV2667_CNTL1_REG);
+	if (rc < 0)
+		goto vreg_off;
+
+	/* gain and input mode */
+	val = (u8) rc;
+
+	/* remove this check after adding support for these modes */
+	if (data->mode == ANALOG_MODE || data->mode == RAM_SEQ_MODE) {
+		dev_err(&data->client->dev, "Mode not supported\n");
+		goto vreg_off;
+	} else
+		val &= ~DRV2667_INPUT_MUX_MASK; /* set digital mode */
+
+	val = (val & DRV2667_GAIN_MASK) | (pdata->gain << DRV2667_GAIN_SHIFT);
+
+	rc = drv2667_write_reg(client, DRV2667_CNTL1_REG, val);
+	if (rc < 0)
+		goto vreg_off;
+
+	if (data->mode == FIFO_MODE) {
+		/* Load a predefined pattern for FIFO mode */
+		data->buf[0] = DRV2667_FIFO_REG;
+		fifo_seq_val = DRV2667_VIB_START_VAL;
+
+		for (i = 1; i < DRV2667_FIFO_SIZE - 1; i++, fifo_seq_val++)
+			data->buf[i] = fifo_seq_val;
+
+		data->time_chunk_ms = DRV2667_FIFO_CHUNK_MS;
+	} else if (data->mode == WAV_SEQ_MODE) {
+		u8 freq, rep, dur;
+
+		/* program wave sequence from pdata */
+		/* id to wave sequence 3, set page */
+		rc = drv2667_write_reg(client, DRV2667_WAV_SEQ3_REG,
+				pdata->wav_seq[DRV2667_WAV_SEQ_ID_IDX]);
+		if (rc < 0)
+			goto vreg_off;
+
+		/* set page to wave form sequence */
+		rc = drv2667_write_reg(client, DRV2667_PAGE_REG,
+				pdata->wav_seq[DRV2667_WAV_SEQ_ID_IDX]);
+		if (rc < 0)
+			goto vreg_off;
+
+		/* program waveform sequence */
+		for (reg = 0, i = 1; i < DRV2667_WAV_SEQ_LEN - 1; i++, reg++) {
+			rc = drv2667_write_reg(client, reg, pdata->wav_seq[i]);
+			if (rc < 0)
+				goto vreg_off;
+		}
+
+		/* set page back to normal register space */
+		rc = drv2667_write_reg(client, DRV2667_PAGE_REG,
+					DRV2667_REG_PAGE_ID);
+		if (rc < 0)
+			goto vreg_off;
+
+		freq = pdata->wav_seq[DRV2667_WAV_SEQ_FREQ_IDX];
+		rep = pdata->wav_seq[DRV2667_WAV_SEQ_REP_IDX];
+		dur = pdata->wav_seq[DRV2667_WAV_SEQ_DUR_IDX];
+
+		data->time_chunk_ms = (rep * dur * MSEC_PER_SEC) /
+				(freq *	DRV2667_WAV_SEQ_FREQ_MIN);
+	}
+
+	drv2667_dump_regs(data, "new");
+
+	/* register with timed output class */
+	data->dev.name = pdata->name;
+	data->dev.get_time = drv2667_get_time;
+	data->dev.enable = drv2667_enable;
+
+	rc = timed_output_dev_register(&data->dev);
+	if (rc) {
+		dev_err(&client->dev, "unable to register with timed_output\n");
+		goto vreg_off;
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	data->es.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + DRV2667_SUS_LEVEL;
+	data->es.suspend = drv2667_early_suspend;
+	data->es.resume = drv2667_late_resume;
+	register_early_suspend(&data->es);
+#endif
+	return 0;
+
+vreg_off:
+	drv2667_vreg_on(data, false);
+deconfig_vreg:
+	drv2667_vreg_config(data, false);
+destroy_mutex:
+	mutex_destroy(&data->lock);
+	return rc;
+}
+
+static int __devexit drv2667_remove(struct i2c_client *client)
+{
+	struct drv2667_data *data = i2c_get_clientdata(client);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&data->es);
+#endif
+	mutex_destroy(&data->lock);
+	timed_output_dev_unregister(&data->dev);
+	hrtimer_cancel(&data->timer);
+	cancel_work_sync(&data->work);
+	drv2667_vreg_on(data, false);
+	drv2667_vreg_config(data, false);
+
+	return 0;
+}
+
+static const struct i2c_device_id drv2667_id_table[] = {
+	{"drv2667", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, drv2667_id_table);
+
+#ifdef CONFIG_OF
+static const struct of_device_id drv2667_of_id_table[] = {
+	{.compatible = "ti, drv2667"},
+	{ },
+};
+#else
+#define drv2667_of_id_table NULL
+#endif
+
+static struct i2c_driver drv2667_i2c_driver = {
+	.driver = {
+		.name = "drv2667",
+		.owner = THIS_MODULE,
+		.of_match_table = drv2667_of_id_table,
+#ifdef CONFIG_PM
+		.pm = &drv2667_pm_ops,
+#endif
+	},
+	.probe = drv2667_probe,
+	.remove = __devexit_p(drv2667_remove),
+	.id_table = drv2667_id_table,
+};
+
+module_i2c_driver(drv2667_i2c_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI DRV2667 chip driver");
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index ddb562e..84a26a1 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -186,6 +186,46 @@
 DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
 	"%llu\n");
 
+static int mmc_max_clock_get(void *data, u64 *val)
+{
+	struct mmc_host *host = data;
+
+	if (!host)
+		return -EINVAL;
+
+	*val = host->f_max;
+
+	return 0;
+}
+
+static int mmc_max_clock_set(void *data, u64 val)
+{
+	struct mmc_host *host = data;
+	int err = -EINVAL;
+	unsigned long freq = val;
+	unsigned int old_freq;
+
+	if (!host || (val < host->f_min))
+		goto out;
+
+	mmc_claim_host(host);
+	if (host->bus_ops && host->bus_ops->change_bus_speed) {
+		old_freq = host->f_max;
+		host->f_max = freq;
+
+		err = host->bus_ops->change_bus_speed(host, &freq);
+
+		if (err)
+			host->f_max = old_freq;
+	}
+	mmc_release_host(host);
+out:
+	return err;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mmc_max_clock_fops, mmc_max_clock_get,
+		mmc_max_clock_set, "%llu\n");
+
 void mmc_add_host_debugfs(struct mmc_host *host)
 {
 	struct dentry *root;
@@ -208,6 +248,10 @@
 			&mmc_clock_fops))
 		goto err_node;
 
+	if (!debugfs_create_file("max_clock", S_IRUSR | S_IWUSR, root, host,
+		&mmc_max_clock_fops))
+		goto err_node;
+
 #ifdef CONFIG_MMC_CLKGATE
 	if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
 				root, &host->clk_delay))
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 0c634ca..4ee18c75 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -536,15 +536,6 @@
 #ifndef CONFIG_MTD_LAZYECCSTATS
 	part_fill_badblockstats(&(slave->mtd));
 #endif
-	if (master->_block_isbad) {
-		uint64_t offs = 0;
-
-		while (offs < slave->mtd.size) {
-			if (mtd_block_isbad(master, offs + slave->offset))
-				slave->mtd.ecc_stats.badblocks++;
-			offs += slave->mtd.erasesize;
-		}
-	}
 
 out_register:
 	return slave;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 81be519..703aca9 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -87,7 +87,7 @@
 struct pm8921_bms_chip {
 	struct device		*dev;
 	struct dentry		*dent;
-	unsigned int		r_sense;
+	int			r_sense_uohm;
 	unsigned int		v_cutoff;
 	unsigned int		fcc;
 	struct single_row_lut	*fcc_temp_lut;
@@ -500,15 +500,15 @@
 #define SLEEP_CLK_HZ		32764
 #define SECONDS_PER_HOUR	3600
 /**
- * ccmicrovolt_to_nvh -
+ * ccmicrovolt_to_uvh -
  * @cc_uv:  coulumb counter converted to uV
  *
- * RETURNS:	coulumb counter based charge in nVh
- *		(nano Volt Hour)
+ * RETURNS:	coulumb counter based charge in uVh
+ *		(micro Volt Hour)
  */
-static s64 ccmicrovolt_to_nvh(s64 cc_uv)
+static s64 ccmicrovolt_to_uvh(s64 cc_uv)
 {
-	return div_s64(cc_uv * CC_READING_TICKS * 1000,
+	return div_s64(cc_uv * CC_READING_TICKS,
 			SLEEP_CLK_HZ * SECONDS_PER_HOUR);
 }
 
@@ -618,7 +618,7 @@
 
 	convert_vbatt_raw_to_uv(the_chip, usb_chg, vbat_raw, vbat_uv);
 	convert_vsense_to_uv(the_chip, vsense_raw, &vsense_uv);
-	*ibat_ua = vsense_uv * 1000 / (int)the_chip->r_sense;
+	*ibat_ua = div_s64((s64)vsense_uv * 1000000LL, the_chip->r_sense_uohm);
 
 	pr_debug("vsense_raw = 0x%x vbat_raw = 0x%x"
 			" ibat_ua = %d vbat_uv = %d\n",
@@ -840,7 +840,7 @@
  */
 static void calculate_cc_uah(struct pm8921_bms_chip *chip, int cc, int *val)
 {
-	int64_t cc_voltage_uv, cc_nvh, cc_uah;
+	int64_t cc_voltage_uv, cc_uvh, cc_uah;
 
 	cc_voltage_uv = cc;
 	cc_voltage_uv -= chip->cc_reading_at_100;
@@ -850,9 +850,9 @@
 	cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
 	cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv);
 	pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv);
-	cc_nvh = ccmicrovolt_to_nvh(cc_voltage_uv);
-	pr_debug("cc_nvh = %lld nano_volt_hour\n", cc_nvh);
-	cc_uah = div_s64(cc_nvh, chip->r_sense);
+	cc_uvh = ccmicrovolt_to_uvh(cc_voltage_uv);
+	pr_debug("cc_uvh = %lld micro_volt_hour\n", cc_uvh);
+	cc_uah = div_s64(cc_uvh * 1000000LL, chip->r_sense_uohm);
 	*val = cc_uah;
 }
 
@@ -2071,25 +2071,25 @@
 
 int pm8921_bms_get_battery_current(int *result_ua)
 {
-	int vsense;
+	int vsense_uv;
 
 	if (!the_chip) {
 		pr_err("called before initialization\n");
 		return -EINVAL;
 	}
-	if (the_chip->r_sense == 0) {
+	if (the_chip->r_sense_uohm == 0) {
 		pr_err("r_sense is zero\n");
 		return -EINVAL;
 	}
 
 	mutex_lock(&the_chip->bms_output_lock);
 	pm_bms_lock_output_data(the_chip);
-	read_vsense_avg(the_chip, &vsense);
+	read_vsense_avg(the_chip, &vsense_uv);
 	pm_bms_unlock_output_data(the_chip);
 	mutex_unlock(&the_chip->bms_output_lock);
-	pr_debug("vsense=%duV\n", vsense);
+	pr_debug("vsense=%duV\n", vsense_uv);
 	/* cast for signed division */
-	*result_ua = vsense * 1000 / (int)the_chip->r_sense;
+	*result_ua = div_s64(vsense_uv * 1000000LL, the_chip->r_sense_uohm);
 	pr_debug("ibat=%duA\n", *result_ua);
 	return 0;
 }
@@ -2897,7 +2897,7 @@
 	mutex_init(&chip->bms_output_lock);
 	mutex_init(&chip->last_ocv_uv_mutex);
 	chip->dev = &pdev->dev;
-	chip->r_sense = pdata->r_sense;
+	chip->r_sense_uohm = pdata->r_sense_uohm;
 	chip->v_cutoff = pdata->v_cutoff;
 	chip->max_voltage_uv = pdata->max_voltage_uv;
 	chip->chg_term_ua = pdata->chg_term_ua;
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index 1b9426a..a586f3d8 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -72,7 +72,7 @@
 	unsigned int		revision;
 	unsigned int		calib_delay_ms;
 	int			eoc_irq;
-	int			r_sense;
+	int			r_sense_uohm;
 	struct delayed_work	calib_ccadc_work;
 };
 
@@ -562,7 +562,8 @@
 		return rc;
 	}
 
-	*bat_current_ua = voltage_uv * 1000/the_chip->r_sense;
+	*bat_current_ua = div_s64((s64)voltage_uv * 1000000LL,
+						the_chip->r_sense_uohm);
 	/*
 	 * ccadc reads +ve current when the battery is charging
 	 * We need to return -ve if the battery is charging
@@ -675,7 +676,7 @@
 	chip->dev = &pdev->dev;
 	chip->revision = pm8xxx_get_revision(chip->dev->parent);
 	chip->eoc_irq = res->start;
-	chip->r_sense = pdata->r_sense;
+	chip->r_sense_uohm = pdata->r_sense_uohm;
 	chip->calib_delay_ms = pdata->calib_delay_ms;
 
 	calib_ccadc_read_offset_and_gain(chip,
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 7b4d97e..1955ff4 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,7 +10,7 @@
  * GNU General Public License for more details.
  */
 
-#define pr_fmt(fmt)	"%s: " fmt, __func__
+#define pr_fmt(fmt)	"BMS: %s: " fmt, __func__
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -21,26 +21,17 @@
 #include <linux/of_device.h>
 #include <linux/power_supply.h>
 #include <linux/spmi.h>
-
-/* Interrupt offsets */
-#define INT_RT_STS(base)		(base + 0x10)
-#define INT_SET_TYPE(base)		(base + 0x11)
-#define INT_POLARITY_HIGH(base)		(base + 0x12)
-#define INT_POLARITY_LOW(base)		(base + 0x13)
-#define INT_LATCHED_CLR(base)		(base + 0x14)
-#define INT_EN_SET(base)		(base + 0x15)
-#define INT_EN_CLR(base)		(base + 0x16)
-#define INT_LATCHED_STS(base)		(base + 0x18)
-#define INT_PENDING_STS(base)		(base + 0x19)
-#define INT_MID_SEL(base)		(base + 0x1A)
-#define INT_PRIORITY(base)		(base + 0x1B)
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
 
 /* BMS Register Offsets */
 #define BMS1_REVISION1			0x0
 #define BMS1_REVISION2			0x1
 #define BMS1_STATUS1			0x8
 #define BMS1_MODE_CTL			0X40
-/* Columb counter clear registers */
+/* Coulomb counter clear registers */
 #define BMS1_CC_DATA_CTL		0x42
 #define BMS1_CC_CLEAR_CTRL		0x43
 /* OCV limit registers */
@@ -49,6 +40,8 @@
 #define BMS1_OCV_USE_HIGH_LIMIT_THR0	0x4A
 #define BMS1_OCV_USE_HIGH_LIMIT_THR1	0x4B
 #define BMS1_OCV_USE_LIMIT_CTL		0x4C
+/* Delay control */
+#define BMS1_S1_DELAY_CTL		0x5A
 /* CC interrupt threshold */
 #define BMS1_CC_THR0			0x7A
 #define BMS1_CC_THR1			0x7B
@@ -60,7 +53,7 @@
 #define BMS1_OCV_FOR_R_DATA1		0x81
 #define BMS1_VSENSE_FOR_R_DATA0		0x82
 #define BMS1_VSENSE_FOR_R_DATA1		0x83
-/* Columb counter data */
+/* Coulomb counter data */
 #define BMS1_CC_DATA0			0x8A
 #define BMS1_CC_DATA1			0x8B
 #define BMS1_CC_DATA2			0x8C
@@ -71,19 +64,45 @@
 #define BMS1_OCV_FOR_SOC_DATA1		0x91
 #define BMS1_VSENSE_PON_DATA0		0x94
 #define BMS1_VSENSE_PON_DATA1		0x95
+#define BMS1_VSENSE_AVG_DATA0		0x98
+#define BMS1_VSENSE_AVG_DATA1		0x99
 #define BMS1_VBAT_AVG_DATA0		0x9E
 #define BMS1_VBAT_AVG_DATA1		0x9F
 /* Extra bms registers */
 #define BMS1_BMS_DATA_REG_0		0xB0
-#define BMS1_BMS_DATA_REG_1		0xB1
-#define BMS1_BMS_DATA_REG_2		0xB2
+#define IAVG_STORAGE_REG		0xB1
+#define SOC_STORAGE_REG			0xB2
 #define BMS1_BMS_DATA_REG_3		0xB3
 
+/* Configuration for saving of shutdown soc/iavg */
+#define IGNORE_SOC_TEMP_DECIDEG		50
+#define IAVG_STEP_SIZE_MA		50
+#define IAVG_START			600
+#define SOC_ZERO			0xFF
+
+#define IAVG_SAMPLES 16
+
 #define QPNP_BMS_DEV_NAME "qcom,qpnp-bms"
 
+struct soc_params {
+	int		fcc_uah;
+	int		cc_uah;
+	int		rbatt;
+	int		iavg_ua;
+	int		uuc_uah;
+	int		ocv_charge_uah;
+};
+
+struct raw_soc_params {
+	uint16_t	last_good_ocv_raw;
+	int64_t		cc;
+	int		last_good_ocv_uv;
+};
+
 struct qpnp_bms_chip {
 	struct device			*dev;
 	struct power_supply		bms_psy;
+	struct power_supply		*batt_psy;
 	struct spmi_device		*spmi;
 	u16				base;
 
@@ -93,13 +112,71 @@
 	bool				online;
 	/* platform data */
 	unsigned int			r_sense_mohm;
-	unsigned int			v_cutoff;
-	unsigned int			max_voltage;
+	unsigned int			v_cutoff_uv;
+	unsigned int			max_voltage_uv;
 	unsigned int			r_conn_mohm;
 	int				shutdown_soc_valid_limit;
 	int				adjust_soc_low_threshold;
 	int				adjust_soc_high_threshold;
-	int				chg_term;
+	int				chg_term_ua;
+	enum battery_type		batt_type;
+	unsigned int			fcc;
+	struct single_row_lut		*fcc_temp_lut;
+	struct single_row_lut		*fcc_sf_lut;
+	struct pc_temp_ocv_lut		*pc_temp_ocv_lut;
+	struct sf_lut			*pc_sf_lut;
+	struct sf_lut			*rbatt_sf_lut;
+	int				default_rbatt_mohm;
+
+	struct delayed_work		calculate_soc_delayed_work;
+
+	struct mutex			bms_output_lock;
+	struct mutex			last_ocv_uv_mutex;
+	struct mutex			soc_invalidation_mutex;
+
+	unsigned int			start_percent;
+	unsigned int			end_percent;
+	bool				ignore_shutdown_soc;
+	int				shutdown_soc_invalid;
+	int				shutdown_soc;
+	int				shutdown_iavg_ma;
+
+	int				low_soc_calc_threshold;
+	int				low_soc_calculate_soc_ms;
+	int				calculate_soc_ms;
+
+	uint16_t			ocv_reading_at_100;
+	int64_t				cc_reading_at_100;
+	uint16_t			prev_last_good_ocv_raw;
+	int				last_ocv_uv;
+	int				last_cc_uah;
+	unsigned long			tm_sec;
+	bool				first_time_calc_soc;
+	bool				first_time_calc_uuc;
+	int				pon_ocv_uv;
+
+	int				iavg_samples_ma[IAVG_SAMPLES];
+	int				iavg_index;
+	int				iavg_num_samples;
+	struct timespec			t_soc_queried;
+	int				last_soc;
+	int				last_soc_est;
+
+	int				charge_time_us;
+	int				catch_up_time_us;
+	struct single_row_lut		*adjusted_fcc_temp_lut;
+
+	unsigned int			vadc_v0625;
+	unsigned int			vadc_v1250;
+
+	int				prev_iavg_ua;
+	int				prev_uuc_iavg_ma;
+	int				prev_pc_unusable;
+	int				ibat_at_cv_ua;
+	int				soc_at_cv;
+	int				prev_chg_soc;
+	int				calculated_soc;
+	int				last_vbat_read_uv;
 };
 
 static struct of_device_id qpnp_bms_match_table[] = {
@@ -119,6 +196,38 @@
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 };
 
+static bool use_voltage_soc;
+
+/* module params */
+static int bms_param_set_bool(const char *val, const struct kernel_param *kp)
+{
+	int rc;
+	struct power_supply *bms_psy;
+
+	rc = param_set_bool(val, kp);
+	if (rc) {
+		pr_err("failed to set %s, rc = %d\n", kp->name, rc);
+		return rc;
+	}
+
+	bms_psy = power_supply_get_by_name("bms");
+
+	if (bms_psy)
+		power_supply_changed(bms_psy);
+	else
+		pr_debug("%s changed but bms has not been initialized yet\n",
+				kp->name);
+
+	return 0;
+}
+
+static struct kernel_param_ops bms_param_ops = {
+	.set = bms_param_set_bool,
+	.get = param_get_bool,
+};
+
+module_param_cb(use_voltage_soc, &bms_param_ops, &use_voltage_soc, 0644);
+
 static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
 			u16 base, int count)
 {
@@ -126,31 +235,1420 @@
 	struct spmi_device *spmi = chip->spmi;
 
 	rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, val, count);
-	if (rc)
+	if (rc) {
 		pr_err("SPMI read failed rc=%d\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
+static int qpnp_write_wrapper(struct qpnp_bms_chip *chip, u8 *val,
+			u16 base, int count)
+{
+	int rc;
+	struct spmi_device *spmi = chip->spmi;
+
+	rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, base, val, count);
+	if (rc) {
+		pr_err("SPMI write failed rc=%d\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
+static int qpnp_masked_write(struct qpnp_bms_chip *chip, u16 addr,
+							u8 mask, u8 val)
+{
+	int rc;
+	u8 reg;
+
+	rc = qpnp_read_wrapper(chip, &reg, chip->base + addr, 1);
+	if (rc) {
+		pr_err("read failed addr = %03X, rc = %d\n",
+				chip->base + addr, rc);
+		return rc;
+	}
+	reg &= ~mask;
+	reg |= val & mask;
+	rc = qpnp_write_wrapper(chip, &reg, chip->base + addr, 1);
+	if (rc) {
+		pr_err("write failed addr = %03X, val = %02x, mask = %02x, reg = %02x, rc = %d\n",
+				chip->base + addr, val, mask, reg, rc);
+		return rc;
+	}
+	return 0;
+}
+
+#define HOLD_OREG_DATA		BIT(0)
+static int lock_output_data(struct qpnp_bms_chip *chip)
+{
+	int rc;
+
+	rc = qpnp_masked_write(chip, BMS1_CC_DATA_CTL,
+				HOLD_OREG_DATA, HOLD_OREG_DATA);
+	if (rc) {
+		pr_err("couldnt lock bms output rc = %d\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
+static int unlock_output_data(struct qpnp_bms_chip *chip)
+{
+	int rc;
+
+	rc = qpnp_masked_write(chip, BMS1_CC_DATA_CTL, HOLD_OREG_DATA, 0);
+	if (rc) {
+		pr_err("fail to unlock BMS_CONTROL rc = %d\n", rc);
+		return rc;
+	}
+	return 0;
+}
+
+#define V_PER_BIT_MUL_FACTOR	97656
+#define V_PER_BIT_DIV_FACTOR	1000
+#define VADC_INTRINSIC_OFFSET	0x6000
+
+static int vadc_reading_to_uv(unsigned int reading)
+{
+	if (reading <= VADC_INTRINSIC_OFFSET)
+		return 0;
+
+	return (reading - VADC_INTRINSIC_OFFSET)
+			* V_PER_BIT_MUL_FACTOR / V_PER_BIT_DIV_FACTOR;
+}
+
+#define VADC_CALIB_UV		625000
+#define VBATT_MUL_FACTOR	3
+
+static int adjust_vbatt_reading(struct qpnp_bms_chip *chip,
+						unsigned int reading_uv)
+{
+	s64 numerator, denominator;
+
+	if (reading_uv == 0)
+		return 0;
+
+	/* don't adjust if not calibrated */
+	if (chip->vadc_v0625 == 0 || chip->vadc_v1250 == 0) {
+		pr_debug("No cal yet return %d\n",
+				VBATT_MUL_FACTOR * reading_uv);
+		return VBATT_MUL_FACTOR * reading_uv;
+	}
+
+	numerator = ((s64)reading_uv - chip->vadc_v0625) * VADC_CALIB_UV;
+	denominator =  (s64)chip->vadc_v1250 - chip->vadc_v0625;
+	if (denominator == 0)
+		return reading_uv * VBATT_MUL_FACTOR;
+	return (VADC_CALIB_UV + div_s64(numerator, denominator))
+						* VBATT_MUL_FACTOR;
+}
+
+static inline int convert_vbatt_raw_to_uv(struct qpnp_bms_chip *chip,
+					uint16_t reading)
+{
+	int uv;
+
+	uv = vadc_reading_to_uv(reading);
+	pr_debug("%u raw converted into %d uv\n", reading, uv);
+	uv = adjust_vbatt_reading(chip, uv);
+	pr_debug("adjusted into %d uv\n", uv);
+	return uv;
+}
+
+#define CC_READING_RESOLUTION_N	542535
+#define CC_READING_RESOLUTION_D	100000
+static int cc_reading_to_uv(int16_t reading)
+{
+	return div_s64(reading * CC_READING_RESOLUTION_N,
+					CC_READING_RESOLUTION_D);
+}
+
+#define QPNP_ADC_GAIN_NV				17857LL
+static s64 cc_adjust_for_gain(s64 uv, uint16_t gain)
+{
+	s64 result_uv;
+
+	pr_debug("adjusting_uv = %lld\n", uv);
+	pr_debug("adjusting by factor: %lld/%hu = %lld%%\n",
+			QPNP_ADC_GAIN_NV, gain,
+			div_s64(QPNP_ADC_GAIN_NV * 100LL, (s64)gain));
+
+	result_uv = div_s64(uv * QPNP_ADC_GAIN_NV, (s64)gain);
+	pr_debug("result_uv = %lld\n", result_uv);
+	return result_uv;
+}
+
+static int convert_vsense_to_uv(struct qpnp_bms_chip *chip,
+					int16_t reading)
+{
+	struct qpnp_iadc_calib calibration;
+
+	qpnp_iadc_get_gain_and_offset(&calibration);
+	return cc_adjust_for_gain(cc_reading_to_uv(reading),
+			calibration.gain_raw);
+}
+
+static int read_vsense_avg(struct qpnp_bms_chip *chip, int *result_uv)
+{
+	int rc;
+	int16_t reading;
+
+	rc = qpnp_read_wrapper(chip, (u8 *)&reading,
+			chip->base + BMS1_VSENSE_AVG_DATA0, 2);
+
+	if (rc) {
+		pr_err("fail to read VSENSE_AVG rc = %d\n", rc);
+		return rc;
+	}
+
+	*result_uv = convert_vsense_to_uv(chip, reading);
+	return 0;
+}
+
+static int get_battery_current(struct qpnp_bms_chip *chip, int *result_ua)
+{
+	int vsense_uv = 0;
+
+	if (chip->r_sense_mohm == 0) {
+		pr_err("r_sense is zero\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&chip->bms_output_lock);
+	lock_output_data(chip);
+	read_vsense_avg(chip, &vsense_uv);
+	unlock_output_data(chip);
+	mutex_unlock(&chip->bms_output_lock);
+
+	pr_debug("vsense_uv=%duV\n", vsense_uv);
+	/* cast for signed division */
+	*result_ua = vsense_uv * 1000 / (int)chip->r_sense_mohm;
+	pr_debug("ibat=%duA\n", *result_ua);
+	return 0;
+}
+
+static int get_battery_voltage(int *result_uv)
+{
+	int rc;
+	struct qpnp_vadc_result adc_result;
+
+	rc = qpnp_vadc_read(VBAT_SNS, &adc_result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					VBAT_SNS, rc);
+		return rc;
+	}
+	pr_debug("mvolts phy = %lld meas = 0x%llx\n", adc_result.physical,
+						adc_result.measurement);
+	*result_uv = (int)adc_result.physical;
+	return 0;
+}
+
+#define CC_36_BIT_MASK 0xFFFFFFFFFLL
+
+static int read_cc_raw(struct qpnp_bms_chip *chip, int64_t *reading)
+{
+	int64_t raw_reading;
+	int rc;
+
+	rc = qpnp_read_wrapper(chip, (u8 *)&raw_reading,
+			chip->base + BMS1_CC_DATA0, 5);
+	if (rc) {
+		pr_err("Error reading cc: rc = %d\n", rc);
+		return -ENXIO;
+	}
+
+	raw_reading = raw_reading & CC_36_BIT_MASK;
+	/* convert 36 bit signed value into 64 signed value */
+	*reading = (raw_reading >> 35) == 0LL ?
+		raw_reading : ((-1LL ^ CC_36_BIT_MASK) | raw_reading);
+	pr_debug("before conversion: %llx, after conversion: %llx\n",
+			raw_reading, *reading);
 
 	return 0;
 }
 
+static int calib_vadc(struct qpnp_bms_chip *chip)
+{
+	int rc;
+	struct qpnp_vadc_result result;
+
+	rc = qpnp_vadc_read(REF_625MV, &result);
+	if (rc) {
+		pr_debug("vadc read failed with rc = %d\n", rc);
+		return rc;
+	}
+	chip->vadc_v0625 = result.physical;
+
+	rc = qpnp_vadc_read(REF_125V, &result);
+	if (rc) {
+		pr_debug("vadc read failed with rc = %d\n", rc);
+		return rc;
+	}
+	chip->vadc_v1250 = result.physical;
+	pr_debug("vadc calib: 0625 = %d, 1250 = %d\n",
+			chip->vadc_v0625, chip->vadc_v1250);
+	return 0;
+}
+
+static void convert_and_store_ocv(struct qpnp_bms_chip *chip,
+				struct raw_soc_params *raw)
+{
+	int rc;
+
+	pr_debug("prev_last_good_ocv_raw = %d, last_good_ocv_raw = %d\n",
+			chip->prev_last_good_ocv_raw,
+			raw->last_good_ocv_raw);
+	rc = calib_vadc(chip);
+	if (rc)
+		pr_err("Vadc reference voltage read failed, rc = %d\n", rc);
+	chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
+	raw->last_good_ocv_uv = convert_vbatt_raw_to_uv(chip,
+					raw->last_good_ocv_raw);
+	chip->last_ocv_uv = raw->last_good_ocv_uv;
+	pr_debug("last_good_ocv_uv = %d\n", raw->last_good_ocv_uv);
+}
+
+static int read_soc_params_raw(struct qpnp_bms_chip *chip,
+				struct raw_soc_params *raw)
+{
+	int rc;
+
+	mutex_lock(&chip->bms_output_lock);
+	lock_output_data(chip);
+
+	rc = qpnp_read_wrapper(chip, (u8 *)&raw->last_good_ocv_raw,
+			chip->base + BMS1_OCV_FOR_SOC_DATA0, 2);
+	if (rc) {
+		pr_err("Error reading ocv: rc = %d\n", rc);
+		return -ENXIO;
+	}
+
+	rc = read_cc_raw(chip, &raw->cc);
+	if (rc) {
+		pr_err("Failed to read raw cc data, rc = %d\n", rc);
+		return rc;
+	}
+
+	unlock_output_data(chip);
+	mutex_unlock(&chip->bms_output_lock);
+
+	if (chip->prev_last_good_ocv_raw == 0) {
+		convert_and_store_ocv(chip, raw);
+		pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
+	} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
+		convert_and_store_ocv(chip, raw);
+		/* forget the old cc value upon ocv */
+		chip->last_cc_uah = 0;
+	} else {
+		raw->last_good_ocv_uv = chip->last_ocv_uv;
+	}
+
+	/* fake a high OCV if done charging */
+	if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
+		chip->ocv_reading_at_100 = 0;
+		chip->cc_reading_at_100 = 0;
+	} else {
+		/*
+		 * force 100% ocv by selecting the highest voltage the
+		 * battery could ever reach
+		 */
+		raw->last_good_ocv_uv = chip->max_voltage_uv;
+		chip->last_ocv_uv = chip->max_voltage_uv;
+	}
+	pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
+			raw->last_good_ocv_raw, raw->last_good_ocv_uv);
+	pr_debug("cc_raw= 0x%llx\n", raw->cc);
+	return 0;
+}
+
+static int calculate_pc(struct qpnp_bms_chip *chip, int ocv_uv,
+							int batt_temp)
+{
+	int pc;
+
+	pc = interpolate_pc(chip->pc_temp_ocv_lut,
+			batt_temp / 10, ocv_uv / 1000);
+	pr_debug("pc = %u %% for ocv = %d uv batt_temp = %d\n",
+					pc, ocv_uv, batt_temp);
+	/* Multiply the initial FCC value by the scale factor. */
+	return pc;
+}
+
+static int calculate_fcc(struct qpnp_bms_chip *chip, int batt_temp)
+{
+	int fcc_uah;
+
+	if (chip->adjusted_fcc_temp_lut == NULL) {
+		/* interpolate_fcc returns a mv value. */
+		fcc_uah = interpolate_fcc(chip->fcc_temp_lut,
+						batt_temp) * 1000;
+		pr_debug("fcc = %d uAh\n", fcc_uah);
+		return fcc_uah;
+	} else {
+		return 1000 * interpolate_fcc(chip->adjusted_fcc_temp_lut,
+				batt_temp);
+	}
+}
+
+/* calculate remaining charge at the time of ocv */
+static int calculate_ocv_charge(struct qpnp_bms_chip *chip,
+						struct raw_soc_params *raw,
+						int fcc_uah,
+						int batt_temp)
+{
+	int  ocv_uv, pc;
+
+	ocv_uv = raw->last_good_ocv_uv;
+	pc = calculate_pc(chip, ocv_uv, batt_temp);
+	pr_debug("ocv_uv = %d pc = %d\n", ocv_uv, pc);
+	return (fcc_uah * pc) / 100;
+}
+
+#define CC_RESOLUTION_N		542535
+#define CC_RESOLUTION_D		100000
+
+static s64 cc_to_uv(s64 cc)
+{
+	return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
+}
+
+#define CC_READING_TICKS	56
+#define SLEEP_CLK_HZ		32764
+#define SECONDS_PER_HOUR	3600
+
+static s64 cc_uv_to_nvh(s64 cc_uv)
+{
+	return div_s64(cc_uv * CC_READING_TICKS * 1000,
+			SLEEP_CLK_HZ * SECONDS_PER_HOUR);
+}
+
+/**
+ * calculate_cc-
+ * @chip:		the bms chip pointer
+ * @cc:			the cc reading from bms h/w
+ * @val:		return value
+ * @coulomb_counter:	adjusted coulomb counter for 100%
+ *
+ * RETURNS: in val pointer coulomb counter based charger in uAh
+ *          (micro Amp hour)
+ */
+static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc)
+{
+	int64_t cc_voltage_uv, cc_nvh, cc_uah;
+	struct qpnp_iadc_calib calibration;
+
+	qpnp_iadc_get_gain_and_offset(&calibration);
+	cc_voltage_uv = cc;
+	cc_voltage_uv -= chip->cc_reading_at_100;
+	pr_debug("cc = %lld. after subtracting 0x%llx cc = %lld\n",
+					cc, chip->cc_reading_at_100,
+					cc_voltage_uv);
+	cc_voltage_uv = cc_to_uv(cc_voltage_uv);
+	cc_voltage_uv = cc_adjust_for_gain(cc_voltage_uv, calibration.gain_raw);
+	pr_debug("cc_voltage_uv = %lld uv\n", cc_voltage_uv);
+	cc_nvh = cc_uv_to_nvh(cc_voltage_uv);
+	pr_debug("cc_nvh = %lld nano_volt_hour\n", cc_nvh);
+	cc_uah = div_s64(cc_nvh, chip->r_sense_mohm);
+	/* cc_raw had 4 bits of extra precision.
+	   By now it should be within 32 bit range */
+	return (int)cc_uah;
+}
+
+static int get_rbatt(struct qpnp_bms_chip *chip,
+					int soc_rbatt_mohm, int batt_temp)
+{
+	int rbatt_mohm, scalefactor;
+
+	rbatt_mohm = chip->default_rbatt_mohm;
+	pr_debug("rbatt before scaling = %d\n", rbatt_mohm);
+	if (chip->rbatt_sf_lut == NULL)  {
+		pr_debug("RBATT = %d\n", rbatt_mohm);
+		return rbatt_mohm;
+	}
+	/* Convert the batt_temp to DegC from deciDegC */
+	batt_temp = batt_temp / 10;
+	scalefactor = interpolate_scalingfactor(chip->rbatt_sf_lut,
+						batt_temp, soc_rbatt_mohm);
+	pr_debug("rbatt sf = %d for batt_temp = %d, soc_rbatt = %d\n",
+				scalefactor, batt_temp, soc_rbatt_mohm);
+	rbatt_mohm = (rbatt_mohm * scalefactor) / 100;
+
+	rbatt_mohm += chip->r_conn_mohm;
+	pr_debug("adding r_conn_mohm = %d rbatt = %d\n",
+				chip->r_conn_mohm, rbatt_mohm);
+
+	pr_debug("RBATT = %d\n", rbatt_mohm);
+	return rbatt_mohm;
+}
+
+static void calculate_iavg(struct qpnp_bms_chip *chip, int cc_uah,
+				int *iavg_ua)
+{
+	int delta_cc_uah, delta_time_s, rc;
+	struct rtc_time tm;
+	struct rtc_device *rtc;
+	unsigned long now_tm_sec = 0;
+
+	rc = 0;
+	/* if anything fails report the previous iavg_ua */
+	*iavg_ua = chip->prev_iavg_ua;
+
+	rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+	if (rtc == NULL) {
+		pr_err("%s: unable to open rtc device (%s)\n",
+			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+		goto out;
+	}
+
+	rc = rtc_read_time(rtc, &tm);
+	if (rc) {
+		pr_err("Error reading rtc device (%s) : %d\n",
+			CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto out;
+	}
+
+	rc = rtc_valid_tm(&tm);
+	if (rc) {
+		pr_err("Invalid RTC time (%s): %d\n",
+			CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto out;
+	}
+	rtc_tm_to_time(&tm, &now_tm_sec);
+
+	if (chip->tm_sec == 0) {
+		get_battery_current(chip, iavg_ua);
+		goto out;
+	}
+
+	delta_time_s = (now_tm_sec - chip->tm_sec);
+
+	/* use the previous iavg if called within 15 seconds */
+	if (delta_time_s < 15) {
+		*iavg_ua = chip->prev_iavg_ua;
+		goto out;
+	}
+
+	delta_cc_uah = cc_uah - chip->last_cc_uah;
+
+	*iavg_ua = div_s64((s64)delta_cc_uah * 3600, delta_time_s);
+
+	pr_debug("tm_sec = %ld, now_tm_sec = %ld delta_s = %d delta_cc = %d iavg_ua = %d\n",
+				chip->tm_sec, now_tm_sec,
+				delta_time_s, delta_cc_uah, (int)*iavg_ua);
+
+out:
+	/* remember the iavg */
+	chip->prev_iavg_ua = *iavg_ua;
+
+	/* remember cc_uah */
+	chip->last_cc_uah = cc_uah;
+
+	/* remember this time */
+	chip->tm_sec = now_tm_sec;
+}
+
+static int calculate_termination_uuc(struct qpnp_bms_chip *chip,
+					struct soc_params *params,
+					int batt_temp, int uuc_iavg_ma,
+					int *ret_pc_unusable)
+{
+	int unusable_uv, pc_unusable, uuc_uah;
+	int i = 0;
+	int ocv_mv;
+	int batt_temp_degc = batt_temp / 10;
+	int rbatt_mohm;
+	int delta_uv;
+	int prev_delta_uv = 0;
+	int prev_rbatt_mohm = 0;
+	int uuc_rbatt_mohm;
+
+	for (i = 0; i <= 100; i++) {
+		ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
+				batt_temp_degc, i);
+		rbatt_mohm = get_rbatt(chip, i, batt_temp);
+		unusable_uv = (rbatt_mohm * uuc_iavg_ma)
+							+ (chip->v_cutoff_uv);
+		delta_uv = ocv_mv * 1000 - unusable_uv;
+
+		pr_debug("soc = %d ocv = %d rbat = %d u_uv = %d delta_v = %d\n",
+				i, ocv_mv, rbatt_mohm, unusable_uv, delta_uv);
+
+		if (delta_uv > 0)
+			break;
+
+		prev_delta_uv = delta_uv;
+		prev_rbatt_mohm = rbatt_mohm;
+	}
+
+	uuc_rbatt_mohm = linear_interpolate(rbatt_mohm, delta_uv,
+					prev_rbatt_mohm, prev_delta_uv,
+					0);
+
+	unusable_uv = (uuc_rbatt_mohm * uuc_iavg_ma) + (chip->v_cutoff_uv);
+
+	pc_unusable = calculate_pc(chip, unusable_uv, batt_temp);
+	uuc_uah = (params->fcc_uah * pc_unusable) / 100;
+	pr_debug("For uuc_iavg_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d uuc = %d\n",
+					uuc_iavg_ma,
+					uuc_rbatt_mohm, unusable_uv,
+					pc_unusable, uuc_uah);
+	*ret_pc_unusable = pc_unusable;
+	return uuc_uah;
+}
+
+static int adjust_uuc(struct qpnp_bms_chip *chip,
+			struct soc_params *params,
+			int new_pc_unusable,
+			int new_uuc_uah,
+			int batt_temp)
+{
+	int new_unusable_mv, new_iavg_ma;
+	int batt_temp_degc = batt_temp / 10;
+
+	if (chip->prev_pc_unusable == -EINVAL
+		|| abs(chip->prev_pc_unusable - new_pc_unusable) <= 1) {
+		chip->prev_pc_unusable = new_pc_unusable;
+		return new_uuc_uah;
+	}
+
+	/* the uuc is trying to change more than 1% restrict it */
+	if (new_pc_unusable > chip->prev_pc_unusable)
+		chip->prev_pc_unusable++;
+	else
+		chip->prev_pc_unusable--;
+
+	new_uuc_uah = (params->fcc_uah * chip->prev_pc_unusable) / 100;
+
+	/* also find update the iavg_ma accordingly */
+	new_unusable_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
+			batt_temp_degc, chip->prev_pc_unusable);
+	if (new_unusable_mv < chip->v_cutoff_uv/1000)
+		new_unusable_mv = chip->v_cutoff_uv/1000;
+
+	new_iavg_ma = (new_unusable_mv * 1000 - chip->v_cutoff_uv)
+						/ params->rbatt;
+	if (new_iavg_ma == 0)
+		new_iavg_ma = 1;
+	chip->prev_uuc_iavg_ma = new_iavg_ma;
+	pr_debug("Restricting UUC to %d (%d%%) unusable_mv = %d iavg_ma = %d\n",
+					new_uuc_uah, chip->prev_pc_unusable,
+					new_unusable_mv, new_iavg_ma);
+
+	return new_uuc_uah;
+}
+
+#define CHARGING_IAVG_MA 250
+#define MIN_SECONDS_FOR_VALID_SAMPLE	20
+static int calculate_unusable_charge_uah(struct qpnp_bms_chip *chip,
+					struct soc_params *params,
+					int batt_temp)
+{
+	int uuc_uah_iavg;
+	int i;
+	int uuc_iavg_ma = params->iavg_ua / 1000;
+	int pc_unusable;
+
+	/*
+	 * if called first time, fill all the samples with
+	 * the shutdown_iavg_ma
+	 */
+	if (chip->first_time_calc_uuc && chip->shutdown_iavg_ma != 0) {
+		pr_debug("Using shutdown_iavg_ma = %d in all samples\n",
+				chip->shutdown_iavg_ma);
+		for (i = 0; i < IAVG_SAMPLES; i++)
+			chip->iavg_samples_ma[i] = chip->shutdown_iavg_ma;
+
+		chip->iavg_index = 0;
+		chip->iavg_num_samples = IAVG_SAMPLES;
+	}
+
+	/*
+	 * if charging use a nominal avg current to keep
+	 * a reasonable UUC while charging
+	 */
+	if (uuc_iavg_ma < 0)
+		uuc_iavg_ma = CHARGING_IAVG_MA;
+	chip->iavg_samples_ma[chip->iavg_index] = uuc_iavg_ma;
+	chip->iavg_index = (chip->iavg_index + 1) % IAVG_SAMPLES;
+	chip->iavg_num_samples++;
+	if (chip->iavg_num_samples >= IAVG_SAMPLES)
+		chip->iavg_num_samples = IAVG_SAMPLES;
+
+	/* now that this sample is added calcualte the average */
+	uuc_iavg_ma = 0;
+	if (chip->iavg_num_samples != 0) {
+		for (i = 0; i < chip->iavg_num_samples; i++) {
+			pr_debug("iavg_samples_ma[%d] = %d\n", i,
+					chip->iavg_samples_ma[i]);
+			uuc_iavg_ma += chip->iavg_samples_ma[i];
+		}
+
+		uuc_iavg_ma = DIV_ROUND_CLOSEST(uuc_iavg_ma,
+						chip->iavg_num_samples);
+	}
+
+	uuc_uah_iavg = calculate_termination_uuc(chip, params, uuc_iavg_ma,
+						batt_temp, &pc_unusable);
+	pr_debug("uuc_iavg_ma = %d uuc with iavg = %d\n",
+						uuc_iavg_ma, uuc_uah_iavg);
+
+	chip->prev_uuc_iavg_ma = uuc_iavg_ma;
+	/* restrict the uuc such that it can increase only by one percent */
+	uuc_uah_iavg = adjust_uuc(chip, params, pc_unusable,
+					uuc_uah_iavg, batt_temp);
+
+	chip->first_time_calc_uuc = 0;
+	return uuc_uah_iavg;
+}
+
+static void find_ocv_for_soc(struct qpnp_bms_chip *chip,
+				struct soc_params *params,
+				int batt_temp,
+				int shutdown_soc,
+				int *ret_ocv_uv)
+{
+	s64 ocv_charge_uah;
+	int pc, new_pc;
+	int batt_temp_degc = batt_temp / 10;
+	int ocv_uv;
+
+	ocv_charge_uah = (s64)shutdown_soc
+				* (params->fcc_uah - params->uuc_uah);
+	ocv_charge_uah = div_s64(ocv_charge_uah, 100)
+				+ params->cc_uah + params->uuc_uah;
+	pc = DIV_ROUND_CLOSEST((int)ocv_charge_uah * 100, params->fcc_uah);
+	pc = clamp(pc, 0, 100);
+
+	ocv_uv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
+
+	pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
+					shutdown_soc, params->fcc_uah,
+					params->uuc_uah, (int)ocv_charge_uah,
+					pc, ocv_uv);
+	new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv_uv);
+	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv_uv);
+
+	while (abs(new_pc - pc) > 1) {
+		int delta_mv = 5;
+
+		if (new_pc > pc)
+			delta_mv = -1 * delta_mv;
+
+		ocv_uv = ocv_uv + delta_mv;
+		new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+				batt_temp_degc, ocv_uv);
+		pr_debug("test revlookup pc = %d for ocv = %d\n",
+				new_pc, ocv_uv);
+	}
+
+	*ret_ocv_uv = ocv_uv * 1000;
+	params->ocv_charge_uah = (int)ocv_charge_uah;
+}
+
+static void calculate_soc_params(struct qpnp_bms_chip *chip,
+						struct raw_soc_params *raw,
+						struct soc_params *params,
+						int batt_temp)
+{
+	int soc_rbatt;
+
+	params->fcc_uah = calculate_fcc(chip, batt_temp);
+	pr_debug("FCC = %uuAh batt_temp = %d\n", params->fcc_uah, batt_temp);
+
+	/* calculate remainging charge */
+	params->ocv_charge_uah = calculate_ocv_charge(
+						chip, raw,
+						params->fcc_uah,
+						batt_temp);
+	pr_debug("ocv_charge_uah = %uuAh\n", params->ocv_charge_uah);
+
+	/* calculate cc micro_volt_hour */
+	params->cc_uah = calculate_cc(chip, raw->cc);
+	pr_debug("cc_uah = %duAh raw->cc = %llx cc = %lld after subtracting %llx\n",
+				params->cc_uah, raw->cc,
+				(int64_t)raw->cc - chip->cc_reading_at_100,
+				chip->cc_reading_at_100);
+
+	soc_rbatt = ((params->ocv_charge_uah - params->cc_uah) * 100)
+							/ params->fcc_uah;
+	if (soc_rbatt < 0)
+		soc_rbatt = 0;
+	params->rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
+
+	calculate_iavg(chip, params->cc_uah, &params->iavg_ua);
+
+	params->uuc_uah = calculate_unusable_charge_uah(chip, params,
+							batt_temp);
+	pr_debug("UUC = %uuAh\n", params->uuc_uah);
+}
+
+static bool is_shutdown_soc_within_limits(struct qpnp_bms_chip *chip, int soc)
+{
+	if (chip->shutdown_soc_invalid) {
+		pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
+		return 0;
+	}
+
+	if (abs(chip->shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
+		pr_debug("rejecting shutdown soc = %d, soc = %d limit = %d\n",
+			chip->shutdown_soc, soc,
+			chip->shutdown_soc_valid_limit);
+		chip->shutdown_soc_invalid = 1;
+		return 0;
+	}
+
+	return 1;
+}
+
+#define BMS_OVERRIDE_MODE_EN_BIT	BIT(7)
+#define EN_VBAT_BIT			BIT(0)
+#define OVERRIDE_MODE_DELAY_MS		20
+static int override_mode_batt_v_and_i(
+		struct qpnp_bms_chip *chip, int *ibat_ua, int *vbat_uv)
+{
+	int16_t vsense_raw, vbat_raw;
+	int vsense_uv, rc;
+	u8 delay;
+
+	mutex_lock(&chip->bms_output_lock);
+
+	delay = 0x00;
+	rc = qpnp_write_wrapper(chip, &delay,
+			chip->base + BMS1_S1_DELAY_CTL, 1);
+	if (rc)
+		pr_err("unable to write into BMS1_S1_DELAY, rc: %d\n", rc);
+
+	rc = qpnp_masked_write(chip, BMS1_MODE_CTL,
+			BMS_OVERRIDE_MODE_EN_BIT | EN_VBAT_BIT,
+			BMS_OVERRIDE_MODE_EN_BIT | EN_VBAT_BIT);
+	if (rc)
+		pr_err("unable to write into BMS1_MODE_CTL, rc: %d\n", rc);
+
+	msleep(OVERRIDE_MODE_DELAY_MS);
+
+	lock_output_data(chip);
+	qpnp_read_wrapper(chip, (u8 *)&vsense_raw,
+			chip->base + BMS1_VSENSE_AVG_DATA0, 2);
+	qpnp_read_wrapper(chip, (u8 *)&vbat_raw,
+			chip->base + BMS1_VBAT_AVG_DATA0, 2);
+	unlock_output_data(chip);
+
+	rc = qpnp_masked_write(chip, BMS1_MODE_CTL,
+			BMS_OVERRIDE_MODE_EN_BIT | EN_VBAT_BIT, 0);
+
+	delay = 0x0B;
+	rc = qpnp_write_wrapper(chip, &delay,
+			chip->base + BMS1_S1_DELAY_CTL, 1);
+	if (rc)
+		pr_err("unable to write into BMS1_S1_DELAY, rc: %d\n", rc);
+
+	mutex_unlock(&chip->bms_output_lock);
+
+	*vbat_uv = convert_vbatt_raw_to_uv(chip, vbat_raw);
+	vsense_uv = convert_vsense_to_uv(chip, vsense_raw);
+	*ibat_ua = vsense_uv * 1000 / (int)chip->r_sense_mohm;
+
+	pr_debug("vsense_raw = 0x%x vbat_raw = 0x%x ibat_ua = %d vbat_uv = %d\n",
+			(uint16_t)vsense_raw, (uint16_t)vbat_raw,
+			*ibat_ua, *vbat_uv);
+	return 0;
+}
+
+static int get_simultaneous_batt_v_and_i(
+						struct qpnp_bms_chip *chip,
+						int *ibat_ua, int *vbat_uv)
+{
+	int rc;
+	union power_supply_propval ret = {0,};
+
+	if (chip->batt_psy == NULL)
+		chip->batt_psy = power_supply_get_by_name("battery");
+	if (chip->batt_psy) {
+		/* if battery has been registered, use the status property */
+		chip->batt_psy->get_property(chip->batt_psy,
+					POWER_SUPPLY_PROP_STATUS, &ret);
+	} else {
+		/* default to using separate vbat/ibat if unregistered */
+		ret.intval = POWER_SUPPLY_STATUS_FULL;
+	}
+
+	if (ret.intval == POWER_SUPPLY_STATUS_FULL) {
+		pr_debug("batfet is open using separate vbat and ibat meas\n");
+		rc = get_battery_voltage(vbat_uv);
+		if (rc < 0) {
+			pr_err("adc vbat failed err = %d\n", rc);
+			return rc;
+		}
+		rc = get_battery_current(chip, ibat_ua);
+		if (rc < 0) {
+			pr_err("bms ibat failed err = %d\n", rc);
+			return rc;
+		}
+	} else {
+		return override_mode_batt_v_and_i(chip, ibat_ua, vbat_uv);
+	}
+
+	return 0;
+}
+
+static int bound_soc(int soc)
+{
+	soc = max(0, soc);
+	soc = min(100, soc);
+	return soc;
+}
+
+static int charging_adjustments(struct qpnp_bms_chip *chip,
+				struct soc_params *params, int soc,
+				int vbat_uv, int ibat_ua, int batt_temp)
+{
+	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;
+
+		chip->prev_chg_soc = chg_soc;
+
+		find_ocv_for_soc(chip, params, batt_temp, chg_soc, &new_ocv_uv);
+		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 adjust_soc(struct qpnp_bms_chip *chip, struct soc_params *params,
+							int soc, int batt_temp)
+{
+	int ibat_ua = 0, vbat_uv = 0;
+	int ocv_est_uv = 0, soc_est = 0, pc_est = 0, pc = 0;
+	int delta_ocv_uv = 0;
+	int n = 0;
+	int rc_new_uah = 0;
+	int pc_new = 0;
+	int soc_new = 0;
+	int slope = 0;
+	int rc = 0;
+	int delta_ocv_uv_limit = 0;
+
+	rc = get_simultaneous_batt_v_and_i(chip, &ibat_ua, &vbat_uv);
+	if (rc < 0) {
+		pr_err("simultaneous vbat ibat failed err = %d\n", rc);
+		goto out;
+	}
+
+	delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
+
+	ocv_est_uv = vbat_uv + (ibat_ua * params->rbatt)/1000;
+	pc_est = calculate_pc(chip, ocv_est_uv, batt_temp);
+	soc_est = div_s64((s64)params->fcc_uah * pc_est - params->uuc_uah*100,
+				(s64)params->fcc_uah - params->uuc_uah);
+	soc_est = bound_soc(soc_est);
+
+	if (ibat_ua < 0) {
+		soc = charging_adjustments(chip, params, soc, vbat_uv, ibat_ua,
+				batt_temp);
+		goto out;
+	}
+
+	/*
+	 * do not adjust
+	 * if soc is same as what bms calculated
+	 * if soc_est is between 45 and 25, this is the flat portion of the
+	 * curve where soc_est is not so accurate. We generally don't want to
+	 * adjust when soc_est is inaccurate except for the cases when soc is
+	 * way far off (higher than 50 or lesser than 20).
+	 * Also don't adjust soc if it is above 90 becuase it might be pulled
+	 * low and cause a bad user experience
+	 */
+	if (soc_est == soc
+		|| (is_between(45, chip->adjust_soc_low_threshold, soc_est)
+		&& is_between(50, chip->adjust_soc_low_threshold - 5, soc))
+		|| soc >= 90)
+		goto out;
+
+	if (chip->last_soc_est == -EINVAL)
+		chip->last_soc_est = soc;
+
+	n = min(200, max(1 , soc + soc_est + chip->last_soc_est));
+	chip->last_soc_est = soc_est;
+
+	pc = calculate_pc(chip, chip->last_ocv_uv, batt_temp);
+	if (pc > 0) {
+		pc_new = calculate_pc(chip,
+				chip->last_ocv_uv - (++slope * 1000),
+				batt_temp);
+		while (pc_new == pc) {
+			/* start taking 10mV steps */
+			slope = slope + 10;
+			pc_new = calculate_pc(chip,
+				chip->last_ocv_uv - (slope * 1000),
+				batt_temp);
+		}
+	} else {
+		/*
+		 * pc is already at the lowest point,
+		 * assume 1 millivolt translates to 1% pc
+		 */
+		pc = 1;
+		pc_new = 0;
+		slope = 1;
+	}
+
+	delta_ocv_uv = div_s64((soc - soc_est) * (s64)slope * 1000,
+							n * (pc - pc_new));
+
+	if (abs(delta_ocv_uv) > delta_ocv_uv_limit) {
+		pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
+				delta_ocv_uv_limit);
+
+		if (delta_ocv_uv > 0)
+			delta_ocv_uv = delta_ocv_uv_limit;
+		else
+			delta_ocv_uv = -1 * delta_ocv_uv_limit;
+		pr_debug("new delta ocv = %d\n", delta_ocv_uv);
+	}
+
+	chip->last_ocv_uv -= delta_ocv_uv;
+
+	if (chip->last_ocv_uv >= chip->max_voltage_uv)
+		chip->last_ocv_uv = chip->max_voltage_uv;
+
+	/* calculate the soc based on this new ocv */
+	pc_new = calculate_pc(chip, chip->last_ocv_uv, batt_temp);
+	rc_new_uah = (params->fcc_uah * pc_new) / 100;
+	soc_new = (rc_new_uah - params->cc_uah - params->uuc_uah)*100
+					/ (params->fcc_uah - params->uuc_uah);
+	soc_new = bound_soc(soc_new);
+
+	/*
+	 * if soc_new is ZERO force it higher so that phone doesnt report soc=0
+	 * soc = 0 should happen only when soc_est == 0
+	 */
+	if (soc_new == 0 && soc_est != 0)
+		soc_new = 1;
+
+	soc = soc_new;
+
+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, rbatt = %d, slope = %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, params->rbatt, slope);
+
+	return soc;
+}
+
+static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
+					struct raw_soc_params *raw,
+					int batt_temp)
+{
+	int soc, new_ocv_uv;
+	int shutdown_soc, new_calculated_soc, remaining_usable_charge_uah;
+	struct soc_params params;
+
+	calculate_soc_params(chip, raw, &params, batt_temp);
+	/* calculate remaining usable charge */
+	remaining_usable_charge_uah = params.ocv_charge_uah
+					- params.cc_uah
+					- params.uuc_uah;
+
+	pr_debug("RUC = %duAh\n", remaining_usable_charge_uah);
+	if (params.fcc_uah - params.uuc_uah <= 0) {
+		pr_warn("FCC = %duAh, UUC = %duAh forcing soc = 0\n",
+						params.fcc_uah,
+						params.uuc_uah);
+		soc = 0;
+	} else {
+		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+					(params.fcc_uah
+						- params.uuc_uah));
+	}
+
+	if (chip->first_time_calc_soc && soc < 0) {
+		/*
+		 * first time calcualtion and the pon ocv  is too low resulting
+		 * in a bad soc. Adjust ocv to get 0 soc
+		 */
+		pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
+		find_ocv_for_soc(chip, &params, batt_temp, 0, &new_ocv_uv);
+		chip->last_ocv_uv = new_ocv_uv;
+
+		remaining_usable_charge_uah = params.ocv_charge_uah
+					- params.cc_uah
+					- params.uuc_uah;
+
+		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+					(params.fcc_uah
+						- params.uuc_uah));
+		pr_debug("DONE for O soc is %d, pon ocv adjusted to %duV\n",
+				soc, chip->last_ocv_uv);
+	}
+
+	if (soc > 100)
+		soc = 100;
+
+	if (soc < 0) {
+		pr_err("bad rem_usb_chg = %d rem_chg %d, cc_uah %d, unusb_chg %d\n",
+				remaining_usable_charge_uah,
+				params.ocv_charge_uah,
+				params.cc_uah, params.uuc_uah);
+
+		pr_err("for bad rem_usb_chg last_ocv_uv = %d batt_temp = %d fcc = %d soc =%d\n",
+				chip->last_ocv_uv, batt_temp,
+				params.fcc_uah, soc);
+		soc = 0;
+	}
+
+	mutex_lock(&chip->soc_invalidation_mutex);
+	shutdown_soc = chip->shutdown_soc;
+
+	if (chip->first_time_calc_soc && soc != shutdown_soc
+			&& is_shutdown_soc_within_limits(chip, soc)) {
+		/*
+		 * soc for the first time - use shutdown soc
+		 * to adjust pon ocv since it is a small percent away from
+		 * the real soc
+		 */
+		pr_debug("soc = %d before forcing shutdown_soc = %d\n",
+							soc, shutdown_soc);
+		find_ocv_for_soc(chip, &params, batt_temp,
+					shutdown_soc, &new_ocv_uv);
+		chip->pon_ocv_uv = chip->last_ocv_uv;
+		chip->last_ocv_uv = new_ocv_uv;
+
+		remaining_usable_charge_uah = params.ocv_charge_uah
+					- params.cc_uah
+					- params.uuc_uah;
+
+		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+					(params.fcc_uah
+						- params.uuc_uah));
+
+		pr_debug("DONE for shutdown_soc = %d soc is %d, adjusted ocv to %duV\n",
+				shutdown_soc, soc, chip->last_ocv_uv);
+	}
+	mutex_unlock(&chip->soc_invalidation_mutex);
+
+	pr_debug("SOC before adjustment = %d\n", soc);
+	new_calculated_soc = adjust_soc(chip, &params, soc, batt_temp);
+
+	if (new_calculated_soc != chip->calculated_soc
+			&& chip->bms_psy.name != NULL) {
+		power_supply_changed(&chip->bms_psy);
+		pr_debug("power supply changed\n");
+	}
+
+	chip->calculated_soc = new_calculated_soc;
+	pr_debug("Set calculated SOC = %d\n", chip->calculated_soc);
+	chip->first_time_calc_soc = 0;
+	return chip->calculated_soc;
+}
+
+static void read_vbat(struct qpnp_bms_chip *chip)
+{
+	int rc;
+	struct qpnp_vadc_result result;
+
+	rc = qpnp_vadc_read(VBAT_SNS, &result);
+	if (rc) {
+		pr_err("error reading vadc VBAT_SNS = %d, rc = %d\n",
+					VBAT_SNS, rc);
+		return;
+	}
+	chip->last_vbat_read_uv = (int)result.physical;
+}
+
+static void calculate_soc_work(struct work_struct *work)
+{
+	struct qpnp_bms_chip *chip = container_of(work,
+				struct qpnp_bms_chip,
+				calculate_soc_delayed_work.work);
+	int batt_temp, rc, soc;
+	struct qpnp_vadc_result result;
+	struct raw_soc_params raw;
+
+	read_vbat(chip);
+
+	rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+	if (rc) {
+		pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
+					LR_MUX1_BATT_THERM, rc);
+		return;
+	}
+	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+						result.measurement);
+	batt_temp = (int)result.physical;
+
+	mutex_lock(&chip->last_ocv_uv_mutex);
+	read_soc_params_raw(chip, &raw);
+	soc = calculate_state_of_charge(chip, &raw, batt_temp);
+	mutex_unlock(&chip->last_ocv_uv_mutex);
+
+	if (soc < chip->low_soc_calc_threshold)
+		schedule_delayed_work(&chip->calculate_soc_delayed_work,
+			round_jiffies_relative(msecs_to_jiffies
+			(chip->low_soc_calculate_soc_ms)));
+	else
+		schedule_delayed_work(&chip->calculate_soc_delayed_work,
+			round_jiffies_relative(msecs_to_jiffies
+			(chip->calculate_soc_ms)));
+}
+
+static void backup_soc_and_iavg(struct qpnp_bms_chip *chip, int batt_temp,
+				int soc)
+{
+	u8 temp;
+	int rc;
+	int iavg_ma = chip->prev_uuc_iavg_ma;
+
+	if (iavg_ma > IAVG_START)
+		temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+	else
+		temp = 0;
+
+	rc = qpnp_write_wrapper(chip, &temp,
+			chip->base + IAVG_STORAGE_REG, 1);
+
+	if (soc == 0)
+		temp = SOC_ZERO;
+	else
+		temp = soc;
+
+	/* don't store soc if temperature is below 5degC */
+	if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
+		rc = qpnp_write_wrapper(chip, &temp,
+				chip->base + SOC_STORAGE_REG, 1);
+}
+
+#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)
+static int scale_soc_while_chg(struct qpnp_bms_chip *chip,
+				int delta_time_us, int new_soc, int prev_soc)
+{
+	int chg_time_sec;
+	int catch_up_sec;
+	int scaled_soc;
+	int numerator;
+
+	/*
+	 * The device must be charging for reporting a higher soc, if
+	 * not ignore this soc and continue reporting the prev_soc.
+	 * Also don't report a high value immediately slowly scale the
+	 * value from prev_soc to the new soc based on a charge time
+	 * weighted average
+	 */
+
+	/* if not charging, return last soc */
+	if (chip->start_percent == -EINVAL)
+		return prev_soc;
+
+	chg_time_sec = DIV_ROUND_UP(chip->charge_time_us, USEC_PER_SEC);
+	catch_up_sec = DIV_ROUND_UP(chip->catch_up_time_us, USEC_PER_SEC);
+	pr_debug("cts= %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
+
+	/*
+	 * if charging for more than catch_up time, simply return
+	 * new soc
+	 */
+	if (chg_time_sec > catch_up_sec)
+		return new_soc;
+
+	numerator = (catch_up_sec - chg_time_sec) * prev_soc
+			+ chg_time_sec * new_soc;
+	scaled_soc = numerator / catch_up_sec;
+
+	pr_debug("cts = %d new_soc = %d prev_soc = %d scaled_soc = %d\n",
+			chg_time_sec, new_soc, prev_soc, scaled_soc);
+
+	return scaled_soc;
+}
+
+/*
+ * bms_fake_battery is set in setups where a battery emulator is used instead
+ * of a real battery. This makes the bms driver report a different/fake value
+ * regardless of the calculated state of charge.
+ */
+static int bms_fake_battery = -EINVAL;
+module_param(bms_fake_battery, int, 0644);
+
+static int report_state_of_charge(struct qpnp_bms_chip *chip)
+{
+	int soc;
+	int delta_time_us;
+	struct timespec now;
+	struct qpnp_vadc_result result;
+	int batt_temp;
+	int rc;
+
+	if (bms_fake_battery != -EINVAL) {
+		pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
+		return bms_fake_battery;
+	}
+
+	soc = chip->calculated_soc;
+
+	rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					LR_MUX1_BATT_THERM, rc);
+		return rc;
+	}
+	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+						result.measurement);
+	batt_temp = (int)result.physical;
+
+	do_posix_clock_monotonic_gettime(&now);
+	if (chip->t_soc_queried.tv_sec != 0) {
+		delta_time_us
+		= (now.tv_sec - chip->t_soc_queried.tv_sec) * USEC_PER_SEC
+			+ (now.tv_nsec - chip->t_soc_queried.tv_nsec) / 1000;
+	} else {
+		/* calculation for the first time */
+		delta_time_us = 0;
+	}
+
+	/*
+	 * account for charge time - limit it to SOC_CATCHUP_SEC to
+	 * avoid overflows when charging continues for extended periods
+	 */
+	if (chip->start_percent != -EINVAL) {
+		if (chip->charge_time_us == 0) {
+			/*
+			 * calculating soc for the first time
+			 * after start of chg. Initialize catchup time
+			 */
+			if (abs(soc - chip->last_soc) < MAX_CATCHUP_SOC)
+				chip->catch_up_time_us =
+				(soc - chip->last_soc)
+					* SOC_CATCHUP_SEC_PER_PERCENT
+					* USEC_PER_SEC;
+			else
+				chip->catch_up_time_us =
+				SOC_CATCHUP_SEC_MAX * USEC_PER_SEC;
+
+			if (chip->catch_up_time_us < 0)
+				chip->catch_up_time_us = 0;
+		}
+
+		/* add charge time */
+		if (chip->charge_time_us < SOC_CATCHUP_SEC_MAX * USEC_PER_SEC)
+			chip->charge_time_us += delta_time_us;
+
+		/* end catchup if calculated soc and last soc are same */
+		if (chip->last_soc == soc)
+			chip->catch_up_time_us = 0;
+	}
+
+	/* last_soc < soc  ... scale and catch up */
+	if (chip->last_soc != -EINVAL && chip->last_soc < soc && soc != 100)
+		soc = scale_soc_while_chg(chip, delta_time_us,
+						soc, chip->last_soc);
+
+	pr_debug("last_soc = %d, calculated_soc = %d, soc = %d\n",
+			chip->last_soc, chip->calculated_soc, soc);
+	chip->last_soc = soc;
+	backup_soc_and_iavg(chip, batt_temp, chip->last_soc);
+	pr_debug("Reported SOC = %d\n", chip->last_soc);
+	chip->t_soc_queried = now;
+
+	return chip->last_soc;
+}
+
+static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip)
+{
+	int voltage_range_uv, voltage_remaining_uv, voltage_based_soc;
+
+	if (chip->last_vbat_read_uv < 0)
+		read_vbat(chip);
+
+	voltage_range_uv = chip->max_voltage_uv - chip->v_cutoff_uv;
+	voltage_remaining_uv = chip->last_vbat_read_uv - chip->v_cutoff_uv;
+	voltage_based_soc = voltage_remaining_uv * 100 / voltage_range_uv;
+
+	return clamp(voltage_based_soc, 0, 100);
+}
+
 /* Returns capacity as a SoC percentage between 0 and 100 */
 static int get_prop_bms_capacity(struct qpnp_bms_chip *chip)
 {
-	/* return 50 until a real algorithm is implemented */
-	return 50;
+	if (use_voltage_soc)
+		return calculate_soc_from_voltage(chip);
+	else
+		return report_state_of_charge(chip);
 }
 
 /* Returns instantaneous current in uA */
 static int get_prop_bms_current_now(struct qpnp_bms_chip *chip)
 {
 	/* temporarily return 0 until a real algorithm is put in */
-	return 0;
+	int rc, result_ua;
+
+	rc = get_battery_current(chip, &result_ua);
+	if (rc) {
+		pr_err("failed to get current: %d\n", rc);
+		return rc;
+	}
+	return result_ua;
 }
 
 /* Returns full charge design in uAh */
 static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
 {
-	/* temporarily return 0 until a real algorithm is put in */
-	return 0;
+	return chip->fcc;
+}
+
+static bool get_prop_bms_online(struct qpnp_bms_chip *chip)
+{
+	return chip->online;
+}
+
+static int get_prop_bms_status(struct qpnp_bms_chip *chip)
+{
+	return chip->charger_status;
 }
 
 static void set_prop_bms_online(struct qpnp_bms_chip *chip, bool online)
@@ -184,6 +1682,12 @@
 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 		val->intval = get_prop_bms_charge_full_design(chip);
 		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = get_prop_bms_status(chip);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = get_prop_bms_online(chip);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -210,24 +1714,206 @@
 	return 0;
 }
 
-#define SPMI_PROPERTY_READ(chip_prop, qpnp_spmi_property, retval, errlabel)\
+static void read_shutdown_soc_and_iavg(struct qpnp_bms_chip *chip)
+{
+	int rc;
+	u8 temp;
+
+	if (chip->ignore_shutdown_soc) {
+		chip->shutdown_soc_invalid = 1;
+		chip->shutdown_soc = 0;
+		chip->shutdown_iavg_ma = 0;
+	} else {
+		rc = qpnp_read_wrapper(chip, &temp,
+				chip->base + IAVG_STORAGE_REG, 1);
+		if (rc) {
+			pr_err("failed to read addr = %d %d assuming %d\n",
+					chip->base + IAVG_STORAGE_REG, rc,
+					IAVG_START);
+			chip->shutdown_iavg_ma = IAVG_START;
+		} else {
+			if (temp == 0) {
+				chip->shutdown_iavg_ma = IAVG_START;
+			} else {
+				chip->shutdown_iavg_ma = IAVG_START
+					+ IAVG_STEP_SIZE_MA * (temp + 1);
+			}
+		}
+
+		rc = qpnp_read_wrapper(chip, &temp,
+				chip->base + SOC_STORAGE_REG, 1);
+		if (rc) {
+			pr_err("failed to read addr = %d %d\n",
+					chip->base + SOC_STORAGE_REG, rc);
+		} else {
+			chip->shutdown_soc = temp;
+
+			if (chip->shutdown_soc == 0) {
+				pr_debug("No shutdown soc available\n");
+				chip->shutdown_soc_invalid = 1;
+				chip->shutdown_iavg_ma = 0;
+			} else if (chip->shutdown_soc == SOC_ZERO) {
+				chip->shutdown_soc = 0;
+			}
+		}
+	}
+
+	pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d\n",
+			chip->shutdown_soc,
+			chip->shutdown_iavg_ma,
+			chip->shutdown_soc_invalid);
+}
+
+#define PALLADIUM_ID_MIN	0x7F40
+#define PALLADIUM_ID_MAX	0x7F5A
+#define DESAY_5200_ID_MIN	0x7F7F
+#define DESAY_5200_ID_MAX	0x802F
+static int32_t read_battery_id(struct qpnp_bms_chip *chip)
+{
+	int rc;
+	struct qpnp_vadc_result result;
+
+	rc = qpnp_vadc_read(LR_MUX2_BAT_ID, &result);
+	if (rc) {
+		pr_err("error reading batt id channel = %d, rc = %d\n",
+					LR_MUX2_BAT_ID, rc);
+		return rc;
+	}
+	pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
+						result.measurement);
+	pr_debug("raw_code = 0x%x\n", result.adc_code);
+	return result.adc_code;
+}
+
+static int set_battery_data(struct qpnp_bms_chip *chip)
+{
+	int64_t battery_id;
+
+	if (chip->batt_type == BATT_DESAY)
+		goto desay;
+	else if (chip->batt_type == BATT_PALLADIUM)
+		goto palladium;
+
+	battery_id = read_battery_id(chip);
+	if (battery_id < 0) {
+		pr_err("cannot read battery id err = %lld\n", battery_id);
+		return battery_id;
+	}
+
+	if (is_between(PALLADIUM_ID_MIN, PALLADIUM_ID_MAX, battery_id)) {
+		goto palladium;
+	} else if (is_between(DESAY_5200_ID_MIN, DESAY_5200_ID_MAX,
+				battery_id)) {
+		goto desay;
+	} else {
+		pr_warn("invalid battid, palladium 1500 assumed batt_id %llx\n",
+				battery_id);
+		goto palladium;
+	}
+
+palladium:
+		chip->fcc = palladium_1500_data.fcc;
+		chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
+		chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
+		chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
+		chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
+		chip->rbatt_sf_lut = palladium_1500_data.rbatt_sf_lut;
+		chip->default_rbatt_mohm
+				= palladium_1500_data.default_rbatt_mohm;
+		goto check_lut;
+desay:
+		chip->fcc = desay_5200_data.fcc;
+		chip->fcc_temp_lut = desay_5200_data.fcc_temp_lut;
+		chip->pc_temp_ocv_lut = desay_5200_data.pc_temp_ocv_lut;
+		chip->pc_sf_lut = desay_5200_data.pc_sf_lut;
+		chip->rbatt_sf_lut = desay_5200_data.rbatt_sf_lut;
+		chip->default_rbatt_mohm = desay_5200_data.default_rbatt_mohm;
+		goto check_lut;
+check_lut:
+		if (chip->pc_temp_ocv_lut == NULL) {
+			pr_err("temp ocv lut table is NULL\n");
+			return -EINVAL;
+		}
+		return 0;
+}
+
+#define SPMI_PROP_READ(chip_prop, qpnp_spmi_property, retval)		\
 do {									\
-	retval = of_property_read_u32(spmi->dev.of_node,		\
+	retval = of_property_read_u32(chip->spmi->dev.of_node,		\
 				"qcom,bms-" qpnp_spmi_property,		\
 					&chip->chip_prop);		\
 	if (retval) {							\
 		pr_err("Error reading " #qpnp_spmi_property		\
 						" property %d\n", rc);	\
-		goto errlabel;						\
+		return -EINVAL;						\
 	}								\
 } while (0)
 
+static inline int bms_read_properties(struct qpnp_bms_chip *chip)
+{
+	int rc;
+
+	SPMI_PROP_READ(r_sense_mohm, "r-sense-mohm", rc);
+	SPMI_PROP_READ(v_cutoff_uv, "v-cutoff-uv", rc);
+	SPMI_PROP_READ(max_voltage_uv, "max-voltage-uv", rc);
+	SPMI_PROP_READ(r_conn_mohm, "r-conn-mohm", rc);
+	SPMI_PROP_READ(chg_term_ua, "chg-term-ua", rc);
+	SPMI_PROP_READ(shutdown_soc_valid_limit,
+			"shutdown-soc-valid-limit", rc);
+	SPMI_PROP_READ(adjust_soc_high_threshold,
+			"adjust-soc-high-threshold", rc);
+	SPMI_PROP_READ(adjust_soc_low_threshold,
+			"adjust-soc-low-threshold", rc);
+	SPMI_PROP_READ(batt_type, "batt-type", rc);
+	SPMI_PROP_READ(low_soc_calc_threshold,
+			"low-soc-calculate-soc-threshold", rc);
+	SPMI_PROP_READ(low_soc_calculate_soc_ms,
+			"low-soc-calculate-soc-ms", rc);
+	SPMI_PROP_READ(calculate_soc_ms, "calculate-soc-ms", rc);
+	chip->ignore_shutdown_soc = of_property_read_bool(
+			chip->spmi->dev.of_node,
+			"qcom,bms-ignore-shutdown-soc");
+	use_voltage_soc = of_property_read_bool(chip->spmi->dev.of_node,
+			"qcom,bms-use-voltage-soc");
+
+	if (chip->adjust_soc_low_threshold >= 45)
+		chip->adjust_soc_low_threshold = 45;
+
+	pr_debug("dts data: r_sense_mohm:%d, v_cutoff_uv:%d, max_v:%d\n",
+			chip->r_sense_mohm, chip->v_cutoff_uv,
+			chip->max_voltage_uv);
+	pr_debug("r_conn:%d, shutdown_soc: %d, adjust_soc_low:%d\n",
+			chip->r_conn_mohm, chip->shutdown_soc_valid_limit,
+			chip->adjust_soc_low_threshold);
+	pr_debug("adjust_soc_high:%d, chg_term_ua:%d, batt_type:%d\n",
+			chip->adjust_soc_high_threshold, chip->chg_term_ua,
+			chip->batt_type);
+	pr_debug("ignore_shutdown_soc:%d, use_voltage_soc:%d\n",
+			chip->ignore_shutdown_soc, use_voltage_soc);
+
+	return 0;
+}
+
+static inline void bms_initialize_constants(struct qpnp_bms_chip *chip)
+{
+	chip->start_percent = -EINVAL;
+	chip->end_percent = -EINVAL;
+	chip->prev_pc_unusable = -EINVAL;
+	chip->soc_at_cv = -EINVAL;
+	chip->calculated_soc = -EINVAL;
+	chip->last_soc = -EINVAL;
+	chip->last_vbat_read_uv = -EINVAL;
+	chip->last_soc_est = -EINVAL;
+	chip->first_time_calc_soc = 1;
+	chip->first_time_calc_uuc = 1;
+}
+
 static int __devinit
 qpnp_bms_probe(struct spmi_device *spmi)
 {
 	struct qpnp_bms_chip *chip;
 	struct resource *bms_resource;
-	int rc;
+	int rc, vbatt;
 
 	chip = kzalloc(sizeof *chip, GFP_KERNEL);
 
@@ -239,6 +1925,10 @@
 	chip->dev = &(spmi->dev);
 	chip->spmi = spmi;
 
+	mutex_init(&chip->bms_output_lock);
+	mutex_init(&chip->last_ocv_uv_mutex);
+	mutex_init(&chip->soc_invalidation_mutex);
+
 	bms_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
 	if (!bms_resource) {
 		dev_err(&spmi->dev, "Unable to get BMS base address\n");
@@ -260,29 +1950,30 @@
 		goto error_read;
 	}
 
-	SPMI_PROPERTY_READ(r_sense_mohm, "r-sense-mohm", rc, error_read);
-	SPMI_PROPERTY_READ(v_cutoff, "v-cutoff-uv", rc, error_read);
-	SPMI_PROPERTY_READ(max_voltage, "max-voltage-uv", rc, error_read);
-	SPMI_PROPERTY_READ(r_conn_mohm, "r-conn-mohm", rc, error_read);
-	SPMI_PROPERTY_READ(shutdown_soc_valid_limit,
-			"shutdown-soc-valid-limit", rc, error_read);
-	SPMI_PROPERTY_READ(adjust_soc_low_threshold,
-			"adjust-soc-low-threshold", rc, error_read);
-	SPMI_PROPERTY_READ(adjust_soc_high_threshold,
-			"adjust-soc-high-threshold", rc, error_read);
-	SPMI_PROPERTY_READ(chg_term, "chg-term-ua", rc, error_read);
+	rc = set_battery_data(chip);
+	if (rc) {
+		pr_err("Bad battery data %d\n", rc);
+		goto error_read;
+	}
 
-	pr_debug("dts data: r_sense_mohm:%d, v_cutoff:%d, max_v:%d, r_conn:%d, shutdown_soc: %d, adjust_soc_low:%d, adjust_soc_high:%d, chg_term:%d\n",
-			chip->r_sense_mohm, chip->v_cutoff,
-			chip->max_voltage, chip->r_conn_mohm,
-			chip->shutdown_soc_valid_limit,
-			chip->adjust_soc_low_threshold,
-			chip->adjust_soc_high_threshold,
-			chip->chg_term);
+	rc = bms_read_properties(chip);
+	if (rc) {
+		pr_err("Unable to read all bms properties, rc = %d\n", rc);
+		goto error_read;
+	}
+
+	bms_initialize_constants(chip);
+
+	INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
+			calculate_soc_work);
+
+	read_shutdown_soc_and_iavg(chip);
 
 	dev_set_drvdata(&spmi->dev, chip);
 	device_init_wakeup(&spmi->dev, 1);
 
+	calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
+
 	/* setup & register the battery power supply */
 	chip->bms_psy.name = "bms";
 	chip->bms_psy.type = POWER_SUPPLY_TYPE_BMS;
@@ -302,6 +1993,12 @@
 		goto unregister_dc;
 	}
 
+	vbatt = 0;
+	get_battery_voltage(&vbatt);
+
+	pr_info("OK battery_capacity_at_boot=%d vbatt = %d\n",
+				get_prop_bms_capacity(chip),
+				vbatt);
 	pr_info("probe success\n");
 	return 0;
 
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index ce285a3..effe418 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -72,6 +72,7 @@
 
 	struct smd_port_info	*pi;
 	struct delayed_work	connect_work;
+	struct work_struct	disconnect_work;
 
 	/* At present, smd does not notify
 	 * control bit change info from modem
@@ -589,6 +590,20 @@
 	}
 }
 
+static void gsmd_disconnect_work(struct work_struct *w)
+{
+	struct gsmd_port *port;
+	struct smd_port_info *pi;
+
+	port = container_of(w, struct gsmd_port, disconnect_work);
+	pi = port->pi;
+
+	pr_debug("%s: port:%p port#%d\n", __func__, port, port->port_num);
+
+	smd_close(port->pi->ch);
+	port->pi->ch = NULL;
+}
+
 static void gsmd_notify_modem(void *gptr, u8 portno, int ctrl_bits)
 {
 	struct gsmd_port *port;
@@ -731,10 +746,8 @@
 				~port->cbits_to_modem);
 	}
 
-	if (port->pi->ch) {
-		smd_close(port->pi->ch);
-		port->pi->ch = NULL;
-	}
+	if (port->pi->ch)
+		queue_work(gsmd_wq, &port->disconnect_work);
 }
 
 #define SMD_CH_MAX_LEN	20
@@ -819,6 +832,7 @@
 	INIT_WORK(&port->pull, gsmd_tx_pull);
 
 	INIT_DELAYED_WORK(&port->connect_work, gsmd_connect_work);
+	INIT_WORK(&port->disconnect_work, gsmd_disconnect_work);
 
 	smd_ports[portno].port = port;
 	pdrv = &smd_ports[portno].pdrv;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 7b616e4..2d69a98 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -324,7 +324,7 @@
 #define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
 
 #define USB_PHY_VDD_DIG_VOL_NONE	0 /*uV */
-#define USB_PHY_VDD_DIG_VOL_MIN		1000000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_MIN		945000 /* uV */
 #define USB_PHY_VDD_DIG_VOL_MAX		1320000 /* uV */
 
 #define HSIC_DBG1_REG		0x38
@@ -641,6 +641,7 @@
 	int cnt = 0, ret;
 	u32 val;
 	int none_vol, max_vol;
+	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
 
 	if (atomic_read(&mehci->in_lpm)) {
 		dev_dbg(mehci->dev, "%s called in lpm\n", __func__);
@@ -719,6 +720,10 @@
 	enable_irq_wake(mehci->wakeup_irq);
 	enable_irq(mehci->wakeup_irq);
 
+	if (pdata && pdata->standalone_latency)
+		pm_qos_update_request(&mehci->pm_qos_req_dma,
+			PM_QOS_DEFAULT_VALUE);
+
 	wake_unlock(&mehci->wlock);
 
 	dev_info(mehci->dev, "HSIC-USB in low power mode\n");
@@ -733,12 +738,17 @@
 	unsigned temp;
 	int min_vol, max_vol;
 	unsigned long flags;
+	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
 
 	if (!atomic_read(&mehci->in_lpm)) {
 		dev_dbg(mehci->dev, "%s called in !in_lpm\n", __func__);
 		return 0;
 	}
 
+	if (pdata && pdata->standalone_latency)
+		pm_qos_update_request(&mehci->pm_qos_req_dma,
+			pdata->standalone_latency + 1);
+
 	spin_lock_irqsave(&mehci->wakeup_lock, flags);
 	if (mehci->wakeup_irq_enabled) {
 		disable_irq_wake(mehci->wakeup_irq);
@@ -1031,9 +1041,9 @@
 				pm_qos_update_request(&mehci->pm_qos_req_dma,
 					pdata->swfi_latency + 1);
 			wait_for_completion(&mehci->gpt0_completion);
-			if (pdata && pdata->swfi_latency)
+			if (pdata && pdata->standalone_latency)
 				pm_qos_update_request(&mehci->pm_qos_req_dma,
-					PM_QOS_DEFAULT_VALUE);
+					pdata->standalone_latency + 1);
 			spin_lock_irq(&ehci->lock);
 		} else {
 			dbg_log_event(NULL, "FPR: Tightloop", 0);
@@ -1680,9 +1690,9 @@
 
 	__mehci = mehci;
 
-	if (pdata && pdata->swfi_latency)
+	if (pdata && pdata->standalone_latency)
 		pm_qos_add_request(&mehci->pm_qos_req_dma,
-			PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+			PM_QOS_CPU_DMA_LATENCY, pdata->standalone_latency + 1);
 
 	/*
 	 * This pdev->dev is assigned parent of root-hub by USB core,
@@ -1721,7 +1731,7 @@
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
 
-	if (pdata && pdata->swfi_latency)
+	if (pdata && pdata->standalone_latency)
 		pm_qos_remove_request(&mehci->pm_qos_req_dma);
 
 	if (mehci->peripheral_status_irq)
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index d04c234..23a9499 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1137,11 +1137,20 @@
 
 	if (legacy_power_supply) {
 		/* legacy support */
-		if (host_mode)
+		if (host_mode) {
 			power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_SYSTEM);
-		else
+		} else {
 			power_supply_set_scope(psy, POWER_SUPPLY_SCOPE_DEVICE);
-		return;
+			/*
+			 * VBUS comparator is disabled by PMIC charging driver
+			 * when SYSTEM scope is selected.  For ID_GND->ID_A
+			 * transition, give 50 msec delay so that PMIC charger
+			 * driver detect the VBUS and ready for accepting
+			 * charging current value from USB.
+			 */
+			if (test_bit(ID_A, &motg->inputs))
+				msleep(50);
+		}
 	} else {
 		motg->host_mode = host_mode;
 		power_supply_changed(psy);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 0c526fd..fc512c1 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -1333,7 +1333,7 @@
 }
 #endif
 
-static ssize_t vsync_show_event(struct device *dev,
+ssize_t mdp_dma_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	ssize_t ret = 0;
@@ -2244,15 +2244,6 @@
 }
 
 #endif
-static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
-static struct attribute *vsync_fs_attrs[] = {
-	&dev_attr_vsync_event.attr,
-	NULL,
-};
-static struct attribute_group vsync_fs_attr_group = {
-	.attrs = vsync_fs_attrs,
-};
-
 static int mdp_on(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -2287,21 +2278,7 @@
 	if (mdp_rev == MDP_REV_303 && mfd->panel.type == MIPI_CMD_PANEL) {
 
 		vsync_cntrl.dev = mfd->fbi->dev;
-
-		if (!vsync_cntrl.sysfs_created) {
-			ret = sysfs_create_group(&vsync_cntrl.dev->kobj,
-				&vsync_fs_attr_group);
-			if (ret) {
-				pr_err("%s: sysfs creation failed, ret=%d\n",
-					__func__, ret);
-				return ret;
-			}
-
-			kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD);
-			pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
-			vsync_cntrl.sysfs_created = 1;
-		}
-		atomic_set(&vsync_cntrl.suspend, 0);
+		atomic_set(&vsync_cntrl.suspend, 1);
 	}
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -2615,6 +2592,7 @@
 	/* link to the latest pdev */
 	mfd->pdev = msm_fb_dev;
 	mfd->mdp_rev = mdp_rev;
+	mfd->vsync_init = NULL;
 
 	mfd->ov0_wb_buf = MDP_ALLOC(sizeof(struct mdp_buf_type));
 	mfd->ov1_wb_buf = MDP_ALLOC(sizeof(struct mdp_buf_type));
@@ -2780,7 +2758,8 @@
 	case MIPI_VIDEO_PANEL:
 #ifndef CONFIG_FB_MSM_MDP303
 		mipi = &mfd->panel_info.mipi;
-		mdp4_dsi_vsync_init(0);
+		mfd->vsync_init = mdp4_dsi_vsync_init;
+		mfd->vsync_show = mdp4_dsi_video_show_event;
 		mfd->hw_refresh = TRUE;
 		mfd->dma_fnc = mdp4_dsi_video_overlay;
 		mfd->lut_update = mdp_lut_update_lcdc;
@@ -2804,6 +2783,7 @@
 		mfd->start_histogram = mdp_histogram_start;
 		mfd->stop_histogram = mdp_histogram_stop;
 		mfd->vsync_ctrl = mdp_dma_video_vsync_ctrl;
+		mfd->vsync_show = mdp_dma_video_show_event;
 		if (mfd->panel_info.pdest == DISPLAY_1)
 			mfd->dma = &dma2_data;
 		else {
@@ -2824,7 +2804,8 @@
 #ifndef CONFIG_FB_MSM_MDP303
 		mfd->dma_fnc = mdp4_dsi_cmd_overlay;
 		mipi = &mfd->panel_info.mipi;
-		mdp4_dsi_rdptr_init(0);
+		mfd->vsync_init = mdp4_dsi_rdptr_init;
+		mfd->vsync_show = mdp4_dsi_cmd_show_event;
 		if (mfd->panel_info.pdest == DISPLAY_1) {
 			if_no = PRIMARY_INTF_SEL;
 			mfd->dma = &dma2_data;
@@ -2843,6 +2824,7 @@
 		mfd->start_histogram = mdp_histogram_start;
 		mfd->stop_histogram = mdp_histogram_stop;
 		mfd->vsync_ctrl = mdp_dma_vsync_ctrl;
+		mfd->vsync_show = mdp_dma_show_event;
 		if (mfd->panel_info.pdest == DISPLAY_1)
 			mfd->dma = &dma2_data;
 		else {
@@ -2860,7 +2842,8 @@
 
 #ifdef CONFIG_FB_MSM_DTV
 	case DTV_PANEL:
-		mdp4_dtv_vsync_init(0);
+		mfd->vsync_init = mdp4_dtv_vsync_init;
+		mfd->vsync_show = mdp4_dtv_show_event;
 		pdata->on = mdp4_dtv_on;
 		pdata->off = mdp4_dtv_off;
 		mfd->hw_refresh = TRUE;
@@ -2899,7 +2882,8 @@
 #endif
 
 #ifdef CONFIG_FB_MSM_MDP40
-		mdp4_lcdc_vsync_init(0);
+		mfd->vsync_init = mdp4_lcdc_vsync_init;
+		mfd->vsync_show = mdp4_lcdc_show_event;
 		if (mfd->panel.type == HDMI_PANEL) {
 			mfd->dma = &dma_e_data;
 			mdp4_display_intf_sel(EXTERNAL_INTF_SEL, LCDC_RGB_INTF);
@@ -2910,6 +2894,7 @@
 #else
 		mfd->dma = &dma2_data;
 		mfd->vsync_ctrl = mdp_dma_lcdc_vsync_ctrl;
+		mfd->vsync_show = mdp_dma_lcdc_show_event;
 		spin_lock_irqsave(&mdp_spin_lock, flag);
 		mdp_intr_mask &= ~MDP_DMA_P_DONE;
 		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
@@ -3010,6 +2995,29 @@
 
 	pdev_list[pdev_list_cnt++] = pdev;
 	mdp4_extn_disp = 0;
+
+	if (mfd->vsync_init != NULL) {
+		mfd->vsync_init(0);
+
+		if (!mfd->vsync_sysfs_created) {
+			mfd->dev_attr.attr.name = "vsync_event";
+			mfd->dev_attr.attr.mode = S_IRUGO;
+			mfd->dev_attr.show = mfd->vsync_show;
+			sysfs_attr_init(&mfd->dev_attr.attr);
+
+			rc = sysfs_create_file(&mfd->fbi->dev->kobj,
+							&mfd->dev_attr.attr);
+			if (rc) {
+				pr_err("%s: sysfs creation failed, ret=%d\n",
+					__func__, rc);
+				return rc;
+			}
+
+			kobject_uevent(&mfd->fbi->dev->kobj, KOBJ_ADD);
+			pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+			mfd->vsync_sysfs_created = 1;
+		}
+	}
 	return 0;
 
       mdp_probe_err:
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index b4a7f79..0bc2532 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -862,6 +862,12 @@
 void mdp_dma_vsync_ctrl(int enable);
 void mdp_dma_video_vsync_ctrl(int enable);
 void mdp_dma_lcdc_vsync_ctrl(int enable);
+ssize_t mdp_dma_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf);
+ssize_t mdp_dma_video_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf);
+ssize_t mdp_dma_lcdc_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf);
 
 #ifdef MDP_HW_VSYNC
 void vsync_clk_prepare_enable(void);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index d9da6f9..2f4fac1 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -557,6 +557,14 @@
 void mdp4_dsi_vsync_init(int cndx);
 void mdp4_lcdc_vsync_init(int cndx);
 void mdp4_dtv_vsync_init(int cndx);
+ssize_t mdp4_dsi_cmd_show_event(struct device *dev,
+	struct device_attribute *attr, char *buf);
+ssize_t mdp4_dsi_video_show_event(struct device *dev,
+	struct device_attribute *attr, char *buf);
+ssize_t mdp4_lcdc_show_event(struct device *dev,
+	struct device_attribute *attr, char *buf);
+ssize_t mdp4_dtv_show_event(struct device *dev,
+	struct device_attribute *attr, char *buf);
 void mdp4_overlay_dsi_state_set(int state);
 int mdp4_overlay_dsi_state_get(void);
 void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 0015403..9cb2b34 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -662,7 +662,7 @@
 	mutex_unlock(&vctrl->update_lock);
 }
 
-static ssize_t vsync_show_event(struct device *dev,
+ssize_t mdp4_dsi_cmd_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	int cndx;
@@ -683,9 +683,12 @@
 	vctrl->wait_vsync_cnt++;
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 
-	ret = wait_for_completion_interruptible(&vctrl->vsync_comp);
-	if (ret)
-		return ret;
+	ret = wait_for_completion_interruptible_timeout(&vctrl->vsync_comp,
+		msecs_to_jiffies(VSYNC_PERIOD * 4));
+	if (ret <= 0) {
+		vctrl->wait_vsync_cnt = 0;
+		return -EBUSY;
+	}
 
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	vsync_tick = ktime_to_ns(vctrl->vsync_time);
@@ -718,6 +721,7 @@
 	init_completion(&vctrl->dmap_comp);
 	init_completion(&vctrl->vsync_comp);
 	spin_lock_init(&vctrl->spin_lock);
+	atomic_set(&vctrl->suspend, 1);
 	INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
 }
 
@@ -986,14 +990,6 @@
 	mdp4_dsi_cmd_do_blt(mfd, req->enable);
 }
 
-static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
-static struct attribute *vsync_fs_attrs[] = {
-	&dev_attr_vsync_event.attr,
-	NULL,
-};
-static struct attribute_group vsync_fs_attr_group = {
-	.attrs = vsync_fs_attrs,
-};
 int mdp4_dsi_cmd_on(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -1018,22 +1014,7 @@
 
 	atomic_set(&vctrl->suspend, 0);
 
-	if (!vctrl->sysfs_created) {
-		ret = sysfs_create_group(&vctrl->dev->kobj,
-			&vsync_fs_attr_group);
-		if (ret) {
-			pr_err("%s: sysfs group creation failed, ret=%d\n",
-				__func__, ret);
-			return ret;
-		}
-
-		kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
-		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
-		vctrl->sysfs_created = 1;
-	}
-
 	pr_debug("%s-:\n", __func__);
-
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 501c4e6..f5df938 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -374,7 +374,7 @@
 	wait_for_completion(&vctrl->ov_comp);
 }
 
-static ssize_t vsync_show_event(struct device *dev,
+ssize_t mdp4_dsi_video_show_event(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	int cndx;
@@ -395,9 +395,12 @@
 		INIT_COMPLETION(vctrl->vsync_comp);
 	vctrl->wait_vsync_cnt++;
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
-	ret = wait_for_completion_interruptible(&vctrl->vsync_comp);
-	if (ret)
-		return ret;
+	ret = wait_for_completion_interruptible_timeout(&vctrl->vsync_comp,
+		msecs_to_jiffies(VSYNC_PERIOD * 4));
+	if (ret <= 0) {
+		vctrl->wait_vsync_cnt = 0;
+		return -EBUSY;
+	}
 
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	vsync_tick = ktime_to_ns(vctrl->vsync_time);
@@ -417,7 +420,7 @@
 		return;
 	}
 
-	pr_info("%s: ndx=%d\n", __func__, cndx);
+	pr_debug("%s: ndx=%d\n", __func__, cndx);
 
 	vctrl = &vsync_ctrl_db[cndx];
 	if (vctrl->inited)
@@ -429,7 +432,7 @@
 	init_completion(&vctrl->vsync_comp);
 	init_completion(&vctrl->dmap_comp);
 	init_completion(&vctrl->ov_comp);
-	atomic_set(&vctrl->suspend, 0);
+	atomic_set(&vctrl->suspend, 1);
 	atomic_set(&vctrl->vsync_resume, 1);
 	spin_lock_init(&vctrl->spin_lock);
 }
@@ -447,16 +450,6 @@
 	vctrl->base_pipe = pipe;
 }
 
-static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
-
-static struct attribute *vsync_fs_attrs[] = {
-	&dev_attr_vsync_event.attr,
-	NULL,
-};
-
-static struct attribute_group vsync_fs_attr_group = {
-	.attrs = vsync_fs_attrs,
-};
 int mdp4_dsi_video_on(struct platform_device *pdev)
 {
 	int dsi_width;
@@ -673,20 +666,6 @@
 
 	mdp_histogram_ctrl_all(TRUE);
 
-	if (!vctrl->sysfs_created) {
-		ret = sysfs_create_group(&vctrl->dev->kobj,
-			&vsync_fs_attr_group);
-		if (ret) {
-			pr_err("%s: sysfs group creation failed, ret=%d\n",
-				__func__, ret);
-			return ret;
-		}
-
-		kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
-		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
-		vctrl->sysfs_created = 1;
-	}
-
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 2d48781..4db684b 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -310,7 +310,7 @@
 	wait_for_completion(&vctrl->dmae_comp);
 }
 
-static ssize_t vsync_show_event(struct device *dev,
+ssize_t mdp4_dtv_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	int cndx;
@@ -337,9 +337,12 @@
 	vctrl->wait_vsync_cnt++;
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 
-	ret = wait_for_completion_interruptible(&vctrl->vsync_comp);
-	if (ret)
-		return ret;
+	ret = wait_for_completion_interruptible_timeout(&vctrl->vsync_comp,
+		msecs_to_jiffies(VSYNC_PERIOD * 4));
+	if (ret <= 0) {
+		vctrl->wait_vsync_cnt = 0;
+		return -EBUSY;
+	}
 
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	vg1fd = vctrl->vg1fd;
@@ -382,7 +385,7 @@
 	init_completion(&vctrl->vsync_comp);
 	init_completion(&vctrl->ov_comp);
 	init_completion(&vctrl->dmae_comp);
-	atomic_set(&vctrl->suspend, 0);
+	atomic_set(&vctrl->suspend, 1);
 	atomic_set(&vctrl->vsync_resume, 1);
 	spin_lock_init(&vctrl->spin_lock);
 }
@@ -561,15 +564,6 @@
 	return 0;
 }
 
-static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
-static struct attribute *vsync_fs_attrs[] = {
-	&dev_attr_vsync_event.attr,
-	NULL,
-};
-static struct attribute_group vsync_fs_attr_group = {
-	.attrs = vsync_fs_attrs,
-};
-
 int mdp4_dtv_on(struct platform_device *pdev)
 {
 	struct msm_fb_data_type *mfd;
@@ -609,21 +603,6 @@
 		pr_warn("%s: panel_next_on failed", __func__);
 
 	atomic_set(&vctrl->suspend, 0);
-
-	if (!vctrl->sysfs_created) {
-		ret = sysfs_create_group(&vctrl->dev->kobj,
-			&vsync_fs_attr_group);
-		if (ret) {
-			pr_err("%s: sysfs group creation failed, ret=%d\n",
-				__func__, ret);
-			return ret;
-		}
-
-		kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
-		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
-		vctrl->sysfs_created = 1;
-	}
-
 	if (mfd->avtimer_phy && (vctrl->avtimer == NULL)) {
 		vctrl->avtimer = (uint32 *)ioremap(mfd->avtimer_phy, 8);
 		if (vctrl->avtimer == NULL)
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index df5c262..172687a 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -359,7 +359,7 @@
 	wait_for_completion(&vctrl->ov_comp);
 }
 
-static ssize_t vsync_show_event(struct device *dev,
+ssize_t mdp4_lcdc_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	int cndx;
@@ -380,9 +380,12 @@
 		INIT_COMPLETION(vctrl->vsync_comp);
 	vctrl->wait_vsync_cnt++;
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
-	ret = wait_for_completion_interruptible(&vctrl->vsync_comp);
-	if (ret)
-		return ret;
+	ret = wait_for_completion_interruptible_timeout(&vctrl->vsync_comp,
+		msecs_to_jiffies(VSYNC_PERIOD * 4));
+	if (ret <= 0) {
+		vctrl->wait_vsync_cnt = 0;
+		return -EBUSY;
+	}
 
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	vsync_tick = ktime_to_ns(vctrl->vsync_time);
@@ -414,7 +417,7 @@
 	init_completion(&vctrl->vsync_comp);
 	init_completion(&vctrl->dmap_comp);
 	init_completion(&vctrl->ov_comp);
-	atomic_set(&vctrl->suspend, 0);
+	atomic_set(&vctrl->suspend, 1);
 	atomic_set(&vctrl->vsync_resume, 1);
 	spin_lock_init(&vctrl->spin_lock);
 }
@@ -432,15 +435,6 @@
 	vctrl->base_pipe = pipe;
 }
 
-static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
-static struct attribute *vsync_fs_attrs[] = {
-	&dev_attr_vsync_event.attr,
-	NULL,
-};
-static struct attribute_group vsync_fs_attr_group = {
-	.attrs = vsync_fs_attrs,
-};
-
 int mdp4_lcdc_on(struct platform_device *pdev)
 {
 	int lcdc_width;
@@ -655,20 +649,6 @@
 
 	mdp_histogram_ctrl_all(TRUE);
 
-	if (!vctrl->sysfs_created) {
-		ret = sysfs_create_group(&vctrl->dev->kobj,
-			&vsync_fs_attr_group);
-		if (ret) {
-			pr_err("%s: sysfs group creation failed, ret=%d\n",
-				__func__, ret);
-			return ret;
-		}
-
-		kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
-		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
-		vctrl->sysfs_created = 1;
-	}
-
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 18c6635..6c2b1f6 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -171,6 +171,8 @@
 	struct vsycn_ctrl *vctrl;
 	struct mdp4_overlay_pipe *pipe;
 	int ret = 0;
+	int undx;
+	struct vsync_update *vp;
 
 	pr_debug("%s+:\n", __func__);
 
@@ -189,6 +191,16 @@
 	mdp4_overlay_pipe_free(pipe);
 	vctrl->base_pipe = NULL;
 
+	undx =  vctrl->update_ndx;
+	vp = &vctrl->vlist[undx];
+	if (vp->update_cnt) {
+		/*
+		 * pipe's iommu will be freed at next overlay play
+		 * and iommu_drop statistic will be increased by one
+		 */
+		vp->update_cnt = 0;     /* empty queue */
+	}
+
 	ret = panel_next_off(pdev);
 
 	mdp_clk_ctrl(1);
@@ -253,6 +265,12 @@
 	mdp4_mixer_stage_up(pipe, 0);
 
 	mdp4_overlayproc_cfg(pipe);
+
+	if (hdmi_prim_display)
+		outpdw(MDP_BASE + 0x100F4, 0x01);
+	else
+		outpdw(MDP_BASE + 0x100F4, 0x02);
+
 	/* MDP cmd block disable */
 	mdp_clk_ctrl(0);
 
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index e2fb8ba..cfbff9a 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -34,7 +34,7 @@
 static int first_pixel_start_x;
 static int first_pixel_start_y;
 
-static ssize_t vsync_show_event(struct device *dev,
+ssize_t mdp_dma_video_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	ssize_t ret = 0;
@@ -52,15 +52,6 @@
 	return ret;
 }
 
-static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
-static struct attribute *vsync_fs_attrs[] = {
-	&dev_attr_vsync_event.attr,
-	NULL,
-};
-static struct attribute_group vsync_fs_attr_group = {
-	.attrs = vsync_fs_attrs,
-};
-
 int mdp_dsi_video_on(struct platform_device *pdev)
 {
 	int dsi_width;
@@ -254,20 +245,6 @@
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
-	if (!vsync_cntrl.sysfs_created) {
-		ret = sysfs_create_group(&vsync_cntrl.dev->kobj,
-			&vsync_fs_attr_group);
-		if (ret) {
-			pr_err("%s: sysfs creation failed, ret=%d\n",
-				__func__, ret);
-			return ret;
-		}
-
-		kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD);
-		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
-		vsync_cntrl.sysfs_created = 1;
-	}
-
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index fbfe35f..c51a99a 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -51,7 +51,7 @@
 int first_pixel_start_x;
 int first_pixel_start_y;
 
-static ssize_t vsync_show_event(struct device *dev,
+ssize_t mdp_dma_lcdc_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	ssize_t ret = 0;
@@ -69,15 +69,6 @@
 	return ret;
 }
 
-static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
-static struct attribute *vsync_fs_attrs[] = {
-	&dev_attr_vsync_event.attr,
-	NULL,
-};
-static struct attribute_group vsync_fs_attr_group = {
-	.attrs = vsync_fs_attrs,
-};
-
 int mdp_lcdc_on(struct platform_device *pdev)
 {
 	int lcdc_width;
@@ -320,20 +311,6 @@
 	/* MDP cmd block disable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
-	if (!vsync_cntrl.sysfs_created) {
-		ret = sysfs_create_group(&vsync_cntrl.dev->kobj,
-			&vsync_fs_attr_group);
-		if (ret) {
-			pr_err("%s: sysfs creation failed, ret=%d\n",
-				__func__, ret);
-			return ret;
-		}
-
-		kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD);
-		pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
-		vsync_cntrl.sysfs_created = 1;
-	}
-
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 808babb..72871aa 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -229,6 +229,7 @@
 	u8 mixer_stage;
 	u8 is_fg;
 	u8 alpha;
+	u8 overfetch_disable;
 	u32 transp;
 
 	struct msm_fb_data_type *mfd;
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index b5f6ddf..f660375 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -707,7 +707,7 @@
 static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
 				struct mdss_mdp_mixer *mixer)
 {
-	struct mdss_mdp_pipe *pipe, *bgpipe = NULL;
+	struct mdss_mdp_pipe *pipe;
 	u32 off, blend_op, blend_stage;
 	u32 mixercfg = 0, blend_color_out = 0, bgalpha = 0;
 	int stage;
@@ -717,26 +717,24 @@
 
 	pr_debug("setup mixer=%d\n", mixer->num);
 
-	for (stage = MDSS_MDP_STAGE_BASE; stage < MDSS_MDP_MAX_STAGE; stage++) {
+	pipe = mixer->stage_pipe[MDSS_MDP_STAGE_BASE];
+	if (pipe == NULL) {
+		mixercfg = MDSS_MDP_LM_BORDER_COLOR;
+	} else {
+		mixercfg = 1 << (3 * pipe->num);
+		if (pipe->src_fmt->alpha_enable)
+			bgalpha = 1;
+	}
+
+	for (stage = MDSS_MDP_STAGE_0; stage < MDSS_MDP_MAX_STAGE; stage++) {
 		pipe = mixer->stage_pipe[stage];
-		if (pipe == NULL) {
-			if (stage == MDSS_MDP_STAGE_BASE)
-				mixercfg |= MDSS_MDP_LM_BORDER_COLOR;
+		if (pipe == NULL)
 			continue;
-		}
 
 		if (stage != pipe->mixer_stage) {
 			mixer->stage_pipe[stage] = NULL;
 			continue;
 		}
-		mixercfg |= stage << (3 * pipe->num);
-
-		if (stage == MDSS_MDP_STAGE_BASE) {
-			bgpipe = pipe;
-			if (pipe->src_fmt->alpha_enable)
-				bgalpha = 1;
-			continue;
-		}
 
 		blend_stage = stage - MDSS_MDP_STAGE_0;
 		off = MDSS_MDP_REG_LM_OFFSET(mixer->num) +
@@ -744,10 +742,8 @@
 
 		if (pipe->is_fg) {
 			bgalpha = 0;
-			if (bgpipe) {
-				mixercfg &= ~(0x7 << (3 * bgpipe->num));
-				mixercfg |= MDSS_MDP_LM_BORDER_COLOR;
-			}
+			mixercfg = MDSS_MDP_LM_BORDER_COLOR;
+
 			blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
 				    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
 			/* keep fg alpha */
@@ -778,6 +774,8 @@
 					stage);
 		}
 
+		mixercfg |= stage << (3 * pipe->num);
+
 		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
 		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_BLEND_FG_ALPHA,
 				   pipe->alpha);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index e4621d4..569e381 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -318,6 +318,7 @@
 	pipe->is_fg = req->is_fg;
 	pipe->alpha = req->alpha;
 	pipe->transp = req->transp_mask;
+	pipe->overfetch_disable = fmt->is_yuv;
 
 	pipe->req_data = *req;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index c28bcfd..3b04633 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -502,6 +502,11 @@
 	ystride1 =  (pipe->src_planes.ystride[2]) |
 		    (pipe->src_planes.ystride[3] << 16);
 
+	if (pipe->overfetch_disable) {
+		img_size = src_size;
+		src_xy = 0;
+	}
+
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_IMG_SIZE, img_size);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_SIZE, src_size);
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_XY, src_xy);
@@ -607,6 +612,28 @@
 	return 0;
 }
 
+static void mdss_mdp_addr_add_offset(struct mdss_mdp_pipe *pipe,
+				    struct mdss_mdp_data *data)
+{
+	data->p[0].addr += pipe->src.x +
+		(pipe->src.y * pipe->src_planes.ystride[0]);
+	if (data->num_planes > 1) {
+		u8 hmap[] = { 1, 2, 1, 2 };
+		u8 vmap[] = { 1, 1, 2, 2 };
+		u16 xoff = pipe->src.x / hmap[pipe->src_fmt->chroma_sample];
+		u16 yoff = pipe->src.y / vmap[pipe->src_fmt->chroma_sample];
+
+		if (data->num_planes == 2) /* pseudo planar */
+			xoff *= 2;
+		data->p[1].addr += xoff + (yoff * pipe->src_planes.ystride[1]);
+
+		if (data->num_planes > 2) { /* planar */
+			data->p[2].addr += xoff +
+				(yoff * pipe->src_planes.ystride[2]);
+		}
+	}
+}
+
 static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
 				   struct mdss_mdp_data *data)
 {
@@ -622,6 +649,9 @@
 	if (ret)
 		return ret;
 
+	if (pipe->overfetch_disable)
+		mdss_mdp_addr_add_offset(pipe, data);
+
 	/* planar format expects YCbCr, swap chroma planes if YCrCb */
 	if (!is_rot && (pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_PLANAR) &&
 	    (pipe->src_fmt->element[0] == C2_R_Cr))
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 7d8ad73..2fd25cc 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -125,6 +125,7 @@
 	__u32 channel_irq;
 
 	struct mdp_dma_data *dma;
+	struct device_attribute dev_attr;
 	void (*dma_fnc) (struct msm_fb_data_type *mfd);
 	int (*cursor_update) (struct fb_info *info,
 			      struct fb_cursor *cursor);
@@ -135,6 +136,8 @@
 	int (*start_histogram) (struct mdp_histogram_start_req *req);
 	int (*stop_histogram) (struct fb_info *info, uint32_t block);
 	void (*vsync_ctrl) (int enable);
+	void (*vsync_init) (int cndx);
+	void *vsync_show;
 	void *cursor_buf;
 	void *cursor_buf_phys;
 
@@ -190,6 +193,7 @@
 	unsigned char *copy_splash_phys;
 	void *cpu_pm_hdl;
 	u32 avtimer_phy;
+	int vsync_sysfs_created;
 };
 
 struct dentry *msm_fb_get_debugfs_root(void);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index d5b195d..a82feb9 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -198,7 +198,8 @@
 		ddl->client_state = DDL_CLIENT_OPEN;
 		ddl->codec_data.hdr.decoding = decoding;
 		ddl->decoding = decoding;
-		ddl_set_default_meta_data_hdr(ddl);
+		if (!res_trk_check_for_sec_session())
+			ddl_set_default_meta_data_hdr(ddl);
 		ddl_set_initial_default_values(ddl);
 		*ddl_handle	= (u32 *) ddl;
 	} else {
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index bb5f394..45d7a3e 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -43,6 +43,7 @@
 #define DIAG_IOCTL_DCI_REG		23
 #define DIAG_IOCTL_DCI_STREAM_INIT	24
 #define DIAG_IOCTL_DCI_HEALTH_STATS	25
+#define DIAG_IOCTL_REMOTE_DEV		32
 
 /* PC Tools IDs */
 #define APQ8060_TOOLS_ID	4062
diff --git a/include/linux/i2c/ti_drv2667.h b/include/linux/i2c/ti_drv2667.h
new file mode 100644
index 0000000..0ae0e5e
--- /dev/null
+++ b/include/linux/i2c/ti_drv2667.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __TI_DRV2667__
+
+#define DRV2667_WAV_SEQ_LEN	11
+
+struct drv2667_pdata {
+	const char *name;
+	u8 mode;
+	/* support one waveform for now */
+	u8 wav_seq[DRV2667_WAV_SEQ_LEN];
+	u8 gain;
+	u8 idle_timeout_ms;
+	u32 max_runtime_ms;
+};
+#endif
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
index c55e47e..afa1843 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -102,7 +102,8 @@
 };
 
 #if defined(CONFIG_PM8921_BMS) || \
-	defined(CONFIG_PM8921_BMS_MODULE)
+	defined(CONFIG_PM8921_BMS_MODULE) || \
+	defined(CONFIG_QPNP_BMS)
 extern struct bms_battery_data  palladium_1500_data;
 extern struct bms_battery_data  desay_5200_data;
 
diff --git a/include/linux/mfd/pm8xxx/ccadc.h b/include/linux/mfd/pm8xxx/ccadc.h
index 29f7a62..fc31f89 100644
--- a/include/linux/mfd/pm8xxx/ccadc.h
+++ b/include/linux/mfd/pm8xxx/ccadc.h
@@ -19,11 +19,11 @@
 
 /**
  * struct pm8xxx_ccadc_platform_data -
- * @r_sense:		sense resistor value in (mOhms)
+ * @r_sense_uohm:		sense resistor value in (micro Ohms)
  * @calib_delay_ms:	how often should the adc calculate gain and offset
  */
 struct pm8xxx_ccadc_platform_data {
-	int		r_sense;
+	int		r_sense_uohm;
 	unsigned int	calib_delay_ms;
 };
 
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index ba70c96..82ec57d 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -30,7 +30,7 @@
 /**
  * struct pm8921_bms_platform_data -
  * @batt_type:		allows to force chose battery calibration data
- * @r_sense:		sense resistor value in (mOhms)
+ * @r_sense_uohm:	sense resistor value in (micro Ohms)
  * @i_test:		current at which the unusable charger cutoff is to be
  *			calculated or the peak system current (mA)
  * @v_cutoff:		the loaded voltage at which the battery
@@ -41,7 +41,7 @@
 struct pm8921_bms_platform_data {
 	struct pm8xxx_bms_core_data	bms_cdata;
 	enum battery_type		battery_type;
-	unsigned int			r_sense;
+	int				r_sense_uohm;
 	unsigned int			i_test;
 	unsigned int			v_cutoff;
 	unsigned int			max_voltage_uv;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index ddfb7c5..48268f0 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1561,6 +1561,32 @@
 #define in_gate_area(mm, addr) ({(void)mm; in_gate_area_no_mm(addr);})
 #endif	/* __HAVE_ARCH_GATE_AREA */
 
+#ifdef CONFIG_USE_USER_ACCESSIBLE_TIMERS
+static inline int use_user_accessible_timers(void) { return 1; }
+extern int in_user_timers_area(struct mm_struct *mm, unsigned long addr);
+extern struct vm_area_struct *get_user_timers_vma(struct mm_struct *mm);
+extern int get_user_timer_page(struct vm_area_struct *vma,
+	struct mm_struct *mm, unsigned long start, unsigned int gup_flags,
+	struct page **pages, int idx, int *goto_next_page);
+#else
+static inline int use_user_accessible_timers(void) { return 0; }
+static inline int in_user_timers_area(struct mm_struct *mm, unsigned long addr)
+{
+	return 0;
+}
+static inline struct vm_area_struct *get_user_timers_vma(struct mm_struct *mm)
+{
+	return NULL;
+}
+static inline int get_user_timer_page(struct vm_area_struct *vma,
+	struct mm_struct *mm, unsigned long start, unsigned int gup_flags,
+	struct page **pages, int idx, int *goto_next_page)
+{
+	*goto_next_page = 0;
+	return 0;
+}
+#endif
+
 int drop_caches_sysctl_handler(struct ctl_table *, int,
 					void __user *, size_t *, loff_t *);
 unsigned long shrink_slab(struct shrink_control *shrink,
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 89a8421..e0d9072 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -548,6 +548,14 @@
  * @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
  *      No Acknowledgement Policy should be applied.
  *
+ * @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition
+ *	Information Element to the WLAN driver
+ *
+ * @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver
+ *	to the supplicant. This will carry the target AP's MAC address along
+ *	with the relevant Information Elements. This event to report received
+ *	FT IEs( MDIE, FTIE,RSN IE, TIE, RICIE).
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -689,6 +697,9 @@
 
 	NL80211_CMD_SET_NOACK_MAP,
 
+	NL80211_CMD_UPDATE_FT_IES,
+	NL80211_CMD_FT_EVENT,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1264,6 +1275,10 @@
  * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
  *      or 0 to disable background scan.
  *
+ * @NL80211_ATTR_MDID: Mobility Domain Identifier
+ *
+ * @NL80211_ATTR_IE_RIC: Resource Information Container Information Element
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1515,6 +1530,9 @@
 
 	NL80211_ATTR_BG_SCAN_PERIOD,
 
+	NL80211_ATTR_MDID,
+	NL80211_ATTR_IE_RIC,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 9d5de90..077ccfc 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -28,7 +28,7 @@
 	DCIN,
 	VCHG_SNS,
 	SPARE1_03,
-	SPARE2_03,
+	USB_ID_MV,
 	VCOIN,
 	VBAT_SNS,
 	VSYS,
@@ -81,44 +81,44 @@
 	LR_MUX7_HW_ID,
 	LR_MUX8_AMUX_THM4,
 	LR_MUX9_AMUX_THM5,
-	LR_MUX10_USB_ID,
+	LR_MUX10_USB_ID_LV,
 	AMUX_PU1,
 	AMUX_PU2,
 	LR_MUX3_BUF_XO_THERM_BUF,
-	LR_MUX1_PU1_BAT_THERM,
-	LR_MUX2_PU1_BAT_ID,
-	LR_MUX3_PU1_XO_THERM,
-	LR_MUX4_PU1_AMUX_THM1,
-	LR_MUX5_PU1_AMUX_THM2,
-	LR_MUX6_PU1_AMUX_THM3,
-	LR_MUX7_PU1_AMUX_HW_ID,
-	LR_MUX8_PU1_AMUX_THM4,
-	LR_MUX9_PU1_AMUX_THM5,
-	LR_MUX10_PU1_AMUX_USB_ID,
-	LR_MUX3_BUF_PU1_XO_THERM_BUF,
-	LR_MUX1_PU2_BAT_THERM,
-	LR_MUX2_PU2_BAT_ID,
-	LR_MUX3_PU2_XO_THERM,
-	LR_MUX4_PU2_AMUX_THM1,
-	LR_MUX5_PU2_AMUX_THM2,
-	LR_MUX6_PU2_AMUX_THM3,
-	LR_MUX7_PU2_AMUX_HW_ID,
-	LR_MUX8_PU2_AMUX_THM4,
-	LR_MUX9_PU2_AMUX_THM5,
-	LR_MUX10_PU2_AMUX_USB_ID,
-	LR_MUX3_BUF_PU2_XO_THERM_BUF,
-	LR_MUX1_PU1_PU2_BAT_THERM,
-	LR_MUX2_PU1_PU2_BAT_ID,
-	LR_MUX3_PU1_PU2_XO_THERM,
-	LR_MUX4_PU1_PU2_AMUX_THM1,
-	LR_MUX5_PU1_PU2_AMUX_THM2,
-	LR_MUX6_PU1_PU2_AMUX_THM3,
-	LR_MUX7_PU1_PU2_AMUX_HW_ID,
-	LR_MUX8_PU1_PU2_AMUX_THM4,
-	LR_MUX9_PU1_PU2_AMUX_THM5,
-	LR_MUX10_PU1_PU2_AMUX_USB_ID,
-	LR_MUX3_BUF_PU1_PU2_XO_THERM_BUF,
-	ALL_OFF,
+	LR_MUX1_PU1_BAT_THERM = 112,
+	LR_MUX2_PU1_BAT_ID = 113,
+	LR_MUX3_PU1_XO_THERM = 114,
+	LR_MUX4_PU1_AMUX_THM1 = 115,
+	LR_MUX5_PU1_AMUX_THM2 = 116,
+	LR_MUX6_PU1_AMUX_THM3 = 117,
+	LR_MUX7_PU1_AMUX_HW_ID = 118,
+	LR_MUX8_PU1_AMUX_THM4 = 119,
+	LR_MUX9_PU1_AMUX_THM5 = 120,
+	LR_MUX10_PU1_AMUX_USB_ID_LV = 121,
+	LR_MUX3_BUF_PU1_XO_THERM_BUF = 124,
+	LR_MUX1_PU2_BAT_THERM = 176,
+	LR_MUX2_PU2_BAT_ID = 177,
+	LR_MUX3_PU2_XO_THERM = 178,
+	LR_MUX4_PU2_AMUX_THM1 = 179,
+	LR_MUX5_PU2_AMUX_THM2 = 180,
+	LR_MUX6_PU2_AMUX_THM3 = 181,
+	LR_MUX7_PU2_AMUX_HW_ID = 182,
+	LR_MUX8_PU2_AMUX_THM4 = 183,
+	LR_MUX9_PU2_AMUX_THM5 = 184,
+	LR_MUX10_PU2_AMUX_USB_ID_LV = 185,
+	LR_MUX3_BUF_PU2_XO_THERM_BUF = 188,
+	LR_MUX1_PU1_PU2_BAT_THERM = 240,
+	LR_MUX2_PU1_PU2_BAT_ID = 241,
+	LR_MUX3_PU1_PU2_XO_THERM = 242,
+	LR_MUX4_PU1_PU2_AMUX_THM1 = 243,
+	LR_MUX5_PU1_PU2_AMUX_THM2 = 244,
+	LR_MUX6_PU1_PU2_AMUX_THM3 = 245,
+	LR_MUX7_PU1_PU2_AMUX_HW_ID = 246,
+	LR_MUX8_PU1_PU2_AMUX_THM4 = 247,
+	LR_MUX9_PU1_PU2_AMUX_THM5 = 248,
+	LR_MUX10_PU1_PU2_AMUX_USB_ID_LV = 249,
+	LR_MUX3_BUF_PU1_PU2_XO_THERM_BUF = 252,
+	ALL_OFF = 255,
 	ADC_MAX_NUM,
 };
 
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 578b9f9..d6fbc64 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -397,7 +397,12 @@
 	unsigned data;
 	struct msm_bus_scale_pdata *bus_scale_table;
 	unsigned log2_irq_thresh;
+
+	/*swfi latency is required while driving resume on to the bus */
 	u32 swfi_latency;
+
+	/*standalone latency is required when HSCI is active*/
+	u32 standalone_latency;
 };
 
 struct msm_usb_host_platform_data {
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index a57c9f9..5c1daf3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1318,6 +1318,21 @@
 };
 
 /**
+ * struct cfg80211_update_ft_ies_params - FT IE Information
+ *
+ * This structure provides information needed to update the fast transition IE
+ *
+ * @md: The Mobility Domain ID, 2 Octet value
+ * @ie: Fast Transition IEs
+ * @ie_len: Length of ft_ie in octets
+ */
+struct cfg80211_update_ft_ies_params {
+	u16 md;
+	u8 *ie;
+	size_t ie_len;
+};
+
+/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -1697,6 +1712,8 @@
 				  u16 noack_map);
 
 	struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
+	int	(*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
+				 struct cfg80211_update_ft_ies_params *ftie);
 };
 
 /*
@@ -3348,6 +3365,32 @@
  */
 u16 cfg80211_calculate_bitrate(struct rate_info *rate);
 
+/**
+ * struct cfg80211_ft_event - FT Information Elements
+ * @dev: network device
+ * @ies: FT IEs
+ * @ies_len: length of the FT IE in bytes
+ * @target_ap: target AP's MAC address
+ * @ric_ies: RIC IE
+ * @ric_ies_len: length of the RIC IE in bytes
+ */
+struct cfg80211_ft_event_params {
+	u8 *ies;
+	size_t ies_len;
+	u8 target_ap[ETH_ALEN];
+	u8 *ric_ies;
+	size_t ric_ies_len;
+};
+
+/**
+ * cfg80211_ft_event - notify userspace about FT IE and RIC IE
+ * @dev: network device
+ * @cfg80211_ft_event_params: IE information
+ */
+int cfg80211_ft_event(struct net_device *dev,
+			struct cfg80211_ft_event_params ft_event);
+
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
index 3d5ffdd..6c60318 100644
--- a/include/sound/msm-dai-q6-v2.h
+++ b/include/sound/msm-dai-q6-v2.h
@@ -20,6 +20,10 @@
 #define MSM_MI2S_SD3 (1 << 3)
 #define MSM_MI2S_CAP_RX 0
 #define MSM_MI2S_CAP_TX 1
+#define MSM_PRIM_MI2S 0
+#define MSM_SEC_MI2S  1
+#define MSM_TERT_MI2S 2
+#define MSM_QUAD_MI2S 3
 
 struct msm_dai_auxpcm_pdata {
 	const char *clk;
@@ -35,6 +39,11 @@
 	int pcm_clk_rate;
 };
 
+struct msm_mi2s_pdata {
+	u16 rx_sd_lines;
+	u16 tx_sd_lines;
+};
+
 struct msm_i2s_data {
 	u32 capability; /* RX or TX */
 	u16 sd_lines;
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index e107130..1324f8a 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -16,6 +16,7 @@
 #define IN			0x000
 #define OUT			0x001
 #define MSM_AFE_MONO        0
+#define MSM_AFE_CH_STEREO   1
 #define MSM_AFE_MONO_RIGHT  1
 #define MSM_AFE_MONO_LEFT   2
 #define MSM_AFE_STEREO      3
diff --git a/mm/Kconfig b/mm/Kconfig
index 4cde97f..bbab5a6 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -390,3 +390,14 @@
           the memory corresponding to the hole to be removed using memblock-
           remove.
 
+config USE_USER_ACCESSIBLE_TIMERS
+	bool "Enables timers accessible from userspace"
+	depends on MMU
+	help
+	  User-accessible timers allow the kernel to map kernel timer
+	  registers to a userspace accessible page, to allow faster
+	  access to time information.  This flag will enable the
+	  interface code in the main kernel.  However, there are
+	  architecture-specific code that will need to be enabled
+	  separately.
+
diff --git a/mm/memory.c b/mm/memory.c
index 6105f47..174fcaa 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1726,6 +1726,19 @@
 			goto next_page;
 		}
 
+		if (use_user_accessible_timers()) {
+			if (!vma && in_user_timers_area(mm, start)) {
+				int goto_next_page = 0;
+				int user_timer_ret = get_user_timer_page(vma,
+					mm, start, gup_flags, pages, i,
+					&goto_next_page);
+				if (goto_next_page)
+					goto next_page;
+				else
+					return user_timer_ret;
+			}
+		}
+
 		if (!vma ||
 		    (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
 		    !(vm_flags & vma->vm_flags))
diff --git a/mm/mlock.c b/mm/mlock.c
index ef726e8..38c77ab 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -229,7 +229,9 @@
 
 	if (!((vma->vm_flags & (VM_DONTEXPAND | VM_RESERVED)) ||
 			is_vm_hugetlb_page(vma) ||
-			vma == get_gate_vma(current->mm))) {
+			vma == get_gate_vma(current->mm) ||
+			((use_user_accessible_timers() &&
+				(vma == get_user_timers_vma(current->mm)))))) {
 
 		__mlock_vma_pages_range(vma, start, end, NULL);
 
@@ -324,7 +326,9 @@
 	int lock = !!(newflags & VM_LOCKED);
 
 	if (newflags == vma->vm_flags || (vma->vm_flags & VM_SPECIAL) ||
-	    is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm))
+	    is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm) ||
+	    ((use_user_accessible_timers()) &&
+		(vma == get_user_timers_vma(current->mm))))
 		goto out;	/* don't set VM_LOCKED,  don't count */
 
 	pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 22a4dbe..fa2469e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1426,6 +1426,11 @@
 	} else {
 		u16 flags;
 
+		if (!(pi->conn)) {
+			kfree_skb(skb);
+			return;
+		}
+
 		bt_cb(skb)->force_active = pi->force_active;
 		BT_DBG("Sending on BR/EDR connection %p", pi->conn->hcon);
 
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index f5a7ac3..dd99041 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -954,3 +954,16 @@
 	return nl80211_unexpected_4addr_frame(dev, addr, gfp);
 }
 EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
+
+int cfg80211_ft_event(struct net_device *dev,
+			struct cfg80211_ft_event_params ft_event)
+{
+	int err = 0;
+	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	nl80211_ft_event(rdev, dev, ft_event);
+
+	return err;
+}
+EXPORT_SYMBOL(cfg80211_ft_event);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e322d4d..0410707 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -206,6 +206,9 @@
 	[NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
 	[NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
 	[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
+	[NL80211_ATTR_MDID] = { .type = NLA_U16 },
+	[NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
+					 .len = IEEE80211_MAX_DATA_LEN },
 };
 
 /* policy for the key attributes */
@@ -6299,6 +6302,26 @@
 	return 0;
 }
 
+static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct cfg80211_update_ft_ies_params ft_params;
+	struct net_device *dev = info->user_ptr[1];
+
+	if (!info->attrs[NL80211_ATTR_MDID])
+		return -EINVAL;
+
+	ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
+
+	if (!info->attrs[NL80211_ATTR_IE])
+		return -EINVAL;
+
+	ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+	ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+
+	return rdev->ops->update_ft_ies(&rdev->wiphy, dev, &ft_params);
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -6887,6 +6910,14 @@
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_UPDATE_FT_IES,
+		.doit = nl80211_update_ft_ies,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 
 };
 
@@ -8080,6 +8111,47 @@
 	.notifier_call = nl80211_netlink_notify,
 };
 
+void nl80211_ft_event(struct cfg80211_registered_device *rdev,
+	struct net_device *netdev, struct cfg80211_ft_event_params ft_event)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+	if (ft_event.target_ap)
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event.target_ap);
+	if (ft_event.ies)
+		NLA_PUT(msg, NL80211_ATTR_IE, ft_event.ies_len, ft_event.ies);
+	if (ft_event.ric_ies)
+		NLA_PUT(msg, NL80211_ATTR_IE_RIC, ft_event.ric_ies_len,
+					ft_event.ric_ies);
+
+	if (genlmsg_end(msg, hdr) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+				nl80211_mlme_mcgrp.id, GFP_KERNEL);
+	return;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 4ffe50d..ffd4c8a 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -123,4 +123,8 @@
 bool nl80211_unexpected_4addr_frame(struct net_device *dev,
 				    const u8 *addr, gfp_t gfp);
 
+void nl80211_ft_event(struct cfg80211_registered_device *rdev,
+			struct net_device *netdev,
+			struct cfg80211_ft_event_params ft_event);
+
 #endif /* __NET_WIRELESS_NL80211_H */
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 0125c1a..59e220d 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -2028,6 +2028,15 @@
 		.be_id = MSM_FRONTEND_DAI_DTMF_RX,
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 	},
+	{
+		.name = "DTMF TX",
+		.stream_name = "DTMF TX",
+		.cpu_dai_name = "msm-dai-stub",
+		.platform_name  = "msm-pcm-dtmf",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.ignore_suspend = 1,
+	},
 
 	/* Backend BT DAI Links */
 	{
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 51c9ed7..4165254 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -498,15 +498,25 @@
 		.name = "VoLTE",
 	},
 	{
+		.playback = {
+			.stream_name = "MI2S_RX_HOSTLESS Playback",
+			.aif_name = "MI2S_DL_HL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 48000,
+		},
 		.capture = {
 			.stream_name = "MI2S_TX Hostless Capture",
 			.aif_name = "MI2S_UL_HL",
 			.rates = SNDRV_PCM_RATE_8000_48000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 8,
-			.rate_min =     8000,
-			.rate_max =    48000,
+			.channels_max = 2,
+			.rate_min = 8000,
+			.rate_max = 48000,
 		},
 		.ops = &msm_fe_dai_ops,
 		.name = "MI2S_TX_HOSTLESS",
diff --git a/sound/soc/msm/msm-pcm-dtmf.c b/sound/soc/msm/msm-pcm-dtmf.c
index 04ab7a9..94cc1ca 100644
--- a/sound/soc/msm/msm-pcm-dtmf.c
+++ b/sound/soc/msm/msm-pcm-dtmf.c
@@ -12,13 +12,86 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
 #include <linux/platform_device.h>
-#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/pcm.h>
 #include <sound/q6afe.h>
 
+#include "msm-pcm-q6.h"
+#include "msm-pcm-routing.h"
+#include "qdsp6/q6voice.h"
+
+enum {
+	DTMF_IN_RX,
+	DTMF_IN_TX,
+};
+
+enum format {
+	FORMAT_S16_LE = 2
+};
+
+struct dtmf_det_info {
+	char     session[MAX_SESSION_NAME_LEN];
+	uint8_t  dir;
+	uint16_t high_freq;
+	uint16_t low_freq;
+};
+
+struct dtmf_buf_node {
+	struct list_head list;
+	struct dtmf_det_info dtmf_det_pkt;
+};
+
+enum dtmf_state {
+	DTMF_GEN_RX_STOPPED,
+	DTMF_GEN_RX_STARTED,
+};
+
+#define DTMF_MAX_Q_LEN 10
+#define DTMF_PKT_SIZE sizeof(struct dtmf_det_info)
+
+struct dtmf_drv_info {
+	enum  dtmf_state state;
+	struct snd_pcm_substream *capture_substream;
+
+	struct list_head out_queue;
+	struct list_head free_out_queue;
+
+	wait_queue_head_t out_wait;
+
+	struct mutex lock;
+	spinlock_t dsp_lock;
+
+	uint8_t capture_start;
+	uint8_t capture_instance;
+
+	unsigned int pcm_capture_size;
+	unsigned int pcm_capture_count;
+	unsigned int pcm_capture_irq_pos;
+	unsigned int pcm_capture_buf_pos;
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware = {
+	.info =                 (SNDRV_PCM_INFO_MMAP |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_INTERLEAVED),
+	.formats =              SNDRV_PCM_FMTBIT_S16_LE,
+	.channels_min =         1,
+	.channels_max =         1,
+	.buffer_bytes_max =	(sizeof(struct dtmf_buf_node) * DTMF_MAX_Q_LEN),
+	.period_bytes_min =	DTMF_PKT_SIZE,
+	.period_bytes_max =	DTMF_PKT_SIZE,
+	.periods_min =		DTMF_MAX_Q_LEN,
+	.periods_max =		DTMF_MAX_Q_LEN,
+	.fifo_size =            0,
+};
+
 static int msm_dtmf_rx_generate_put(struct snd_kcontrol *kcontrol,
 				    struct snd_ctl_elem_value *ucontrol)
 {
@@ -33,7 +106,7 @@
 	return 0;
 }
 
-static int msm_dtmf_rx_generate_get(struct snd_kcontrol *kcontrol,
+static int msm_dtmf_rx_generate_get(struct  snd_kcontrol *kcontrol,
 				    struct snd_ctl_elem_value *ucontrol)
 {
 	pr_debug("%s:\n", __func__);
@@ -41,11 +114,55 @@
 	return 0;
 }
 
+static int msm_dtmf_detect_voice_rx_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int enable = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: enable=%d\n", __func__, enable);
+	voc_enable_dtmf_rx_detection(voc_get_session_id(VOICE_SESSION_NAME),
+				     enable);
+
+	return 0;
+}
+
+static int msm_dtmf_detect_voice_rx_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_dtmf_detect_volte_rx_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int enable = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: enable=%d\n", __func__, enable);
+	voc_enable_dtmf_rx_detection(voc_get_session_id(VOLTE_SESSION_NAME),
+				     enable);
+
+	return 0;
+}
+
+static int msm_dtmf_detect_volte_rx_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
 static struct snd_kcontrol_new msm_dtmf_controls[] = {
 	SOC_SINGLE_MULTI_EXT("DTMF_Generate Rx Low High Duration Gain",
 			     SND_SOC_NOPM, 0, 5000, 0, 4,
 			     msm_dtmf_rx_generate_get,
 			     msm_dtmf_rx_generate_put),
+	SOC_SINGLE_EXT("DTMF_Detect Rx Voice enable", SND_SOC_NOPM, 0, 1, 0,
+				msm_dtmf_detect_voice_rx_get,
+				msm_dtmf_detect_voice_rx_put),
+	SOC_SINGLE_EXT("DTMF_Detect Rx VoLTE enable", SND_SOC_NOPM, 0, 1, 0,
+				msm_dtmf_detect_volte_rx_get,
+				msm_dtmf_detect_volte_rx_put),
 };
 
 static int msm_pcm_dtmf_probe(struct snd_soc_platform *platform)
@@ -55,16 +172,384 @@
 	return 0;
 }
 
-static struct snd_pcm_ops msm_pcm_ops = {};
+static void dtmf_rx_detected_cb(uint8_t *pkt,
+				char *session,
+				void *private_data)
+{
+	struct dtmf_buf_node *buf_node = NULL;
+	struct vss_istream_evt_rx_dtmf_detected *dtmf_det_pkt =
+		(struct vss_istream_evt_rx_dtmf_detected *)pkt;
+	struct dtmf_drv_info *prtd = private_data;
+	unsigned long dsp_flags;
+
+	pr_debug("%s\n", __func__);
+	if (prtd->capture_substream == NULL)
+		return;
+
+	/* Copy dtmf detected info into out_queue. */
+	spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+	/* discarding dtmf detection info till start is received */
+	if (!list_empty(&prtd->free_out_queue) && prtd->capture_start) {
+		buf_node = list_first_entry(&prtd->free_out_queue,
+					    struct dtmf_buf_node, list);
+		list_del(&buf_node->list);
+		buf_node->dtmf_det_pkt.high_freq = dtmf_det_pkt->high_freq;
+		buf_node->dtmf_det_pkt.low_freq = dtmf_det_pkt->low_freq;
+		if (session != NULL)
+			strlcpy(buf_node->dtmf_det_pkt.session,
+				session, MAX_SESSION_NAME_LEN);
+
+		buf_node->dtmf_det_pkt.dir = DTMF_IN_RX;
+		pr_debug("high =%d, low=%d session=%s\n",
+			 buf_node->dtmf_det_pkt.high_freq,
+			 buf_node->dtmf_det_pkt.low_freq,
+			 buf_node->dtmf_det_pkt.session);
+		list_add_tail(&buf_node->list, &prtd->out_queue);
+		prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
+		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+		snd_pcm_period_elapsed(prtd->capture_substream);
+	} else {
+		spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+		pr_err("DTMF detection pkt in Rx  dropped, no free node available\n");
+	}
+
+	wake_up(&prtd->out_wait);
+}
+
+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 count = 0;
+	struct dtmf_buf_node *buf_node = NULL;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct dtmf_drv_info *prtd = runtime->private_data;
+	unsigned long dsp_flags;
+
+	count = frames_to_bytes(runtime, frames);
+
+	ret = wait_event_interruptible_timeout(prtd->out_wait,
+				(!list_empty(&prtd->out_queue)),
+				1 * HZ);
+
+	if (ret > 0) {
+		if (count <= DTMF_PKT_SIZE) {
+			spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+			buf_node = list_first_entry(&prtd->out_queue,
+					struct dtmf_buf_node, list);
+			list_del(&buf_node->list);
+			spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+			ret = copy_to_user(buf,
+					   &buf_node->dtmf_det_pkt,
+					   count);
+			if (ret) {
+				pr_err("%s: Copy to user retuned %d\n",
+					__func__, ret);
+				ret = -EFAULT;
+			}
+			spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+			list_add_tail(&buf_node->list,
+				      &prtd->free_out_queue);
+			spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
+
+		} else {
+			pr_err("%s: Read count %d > DTMF_PKT_SIZE\n",
+				__func__, count);
+			ret = -ENOMEM;
+		}
+	} else if (ret == 0) {
+		pr_err("%s: No UL data available\n", __func__);
+		ret = -ETIMEDOUT;
+	} else {
+		pr_err("%s: Read was interrupted\n", __func__);
+		ret = -ERESTARTSYS;
+	}
+	return ret;
+}
+
+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;
+	pr_debug("%s() DTMF\n", __func__);
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+
+	return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct dtmf_drv_info *prtd = NULL;
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		prtd = kzalloc(sizeof(struct dtmf_drv_info), GFP_KERNEL);
+
+		if (prtd == NULL) {
+			pr_err("Failed to allocate memory for msm_audio\n");
+			ret = -ENOMEM;
+			goto done;
+		}
+
+		mutex_init(&prtd->lock);
+		spin_lock_init(&prtd->dsp_lock);
+		init_waitqueue_head(&prtd->out_wait);
+		INIT_LIST_HEAD(&prtd->out_queue);
+		INIT_LIST_HEAD(&prtd->free_out_queue);
+
+		runtime->hw = msm_pcm_hardware;
+
+		ret = snd_pcm_hw_constraint_integer(runtime,
+						    SNDRV_PCM_HW_PARAM_PERIODS);
+		if (ret < 0)
+			pr_info("snd_pcm_hw_constraint_integer failed\n");
+
+		prtd->capture_substream = substream;
+		prtd->capture_instance++;
+		runtime->private_data = prtd;
+	}
+
+done:
+	return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct list_head *ptr = NULL;
+	struct list_head *next = NULL;
+	struct dtmf_buf_node *buf_node = NULL;
+	struct snd_dma_buffer *c_dma_buf;
+	struct snd_pcm_substream *c_substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct dtmf_drv_info *prtd = runtime->private_data;
+	unsigned long dsp_flags;
+
+	pr_debug("%s() DTMF\n", __func__);
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		mutex_lock(&prtd->lock);
+		wake_up(&prtd->out_wait);
+
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			prtd->capture_instance--;
+
+		if (!prtd->capture_instance) {
+			if (prtd->state == DTMF_GEN_RX_STARTED) {
+				prtd->state = DTMF_GEN_RX_STOPPED;
+				voc_disable_dtmf_det_on_active_sessions();
+				voc_register_dtmf_rx_detection_cb(NULL, NULL);
+			}
+			/* release all buffer */
+			/* release out_queue and free_out_queue */
+			pr_debug("release all buffer\n");
+			c_substream = prtd->capture_substream;
+			if (c_substream == NULL) {
+				pr_debug("c_substream is NULL\n");
+				mutex_unlock(&prtd->lock);
+				return -EINVAL;
+			}
+
+			c_dma_buf = &c_substream->dma_buffer;
+			if (c_dma_buf == NULL) {
+				pr_debug("c_dma_buf is NULL.\n");
+				mutex_unlock(&prtd->lock);
+				return -EINVAL;
+			}
+
+			if (c_dma_buf->area != NULL) {
+				spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
+				list_for_each_safe(ptr, next,
+							&prtd->out_queue) {
+					buf_node = list_entry(ptr,
+						   struct dtmf_buf_node, list);
+					list_del(&buf_node->list);
+				}
+
+				list_for_each_safe(ptr, next,
+						   &prtd->free_out_queue) {
+					buf_node = list_entry(ptr,
+						   struct dtmf_buf_node, list);
+					list_del(&buf_node->list);
+				}
+
+				spin_unlock_irqrestore(&prtd->dsp_lock,
+						       dsp_flags);
+				dma_free_coherent(c_substream->pcm->card->dev,
+						  runtime->hw.buffer_bytes_max,
+						  c_dma_buf->area,
+						  c_dma_buf->addr);
+				c_dma_buf->area = NULL;
+			}
+		}
+		prtd->capture_substream = NULL;
+		mutex_unlock(&prtd->lock);
+	}
+
+	return ret;
+}
+
+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 dtmf_drv_info *prtd = runtime->private_data;
+	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+	struct dtmf_buf_node *buf_node = NULL;
+	int i = 0, offset = 0;
+	int ret = 0;
+
+	pr_debug("%s: DTMF\n", __func__);
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		mutex_lock(&prtd->lock);
+		dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+		dma_buf->dev.dev = substream->pcm->card->dev;
+		dma_buf->private_data = NULL;
+
+		dma_buf->area = dma_alloc_coherent(substream->pcm->card->dev,
+						runtime->hw.buffer_bytes_max,
+						&dma_buf->addr, GFP_KERNEL);
+		if (!dma_buf->area) {
+			pr_err("%s:MSM DTMF dma_alloc failed\n", __func__);
+			mutex_unlock(&prtd->lock);
+			return -ENOMEM;
+		}
+
+		dma_buf->bytes = runtime->hw.buffer_bytes_max;
+		memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
+
+		for (i = 0; i < DTMF_MAX_Q_LEN; i++) {
+			pr_debug("node =%d\n", i);
+			buf_node = (void *) dma_buf->area + offset;
+			list_add_tail(&buf_node->list,
+				      &prtd->free_out_queue);
+			offset = offset + sizeof(struct dtmf_buf_node);
+		}
+
+		snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+		mutex_unlock(&prtd->lock);
+	}
+
+	return ret;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct dtmf_drv_info *prtd = runtime->private_data;
+
+	pr_debug("%s: DTMF\n", __func__);
+	prtd->pcm_capture_size  = snd_pcm_lib_buffer_bytes(substream);
+	prtd->pcm_capture_count = snd_pcm_lib_period_bytes(substream);
+	prtd->pcm_capture_irq_pos = 0;
+	prtd->pcm_capture_buf_pos = 0;
+	return 0;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct dtmf_drv_info *prtd = runtime->private_data;
+
+	pr_debug("%s: DTMF\n", __func__);
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		mutex_lock(&prtd->lock);
+
+		msm_pcm_capture_prepare(substream);
+
+		if (runtime->format != FORMAT_S16_LE) {
+			pr_err("format:%u doesnt match %d\n",
+			       (uint32_t)runtime->format, FORMAT_S16_LE);
+			mutex_unlock(&prtd->lock);
+			return -EINVAL;
+		}
+
+		if (prtd->capture_instance &&
+			(prtd->state != DTMF_GEN_RX_STARTED)) {
+			voc_register_dtmf_rx_detection_cb(dtmf_rx_detected_cb,
+							  prtd);
+			prtd->state = DTMF_GEN_RX_STARTED;
+		}
+		mutex_unlock(&prtd->lock);
+	}
+
+	return 0;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	int ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct dtmf_drv_info *prtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		pr_debug("%s: Trigger start\n", __func__);
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			prtd->capture_start = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			prtd->capture_start = 0;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	snd_pcm_uframes_t ret = 0;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct dtmf_drv_info *prtd = runtime->private_data;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (prtd->pcm_capture_irq_pos >= prtd->pcm_capture_size)
+			prtd->pcm_capture_irq_pos = 0;
+		ret = bytes_to_frames(runtime, (prtd->pcm_capture_irq_pos));
+	}
+
+	return ret;
+}
+
+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,
+	.prepare        = msm_pcm_prepare,
+	.trigger        = msm_pcm_trigger,
+	.pointer        = msm_pcm_pointer,
+};
+
+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,
 	.probe		= msm_pcm_dtmf_probe,
 };
 
 static __devinit int msm_pcm_probe(struct platform_device *pdev)
 {
-	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
 	return snd_soc_register_platform(&pdev->dev,
 					 &msm_soc_platform);
 }
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 1ddb6c9..23eee9d 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1597,8 +1597,8 @@
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
 	SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX,
-	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_stub_mixer,
-	msm_routing_put_voice_stub_mixer),
+	MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index cb2e39b..3b1e722 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -146,6 +146,21 @@
 	v->cvp_handle = cvp_handle;
 }
 
+char *voc_get_session_name(u16 session_id)
+{
+	char *session_name = NULL;
+
+	if (session_id == common.voice[VOC_PATH_PASSIVE].session_id) {
+		session_name = VOICE_SESSION_NAME;
+	} else if (session_id ==
+			common.voice[VOC_PATH_VOLTE_PASSIVE].session_id) {
+		session_name = VOLTE_SESSION_NAME;
+	} else if (session_id == common.voice[VOC_PATH_FULL].session_id) {
+		session_name = VOIP_SESSION_NAME;
+	}
+	return session_name;
+}
+
 uint16_t voc_get_session_id(char *name)
 {
 	u16 session_id = 0;
@@ -894,6 +909,105 @@
 	return 0;
 }
 
+static int voice_send_dtmf_rx_detection_cmd(struct voice_data *v,
+					    uint32_t enable)
+{
+	int ret = 0;
+	void *apr_cvs;
+	u16 cvs_handle;
+	struct cvs_set_rx_dtmf_detection_cmd cvs_dtmf_rx_detection;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	cvs_handle = voice_get_cvs_handle(v);
+
+	/* Set SET_DTMF_RX_DETECTION */
+	cvs_dtmf_rx_detection.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+	cvs_dtmf_rx_detection.hdr.pkt_size =
+				APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvs_dtmf_rx_detection) - APR_HDR_SIZE);
+	cvs_dtmf_rx_detection.hdr.src_port = v->session_id;
+	cvs_dtmf_rx_detection.hdr.dest_port = cvs_handle;
+	cvs_dtmf_rx_detection.hdr.token = 0;
+	cvs_dtmf_rx_detection.hdr.opcode =
+					VSS_ISTREAM_CMD_SET_RX_DTMF_DETECTION;
+	cvs_dtmf_rx_detection.cvs_dtmf_det.enable = enable;
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_dtmf_rx_detection);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_DTMF_RX_DETECTION\n",
+		       __func__,
+		       ret);
+		return -EINVAL;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+void voc_disable_dtmf_det_on_active_sessions(void)
+{
+	struct voice_data *v = NULL;
+	int i;
+	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+		v = &common.voice[i];
+		if ((v->dtmf_rx_detect_en) &&
+			((v->voc_state == VOC_RUN) ||
+			 (v->voc_state == VOC_CHANGE) ||
+			 (v->voc_state == VOC_STANDBY))) {
+			pr_debug("disable dtmf det on ses_id=%d\n",
+				 v->session_id);
+			voice_send_dtmf_rx_detection_cmd(v, 0);
+		}
+	}
+}
+
+int voc_enable_dtmf_rx_detection(uint16_t session_id, uint32_t enable)
+{
+	struct voice_data *v = voice_get_session(session_id);
+	int ret = 0;
+
+	if (v == NULL) {
+		pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+		return -EINVAL;
+	}
+
+	mutex_lock(&v->lock);
+	v->dtmf_rx_detect_en = enable;
+
+	if ((v->voc_state == VOC_RUN) ||
+	    (v->voc_state == VOC_CHANGE) ||
+	    (v->voc_state == VOC_STANDBY))
+		ret = voice_send_dtmf_rx_detection_cmd(v,
+						       v->dtmf_rx_detect_en);
+
+	mutex_unlock(&v->lock);
+
+	return ret;
+}
+
 static int voice_config_cvs_vocoder(struct voice_data *v)
 {
 	int ret = 0;
@@ -2207,6 +2321,9 @@
 	if (v->rec_info.rec_enable)
 		voice_cvs_start_record(v, v->rec_info.rec_mode);
 
+	if (v->dtmf_rx_detect_en)
+		voice_send_dtmf_rx_detection_cmd(v, v->dtmf_rx_detect_en);
+
 	rtac_add_voice(voice_get_cvs_handle(v),
 		voice_get_cvp_handle(v),
 		v->dev_rx.port_id, v->dev_tx.port_id,
@@ -2445,6 +2562,10 @@
 	/* send stop voice cmd */
 	voice_send_stop_voice_cmd(v);
 
+	/* send stop dtmf detecton cmd */
+	if (v->dtmf_rx_detect_en)
+		voice_send_dtmf_rx_detection_cmd(v, 0);
+
 	/* Clear mute setting */
 	v->dev_tx.mute = common.default_mute_val;
 
@@ -3700,6 +3821,13 @@
 	common.mvs_info.private_data = private_data;
 }
 
+void voc_register_dtmf_rx_detection_cb(dtmf_rx_det_cb_fn dtmf_rx_ul_cb,
+				       void *private_data)
+{
+	common.dtmf_info.dtmf_rx_ul_cb = dtmf_rx_ul_cb;
+	common.dtmf_info.private_data = private_data;
+}
+
 void voc_config_vocoder(uint32_t media_type,
 			  uint32_t rate,
 			  uint32_t network_type,
@@ -3876,6 +4004,7 @@
 			case VSS_ISTREAM_CMD_STOP_PLAYBACK:
 			case VSS_ISTREAM_CMD_START_RECORD:
 			case VSS_ISTREAM_CMD_STOP_RECORD:
+			case VSS_ISTREAM_CMD_SET_RX_DTMF_DETECTION:
 				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
 				v->cvs_state = CMD_STATUS_SUCCESS;
 				wake_up(&v->cvs_wait);
@@ -3947,8 +4076,30 @@
 	} else if (data->opcode ==  VOICE_EVT_GET_PARAM_ACK) {
 		rtac_make_voice_callback(RTAC_CVS, data->payload,
 					data->payload_size);
-	} else
+	} else if (data->opcode == VSS_ISTREAM_EVT_RX_DTMF_DETECTED) {
+		struct vss_istream_evt_rx_dtmf_detected *dtmf_rx_detected;
+		uint32_t *voc_pkt = data->payload;
+		uint32_t pkt_len = data->payload_size;
+
+		if ((voc_pkt != NULL) &&
+		    (pkt_len ==
+			sizeof(struct vss_istream_evt_rx_dtmf_detected))) {
+
+			dtmf_rx_detected =
+			(struct vss_istream_evt_rx_dtmf_detected *) voc_pkt;
+			pr_debug("RX_DTMF_DETECTED low_freq=%d high_freq=%d\n",
+				 dtmf_rx_detected->low_freq,
+				 dtmf_rx_detected->high_freq);
+			if (c->dtmf_info.dtmf_rx_ul_cb)
+				c->dtmf_info.dtmf_rx_ul_cb((uint8_t *)voc_pkt,
+					voc_get_session_name(v->session_id),
+					c->dtmf_info.private_data);
+		} else {
+			pr_err("Invalid packet\n");
+		}
+	} else {
 		pr_debug("Unknown opcode 0x%x\n", data->opcode);
+	}
 
 fail:
 	return 0;
@@ -3971,7 +4122,6 @@
 	v = voice_get_session(data->dest_port);
 	if (v == NULL) {
 		pr_err("%s: v is NULL\n", __func__);
-
 		return -EINVAL;
 	}
 
@@ -4141,6 +4291,7 @@
 		common.voice[i].dev_tx.port_id = 1;
 		common.voice[i].dev_rx.port_id = 0;
 		common.voice[i].sidetone_gain = 0x512;
+		common.voice[i].dtmf_rx_detect_en = 0;
 
 		common.voice[i].voc_state = VOC_INIT;
 
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 34b1b52..2fc2266 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -567,6 +567,55 @@
 	/* Reserved, set to 0. */
 };
 
+/*
+ * Event sent by the stream to the client that enables Rx DTMF
+ * detection whenever DTMF is detected in the Rx path.
+ *
+ * The DTMF detection feature can only be used to detect DTMF
+ * frequencies as listed in the vss_istream_evt_rx_dtmf_detected_t
+ * structure.
+ */
+
+#define VSS_ISTREAM_EVT_RX_DTMF_DETECTED (0x0001101A)
+
+struct vss_istream_cmd_set_rx_dtmf_detection {
+	/*
+	 * Enables/disables Rx DTMF detection
+	 *
+	 * Possible values are
+	 * 0 - disable
+	 * 1 - enable
+	 *
+	 */
+	uint32_t enable;
+};
+
+#define VSS_ISTREAM_CMD_SET_RX_DTMF_DETECTION (0x00011027)
+
+struct vss_istream_evt_rx_dtmf_detected {
+	uint16_t low_freq;
+	/*
+	 * Detected low frequency. Possible values:
+	 * 697 Hz
+	 * 770 Hz
+	 * 852 Hz
+	 * 941 Hz
+	 */
+	uint16_t high_freq;
+	/*
+	 * Detected high frequency. Possible values:
+	 * 1209 Hz
+	 * 1336 Hz
+	 * 1477 Hz
+	 * 1633 Hz
+	 */
+};
+
+struct cvs_set_rx_dtmf_detection_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_set_rx_dtmf_detection cvs_dtmf_det;
+} __packed;
+
 struct cvs_create_passive_ctl_session_cmd {
 	struct apr_hdr hdr;
 	struct vss_istream_cmd_create_passive_control_session_t cvs_session;
@@ -858,6 +907,10 @@
 			 uint32_t *pkt_len,
 			 void *private_data);
 
+/* CB for DTMF RX Detection */
+typedef void (*dtmf_rx_det_cb_fn)(uint8_t *pkt,
+				  char *session,
+				  void *private_data);
 
 struct mvs_driver_info {
 	uint32_t media_type;
@@ -869,6 +922,11 @@
 	void *private_data;
 };
 
+struct dtmf_driver_info {
+	dtmf_rx_det_cb_fn dtmf_rx_ul_cb;
+	void *private_data;
+};
+
 struct incall_rec_info {
 	uint32_t rec_enable;
 	uint32_t rec_mode;
@@ -915,6 +973,8 @@
 	/* FENC enable value */
 	uint32_t fens_enable;
 
+	uint32_t dtmf_rx_detect_en;
+
 	struct voice_dev_route_state voc_route_state;
 
 	u16 session_id;
@@ -961,6 +1021,8 @@
 
 	struct mvs_driver_info mvs_info;
 
+	struct dtmf_driver_info dtmf_info;
+
 	struct voice_data voice[MAX_VOC_SESSIONS];
 };
 
@@ -968,6 +1030,9 @@
 			dl_cb_fn dl_cb,
 			void *private_data);
 
+void voc_register_dtmf_rx_detection_cb(dtmf_rx_det_cb_fn dtmf_rx_ul_cb,
+				       void *private_data);
+
 void voc_config_vocoder(uint32_t media_type,
 			uint32_t rate,
 			uint32_t network_type,
@@ -1005,11 +1070,20 @@
 int voc_enable_cvp(uint16_t session_id);
 int voc_set_route_flag(uint16_t session_id, uint8_t path_dir, uint8_t set);
 uint8_t voc_get_route_flag(uint16_t session_id, uint8_t path_dir);
+int voc_enable_dtmf_rx_detection(uint16_t session_id, uint32_t enable);
+void voc_disable_dtmf_det_on_active_sessions(void);
 
+#define MAX_SESSION_NAME_LEN 32
 #define VOICE_SESSION_NAME "Voice session"
 #define VOIP_SESSION_NAME "VoIP session"
 #define VOLTE_SESSION_NAME "VoLTE session"
 #define SGLTE_SESSION_NAME "SGLTE session"
+
+#define VOC_PATH_PASSIVE 0
+#define VOC_PATH_FULL 1
+#define VOC_PATH_VOLTE_PASSIVE 2
+#define VOC_PATH_SGLTE_PASSIVE 3
+
 uint16_t voc_get_session_id(char *name);
 
 int voc_start_playback(uint32_t set);
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 7399053..621d24b 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -37,9 +37,39 @@
 	DECLARE_BITMAP(status_mask, STATUS_MAX);
 	u32 rate;
 	u32 channels;
+	u32 bitwidth;
 	union afe_port_config port_config;
 };
 
+struct msm_dai_q6_mi2s_dai_config {
+	u16 pdata_mi2s_lines;
+	struct msm_dai_q6_dai_data mi2s_dai_data;
+};
+
+struct msm_dai_q6_mi2s_dai_data {
+	struct msm_dai_q6_mi2s_dai_config tx_dai;
+	struct msm_dai_q6_mi2s_dai_config rx_dai;
+	struct snd_pcm_hw_constraint_list rate_constraint;
+	struct snd_pcm_hw_constraint_list bitwidth_constraint;
+};
+
+/* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command
+ *  0: linear PCM
+ *  1: non-linear PCM
+ *  2: PCM data in IEC 60968 container
+ *  3: compressed data in IEC 60958 container
+ */
+static const char *const mi2s_format[] = {
+	"LPCM",
+	"Compr",
+	"LPCM-60958",
+	"Compr-60958"
+};
+
+static const struct soc_enum mi2s_config_enum[] = {
+	SOC_ENUM_SINGLE_EXT(4, mi2s_format),
+};
+
 static struct clk *pcm_src_clk;
 static struct clk *pcm_branch_clk;
 static struct clk *pcm_oe_src_clk;
@@ -1155,6 +1185,611 @@
 	.remove = msm_dai_q6_dai_remove,
 };
 
+static int msm_dai_q6_mi2s_format_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+	int value = ucontrol->value.integer.value[0];
+	dai_data->port_config.i2s.data_format = value;
+	pr_debug("%s: value = %d, channel = %d, line = %d\n",
+		 __func__, value, dai_data->port_config.i2s.mono_stereo,
+		 dai_data->port_config.i2s.channel_mode);
+	return 0;
+}
+
+static int msm_dai_q6_mi2s_format_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+	ucontrol->value.integer.value[0] =
+		dai_data->port_config.i2s.data_format;
+	return 0;
+}
+
+static const struct snd_kcontrol_new mi2s_config_controls[] = {
+	SOC_ENUM_EXT("PRI MI2S RX Format", mi2s_config_enum[0],
+		     msm_dai_q6_mi2s_format_get,
+		     msm_dai_q6_mi2s_format_put),
+	SOC_ENUM_EXT("SEC RX Format", mi2s_config_enum[0],
+		     msm_dai_q6_mi2s_format_get,
+		     msm_dai_q6_mi2s_format_put),
+	SOC_ENUM_EXT("PRI MI2S TX Format", mi2s_config_enum[0],
+		     msm_dai_q6_mi2s_format_get,
+		     msm_dai_q6_mi2s_format_put),
+};
+
+static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+			dev_get_drvdata(dai->dev);
+	struct snd_kcontrol *kcontrol = NULL;
+	int rc = 0;
+
+	if (mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.i2s.channel_mode) {
+		kcontrol = snd_ctl_new1(&mi2s_config_controls[0],
+					&mi2s_dai_data->rx_dai.mi2s_dai_data);
+		rc = snd_ctl_add(dai->card->snd_card, kcontrol);
+
+		if (IS_ERR_VALUE(rc)) {
+			dev_err(dai->dev, "%s: err add RX fmt ctl\n", __func__);
+			goto rtn;
+		}
+	}
+	if (mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.channel_mode) {
+		rc = snd_ctl_add(dai->card->snd_card,
+				snd_ctl_new1(&mi2s_config_controls[2],
+				&mi2s_dai_data->tx_dai.mi2s_dai_data));
+
+		if (IS_ERR_VALUE(rc)) {
+			if (kcontrol)
+				snd_ctl_remove(dai->card->snd_card, kcontrol);
+			dev_err(dai->dev, "%s: err add TX fmt ctl\n", __func__);
+		}
+	}
+rtn:
+	return rc;
+}
+
+
+static int msm_dai_q6_dai_mi2s_remove(struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+	int rc;
+
+	/* If AFE port is still up, close it */
+	if (test_bit(STATUS_PORT_STARTED,
+		     mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask)) {
+		rc = afe_close(MI2S_RX); /* can block */
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close MI2S_RX port\n");
+		clear_bit(STATUS_PORT_STARTED,
+			  mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask);
+	}
+	if (test_bit(STATUS_PORT_STARTED,
+		     mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
+		rc = afe_close(MI2S_TX); /* can block */
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close MI2S_TX port\n");
+		clear_bit(STATUS_PORT_STARTED,
+			  mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask);
+	}
+	kfree(mi2s_dai_data);
+	snd_soc_unregister_dai(dai->dev);
+	return 0;
+}
+
+static int msm_dai_q6_mi2s_startup(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+
+	dev_dbg(dai->dev, "%s: cnst list %p\n", __func__,
+		mi2s_dai_data->rate_constraint.list);
+
+	if (mi2s_dai_data->rate_constraint.list) {
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE,
+				&mi2s_dai_data->rate_constraint);
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+				SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+				&mi2s_dai_data->bitwidth_constraint);
+	}
+
+	return 0;
+}
+
+
+static int msm_mi2s_get_port_id(u32 mi2s_id, int stream, u16 *port_id)
+{
+	int ret = 0;
+
+	switch (stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		switch (mi2s_id) {
+		case MSM_PRIM_MI2S:
+			*port_id = MI2S_RX;
+		break;
+		default:
+			ret = -1;
+		break;
+		}
+	break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		switch (mi2s_id) {
+		case MSM_PRIM_MI2S:
+			*port_id = MI2S_TX;
+		break;
+		default:
+			ret = -1;
+		break;
+		}
+	break;
+	default:
+		ret = -1;
+	break;
+	}
+	pr_debug("%s: port_id = %x\n", __func__, *port_id);
+	return ret;
+}
+
+static int msm_dai_q6_mi2s_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+	struct msm_dai_q6_dai_data *dai_data =
+		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		 &mi2s_dai_data->rx_dai.mi2s_dai_data :
+		 &mi2s_dai_data->tx_dai.mi2s_dai_data);
+	u16 port_id = 0;
+	int rc = 0;
+
+	dev_dbg(dai->dev, "%s: device name %s dai id %x,port id = %x\n",
+		__func__, dai->name, dai->id, port_id);
+
+	if (msm_mi2s_get_port_id(dai->id, substream->stream,
+				 &port_id) != 0) {
+		dev_err(dai->dev, "%s: Invalid Port ID\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		/* PORT START should be set if prepare called
+		 * in active state.
+		 */
+		rc = afe_port_start(port_id, &dai_data->port_config,
+				    dai_data->rate);
+
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to open AFE port %x\n",
+				dai->id);
+		else
+			set_bit(STATUS_PORT_STARTED,
+				dai_data->status_mask);
+	}
+	return rc;
+}
+
+static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+		dev_get_drvdata(dai->dev);
+	struct msm_dai_q6_mi2s_dai_config *mi2s_dai_config =
+		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+	struct msm_dai_q6_dai_data *dai_data = &mi2s_dai_config->mi2s_dai_data;
+
+	dai_data->channels = params_channels(params);
+	switch (dai_data->channels) {
+	case 8:
+	case 7:
+		if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_8CHS)
+			goto error_invalid_data;
+		dai_data->port_config.i2s.channel_mode = AFE_PORT_I2S_8CHS;
+		break;
+	case 6:
+	case 5:
+		if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_6CHS)
+			goto error_invalid_data;
+		dai_data->port_config.i2s.channel_mode = AFE_PORT_I2S_6CHS;
+		break;
+	case 4:
+	case 3:
+		if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_QUAD01)
+			goto error_invalid_data;
+		if (mi2s_dai_config->pdata_mi2s_lines == AFE_PORT_I2S_QUAD23)
+			dai_data->port_config.i2s.channel_mode =
+				mi2s_dai_config->pdata_mi2s_lines;
+		else
+			dai_data->port_config.i2s.channel_mode =
+					AFE_PORT_I2S_QUAD01;
+		break;
+	case 2:
+	case 1:
+		if (mi2s_dai_config->pdata_mi2s_lines < AFE_PORT_I2S_SD0)
+			goto error_invalid_data;
+		switch (mi2s_dai_config->pdata_mi2s_lines) {
+		case AFE_PORT_I2S_SD0:
+		case AFE_PORT_I2S_SD1:
+		case AFE_PORT_I2S_SD2:
+		case AFE_PORT_I2S_SD3:
+			dai_data->port_config.i2s.channel_mode =
+				mi2s_dai_config->pdata_mi2s_lines;
+			break;
+		case AFE_PORT_I2S_QUAD01:
+		case AFE_PORT_I2S_6CHS:
+		case AFE_PORT_I2S_8CHS:
+			dai_data->port_config.i2s.channel_mode =
+						AFE_PORT_I2S_SD0;
+			break;
+		case AFE_PORT_I2S_QUAD23:
+			dai_data->port_config.i2s.channel_mode =
+						AFE_PORT_I2S_SD2;
+			break;
+		}
+		if (dai_data->channels == 2)
+			dai_data->port_config.i2s.mono_stereo =
+						MSM_AFE_CH_STEREO;
+		else
+			dai_data->port_config.i2s.mono_stereo = MSM_AFE_MONO;
+		break;
+	default:
+		goto error_invalid_data;
+	}
+	dai_data->rate = params_rate(params);
+	dai_data->port_config.i2s.bit_width = 16;
+	dai_data->bitwidth = 16;
+	dai_data->port_config.i2s.i2s_cfg_minor_version =
+			AFE_API_VERSION_I2S_CONFIG;
+	dai_data->port_config.i2s.sample_rate = dai_data->rate;
+	if (!mi2s_dai_data->rate_constraint.list) {
+		mi2s_dai_data->rate_constraint.list = &dai_data->rate;
+		mi2s_dai_data->bitwidth_constraint.list = &dai_data->bitwidth;
+	}
+
+	pr_debug("%s: dai_data->channels = %d, line = %d\n"
+		 ",mono_stereo =%x sample rate = %x\n", __func__,
+		 dai_data->channels, dai_data->port_config.i2s.channel_mode,
+		 dai_data->port_config.i2s.mono_stereo, dai_data->rate);
+	return 0;
+error_invalid_data:
+	pr_debug("%s: dai_data->channels = %d, line = %d\n", __func__,
+		 dai_data->channels, dai_data->port_config.i2s.channel_mode);
+	return -EINVAL;
+}
+
+
+static int msm_dai_q6_mi2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+	dev_get_drvdata(dai->dev);
+
+	if (test_bit(STATUS_PORT_STARTED,
+	    mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) ||
+	    test_bit(STATUS_PORT_STARTED,
+	    mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
+		dev_err(dai->dev, "%s: err chg i2s mode while dai running",
+			__func__);
+		return -EPERM;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.i2s.ws_src = 1;
+		mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.ws_src = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.i2s.ws_src = 0;
+		mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.ws_src = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void msm_dai_q6_mi2s_shutdown(struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+			dev_get_drvdata(dai->dev);
+	struct msm_dai_q6_dai_data *dai_data =
+		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		 &mi2s_dai_data->rx_dai.mi2s_dai_data :
+		 &mi2s_dai_data->tx_dai.mi2s_dai_data);
+	 u16 port_id = 0;
+	int rc = 0;
+
+	if (msm_mi2s_get_port_id(dai->id, substream->stream,
+				 &port_id) != 0) {
+		dev_err(dai->dev, "%s: Invalid Port ID\n", __func__);
+	}
+
+	dev_dbg(dai->dev, "%s: device name %s port id = %x\n",
+		__func__, dai->name, port_id);
+
+	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+		rc = afe_close(port_id);
+		if (IS_ERR_VALUE(rc))
+			dev_err(dai->dev, "fail to close AFE port\n");
+		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+	}
+
+	if (!test_bit(STATUS_PORT_STARTED,
+			mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) &&
+		!test_bit(STATUS_PORT_STARTED,
+			mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask)) {
+		mi2s_dai_data->rate_constraint.list = NULL;
+		mi2s_dai_data->bitwidth_constraint.list = NULL;
+	}
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_mi2s_ops = {
+	.startup	= msm_dai_q6_mi2s_startup,
+	.prepare	= msm_dai_q6_mi2s_prepare,
+	.hw_params	= msm_dai_q6_mi2s_hw_params,
+	.set_fmt	= msm_dai_q6_mi2s_set_fmt,
+	.shutdown	= msm_dai_q6_mi2s_shutdown,
+};
+
+/* Channel min and max are initialized base on platform data */
+static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.rate_min =     8000,
+		.rate_max =     48000,
+	},
+	.capture = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.rate_min =     8000,
+		.rate_max =     48000,
+	},
+	.ops = &msm_dai_q6_mi2s_ops,
+	.probe = msm_dai_q6_dai_mi2s_probe,
+	.remove = msm_dai_q6_dai_mi2s_remove,
+};
+
+
+static int msm_dai_q6_mi2s_get_lineconfig(u16 sd_lines, u16 *config_ptr,
+					  unsigned int *ch_cnt)
+{
+	u8 num_of_sd_lines;
+
+	num_of_sd_lines = num_of_bits_set(sd_lines);
+	switch (num_of_sd_lines) {
+	case 0:
+		pr_debug("%s: no line is assigned\n", __func__);
+		break;
+	case 1:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0:
+			*config_ptr = AFE_PORT_I2S_SD0;
+			break;
+		case MSM_MI2S_SD1:
+			*config_ptr = AFE_PORT_I2S_SD1;
+			break;
+		case MSM_MI2S_SD2:
+			*config_ptr = AFE_PORT_I2S_SD2;
+			break;
+		case MSM_MI2S_SD3:
+			*config_ptr = AFE_PORT_I2S_SD3;
+			break;
+		default:
+			pr_err("%s: invalid SD line\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 2:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1:
+			*config_ptr = AFE_PORT_I2S_QUAD01;
+			break;
+		case MSM_MI2S_SD2 | MSM_MI2S_SD3:
+			*config_ptr = AFE_PORT_I2S_QUAD23;
+			break;
+		default:
+			pr_err("%s: invalid SD line\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 3:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
+			*config_ptr = AFE_PORT_I2S_6CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 4:
+		switch (sd_lines) {
+		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
+			*config_ptr = AFE_PORT_I2S_8CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines\n",
+				   __func__);
+			goto error_invalid_data;
+		}
+		break;
+	default:
+		pr_err("%s: invalid SD lines\n", __func__);
+		goto error_invalid_data;
+	}
+	*ch_cnt = num_of_sd_lines;
+	return 0;
+
+error_invalid_data:
+	return -EINVAL;
+}
+
+static int msm_dai_q6_mi2s_platform_data_validation(
+	struct platform_device *pdev, struct snd_soc_dai_driver *dai_driver)
+{
+	struct msm_dai_q6_mi2s_dai_data *dai_data = dev_get_drvdata(&pdev->dev);
+	struct msm_mi2s_pdata *mi2s_pdata =
+			(struct msm_mi2s_pdata *) pdev->dev.platform_data;
+	unsigned int ch_cnt;
+	int rc = 0;
+	u16 sd_line;
+
+	if (mi2s_pdata == NULL) {
+		pr_err("%s: mi2s_pdata NULL", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->rx_sd_lines,
+					    &sd_line, &ch_cnt);
+
+	if (IS_ERR_VALUE(rc)) {
+		dev_err(&pdev->dev, "invalid MI2S RX sd line config\n");
+		goto rtn;
+	}
+
+	if (ch_cnt) {
+		dai_data->rx_dai.mi2s_dai_data.port_config.i2s.channel_mode =
+				mi2s_pdata->rx_sd_lines;
+		dai_data->rx_dai.pdata_mi2s_lines = mi2s_pdata->rx_sd_lines;
+		dai_driver->playback.channels_min = 1;
+		dai_driver->playback.channels_max = ch_cnt << 1;
+	} else {
+		dai_driver->playback.channels_min = 0;
+		dai_driver->playback.channels_max = 0;
+	}
+	rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->tx_sd_lines,
+					    &sd_line, &ch_cnt);
+
+	if (IS_ERR_VALUE(rc)) {
+		dev_err(&pdev->dev, "invalid MI2S TX sd line config\n");
+		goto rtn;
+	}
+
+	if (ch_cnt) {
+		dai_data->tx_dai.mi2s_dai_data.port_config.i2s.channel_mode =
+			mi2s_pdata->tx_sd_lines;
+		dai_data->tx_dai.pdata_mi2s_lines = mi2s_pdata->tx_sd_lines;
+		dai_driver->capture.channels_min = 1;
+		dai_driver->capture.channels_max = ch_cnt << 1;
+	} else {
+		dai_driver->capture.channels_min = 0;
+		dai_driver->capture.channels_max = 0;
+	}
+
+	dev_dbg(&pdev->dev, "%s: playback sdline %x capture sdline %x\n",
+		__func__, dai_data->rx_dai.pdata_mi2s_lines,
+		dai_data->tx_dai.pdata_mi2s_lines);
+	dev_dbg(&pdev->dev, "%s: playback ch_max %d capture ch_mx %d\n",
+		__func__, dai_driver->playback.channels_max,
+		dai_driver->capture.channels_max);
+rtn:
+	return rc;
+}
+
+static __devinit int msm_dai_q6_mi2s_dev_probe(struct platform_device *pdev)
+{
+	struct msm_dai_q6_mi2s_dai_data *dai_data;
+	const char *q6_mi2s_dev_id = "qcom,msm-dai-q6-mi2s-dev-id";
+	u32 tx_line = 0;
+	u32  rx_line = 0;
+	u32 mi2s_intf = 0;
+	struct msm_mi2s_pdata *mi2s_pdata;
+	int rc = 0;
+
+
+	rc = of_property_read_u32(pdev->dev.of_node, q6_mi2s_dev_id,
+				  &mi2s_intf);
+	if (rc) {
+		dev_err(&pdev->dev,
+			"%s: missing %x in dt node\n", __func__, mi2s_intf);
+	return rc;
+	}
+
+	if (mi2s_intf > MSM_QUAD_MI2S) {
+		dev_err(&pdev->dev, "%s: Invalid MI2S ID from Device Tree\n",
+			 __func__);
+		return -EINVAL;
+	}
+
+	if (mi2s_intf == MSM_PRIM_MI2S) {
+		dev_set_name(&pdev->dev, "%s.%d", "msm-dai-q6-mi2s",
+			     MSM_PRIM_MI2S);
+		pdev->id = MSM_PRIM_MI2S;
+	}
+
+	mi2s_pdata = kzalloc(sizeof(struct msm_mi2s_pdata), GFP_KERNEL);
+	if (!mi2s_pdata) {
+		dev_err(&pdev->dev, "fail to allocate mi2s_pdata data\n");
+		rc = -ENOMEM;
+		goto rtn;
+	}
+
+	dev_dbg(&pdev->dev, "dev name %s dev id %x\n", dev_name(&pdev->dev),
+		pdev->id);
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-mi2s-rx-lines",
+				  &rx_line);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: Rx line from DT file %s\n", __func__,
+			"qcom,msm-mi2s-rx-lines");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-mi2s-tx-lines",
+				  &tx_line);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: Tx line from DT file %s\n", __func__,
+			"qcom,msm-mi2s-tx-lines");
+		return rc;
+	}
+	dev_dbg(&pdev->dev, "dev name %s Rx line %x , Tx ine %x\n",
+		dev_name(&pdev->dev), rx_line, tx_line);
+	mi2s_pdata->rx_sd_lines = rx_line;
+	mi2s_pdata->tx_sd_lines = tx_line;
+	dai_data = kzalloc(sizeof(struct msm_dai_q6_mi2s_dai_data),
+				GFP_KERNEL);
+	if (!dai_data) {
+		dev_err(&pdev->dev, "fail to allocate dai data\n");
+		rc = -ENOMEM;
+		goto rtn;
+	} else
+		dev_set_drvdata(&pdev->dev, dai_data);
+	pdev->dev.platform_data = mi2s_pdata;
+	rc = msm_dai_q6_mi2s_platform_data_validation(pdev,
+					&msm_dai_q6_mi2s_dai);
+	if (IS_ERR_VALUE(rc))
+		goto err_pdata;
+	dai_data->rate_constraint.count = 1;
+	dai_data->bitwidth_constraint.count = 1;
+	rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_mi2s_dai);
+	if (IS_ERR_VALUE(rc))
+		goto err_pdata;
+	return 0;
+err_pdata:
+	dev_err(&pdev->dev, "fail to msm_dai_q6_mi2s_dev_probe\n");
+	kfree(dai_data);
+rtn:
+	return rc;
+}
+
+static __devexit int msm_dai_q6_mi2s_dev_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
 static int msm_dai_q6_dev_probe(struct platform_device *pdev)
 {
 	int rc, id;
@@ -1281,6 +1916,57 @@
 	},
 };
 
+static int msm_dai_mi2s_q6_probe(struct platform_device *pdev)
+{
+	int rc;
+	rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n",
+			__func__, rc);
+	} else
+		dev_dbg(&pdev->dev, "%s: added child node\n", __func__);
+	return rc;
+}
+
+static int msm_dai_mi2s_q6_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id msm_dai_mi2s_dt_match[] = {
+	{ .compatible = "qcom,msm-dai-mi2s", },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, msm_dai_mi2s_dt_match);
+
+static struct platform_driver msm_dai_mi2s_q6 = {
+	.probe  = msm_dai_mi2s_q6_probe,
+	.remove = msm_dai_mi2s_q6_remove,
+	.driver = {
+		.name = "msm-dai-mi2s",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_dai_mi2s_dt_match,
+	},
+};
+
+static const struct of_device_id msm_dai_q6_mi2s_dev_dt_match[] = {
+	{ .compatible = "qcom,msm-dai-q6-mi2s", },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, msm_dai_q6_mi2s_dev_dt_match);
+
+static struct platform_driver msm_dai_q6_mi2s_driver = {
+	.probe  = msm_dai_q6_mi2s_dev_probe,
+	.remove  = __devexit_p(msm_dai_q6_mi2s_dev_remove),
+	.driver = {
+		.name = "msm-dai-q6-mi2s",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_dai_q6_mi2s_dev_dt_match,
+	},
+};
+
 static int __init msm_dai_q6_init(void)
 {
 	int rc;
@@ -1293,26 +1979,44 @@
 
 	if (rc) {
 		pr_err("%s: fail to register cpu dai driver\n", __func__);
-		platform_driver_unregister(&msm_auxpcm_dev_driver);
-		goto fail;
+		goto aux_pcm_resource_fail;
 	}
 
 	rc = platform_driver_register(&msm_dai_q6);
 	if (rc) {
 		pr_err("%s: fail to register dai q6 driver", __func__);
-		platform_driver_unregister(&msm_auxpcm_dev_driver);
-		platform_driver_unregister(&msm_auxpcm_resource_driver);
-		goto fail;
+		goto dai_q6_fail;
 	}
 
 	rc = platform_driver_register(&msm_dai_q6_dev);
 	if (rc) {
 		pr_err("%s: fail to register dai q6 dev driver", __func__);
-		platform_driver_unregister(&msm_dai_q6);
-		platform_driver_unregister(&msm_auxpcm_dev_driver);
-		platform_driver_unregister(&msm_auxpcm_resource_driver);
-		goto fail;
+		goto dai_q6_dev_fail;
 	}
+
+	rc = platform_driver_register(&msm_dai_q6_mi2s_driver);
+	if (rc) {
+		pr_err("%s: fail to register dai MI2S dev drv\n", __func__);
+		goto dai_q6_mi2s_drv_fail;
+	}
+
+	rc = platform_driver_register(&msm_dai_mi2s_q6);
+	if (rc) {
+		pr_err("%s: fail to register dai MI2S\n", __func__);
+		goto dai_mi2s_q6_fail;
+	}
+	return rc;
+
+dai_mi2s_q6_fail:
+	platform_driver_unregister(&msm_dai_q6_mi2s_driver);
+dai_q6_mi2s_drv_fail:
+	platform_driver_unregister(&msm_dai_q6_dev);
+dai_q6_dev_fail:
+	platform_driver_unregister(&msm_dai_q6);
+dai_q6_fail:
+	platform_driver_unregister(&msm_auxpcm_resource_driver);
+aux_pcm_resource_fail:
+	platform_driver_unregister(&msm_auxpcm_dev_driver);
 fail:
 	return rc;
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 4ab3340..2e0c229 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -1352,6 +1352,9 @@
 	SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_MI2S_RX,
 	MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
 	msm_routing_put_port_mixer),
+	SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_RX,
+	MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+	msm_routing_put_port_mixer),
 };
 
 static const struct snd_kcontrol_new fm_switch_mixer_controls =
@@ -1608,6 +1611,9 @@
 	SND_SOC_DAPM_AIF_OUT("MI2S_UL_HL", "MI2S_TX_HOSTLESS Capture",
 		0, 0, 0, 0),
 
+	SND_SOC_DAPM_AIF_OUT("MI2S_DL_HL", "MI2S_RX_HOSTLESS Playback",
+		0, 0, 0, 0),
+
 	/* Backend AIF */
 	/* Stream name equals to backend dai link stream name
 	*/
@@ -1933,6 +1939,8 @@
 	{"INTFM_UL_HL", NULL, "INT_FM_TX"},
 	{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
 	{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
+	{"MI2S_RX", NULL, "MI2S_DL_HL"},
+	{"MI2S_UL_HL", NULL, "MI2S_TX"},
 	{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
 	{"PCM_RX", NULL, "PCM_RX_DL_HL"},
 	{"MI2S_UL_HL", NULL, "MI2S_TX"},
@@ -1961,6 +1969,9 @@
 	{"SLIMBUS_1_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
 	{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+	{"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+	{"MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+	{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
 	{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
 	{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
 
@@ -1983,6 +1994,7 @@
 	{"SEC_I2S_RX", NULL, "SEC_I2S_RX Port Mixer"},
 
 	{"MI2S_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+	{"MI2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
 	{"MI2S_RX", NULL, "MI2S_RX Port Mixer"},
 	/* Backend Enablement */
 
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 4819e0a..8d8ff5d 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -630,6 +630,11 @@
 	int ret = 0;
 	int index = 0;
 
+	if (rx_port == MI2S_RX)
+		rx_port = AFE_PORT_ID_PRIMARY_MI2S_RX;
+	if (tx_port == MI2S_TX)
+		tx_port = AFE_PORT_ID_PRIMARY_MI2S_TX;
+
 	ret = afe_q6_interface_prepare();
 	if (ret != 0)
 		return ret;