Merge "arm/dt: Add MSM8226 Device tree support for LPM drivers"
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index 4919391..38e552e 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -75,7 +75,7 @@
 		interrupts = <0 105 0>;
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <24000000>;
+		qcom,i2c-src-freq = <19200000>;
 		gpios = <&msmgpio 83 0>, /* DAT  */
 			<&msmgpio 84 0>; /* CLK */
 	};
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
new file mode 100644
index 0000000..511f91f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -0,0 +1,171 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+/ {
+	qcom,smp2p-modem {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-adsp {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 158 1>;
+	};
+
+	qcom,smp2p-wcnss {
+		compatible = "qcom,smp2p";
+		reg = <0xfa006000 0x1000>, <0x8 0x0>;
+		reg-names = "irq-reg-base", "irq-reg-offset";
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	/* SMP2P Test Driver for inbound entries */
+	smp2pgpio_smp2p_7_in: qcom,smp2pgpio-smp2p-7-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_7_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_in";
+		gpios = <&smp2pgpio_smp2p_7_in 0 0>;
+	};
+
+	/* SMP2P Test Driver for outbound entries */
+	smp2pgpio_smp2p_7_out: qcom,smp2pgpio-smp2p-7-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <7>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_7_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_7_out";
+		gpios = <&smp2pgpio_smp2p_7_out 0 0>;
+	};
+
+	/* SMP2P Test Driver for modem inbound */
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	/* SMP2P Test Driver for modem output */
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	/* SMP2P Test Driver for adsp inbound */
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	/* SMP2P Test Driver for adsp output */
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	/* SMP2P Test Driver for wcnss inbound */
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	/* SMP2P Test Driver for wcnss output */
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c7505cb..eb1a108 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -19,6 +19,7 @@
 /include/ "msm8974-ion.dtsi"
 /include/ "msm8974-gpu.dtsi"
 /include/ "msm8974-mdss.dtsi"
+/include/ "msm8974-smp2p.dtsi"
 
 / {
 	model = "Qualcomm MSM 8974";
@@ -595,7 +596,7 @@
 		interrupts = <0 105 0>;
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <24000000>;
+		qcom,i2c-src-freq = <19200000>;
 	};
 
 	i2c@f9924000 {
@@ -608,7 +609,7 @@
 		interrupts = <0 96 0>;
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <100000>;
-		qcom,i2c-src-freq = <24000000>;
+		qcom,i2c-src-freq = <19200000>;
 	};
 
 	spi@f9923000 {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d374b59..7e32126 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -81,7 +81,7 @@
 		vbus_otg-supply = <&usb_vbus>;
 
 		qcom,hsusb-otg-phy-type = <2>;
-		qcom,hsusb-otg-mode = <3>;
+		qcom,hsusb-otg-mode = <1>;
 		qcom,hsusb-otg-otg-control = <1>;
 		qcom,hsusb-otg-disable-reset;
 	};
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 04b18d7..463ce85 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -179,3 +179,9 @@
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_OCMEM=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index a5a9620..ba0036b 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -45,6 +45,8 @@
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_PKG4=y
 CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
 CONFIG_MSM_IPC_LOGGING=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
@@ -76,6 +78,7 @@
 CONFIG_MSM_L1_ERR_LOG=y
 CONFIG_MSM_L2_ERP_2BIT_PANIC=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_UARTDM_Core_v14=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -260,6 +263,7 @@
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
@@ -337,6 +341,7 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8974=y
+CONFIG_USB_SUSPEND=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index ef61e66..99e4e6e 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -44,6 +44,8 @@
 CONFIG_MSM_SMD=y
 CONFIG_MSM_SMD_PKG4=y
 CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
 CONFIG_MSM_IPC_LOGGING=y
 CONFIG_MSM_IPC_ROUTER=y
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
@@ -80,6 +82,7 @@
 CONFIG_MSM_CACHE_DUMP=y
 CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
 CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_UARTDM_Core_v14=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -264,6 +267,7 @@
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_HSL=y
 CONFIG_SERIAL_MSM_HSL_CONSOLE=y
 CONFIG_DIAG_CHAR=y
@@ -340,6 +344,7 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8974=y
+CONFIG_USB_SUSPEND=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_ROOT_HUB_TT=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 0cf684d..15c9adb 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -529,7 +529,7 @@
 
 config MSM_LPM_TEST
 	bool "Low Power Mode test framework"
-	depends on MSM_RPM
+	depends on MSM_RPM || MSM_RPM_SMD
 	depends on MSM_PM8X60
 	help
 	  LPM_TEST is a test framework that assists in exercising the low
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 61c2aa8..b84d345 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -37,6 +37,10 @@
 static struct msm_rpmrs_level *msm_lpm_levels;
 static int msm_lpm_level_count;
 
+static DEFINE_PER_CPU(uint32_t , msm_lpm_sleep_time);
+static DEFINE_PER_CPU(int , lpm_permitted_level);
+static DEFINE_PER_CPU(struct atomic_notifier_head, lpm_notify_head);
+
 static void msm_lpm_level_update(void)
 {
 	unsigned int lpm_level;
@@ -55,6 +59,12 @@
 	int ret = 0;
 	int debug_mask;
 	struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
+	struct msm_lpm_sleep_data sleep_data;
+
+	sleep_data.limits = limits;
+	sleep_data.kernel_sleep = __get_cpu_var(msm_lpm_sleep_time);
+	atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
+		MSM_LPM_STATE_ENTER, &sleep_data);
 
 	ret = msm_rpm_enter_sleep();
 	if (ret) {
@@ -88,6 +98,8 @@
 	msm_rpm_exit_sleep();
 	msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
 				from_idle, notify_rpm, collapsed);
+	atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
+			MSM_LPM_STATE_EXIT, NULL);
 }
 
 void msm_lpm_show_resources(void)
@@ -96,6 +108,48 @@
 	return;
 }
 
+uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits)
+{
+	return limits->pxo;
+}
+
+uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits)
+{
+	return limits->l2_cache;
+}
+
+uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits)
+{
+	return limits->vdd_mem_upper_bound;
+}
+
+uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits)
+{
+	return limits->vdd_dig_upper_bound;
+}
+
+static bool lpm_level_permitted(int cur_level_count)
+{
+	if (__get_cpu_var(lpm_permitted_level) == msm_lpm_level_count + 1)
+		return true;
+	return (__get_cpu_var(lpm_permitted_level) == cur_level_count);
+}
+
+int msm_lpm_register_notifier(int cpu, int level_iter,
+			struct notifier_block *nb, bool is_latency_measure)
+{
+	per_cpu(lpm_permitted_level, cpu) = level_iter;
+	return atomic_notifier_chain_register(&per_cpu(lpm_notify_head,
+			cpu), nb);
+}
+
+int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb)
+{
+	per_cpu(lpm_permitted_level, cpu) = msm_lpm_level_count + 1;
+	return atomic_notifier_chain_unregister(&per_cpu(lpm_notify_head, cpu),
+				nb);
+}
+
 s32 msm_cpuidle_get_deep_idle_latency(void)
 {
 	int i;
@@ -127,7 +181,7 @@
 	struct msm_rpmrs_level *best_level = NULL;
 	uint32_t pwr;
 	int i;
-
+	int best_level_iter = msm_lpm_level_count + 1;
 	if (!msm_lpm_levels)
 		return NULL;
 
@@ -170,14 +224,31 @@
 			level->rs_limits.latency_us[cpu] = level->latency_us;
 			level->rs_limits.power[cpu] = pwr;
 			best_level = level;
-
+			best_level_iter = i;
 			if (power)
 				*power = pwr;
 		}
 	}
+	if (best_level && !lpm_level_permitted(best_level_iter))
+		best_level = NULL;
+	else
+		per_cpu(msm_lpm_sleep_time, cpu) =
+			time_param->modified_time_us ?
+			time_param->modified_time_us : time_param->sleep_us;
 
 	return best_level ? &best_level->rs_limits : NULL;
 }
+
+static struct lpm_test_platform_data lpm_test_pdata;
+
+static struct platform_device msm_lpm_test_device = {
+	.name		= "lpm_test",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &lpm_test_pdata,
+	},
+};
+
 static struct msm_pm_sleep_ops msm_lpm_ops = {
 	.lowest_limits = msm_lpm_lowest_limits,
 	.enter_sleep = msm_lpm_enter_sleep,
@@ -194,6 +265,7 @@
 	int ret = 0;
 	uint32_t num_levels = 0;
 	int idx = 0;
+	unsigned int m_cpu = 0;
 
 	for_each_child_of_node(pdev->dev.of_node, node)
 		num_levels++;
@@ -279,6 +351,14 @@
 	msm_lpm_levels = levels;
 	msm_lpm_level_count = idx;
 
+	lpm_test_pdata.msm_lpm_test_levels = msm_lpm_levels;
+	lpm_test_pdata.msm_lpm_test_level_count = msm_lpm_level_count;
+
+	for_each_possible_cpu(m_cpu)
+		per_cpu(lpm_permitted_level, m_cpu) =
+					msm_lpm_level_count + 1;
+
+	platform_device_register(&msm_lpm_test_device);
 	msm_pm_set_sleep_ops(&msm_lpm_ops);
 
 	return 0;
diff --git a/arch/arm/mach-msm/lpm_resources.h b/arch/arm/mach-msm/lpm_resources.h
index 120832f..42e43c2 100644
--- a/arch/arm/mach-msm/lpm_resources.h
+++ b/arch/arm/mach-msm/lpm_resources.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
 #define __ARCH_ARM_MACH_MSM_LPM_RESOURCES_H
 
 #include "pm.h"
+#include "test-lpm.h"
 
 enum {
 	MSM_LPM_PXO_OFF = 0,
@@ -50,6 +51,93 @@
 	uint32_t time_overhead_us;
 };
 
+enum {
+	MSM_LPM_STATE_ENTER = 0,
+	MSM_LPM_STATE_EXIT = 1,
+};
+
+#define MSM_PM(field) MSM_LPM_##field
+
+/**
+ * msm_pm_get_pxo() -  get the limits for pxo
+ * @limits:            pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource pxo on
+ * 8974
+ */
+
+uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_l2_cache() -  get the limits for l2 cache
+ * @limits:            pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource l2 cache
+ * on 8974
+ */
+
+uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_vdd_mem() -  get the limits for pxo
+ * @limits:            pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource vdd mem
+ * on 8974
+ */
+
+uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_vdd_dig() -  get the limits for vdd dig
+ * @limits:            pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource on 8974
+ */
+
+uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits);
+
+/**
+ * struct msm_lpm_sleep_data - abstraction to get sleep data
+ * @limits:	pointer to the msm_rpmrs_limits structure
+ * @kernel_sleep:	kernel sleep time as decided by the power calculation
+ *			algorithm
+ *
+ * This structure is an abstraction to get the limits and kernel sleep time
+ * during enter sleep.
+ */
+
+struct msm_lpm_sleep_data {
+	struct msm_rpmrs_limits *limits;
+	uint32_t kernel_sleep;
+};
+
+/**
+ * msm_lpm_register_notifier() - register for notifications
+ * @cpu:               cpu to debug
+ * @level_iter:        low power level index to debug
+ * @nb:       notifier block to callback on notifications
+ * @is_latency_measure: is it latency measure
+ *
+ * This function sets the permitted level to the index of the
+ * level under test and registers notifier for callback.
+ */
+
+int msm_lpm_register_notifier(int cpu, int level_iter,
+		struct notifier_block *nb, bool is_latency_measure);
+
+/**
+ * msm_lpm_unregister_notifier() - unregister from notifications
+ * @cpu:               cpu to debug
+ * @nb:       notifier block to callback on notifications
+ *
+ * This function sets the permitted level to a value one more than
+ * available levels count which indicates that all levels are
+ * permitted and it also unregisters notifier for callback.
+ */
+
+int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb);
+
 #ifdef CONFIG_MSM_RPM_SMD
 
 /**
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index d460c70..0db6e68 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, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2011, 2013 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -48,3 +48,4 @@
 	return -ENOSYS;
 }
 
+void msm_pm_enable_retention(bool enable) {}
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index e35d843..261d433 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -118,6 +118,7 @@
 static struct msm_pm_init_data_type msm_pm_init_data;
 static struct hrtimer pm_hrtimer;
 static struct msm_pm_sleep_ops pm_sleep_ops;
+static bool msm_pm_ldo_retention_enabled = true;
 /*
  * Write out the attribute.
  */
@@ -820,6 +821,14 @@
 			}
 			/* fall through */
 		case MSM_PM_SLEEP_MODE_RETENTION:
+			/*
+			 * The Krait BHS regulator doesn't have enough head
+			 * room to drive the retention voltage on LDO and so
+			 * has disabled retention
+			 */
+			if (!msm_pm_ldo_retention_enabled)
+				break;
+
 			if (!allow)
 				break;
 
@@ -995,6 +1004,34 @@
 		msm_pm_swfi();
 }
 
+static void msm_pm_ack_retention_disable(void *data)
+{
+	/*
+	 * This is a NULL function to ensure that the core has woken up
+	 * and is safe to disable retention.
+	 */
+}
+/**
+ * msm_pm_enable_retention() - Disable/Enable retention on all cores
+ * @enable: Enable/Disable retention
+ *
+ */
+void msm_pm_enable_retention(bool enable)
+{
+	msm_pm_ldo_retention_enabled = enable;
+	/*
+	 * If retention is being disabled, wakeup all online core to ensure
+	 * that it isn't executing retention. Offlined cores need not be woken
+	 * up as they enter the deepest sleep mode, namely RPM assited power
+	 * collapse
+	 */
+	if (!enable)
+		smp_call_function_many(cpu_online_mask,
+				msm_pm_ack_retention_disable,
+				NULL, true);
+}
+EXPORT_SYMBOL(msm_pm_enable_retention);
+
 static int msm_pm_enter(suspend_state_t state)
 {
 	bool allow[MSM_PM_SLEEP_MODE_NR];
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index 6f4743f..08cdf5d 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -30,7 +30,7 @@
 
 	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RETENTION)] = {
 		.idle_supported = 1,
-		.suspend_supported = 1,
+		.suspend_supported = 0,
 		.idle_enabled = 0,
 		.suspend_enabled = 0,
 	},
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 86d8f98..399194a 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/pm.h
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  * Author: San Mehat <san@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -114,6 +114,7 @@
 int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
 void msm_pm_cpu_enter_lowpower(unsigned int cpu);
 void __init msm_pm_set_tz_retention_flag(unsigned int flag);
+void msm_pm_enable_retention(bool enable);
 
 #ifdef CONFIG_MSM_PM8X60
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
diff --git a/arch/arm/mach-msm/test-lpm.c b/arch/arm/mach-msm/test-lpm.c
index dbc8100..031b2dc 100644
--- a/arch/arm/mach-msm/test-lpm.c
+++ b/arch/arm/mach-msm/test-lpm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,9 @@
 #if defined(CONFIG_MSM_RPM)
 #include "rpm_resources.h"
 #endif
+#if defined(CONFIG_MSM_RPM_SMD)
+#include "lpm_resources.h"
+#endif
 #include "timer.h"
 #include "test-lpm.h"
 
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 042ba37..844c65f 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -7,7 +7,7 @@
  * Copyright (c) 2000 Nokia Research Center
  *                    Tampere, FINLAND
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -100,6 +100,9 @@
 			int disc_indicator_set;
 			int pes_length_mismatch;
 			u64 stc;
+			u32 tei_counter;
+			u32 cont_err_counter;
+			u32 ts_packets_num;
 		} pes_end;
 
 		struct {
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index f5a505c..bddbb5f 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1861,6 +1861,9 @@
 
 			event.params.pes.flags = 0;
 			event.params.pes.stc = 0;
+			event.params.pes.transport_error_indicator_counter = 0;
+			event.params.pes.continuity_error_counter = 0;
+			event.params.pes.ts_packets_num = 0;
 
 			dvb_dmxdev_add_event(events, &event);
 			events->current_event_data_size = 0;
@@ -2109,6 +2112,13 @@
 					DMX_FILTER_PES_LENGTH_ERROR;
 
 			event.params.pes.stc = dmx_data_ready->pes_end.stc;
+			event.params.pes.transport_error_indicator_counter =
+				dmx_data_ready->pes_end.tei_counter;
+			event.params.pes.continuity_error_counter =
+				dmx_data_ready->pes_end.cont_err_counter;
+			event.params.pes.ts_packets_num =
+				dmx_data_ready->pes_end.ts_packets_num;
+
 			dvb_dmxdev_add_event(events, &event);
 
 			events->current_event_data_size = 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index eea83c2..488f42c 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -5,7 +5,7 @@
  *		       & Marcus Metzler <marcus@convergence.de>
  *			 for convergence integrated media GmbH
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -127,15 +127,15 @@
 {
 	int count = payload(buf);
 	int p;
-	//int ccok;
-	//u8 cc;
+	int ccok;
+	u8 cc;
+	struct dmx_data_ready data;
 
 	if (count == 0)
 		return -1;
 
 	p = 188 - count;
 
-	/*
 	cc = buf[3] & 0x0f;
 	if (feed->first_cc)
 		ccok = 1;
@@ -144,26 +144,41 @@
 
 	feed->first_cc = 0;
 	feed->cc = cc;
-	if (!ccok)
-		printk("missed packet!\n");
-	*/
 
 	/* PUSI ? */
 	if (buf[1] & 0x40) {
-		if (feed->pusi_seen)
+		if (feed->pusi_seen) {
 			/* We had seen PUSI before, this means
 			 * that previous PES can be closed now.
 			 */
-			feed->cb.ts(NULL, 0, NULL, 0,
-						&feed->feed.ts, DMX_OK_PES_END);
+			data.status = DMX_OK_PES_END;
+			data.data_length = 0;
+			data.pes_end.start_gap = 0;
+			data.pes_end.actual_length = feed->peslen;
+			data.pes_end.disc_indicator_set = 0;
+			data.pes_end.pes_length_mismatch = 0;
+			data.pes_end.stc = 0;
+			data.pes_end.tei_counter = feed->pes_tei_counter;
+			data.pes_end.cont_err_counter =
+				feed->pes_cont_err_counter;
+			data.pes_end.ts_packets_num = feed->pes_ts_packets_num;
+			feed->data_ready_cb.ts(&feed->feed.ts, &data);
+		}
 
 		feed->pusi_seen = 1;
 		feed->peslen = 0;
+		feed->pes_tei_counter = 0;
+		feed->pes_ts_packets_num = 0;
+		feed->pes_cont_err_counter = 0;
 	}
 
 	if (feed->pusi_seen == 0)
 		return 0;
 
+	feed->pes_ts_packets_num++;
+	feed->pes_cont_err_counter += !ccok;
+	feed->pes_tei_counter += (buf[1] & 0x80) ? 1 : 0;
+
 	feed->peslen += count;
 
 	return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
@@ -1243,6 +1258,9 @@
 	feed->demux = demux;
 	feed->pid = 0xffff;
 	feed->peslen = 0;
+	feed->pes_tei_counter = 0;
+	feed->pes_ts_packets_num = 0;
+	feed->pes_cont_err_counter = 0;
 	feed->buffer = NULL;
 	feed->tsp_out_format = DMX_TSP_FORMAT_188;
 	memset(&feed->indexing_params, 0,
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 2e4a468..5e98ea1 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -4,7 +4,7 @@
  * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
  *                         for convergence integrated media GmbH
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -105,6 +105,9 @@
 	int pusi_seen;		/* prevents feeding of garbage from previous section */
 
 	u32 peslen;
+	u32 pes_tei_counter;
+	u32 pes_cont_err_counter;
+	u32 pes_ts_packets_num;
 
 	struct list_head list_head;
 	unsigned int index;	/* a unique index for each feed (can be used as hardware pid filter index) */
diff --git a/drivers/media/video/msmb/sensor/msm_sensor.c b/drivers/media/video/msmb/sensor/msm_sensor.c
index 1f54951..78c3207 100644
--- a/drivers/media/video/msmb/sensor/msm_sensor.c
+++ b/drivers/media/video/msmb/sensor/msm_sensor.c
@@ -783,7 +783,7 @@
 
 int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
 {
-	int32_t rc = 0, index = 0, clk_index = 0;
+	int32_t rc = 0, index = 0;
 	struct msm_sensor_power_setting_array *power_setting_array = NULL;
 	struct msm_sensor_power_setting *power_setting = NULL;
 	struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
@@ -900,17 +900,22 @@
 	return 0;
 power_up_failed:
 	pr_err("%s:%d failed\n", __func__, __LINE__);
+	if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE) {
+		s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_util(
+			s_ctrl->sensor_i2c_client, MSM_CCI_RELEASE);
+	}
+
 	for (index--; index >= 0; index--) {
 		CDBG("%s index %d\n", __func__, index);
 		power_setting = &power_setting_array->power_setting[index];
 		CDBG("%s type %d\n", __func__, power_setting->seq_type);
 		switch (power_setting->seq_type) {
 		case SENSOR_CLK:
-			for (clk_index--; clk_index >= 0; clk_index--)
-				msm_cam_clk_enable(s_ctrl->dev,
-					&s_ctrl->clk_info[clk_index],
-					(struct clk **)&power_setting->data[0],
-					1, 0);
+			msm_cam_clk_enable(s_ctrl->dev,
+				&s_ctrl->clk_info[0],
+				(struct clk **)&power_setting->data[0],
+				s_ctrl->clk_info_size,
+				0);
 			break;
 		case SENSOR_GPIO:
 			gpio_set_value_cansleep(
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 295c55c..83f486c 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -746,6 +746,112 @@
 	return 0;
 }
 
+/* support for 9 new rmnet ports */
+#define RMNET_REV_DEVICE_COUNT (9)
+static struct net_device *netdevs_rev[RMNET_REV_DEVICE_COUNT];
+static struct platform_driver bam_rmnet_rev_drivers[RMNET_REV_DEVICE_COUNT];
+
+static int bam_rmnet_rev_probe(struct platform_device *pdev)
+{
+	int i;
+	char name[BAM_DMUX_CH_NAME_MAX_LEN];
+	struct rmnet_private *p;
+
+	for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
+		scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+					(i+BAM_DMUX_DATA_REV_RMNET_0));
+		if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
+			break;
+	}
+
+	if (i >= RMNET_REV_DEVICE_COUNT) {
+		pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
+		return 0;
+	}
+
+	p = netdev_priv(netdevs_rev[i]);
+	if (p->in_reset) {
+		p->in_reset = 0;
+		msm_bam_dmux_open(p->ch_id, netdevs_rev[i], bam_notify);
+		netif_carrier_on(netdevs_rev[i]);
+		netif_start_queue(netdevs_rev[i]);
+	}
+
+	return 0;
+}
+
+static int bam_rmnet_rev_remove(struct platform_device *pdev)
+{
+	int i;
+	char name[BAM_DMUX_CH_NAME_MAX_LEN];
+	struct rmnet_private *p;
+
+	for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
+		scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+				(i+BAM_DMUX_DATA_REV_RMNET_0));
+		if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
+			break;
+	}
+
+	if (i >= RMNET_REV_DEVICE_COUNT) {
+		pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
+		return 0;
+	}
+
+	p = netdev_priv(netdevs_rev[i]);
+	p->in_reset = 1;
+	if (p->waiting_for_ul_skb != NULL) {
+		dev_kfree_skb_any(p->waiting_for_ul_skb);
+		p->waiting_for_ul_skb = NULL;
+	}
+	msm_bam_dmux_close(p->ch_id);
+	netif_carrier_off(netdevs_rev[i]);
+	netif_stop_queue(netdevs_rev[i]);
+	return 0;
+}
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
+{
+	struct device *d;
+	d = &(dev->dev);
+	return device_create_file(d, &dev_attr_timeout_suspend);
+}
+#else
+static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
+{
+	return 0;
+}
+#endif
+static int rmnet_debug_init(struct net_device *dev)
+{
+
+	struct device *d;
+	struct rmnet_private *p;
+	int err = 0;
+	d = &(dev->dev);
+	p = netdev_priv(dev);
+	p->timeout_us = 0;
+	p->wakeups_xmit = p->wakeups_rcv = 0;
+	err = device_create_file(d, &dev_attr_timeout);
+	if (err)
+		return err;
+	err = device_create_file(d, &dev_attr_wakeups_xmit);
+	if (err)
+		return err;
+	err = device_create_file(d, &dev_attr_wakeups_rcv);
+	if (err)
+		return err;
+	err = rmnet_debug_init_timeout_suspend(dev);
+	return err;
+}
+#else
+static int rmnet_debug_init(struct net_device *dev)
+{
+	return 0;
+}
+#endif
 static int __init rmnet_init(void)
 {
 	int ret;
@@ -828,6 +934,53 @@
 			return ret;
 		}
 	}
+	/*Support for new rmnet ports */
+	for (n = 0; n < RMNET_REV_DEVICE_COUNT; n++) {
+		dev = alloc_netdev(sizeof(struct rmnet_private),
+				   "rev_rmnet%d", rmnet_setup);
+
+		if (!dev) {
+			pr_err("%s: no memory for rev netdev %d\n",
+							__func__, n);
+			return -ENOMEM;
+		}
+
+		netdevs_rev[n] = dev;
+		d = &(dev->dev);
+		p = netdev_priv(dev);
+		/* Initial config uses Ethernet */
+		p->operation_mode = RMNET_MODE_LLP_ETH;
+		p->ch_id = n+BAM_DMUX_DATA_REV_RMNET_0;
+		p->waiting_for_ul_skb = NULL;
+		p->in_reset = 0;
+		spin_lock_init(&p->lock);
+		spin_lock_init(&p->tx_queue_lock);
+
+		ret = register_netdev(dev);
+		if (ret) {
+			pr_err("%s: unable to register rev netdev %d rc=%d\n",
+							__func__, n, ret);
+			free_netdev(dev);
+			return ret;
+		}
+		if (rmnet_debug_init(dev))
+			continue;
+		bam_rmnet_rev_drivers[n].probe = bam_rmnet_rev_probe;
+		bam_rmnet_rev_drivers[n].remove = bam_rmnet_rev_remove;
+		tempname = kmalloc(BAM_DMUX_CH_NAME_MAX_LEN, GFP_KERNEL);
+		if (tempname == NULL)
+			return -ENOMEM;
+		scnprintf(tempname, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+					(n+BAM_DMUX_DATA_REV_RMNET_0));
+		bam_rmnet_rev_drivers[n].driver.name = tempname;
+		bam_rmnet_rev_drivers[n].driver.owner = THIS_MODULE;
+		ret = platform_driver_register(&bam_rmnet_rev_drivers[n]);
+		if (ret) {
+			pr_err("%s: new rev driver registration failed n=%d rc=%d\n",
+					__func__, n, ret);
+			return ret;
+		}
+	}
 	return 0;
 }
 
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index 460cba3..53bbd5e 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -5,7 +5,7 @@
  *                  & Ralph  Metzler <ralph@convergence.de>
  *                    for convergence integrated media GmbH
  *
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -250,6 +250,18 @@
 
 	/* Flags passed in filter events */
 	__u32 flags;
+
+	/*
+	 * Number of TS packets with Transport Error Indicator (TEI)
+	 * found while constructing the PES.
+	 */
+	__u32 transport_error_indicator_counter;
+
+	/* Number of continuity errors found while constructing the PES */
+	__u32 continuity_error_counter;
+
+	/* Total number of TS packets holding the PES */
+	__u32 ts_packets_num;
 };
 
 /* Section info associated with DMX_EVENT_NEW_SECTION event */
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index d7521f8..6f81063 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -339,7 +339,7 @@
 
 	struct wcd9xxx_pdata *pdata;
 	u32 anc_slot;
-
+	bool anc_func;
 	bool no_mic_headset_override;
 	/* Delayed work to report long button press */
 	struct delayed_work mbhc_btn_dwork;
@@ -539,6 +539,48 @@
 	return 0;
 }
 
+static int tabla_get_anc_func(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	ucontrol->value.integer.value[0] = (tabla->anc_func == true ? 1 : 0);
+	return 0;
+}
+
+static int tabla_put_anc_func(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	mutex_lock(&dapm->codec->mutex);
+
+	tabla->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
+
+	dev_dbg(codec->dev, "%s: anc_func %x", __func__, tabla->anc_func);
+
+	if (tabla->anc_func == true) {
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_enable_pin(dapm, "ANC HEADPHONE");
+		snd_soc_dapm_disable_pin(dapm, "HPHR");
+		snd_soc_dapm_disable_pin(dapm, "HPHL");
+		snd_soc_dapm_disable_pin(dapm, "HEADPHONE");
+	} else {
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+		snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+		snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+		snd_soc_dapm_enable_pin(dapm, "HPHR");
+		snd_soc_dapm_enable_pin(dapm, "HPHL");
+		snd_soc_dapm_enable_pin(dapm, "HEADPHONE");
+	}
+	snd_soc_dapm_sync(dapm);
+	mutex_unlock(&dapm->codec->mutex);
+	return 0;
+}
+
 static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -987,6 +1029,10 @@
 	return 0;
 }
 
+static const char *const tabla_anc_func_text[] = {"OFF", "ON"};
+static const struct soc_enum tabla_anc_func_enum =
+	SOC_ENUM_SINGLE_EXT(2, tabla_anc_func_text);
+
 static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
 static const struct soc_enum tabla_ear_pa_gain_enum[] = {
 		SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
@@ -1130,6 +1176,8 @@
 
 	SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
 		tabla_put_anc_slot),
+	SOC_ENUM_EXT("ANC Function", tabla_anc_func_enum, tabla_get_anc_func,
+		tabla_put_anc_func),
 	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
 	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
 	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
@@ -2476,111 +2524,6 @@
 	return 0;
 }
 
-static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	const char *filename;
-	const struct firmware *fw;
-	int i;
-	int ret;
-	int num_anc_slots;
-	struct anc_header *anc_head;
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	u32 anc_writes_size = 0;
-	int anc_size_remaining;
-	u32 *anc_ptr;
-	u16 reg;
-	u8 mask, val, old_val;
-
-	pr_debug("%s %d\n", __func__, event);
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-
-		filename = "wcd9310/wcd9310_anc.bin";
-
-		ret = request_firmware(&fw, filename, codec->dev);
-		if (ret != 0) {
-			dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
-				ret);
-			return -ENODEV;
-		}
-
-		if (fw->size < sizeof(struct anc_header)) {
-			dev_err(codec->dev, "Not enough data\n");
-			release_firmware(fw);
-			return -ENOMEM;
-		}
-
-		/* First number is the number of register writes */
-		anc_head = (struct anc_header *)(fw->data);
-		anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
-		anc_size_remaining = fw->size - sizeof(struct anc_header);
-		num_anc_slots = anc_head->num_anc_slots;
-
-		if (tabla->anc_slot >= num_anc_slots) {
-			dev_err(codec->dev, "Invalid ANC slot selected\n");
-			release_firmware(fw);
-			return -EINVAL;
-		}
-
-		for (i = 0; i < num_anc_slots; i++) {
-
-			if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
-				dev_err(codec->dev, "Invalid register format\n");
-				release_firmware(fw);
-				return -EINVAL;
-			}
-			anc_writes_size = (u32)(*anc_ptr);
-			anc_size_remaining -= sizeof(u32);
-			anc_ptr += 1;
-
-			if (anc_writes_size * TABLA_PACKED_REG_SIZE
-				> anc_size_remaining) {
-				dev_err(codec->dev, "Invalid register format\n");
-				release_firmware(fw);
-				return -ENOMEM;
-			}
-
-			if (tabla->anc_slot == i)
-				break;
-
-			anc_size_remaining -= (anc_writes_size *
-				TABLA_PACKED_REG_SIZE);
-			anc_ptr += anc_writes_size;
-		}
-		if (i == num_anc_slots) {
-			dev_err(codec->dev, "Selected ANC slot not present\n");
-			release_firmware(fw);
-			return -ENOMEM;
-		}
-
-		for (i = 0; i < anc_writes_size; i++) {
-			TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
-				mask, val);
-			old_val = snd_soc_read(codec, reg);
-			snd_soc_write(codec, reg, (old_val & ~mask) |
-				(val & mask));
-		}
-		release_firmware(fw);
-
-		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
-		/* if MBHC polling is active, set TX7_MBHC_EN bit 7 */
-		if (tabla->mbhc_polling_active)
-			snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80,
-					    0x80);
-		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		/* unset TX7_MBHC_EN bit 7 */
-		snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
-
-		snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
-		snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
-		break;
-	}
-	return 0;
-}
 
 /* called under codec_resource_lock acquisition */
 static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
@@ -3283,6 +3226,160 @@
 			  WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
 }
 
+static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	const char *filename;
+	const struct firmware *fw;
+	int i;
+	int ret;
+	int num_anc_slots;
+	struct anc_header *anc_head;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	u32 anc_writes_size = 0;
+	int anc_size_remaining;
+	u32 *anc_ptr;
+	u16 reg;
+	u8 mask, val, old_val;
+	u8 mbhc_micb_ctl_val;
+
+	pr_debug("%s: DAPM Event %d ANC func is %d\n",
+		 __func__, event, tabla->anc_func);
+
+	if (tabla->anc_func == 0)
+		return 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		mbhc_micb_ctl_val = snd_soc_read(codec,
+			tabla->mbhc_bias_regs.ctl_reg);
+
+		if (!(mbhc_micb_ctl_val & 0x80)) {
+			TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+			tabla_codec_switch_micbias(codec, 1);
+			TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+		}
+
+		filename = "wcd9310/wcd9310_anc.bin";
+
+		ret = request_firmware(&fw, filename, codec->dev);
+		if (ret != 0) {
+			dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
+				ret);
+			return -ENODEV;
+		}
+
+		if (fw->size < sizeof(struct anc_header)) {
+			dev_err(codec->dev, "Not enough data\n");
+			release_firmware(fw);
+			return -ENOMEM;
+		}
+
+		/* First number is the number of register writes */
+		anc_head = (struct anc_header *)(fw->data);
+		anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
+		anc_size_remaining = fw->size - sizeof(struct anc_header);
+		num_anc_slots = anc_head->num_anc_slots;
+
+		if (tabla->anc_slot >= num_anc_slots) {
+			dev_err(codec->dev, "Invalid ANC slot selected\n");
+			release_firmware(fw);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < num_anc_slots; i++) {
+
+			if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
+				dev_err(codec->dev, "Invalid register format\n");
+				release_firmware(fw);
+				return -EINVAL;
+			}
+			anc_writes_size = (u32)(*anc_ptr);
+			anc_size_remaining -= sizeof(u32);
+			anc_ptr += 1;
+
+			if (anc_writes_size * TABLA_PACKED_REG_SIZE
+				> anc_size_remaining) {
+				dev_err(codec->dev, "Invalid register format\n");
+				release_firmware(fw);
+				return -ENOMEM;
+			}
+
+			if (tabla->anc_slot == i)
+				break;
+
+			anc_size_remaining -= (anc_writes_size *
+				TABLA_PACKED_REG_SIZE);
+			anc_ptr += anc_writes_size;
+		}
+		if (i == num_anc_slots) {
+			dev_err(codec->dev, "Selected ANC slot not present\n");
+			release_firmware(fw);
+			return -ENOMEM;
+		}
+
+		for (i = 0; i < anc_writes_size; i++) {
+			TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
+				mask, val);
+			old_val = snd_soc_read(codec, reg);
+			snd_soc_write(codec, reg, (old_val & ~mask) |
+				(val & mask));
+		}
+		usleep_range(10000, 10000);
+		snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x30);
+		msleep(30);
+		release_firmware(fw);
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+		/* if MBHC polling is active, set TX7_MBHC_EN bit 7 */
+		if (tabla->mbhc_polling_active)
+			snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80,
+						0x80);
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* schedule work is required because at the time HPH PA DAPM
+		 * event callback is called by DAPM framework, CODEC dapm mutex
+		 * would have been locked while snd_soc_jack_report also
+		 * attempts to acquire same lock.
+		*/
+		if (w->shift == 5) {
+			clear_bit(TABLA_HPHL_PA_OFF_ACK,
+				&tabla->hph_pa_dac_state);
+			clear_bit(TABLA_HPHL_DAC_OFF_ACK,
+				&tabla->hph_pa_dac_state);
+			if (tabla->hph_status & SND_JACK_OC_HPHL)
+				schedule_work(&tabla->hphlocp_work);
+		} else if (w->shift == 4) {
+			clear_bit(TABLA_HPHR_PA_OFF_ACK,
+				&tabla->hph_pa_dac_state);
+			clear_bit(TABLA_HPHR_DAC_OFF_ACK,
+				&tabla->hph_pa_dac_state);
+			if (tabla->hph_status & SND_JACK_OC_HPHR)
+				schedule_work(&tabla->hphrocp_work);
+		}
+
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+		tabla_codec_switch_micbias(codec, 0);
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
+		msleep(40);
+		/* unset TX7_MBHC_EN bit 7 */
+		snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
+		snd_soc_update_bits(codec, TABLA_A_CDC_ANC1_CTL, 0x01, 0x00);
+		snd_soc_update_bits(codec, TABLA_A_CDC_ANC2_CTL, 0x01, 0x00);
+		msleep(20);
+		snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0x0F);
+		snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
+		snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
+		break;
+	}
+	return 0;
+}
+
 static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -3592,7 +3689,6 @@
 
 	{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
 	{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
-	{"ANC", NULL, "ANC1 FB MUX"},
 
 	/* Headset (RX MIX1 and RX MIX2) */
 	{"HEADPHONE", NULL, "HPHL"},
@@ -3607,19 +3703,26 @@
 	{"HPHL DAC", NULL, "CP"},
 	{"HPHR DAC", NULL, "CP"},
 
-	{"ANC", NULL, "ANC1 MUX"},
-	{"ANC", NULL, "ANC2 MUX"},
+	{"ANC HEADPHONE", NULL, "ANC HPHL"},
+	{"ANC HEADPHONE", NULL, "ANC HPHR"},
+
+	{"ANC HPHL", NULL, "HPHL_PA_MIXER"},
+	{"ANC HPHR", NULL, "HPHR_PA_MIXER"},
+
 	{"ANC1 MUX", "ADC1", "ADC1"},
 	{"ANC1 MUX", "ADC2", "ADC2"},
 	{"ANC1 MUX", "ADC3", "ADC3"},
 	{"ANC1 MUX", "ADC4", "ADC4"},
+	{"ANC1 MUX", "DMIC1", "DMIC1"},
+	{"ANC1 MUX", "DMIC2", "DMIC2"},
+	{"ANC1 MUX", "DMIC3", "DMIC3"},
+	{"ANC1 MUX", "DMIC4", "DMIC4"},
 	{"ANC2 MUX", "ADC1", "ADC1"},
 	{"ANC2 MUX", "ADC2", "ADC2"},
 	{"ANC2 MUX", "ADC3", "ADC3"},
 	{"ANC2 MUX", "ADC4", "ADC4"},
 
-	{"ANC", NULL, "CDC_CONN"},
-
+	{"ANC HPHR", NULL, "CDC_CONN"},
 	{"DAC1", "Switch", "RX1 CHAIN"},
 	{"HPHL DAC", "Switch", "RX1 CHAIN"},
 	{"HPHR DAC", NULL, "RX2 CHAIN"},
@@ -3646,8 +3749,8 @@
 
 	{"RX1 CHAIN", NULL, "RX1 MIX2"},
 	{"RX2 CHAIN", NULL, "RX2 MIX2"},
-	{"RX1 CHAIN", NULL, "ANC"},
-	{"RX2 CHAIN", NULL, "ANC"},
+	{"RX1 MIX2", NULL, "ANC1 MUX"},
+	{"RX2 MIX2", NULL, "ANC2 MUX"},
 
 	{"CP", NULL, "RX_BIAS"},
 	{"LINEOUT1 DAC", NULL, "RX_BIAS"},
@@ -4052,6 +4155,14 @@
 		(reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
 		return 1;
 
+	/* ANC filter registers are not cacheable */
+	if ((reg >= TABLA_A_CDC_ANC1_FILT1_B1_CTL) &&
+		(reg <= TABLA_A_CDC_ANC1_FILT2_B3_CTL))
+		return 1;
+	if ((reg >= TABLA_A_CDC_ANC2_FILT1_B1_CTL) &&
+		(reg <= TABLA_A_CDC_ANC2_FILT2_B3_CTL))
+		return 1;
+
 	/* Digital gain register is not cacheable so we have to write
 	 * the setting even it is the same
 	 */
@@ -5284,9 +5395,13 @@
 	SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
 	SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
 
-	SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
-		tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
+	SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tabla_codec_enable_anc,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 0, 0, NULL, 0,
+		tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU),
+
 
 	SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
 
@@ -8650,6 +8765,12 @@
 		       "tabla_gpio_irq_resend");
 	tabla->gpio_irq_resend = false;
 
+	mutex_lock(&dapm->codec->mutex);
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
+	snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
+	snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
+	snd_soc_dapm_sync(dapm);
+	mutex_unlock(&dapm->codec->mutex);
 
 #ifdef CONFIG_DEBUG_FS
 	if (ret == 0) {
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index f151e51..145f095 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -590,7 +590,7 @@
 	pr_debug("%s\n", __func__);
 	audio_ocmem_lcl.audio_ocmem_workqueue =
 		alloc_workqueue("ocmem_audio_client_driver_audio",
-					WQ_NON_REENTRANT, 0);
+					WQ_NON_REENTRANT | WQ_UNBOUND, 0);
 	if (!audio_ocmem_lcl.audio_ocmem_workqueue) {
 		pr_err("%s: Failed to create ocmem audio work queue\n",
 			__func__);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 5ac643416..99047178 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -78,7 +78,7 @@
 	[snd_soc_dapm_pre] = 0,
 	[snd_soc_dapm_aif_in] = 1,
 	[snd_soc_dapm_aif_out] = 1,
-	[snd_soc_dapm_adc] = 1,
+	[snd_soc_dapm_adc] = 5,
 	[snd_soc_dapm_hp] = 2,
 	[snd_soc_dapm_spk] = 2,
 	[snd_soc_dapm_out_drv] = 2,