Merge "arm/dt: msm8974: Add device and GPIO configuration for GPIO based keys" into msm-3.4
diff --git a/Documentation/devicetree/bindings/gpio/qpnp-pin.txt b/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
index c58e073..31c3bc2 100644
--- a/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
+++ b/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
@@ -94,7 +94,7 @@
 			QPNP_PIN_OUT_STRENGTH_MED  = 2, (GPIO)
 			QPNP_PIN_OUT_STRENGTH_HIGH = 3, (GPIO)
 
-  - qcom,select:	select a function for the pin. Certain pins
+  - qcom,src-select:	select a function for the pin. Certain pins
 			can be paired (shorted) with each other. Some gpio pins
 			can act as alternate functions.
 			In the context of gpio, this acts as a source select.
diff --git a/arch/arm/boot/dts/msm9625.dts b/arch/arm/boot/dts/msm9625.dts
index 09d54b1..041b4dd 100644
--- a/arch/arm/boot/dts/msm9625.dts
+++ b/arch/arm/boot/dts/msm9625.dts
@@ -42,7 +42,6 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
-		#gpio-cells = <2>;
 	};
 
 	timer: msm-qtimer@f9021000 {
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 3854403..3fad6b7 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -59,7 +59,7 @@
 CONFIG_MACH_MPQ8064_HRD=y
 CONFIG_MACH_MPQ8064_DTV=y
 # CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_KERNEL_PMEM_EBI_REGION=y
+CONFIG_KERNEL_MSM_CONTIG_MEM_REGION=y
 # CONFIG_MSM_FIQ_SUPPORT is not set
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_SMD=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 06501ba..cd79e98 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -58,7 +58,7 @@
 CONFIG_MACH_MPQ8064_HRD=y
 CONFIG_MACH_MPQ8064_DTV=y
 # CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_KERNEL_PMEM_EBI_REGION=y
+CONFIG_KERNEL_MSM_CONTIG_MEM_REGION=y
 # CONFIG_MSM_FIQ_SUPPORT is not set
 # CONFIG_MSM_PROC_COMM is not set
 CONFIG_MSM_SMD=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5331f2c..145375d 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -890,12 +890,15 @@
 	default "0x40200000" if ARCH_MSM8X60
 	default "0x10000000"
 
-config KERNEL_PMEM_EBI_REGION
-	bool "Enable in-kernel PMEM region for EBI"
+config KERNEL_MSM_CONTIG_MEM_REGION
+	bool "Enable in-kernel contiguous memory region"
 	default y if ARCH_MSM8X60
 	depends on ANDROID_PMEM && (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM8974)
 	help
-	   Enable the in-kernel PMEM allocator to use EBI memory.
+	   Enable the in-kernel contiguous memory allocator. Sets up a
+	   region of physically contiguous memory. This memory is
+	   reserved during initialization, and can be used
+	   generically.
 
 config KERNEL_PMEM_SMI_REGION
 	bool "Enable in-kernel PMEM region for SMI"
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index b35e949..04e751a 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -47,16 +47,29 @@
 #define BAM_MUX_HDR_CMD_STATUS		3 /* unused */
 #define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC	4
 
-#define POLLING_MIN_SLEEP	950	/* 0.95 ms */
-#define POLLING_MAX_SLEEP	1050	/* 1.05 ms */
-#define POLLING_INACTIVITY	40	/* cycles before switch to intr mode */
 
 #define LOW_WATERMARK		2
 #define HIGH_WATERMARK		4
+#define DEFAULT_POLLING_MIN_SLEEP (950)
+#define MAX_POLLING_SLEEP (6050)
+#define MIN_POLLING_SLEEP (950)
 
 static int msm_bam_dmux_debug_enable;
 module_param_named(debug_enable, msm_bam_dmux_debug_enable,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_MIN_SLEEP = 950;
+module_param_named(min_sleep, POLLING_MIN_SLEEP,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_MAX_SLEEP = 1050;
+module_param_named(max_sleep, POLLING_MAX_SLEEP,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_INACTIVITY = 40;
+module_param_named(inactivity, POLLING_INACTIVITY,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int bam_adaptive_timer_enabled = 1;
+module_param_named(adaptive_timer_enabled,
+			bam_adaptive_timer_enabled,
+		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 
 #if defined(DEBUG)
 static uint32_t bam_dmux_read_cnt;
@@ -177,6 +190,7 @@
 static int bam_mux_initialized;
 
 static int polling_mode;
+static unsigned long rx_timer_interval;
 
 static LIST_HEAD(bam_rx_pool);
 static DEFINE_MUTEX(bam_rx_pool_mutexlock);
@@ -1116,6 +1130,7 @@
 	struct rx_pkt_info *info;
 	int inactive_cycles = 0;
 	int ret;
+	u32 buffs_unused, buffs_used;
 
 	while (bam_connection_is_active) { /* timer loop */
 		++inactive_cycles;
@@ -1162,12 +1177,47 @@
 			handle_bam_mux_cmd(&info->work);
 		}
 
-		if (inactive_cycles == POLLING_INACTIVITY) {
+		if (inactive_cycles >= POLLING_INACTIVITY) {
 			rx_switch_to_interrupt_mode();
 			break;
 		}
 
-		usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+		if (bam_adaptive_timer_enabled) {
+			usleep_range(rx_timer_interval, rx_timer_interval + 50);
+
+			ret = sps_get_unused_desc_num(bam_rx_pipe,
+						&buffs_unused);
+
+			if (ret) {
+				pr_err("%s: error getting num buffers unused after sleep\n",
+					__func__);
+
+				break;
+			}
+
+			buffs_used = NUM_BUFFERS - buffs_unused;
+
+			if (buffs_unused == 0) {
+				rx_timer_interval = MIN_POLLING_SLEEP;
+			} else {
+				if (buffs_used > 0) {
+					rx_timer_interval =
+						(2 * NUM_BUFFERS *
+							rx_timer_interval)/
+						(3 * buffs_used);
+				} else {
+					rx_timer_interval =
+						MAX_POLLING_SLEEP;
+				}
+			}
+
+			if (rx_timer_interval > MAX_POLLING_SLEEP)
+				rx_timer_interval = MAX_POLLING_SLEEP;
+			else if (rx_timer_interval < MIN_POLLING_SLEEP)
+				rx_timer_interval = MIN_POLLING_SLEEP;
+		} else {
+			usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+		}
 	}
 }
 
@@ -2379,6 +2429,8 @@
 		bam_dmux_state_logging_disabled = 1;
 	}
 
+	rx_timer_interval = DEFAULT_POLLING_MIN_SLEEP;
+
 	subsys_notif_register_notifier("modem", &restart_notifier);
 	return platform_driver_register(&bam_dmux_driver);
 }
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index da0fd31..5780ca1 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -236,18 +236,9 @@
 	.name = "mdp",
 };
 
-static int mdp_core_clk_rate_table[] = {
-	59080000,
-	128000000,
-	160000000,
-	200000000,
-};
-
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-	.mdp_core_clk_rate = 59080000,
-	.mdp_core_clk_table = mdp_core_clk_rate_table,
-	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_max_clk = 200000000,
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 	.mdp_rev = MDP_REV_44,
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -1026,8 +1017,6 @@
  */
 static void set_mdp_clocks_for_wuxga(void)
 {
-	int i;
-
 	mdp_ui_vectors[0].ab = 2000000000;
 	mdp_ui_vectors[0].ib = 2000000000;
 	mdp_vga_vectors[0].ab = 2000000000;
@@ -1037,11 +1026,6 @@
 	mdp_1080p_vectors[0].ab = 2000000000;
 	mdp_1080p_vectors[0].ib = 2000000000;
 
-	mdp_pdata.mdp_core_clk_rate = 200000000;
-
-	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
-		mdp_core_clk_rate_table[i] = 200000000;
-
 	if (apq8064_hdmi_as_primary_selected()) {
 		dtv_bus_def_vectors[0].ab = 2000000000;
 		dtv_bus_def_vectors[0].ib = 2000000000;
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index e77e7c0..1f39d3f 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -389,11 +389,12 @@
 
 static struct pm8921_bms_platform_data
 apq8064_pm8921_bms_pdata __devinitdata = {
-	.battery_type	= BATT_UNKNOWN,
+	.battery_type		= BATT_UNKNOWN,
 	.r_sense		= 10,
-	.i_test			= 2500,
-	.v_failure		= 3000,
+	.v_cutoff		= 3400,
 	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
+	.shutdown_soc_valid_limit = 20,
+	.adjust_soc_low_threshold = 25,
 };
 
 static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 37bd16b..68a85c0 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -95,7 +95,7 @@
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define HOLE_SIZE		0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#define MSM_CONTIG_MEM_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE		0x3800000
 #define MSM_ION_SF_SIZE		0
@@ -111,7 +111,7 @@
 #define MSM_ION_MFC_SIZE	SZ_8K
 #define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
 #else
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
+#define MSM_CONTIG_MEM_SIZE  0x110C000
 #define MSM_ION_HEAP_NUM	1
 #endif
 
@@ -133,14 +133,14 @@
 #define PCIE_PWR_EN_PMIC_GPIO 13
 #define PCIE_RST_N_PMIC_MPP 1
 
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
 {
-	pmem_kernel_ebi1_size = memparse(p, NULL);
+	msm_contig_mem_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
 #endif
 
 #ifdef CONFIG_ANDROID_PMEM
@@ -263,7 +263,7 @@
 	reserve_memory_for(&android_pmem_pdata);
 	reserve_memory_for(&android_pmem_audio_pdata);
 #endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
-	apq8064_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+	apq8064_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
 #endif /*CONFIG_ANDROID_PMEM*/
 }
 
@@ -2292,6 +2292,7 @@
 	&apq8064_iommu_domain_device,
 	&msm_tsens_device,
 	&apq8064_cache_dump_device,
+	&msm_8064_device_tspp,
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index d975997..2a8e918 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -413,31 +413,9 @@
 
 #endif
 
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static int mdp_core_clk_rate_table[] = {
-	200000000,
-	200000000,
-	200000000,
-	200000000,
-};
-#else
-static int mdp_core_clk_rate_table[] = {
-	85330000,
-	128000000,
-	160000000,
-	200000000,
-};
-#endif
-
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-	.mdp_core_clk_rate = 200000000,
-#else
-	.mdp_core_clk_rate = 85330000,
-#endif
-	.mdp_core_clk_table = mdp_core_clk_rate_table,
-	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_max_clk = 200000000,
 #ifdef CONFIG_MSM_BUS_SCALING
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 #endif
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index a1a4b7c..c16f55d 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -340,11 +340,12 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
-	.battery_type	= BATT_UNKNOWN,
+	.battery_type		= BATT_UNKNOWN,
 	.r_sense		= 10,
-	.i_test			= 2500,
-	.v_failure		= 3000,
+	.v_cutoff		= 3400,
 	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
+	.shutdown_soc_valid_limit = 20,
+	.adjust_soc_low_threshold = 25,
 };
 
 static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 4fce029..d5014bd 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -141,7 +141,7 @@
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define HOLE_SIZE	0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#define MSM_CONTIG_MEM_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE            0x3800000 /* Need to be multiple of 64K */
 #define MSM_ION_SF_SIZE            0x0
@@ -168,18 +168,18 @@
 #define MSM8930_FW_START	MSM8930_FIXED_AREA_START
 
 #else
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
+#define MSM_CONTIG_MEM_SIZE  0x110C000
 #define MSM_ION_HEAP_NUM	1
 #endif
 
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
 {
-	pmem_kernel_ebi1_size = memparse(p, NULL);
+	msm_contig_mem_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
 #endif
 
 #ifdef CONFIG_ANDROID_PMEM
@@ -322,7 +322,7 @@
 	reserve_memory_for(&android_pmem_pdata);
 	reserve_memory_for(&android_pmem_audio_pdata);
 #endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
-	msm8930_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+	msm8930_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
 #endif /*CONFIG_ANDROID_PMEM*/
 }
 
@@ -2297,6 +2297,7 @@
 	&msm_cpudai_incall_record_rx,
 	&msm_cpudai_incall_record_tx,
 	&msm_pcm_hostless,
+	&msm_multi_ch_pcm,
 };
 
 static void __init msm8930_i2c_init(void)
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index ddeba32..f993ed8 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -573,18 +573,9 @@
 
 #endif
 
-static int mdp_core_clk_rate_table[] = {
-	85330000,
-	128000000,
-	160000000,
-	200000000,
-};
-
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-	.mdp_core_clk_rate = 85330000,
-	.mdp_core_clk_table = mdp_core_clk_rate_table,
-	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_max_clk = 200000000,
 #ifdef CONFIG_MSM_BUS_SCALING
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 #endif
@@ -1043,8 +1034,6 @@
  */
 static void set_mdp_clocks_for_wuxga(void)
 {
-	int i;
-
 	mdp_ui_vectors[0].ab = 2000000000;
 	mdp_ui_vectors[0].ib = 2000000000;
 	mdp_vga_vectors[0].ab = 2000000000;
@@ -1054,11 +1043,6 @@
 	mdp_1080p_vectors[0].ab = 2000000000;
 	mdp_1080p_vectors[0].ib = 2000000000;
 
-	mdp_pdata.mdp_core_clk_rate = 200000000;
-
-	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
-		mdp_core_clk_rate_table[i] = 200000000;
-
 	if (hdmi_is_primary) {
 		dtv_bus_def_vectors[0].ab = 2000000000;
 		dtv_bus_def_vectors[0].ib = 2000000000;
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 5950026..46d317b 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -420,12 +420,13 @@
 };
 
 static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
-	.battery_type	= BATT_UNKNOWN,
+	.battery_type		= BATT_UNKNOWN,
 	.r_sense		= 10,
-	.i_test			= 2500,
-	.v_failure		= 3000,
+	.v_cutoff		= 3400,
 	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
 	.rconn_mohm		= 18,
+	.shutdown_soc_valid_limit = 20,
+	.adjust_soc_low_threshold = 25,
 };
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 541bf85..22a5021 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -145,7 +145,7 @@
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define HOLE_SIZE	0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x65000
+#define MSM_CONTIG_MEM_SIZE  0x65000
 #ifdef CONFIG_MSM_IOMMU
 #define MSM_ION_MM_SIZE            0x3800000 /* Need to be multiple of 64K */
 #define MSM_ION_SF_SIZE            0x0
@@ -173,18 +173,18 @@
 
 static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
 #else
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
+#define MSM_CONTIG_MEM_SIZE  0x110C000
 #define MSM_ION_HEAP_NUM	1
 #endif
 
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
 {
-	pmem_kernel_ebi1_size = memparse(p, NULL);
+	msm_contig_mem_size = memparse(p, NULL);
 	return 0;
 }
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
 #endif
 
 #ifdef CONFIG_ANDROID_PMEM
@@ -336,7 +336,7 @@
 	reserve_memory_for(&android_pmem_pdata);
 	reserve_memory_for(&android_pmem_audio_pdata);
 #endif
-	msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+	msm8960_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
 #endif
 }
 
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 8adfdab..4524f43 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -4539,19 +4539,10 @@
 	.mddi_client_power = msm_fb_mddi_client_power,
 };
 
-int mdp_core_clk_rate_table[] = {
-	122880000,
-	122880000,
-	192000000,
-	192000000,
-};
-
 static struct msm_panel_common_pdata mdp_pdata = {
 	.hw_revision_addr = 0xac001270,
 	.gpio = 30,
-	.mdp_core_clk_rate = 122880000,
-	.mdp_core_clk_table = mdp_core_clk_rate_table,
-	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_max_clk = 192000000,
 	.mdp_rev = MDP_REV_40,
 	.mem_hid = MEMTYPE_EBI0,
 };
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 7ddf88e..47d847e 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -9651,27 +9651,9 @@
 }
 #endif
 
-#ifdef CONFIG_FB_MSM_MIPI_DSI
-int mdp_core_clk_rate_table[] = {
-	85330000,
-	128000000,
-	160000000,
-	200000000,
-};
-#else
-int mdp_core_clk_rate_table[] = {
-	59080000,
-	128000000,
-	128000000,
-	200000000,
-};
-#endif
-
 static struct msm_panel_common_pdata mdp_pdata = {
 	.gpio = MDP_VSYNC_GPIO,
-	.mdp_core_clk_rate = 59080000,
-	.mdp_core_clk_table = mdp_core_clk_rate_table,
-	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_max_clk = 200000000,
 #ifdef CONFIG_MSM_BUS_SCALING
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 #endif
@@ -9764,9 +9746,7 @@
 static void __init msm_fb_add_devices(void)
 {
 #ifdef CONFIG_FB_MSM_LCDC_DSUB
-	mdp_pdata.mdp_core_clk_table = NULL;
-	mdp_pdata.num_mdp_clk = 0;
-	mdp_pdata.mdp_core_clk_rate = 200000000;
+	mdp_pdata.mdp_max_clk = 200000000;
 #endif
 	msm_fb_register_device("mdp", &mdp_pdata);
 
@@ -9790,8 +9770,6 @@
  */
 static void set_mdp_clocks_for_wuxga(void)
 {
-	int i;
-
 	mdp_sd_smi_vectors[0].ab = 2000000000;
 	mdp_sd_smi_vectors[0].ib = 2000000000;
 	mdp_sd_smi_vectors[1].ab = 2000000000;
@@ -9817,10 +9795,7 @@
 	mdp_1080p_vectors[1].ab = 2000000000;
 	mdp_1080p_vectors[1].ib = 2000000000;
 
-	mdp_pdata.mdp_core_clk_rate = 200000000;
-
-	for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
-		mdp_core_clk_rate_table[i] = 200000000;
+	mdp_pdata.mdp_max_clk = 200000000;
 }
 
 #if (defined(CONFIG_MARIMBA_CORE)) && \
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 0d05df9..e5261b0 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -29,6 +29,7 @@
 #include <sound/msm-dai-q6.h>
 #include <sound/apr_audio.h>
 #include <mach/msm_tsif.h>
+#include <mach/msm_tspp.h>
 #include <mach/msm_bus_board.h>
 #include <mach/rpm.h>
 #include <mach/mdm2.h>
@@ -583,6 +584,67 @@
 	}
 };
 
+#define MSM_TSPP_PHYS			(0x18202000)
+#define MSM_TSPP_SIZE			(0x1000)
+#define MSM_TSPP_BAM_PHYS		(0x18204000)
+#define MSM_TSPP_BAM_SIZE		(0x2000)
+
+static const struct msm_gpio tspp_gpios[] = {
+	{ .gpio_cfg = TSIF_0_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_0_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_0_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_0_SYNC, .label =  "tsif_sync", },
+	{ .gpio_cfg = TSIF_1_CLK,  .label =  "tsif_clk", },
+	{ .gpio_cfg = TSIF_1_EN,   .label =  "tsif_en", },
+	{ .gpio_cfg = TSIF_1_DATA, .label =  "tsif_data", },
+	{ .gpio_cfg = TSIF_1_SYNC, .label =  "tsif_sync", },
+};
+
+static struct resource tspp_resources[] = {
+	[0] = {
+		.flags = IORESOURCE_IRQ,
+		.start = TSIF_TSPP_IRQ,
+		.end   = TSIF1_IRQ,
+	},
+	[1] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF0_PHYS,
+		.end   = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[2] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSIF1_PHYS,
+		.end   = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
+	},
+	[3] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSPP_PHYS,
+		.end   = MSM_TSPP_PHYS + MSM_TSPP_SIZE - 1,
+	},
+	[4] = {
+		.flags = IORESOURCE_MEM,
+		.start = MSM_TSPP_BAM_PHYS,
+		.end   = MSM_TSPP_BAM_PHYS + MSM_TSPP_BAM_SIZE - 1,
+	},
+};
+
+static struct msm_tspp_platform_data tspp_platform_data = {
+	.num_gpios = ARRAY_SIZE(tspp_gpios),
+	.gpios = tspp_gpios,
+	.tsif_pclk = "iface_clk",
+	.tsif_ref_clk = "ref_clk",
+};
+
+struct platform_device msm_8064_device_tspp = {
+	.name          = "msm_tspp",
+	.id            = 0,
+	.num_resources = ARRAY_SIZE(tspp_resources),
+	.resource      = tspp_resources,
+	.dev = {
+		.platform_data = &tspp_platform_data
+	},
+};
+
 /*
  * Machine specific data for AUX PCM Interface
  * which the driver will  be unware of.
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 4e08465..55c1e03 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -190,6 +190,7 @@
 
 extern struct platform_device msm_device_tsif[2];
 extern struct platform_device msm_8064_device_tsif[2];
+extern struct platform_device msm_8064_device_tspp;
 
 extern struct platform_device msm_device_ssbi_pmic1;
 extern struct platform_device msm_device_ssbi_pmic2;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index f53ee09..f529522 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -391,9 +391,7 @@
 	void (*panel_config_gpio)(int);
 	int (*vga_switch)(int select_vga);
 	int *gpio_num;
-	int mdp_core_clk_rate;
-	unsigned num_mdp_clk;
-	int *mdp_core_clk_table;
+	u32 mdp_max_clk;
 #ifdef CONFIG_MSM_BUS_SCALING
 	struct msm_bus_scale_pdata *mdp_bus_scale_table;
 #endif
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 4bd092a..96c4809 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -70,7 +70,7 @@
 #define CORE_VOLTAGE_MIN		900000
 
 #define KRAIT_LDO_VOLTAGE_MIN		465000
-#define KRAIT_LDO_VOLTAGE_OFFSET	460000
+#define KRAIT_LDO_VOLTAGE_OFFSET	465000
 #define KRAIT_LDO_STEP			5000
 
 #define BHS_SETTLING_DELAY_US		1
@@ -734,6 +734,22 @@
 
 module_exit(krait_power_exit);
 
+void secondary_cpu_hs_init(void *base_ptr)
+{
+	/* 605mV retention and 705mV operational voltage */
+	writel_relaxed(0x1C30, base_ptr + APC_LDO_VREF_SET);
+	writel_relaxed(0x430000, base_ptr + 0x20);
+	writel_relaxed(0x21, base_ptr + 0x1C);
+
+	/* Turn on the BHS, turn off LDO Bypass and power down LDO */
+	writel_relaxed(0x403F007F, base_ptr + APC_PWR_GATE_CTL);
+	mb();
+	udelay(1);
+
+	/* Finally turn on the bypass so that BHS supplies power */
+	writel_relaxed(0x403F3F7F, base_ptr + APC_PWR_GATE_CTL);
+}
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("KRAIT POWER regulator driver");
 MODULE_VERSION("1.0");
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 28b7748..b2d3dfa 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/regulator/krait-regulator.h>
 
 #include <asm/hardware/gic.h>
 #include <asm/cacheflush.h>
@@ -126,6 +127,8 @@
 	if (!base_ptr)
 		return -ENODEV;
 
+	secondary_cpu_hs_init(base_ptr);
+
 	writel_relaxed(0x021, base_ptr+0x04);
 	mb();
 	udelay(2);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index decee95..e82e44b 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -2264,13 +2264,17 @@
 
 int smd_is_pkt_avail(smd_channel_t *ch)
 {
+	unsigned long flags;
+
 	if (!ch || !ch->is_pkt_ch)
 		return -EINVAL;
 
 	if (ch->current_packet)
 		return 1;
 
+	spin_lock_irqsave(&smd_lock, flags);
 	update_packet_state(ch);
+	spin_unlock_irqrestore(&smd_lock, flags);
 
 	return ch->current_packet ? 1 : 0;
 }
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 65da903..fdde328 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -59,7 +59,7 @@
 	char wlname[64];
 	struct work_struct work;
 	spinlock_t restart_lock;
-	bool restarting;
+	int restart_count;
 
 	void *notify;
 
@@ -406,8 +406,9 @@
 
 out:
 	spin_lock_irqsave(&dev->restart_lock, flags);
-	wake_unlock(&dev->wake_lock);
-	dev->restarting = false;
+	dev->restart_count--;
+	if (!dev->restart_count)
+		wake_unlock(&dev->wake_lock);
 	spin_unlock_irqrestore(&dev->restart_lock, flags);
 }
 
@@ -416,16 +417,21 @@
 	struct subsys_desc *desc = dev->desc;
 	unsigned long flags;
 
-	spin_lock_irqsave(&dev->restart_lock, flags);
-	if (!dev->restarting) {
-		pr_debug("Restarting %s [level=%d]!\n", desc->name,
-				restart_level);
+	pr_debug("Restarting %s [level=%d]!\n", desc->name, restart_level);
 
-		dev->restarting = true;
+	spin_lock_irqsave(&dev->restart_lock, flags);
+	if (!dev->restart_count)
 		wake_lock(&dev->wake_lock);
-		queue_work(ssr_wq, &dev->work);
-	}
+	dev->restart_count++;
 	spin_unlock_irqrestore(&dev->restart_lock, flags);
+
+	if (!queue_work(ssr_wq, &dev->work)) {
+		spin_lock_irqsave(&dev->restart_lock, flags);
+		dev->restart_count--;
+		if (!dev->restart_count)
+			wake_unlock(&dev->wake_lock);
+		spin_unlock_irqrestore(&dev->restart_lock, flags);
+	}
 }
 
 int subsystem_restart_dev(struct subsys_device *dev)
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 318523b..cbf1d72 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -180,8 +180,13 @@
 static void riva_crash_shutdown(const struct subsys_desc *subsys)
 {
 	pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
-	if (riva_crash != true)
+	if (riva_crash != true) {
 		smsm_riva_reset();
+		/* give sufficient time for wcnss to finish it's error
+		 * fatal routine */
+		msleep(3000);
+	}
+
 }
 
 static struct subsys_desc riva_8960 = {
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 95d2f17..b5d38d5 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1010,8 +1010,16 @@
 int dpm_suspend_end(pm_message_t state)
 {
 	int error = dpm_suspend_late(state);
+	if (error)
+		return error;
 
-	return error ? : dpm_suspend_noirq(state);
+	error = dpm_suspend_noirq(state);
+	if (error) {
+		dpm_resume_early(state);
+		return error;
+	}
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(dpm_suspend_end);
 
diff --git a/drivers/gpio/gpio-msm-v3.c b/drivers/gpio/gpio-msm-v3.c
index 977619b..26716a0 100644
--- a/drivers/gpio/gpio-msm-v3.c
+++ b/drivers/gpio/gpio-msm-v3.c
@@ -167,15 +167,12 @@
 {
 	unsigned cfg;
 
-	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
-
 	/* RAW_STATUS_EN is left on for all gpio irqs. Due to the
 	 * internal circuitry of TLMM, toggling the RAW_STATUS
 	 * could cause the INTR_STATUS to be set for EDGE interrupts.
 	 */
-	cfg |= (INTR_RAW_STATUS_EN | INTR_TARGET_PROC_APPS);
+	cfg = INTR_RAW_STATUS_EN | INTR_TARGET_PROC_APPS;
 	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
-	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
 	cfg &= ~INTR_DECT_CTL_MASK;
 	if (type == IRQ_TYPE_EDGE_RISING)
 		cfg |= INTR_DECT_CTL_POS_EDGE;
@@ -186,10 +183,10 @@
 	else
 		cfg |= INTR_DECT_CTL_LEVEL;
 
-	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
-		cfg |= INTR_POL_CTL_HI;
-	else
+	if (type & IRQ_TYPE_LEVEL_LOW)
 		cfg &= ~INTR_POL_CTL_HI;
+	else
+		cfg |= INTR_POL_CTL_HI;
 
 	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
 	/* Sometimes it might take a little while to update
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index e7f5935..0426339 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -824,3 +824,13 @@
 		kgsl_mmu_type = KGSL_MMU_TYPE_NONE;
 }
 EXPORT_SYMBOL(kgsl_mmu_set_mmutype);
+
+int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
+{
+	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
+		return 1;
+	return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
+		(gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
+}
+EXPORT_SYMBOL(kgsl_mmu_gpuaddr_in_range);
+
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 5293d66..8221b80 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -205,6 +205,7 @@
 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);
 
 /*
  * Static inline functions of MMU that simply call the SMMU specific
@@ -293,12 +294,6 @@
 		mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ts_valid);
 }
 
-static inline int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
-{
-	return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
-		(gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
-}
-
 static inline unsigned int kgsl_mmu_get_int_mask(void)
 {
 	/* Dont enable gpummu interrupts, if iommu is enabled */
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index c0a35f9..1894465 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2347,37 +2347,6 @@
 	int retval;
 	radio->region = req_region;
 
-	switch (radio->region) {
-	case IRIS_REGION_US:
-		radio->recv_conf.band_low_limit =
-			REGION_US_EU_BAND_LOW;
-		radio->recv_conf.band_high_limit =
-			REGION_US_EU_BAND_HIGH;
-		break;
-	case IRIS_REGION_EU:
-		radio->recv_conf.band_low_limit =
-			REGION_US_EU_BAND_LOW;
-		radio->recv_conf.band_high_limit =
-			REGION_US_EU_BAND_HIGH;
-		break;
-	case IRIS_REGION_JAPAN:
-		radio->recv_conf.band_low_limit =
-			REGION_JAPAN_STANDARD_BAND_LOW;
-		radio->recv_conf.band_high_limit =
-			REGION_JAPAN_STANDARD_BAND_HIGH;
-		break;
-	case IRIS_REGION_JAPAN_WIDE:
-		radio->recv_conf.band_low_limit =
-			REGION_JAPAN_WIDE_BAND_LOW;
-		radio->recv_conf.band_high_limit =
-			REGION_JAPAN_WIDE_BAND_HIGH;
-		break;
-	default:
-		/* The user specifies the value.
-		   So nothing needs to be done */
-		break;
-	}
-
 	retval = hci_set_fm_recv_conf(
 			&radio->recv_conf,
 			radio->fm_hdev);
@@ -2391,34 +2360,6 @@
 	int retval;
 	radio->region = req_region;
 
-	switch (radio->region) {
-	case IRIS_REGION_US:
-		radio->trans_conf.band_low_limit =
-			REGION_US_EU_BAND_LOW;
-		radio->trans_conf.band_high_limit =
-			REGION_US_EU_BAND_HIGH;
-		break;
-	case IRIS_REGION_EU:
-		radio->trans_conf.band_low_limit =
-			REGION_US_EU_BAND_LOW;
-		radio->trans_conf.band_high_limit =
-			REGION_US_EU_BAND_HIGH;
-		break;
-	case IRIS_REGION_JAPAN:
-		radio->trans_conf.band_low_limit =
-			REGION_JAPAN_STANDARD_BAND_LOW;
-		radio->trans_conf.band_high_limit =
-			REGION_JAPAN_STANDARD_BAND_HIGH;
-		break;
-	case IRIS_REGION_JAPAN_WIDE:
-		radio->recv_conf.band_low_limit =
-			REGION_JAPAN_WIDE_BAND_LOW;
-		radio->recv_conf.band_high_limit =
-			REGION_JAPAN_WIDE_BAND_HIGH;
-	default:
-		break;
-	}
-
 	retval = hci_set_fm_trans_conf(
 			&radio->trans_conf,
 				radio->fm_hdev);
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 7d58091..0919799 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1542,7 +1542,6 @@
 	case NOTIFY_VFE_MSG_STATS:
 	case NOTIFY_VFE_MSG_COMP_STATS:
 	case NOTIFY_VFE_CAMIF_ERROR:
-	case NOTIFY_VFE_IRQ:
 	default:
 		interface = PIX_0;
 		break;
@@ -1593,11 +1592,10 @@
 	case NOTIFY_VFE_IRQ:{
 		struct msm_vfe_cfg_cmd cfg_cmd;
 		struct msm_camvfe_params vfe_params;
-		p_mctl = msm_cam_server_get_mctl(mctl_handle);
 		cfg_cmd.cmd_type = CMD_VFE_PROCESS_IRQ;
 		vfe_params.vfe_cfg = &cfg_cmd;
 		vfe_params.data = arg;
-		rc = v4l2_subdev_call(p_mctl->isp_sdev->sd,
+		rc = v4l2_subdev_call(sd,
 			core, ioctl, 0, &vfe_params);
 	}
 		break;
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index 3e01437..c8d22d4 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -4359,7 +4359,7 @@
 				VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
 			if (stat_interrupt)
 				vfe32_ctrl->simultaneous_sof_stat = 1;
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS0_CAMIF_SOF_MASK);
 		}
@@ -4367,25 +4367,25 @@
 		/* interrupt to be processed,  *qcmd has the payload.  */
 		if (qcmd->vfeInterruptStatus0 &
 				VFE_IRQ_STATUS0_REG_UPDATE_MASK)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
 
 		if (qcmd->vfeInterruptStatus1 &
 				VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS1_RDI0_REG_UPDATE);
 
 		if (qcmd->vfeInterruptStatus1 &
 				VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IRQ_STATUS1_RDI1_REG_UPDATE);
 
 		if (qcmd->vfeInterruptStatus1 &
 				VFE_IMASK_WHILE_STOPPING_1)
-			v4l2_subdev_notify(&axi_ctrl->subdev,
+			v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_IRQ,
 				(void *)VFE_IMASK_WHILE_STOPPING_1);
 
@@ -4410,7 +4410,7 @@
 				if (qcmd->vfeInterruptStatus0 &
 					VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
 					CDBG("Stats composite irq occured.\n");
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)qcmd->vfeInterruptStatus0);
 				}
@@ -4418,60 +4418,60 @@
 				/* process individual stats interrupt. */
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_AEC_BG)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_AEC_BG);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_AWB)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_AWB);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_AF_BF)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_AF_BF);
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_SK_BHIST)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_SK_BHIST);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_IHIST)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_IHIST);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_RS)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_RS);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_STATS_CS)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_STATS_CS);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_SYNC_TIMER0)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_SYNC_TIMER0);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_SYNC_TIMER1)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_SYNC_TIMER1);
 
 				if (qcmd->vfeInterruptStatus0 &
 						VFE_IRQ_STATUS0_SYNC_TIMER2)
-					v4l2_subdev_notify(&axi_ctrl->subdev,
+					v4l2_subdev_notify(&vfe32_ctrl->subdev,
 					NOTIFY_VFE_IRQ,
 					(void *)VFE_IRQ_STATUS0_SYNC_TIMER2);
 			}
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 5b1928b..282da64 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -621,6 +621,11 @@
 	unsigned long flags;
 	struct vb2_buf_entry *temp;
 	struct list_head *ptr, *next;
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		pr_err("Failed to get Buffer Requirements : %d\n", rc);
+		goto fail_start;
+	}
 	rc = msm_comm_set_scratch_buffers(inst);
 	if (rc) {
 		pr_err("Failed to set scratch buffers: %d\n", rc);
@@ -757,7 +762,12 @@
 	void *pdata;
 	struct msm_vidc_inst *inst = container_of(ctrl->handler,
 					struct msm_vidc_inst, ctrl_handler);
-
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+	if (rc) {
+		pr_err("Failed to move inst: %p to start done state\n",
+				inst);
+		goto failed_open_done;
+	}
 	control.id = ctrl->id;
 	control.value = ctrl->val;
 
@@ -1177,6 +1187,7 @@
 	}
 	if (rc)
 		pr_err("Failed to set hal property for framesize\n");
+failed_open_done:
 	return rc;
 }
 static int msm_venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 304dc6b..88e0948 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -20,6 +20,7 @@
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/ccadc.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
@@ -27,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
+#include <linux/rtc.h>
 
 #define BMS_CONTROL		0x224
 #define BMS_S1_DELAY		0x225
@@ -49,6 +51,9 @@
 
 #define TEMP_SOC_STORAGE	0x107
 
+#define TEMP_IAVG_STORAGE	0x105
+#define TEMP_IAVG_STORAGE_USE_MASK	0x0F
+
 enum pmic_bms_interrupts {
 	PM8921_BMS_SBI_WRITE_OK,
 	PM8921_BMS_CC_THR,
@@ -67,16 +72,6 @@
 	int		last_good_ocv_uv;
 };
 
-struct pm8921_rbatt_params {
-	uint16_t	ocv_for_rbatt_raw;
-	uint16_t	vsense_for_rbatt_raw;
-	uint16_t	vbatt_for_rbatt_raw;
-
-	int		ocv_for_rbatt_uv;
-	int		vsense_for_rbatt_uv;
-	int		vbatt_for_rbatt_uv;
-};
-
 /**
  * struct pm8921_bms_chip -
  * @bms_output_lock:	lock to prevent concurrent bms reads
@@ -92,8 +87,7 @@
 	struct device		*dev;
 	struct dentry		*dent;
 	unsigned int		r_sense;
-	unsigned int		i_test;
-	unsigned int		v_failure;
+	unsigned int		v_cutoff;
 	unsigned int		fcc;
 	struct single_row_lut	*fcc_temp_lut;
 	struct single_row_lut	*fcc_sf_lut;
@@ -102,6 +96,8 @@
 	struct sf_lut		*rbatt_sf_lut;
 	int			delta_rbatt_mohm;
 	struct work_struct	calib_hkadc_work;
+	struct delayed_work	calib_hkadc_delayed_work;
+	struct mutex		calib_mutex;
 	unsigned int		revision;
 	unsigned int		xoadc_v0625_usb_present;
 	unsigned int		xoadc_v0625_usb_absent;
@@ -119,29 +115,42 @@
 	unsigned int		charging_began;
 	unsigned int		start_percent;
 	unsigned int		end_percent;
+	int			charge_time_us;
+	int			catch_up_time_us;
 	enum battery_type	batt_type;
 	uint16_t		ocv_reading_at_100;
 	int			cc_reading_at_100;
 	int			max_voltage_uv;
 
-	int			batt_temp_suspend;
-	int			soc_rbatt_suspend;
 	int			default_rbatt_mohm;
 	int			amux_2_trim_delta;
 	uint16_t		prev_last_good_ocv_raw;
 	unsigned int		rconn_mohm;
 	struct mutex		last_ocv_uv_mutex;
 	int			last_ocv_uv;
+	int			pon_ocv_uv;
 	int			last_cc_uah;
-	struct timeval		t;
-	int			last_uuc_uah;
+	unsigned long		tm_sec;
 	int			enable_fcc_learning;
 	int			shutdown_soc;
-	int			timer_uuc_expired;
-	struct delayed_work	uuc_timer_work;
-	int			uuc_uah_iavg_prev;
+	int			shutdown_iavg_ua;
+	int			shutdown_soc_timer_expired;
+	struct delayed_work	shutdown_soc_work;
+	struct delayed_work	calculate_soc_delayed_work;
+	struct timespec		t_soc_queried;
+	int			shutdown_soc_valid_limit;
+	int			ignore_shutdown_soc;
+	int			prev_iavg_ua;
+	int			prev_uuc_iavg_ma;
+	int			prev_pc_unusable;
+	int			adjust_soc_low_threshold;
 };
 
+/*
+ * protects against simultaneous adjustment of ocv based on shutdown soc and
+ * invalidating the shutdown soc
+ */
+static DEFINE_MUTEX(soc_invalidation_mutex);
 static int shutdown_soc_invalid;
 static struct pm8921_bms_chip *the_chip;
 
@@ -157,7 +166,7 @@
 module_param(last_chargecycles, int, 0644);
 module_param(last_charge_increase, int, 0644);
 
-static int last_rbatt = -EINVAL;
+static int calculated_soc = -EINVAL;
 static int last_soc = -EINVAL;
 static int last_real_fcc_mah = -EINVAL;
 static int last_real_fcc_batt_temp = -EINVAL;
@@ -175,7 +184,6 @@
 	.get = param_get_int,
 };
 
-module_param_cb(last_rbatt, &bms_param_ops, &last_rbatt, 0644);
 module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
 
 /*
@@ -337,19 +345,13 @@
 
 static int usb_chg_plugged_in(void)
 {
-	union power_supply_propval ret = {0,};
-	static struct power_supply *psy;
+	int val = pm8921_is_usb_chg_plugged_in();
 
-	if (psy == NULL) {
-		psy = power_supply_get_by_name("usb");
-		if (psy == NULL)
-			return 0;
-	}
+	/* treat as if usb is not present in case of error */
+	if (val == -EINVAL)
+		val = 0;
 
-	if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
-		return 0;
-
-	return ret.intval;
+	return val;
 }
 
 #define HOLD_OREG_DATA		BIT(1)
@@ -483,8 +485,8 @@
 	return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
 }
 
-#define CC_READING_TICKS	55
-#define SLEEP_CLK_HZ		32768
+#define CC_READING_TICKS	56
+#define SLEEP_CLK_HZ		32764
 #define SECONDS_PER_HOUR	3600
 /**
  * ccmicrovolt_to_nvh -
@@ -732,6 +734,82 @@
 	return 0;
 }
 
+/* get ocv given a soc  -- reverse lookup */
+static int interpolate_ocv(struct pm8921_bms_chip *chip,
+				int batt_temp_degc, int pc)
+{
+	int i, ocvrow1, ocvrow2, ocv;
+	int rows, cols;
+	int row1 = 0;
+	int row2 = 0;
+
+	rows = chip->pc_temp_ocv_lut->rows;
+	cols = chip->pc_temp_ocv_lut->cols;
+	if (pc > chip->pc_temp_ocv_lut->percent[0]) {
+		pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
+		row1 = 0;
+		row2 = 0;
+	}
+	if (pc < chip->pc_temp_ocv_lut->percent[rows - 1]) {
+		pr_debug("pc %d less than known pc ranges for sf\n", pc);
+		row1 = rows - 1;
+		row2 = rows - 1;
+	}
+	for (i = 0; i < rows; i++) {
+		if (pc == chip->pc_temp_ocv_lut->percent[i]) {
+			row1 = i;
+			row2 = i;
+			break;
+		}
+		if (pc > chip->pc_temp_ocv_lut->percent[i]) {
+			row1 = i - 1;
+			row2 = i;
+			break;
+		}
+	}
+
+	if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0])
+		batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
+	if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1])
+		batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
+
+	for (i = 0; i < cols; i++)
+		if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[i])
+			break;
+	if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[i]) {
+		ocv = linear_interpolate(
+				chip->pc_temp_ocv_lut->ocv[row1][i],
+				chip->pc_temp_ocv_lut->percent[row1],
+				chip->pc_temp_ocv_lut->ocv[row2][i],
+				chip->pc_temp_ocv_lut->percent[row2],
+				pc);
+		return ocv;
+	}
+
+	ocvrow1 = linear_interpolate(
+				chip->pc_temp_ocv_lut->ocv[row1][i - 1],
+				chip->pc_temp_ocv_lut->temp[i - 1],
+				chip->pc_temp_ocv_lut->ocv[row1][i],
+				chip->pc_temp_ocv_lut->temp[i],
+				batt_temp_degc);
+
+	ocvrow2 = linear_interpolate(
+				chip->pc_temp_ocv_lut->ocv[row2][i - 1],
+				chip->pc_temp_ocv_lut->temp[i - 1],
+				chip->pc_temp_ocv_lut->ocv[row2][i],
+				chip->pc_temp_ocv_lut->temp[i],
+				batt_temp_degc);
+
+	ocv = linear_interpolate(
+				ocvrow1,
+				chip->pc_temp_ocv_lut->percent[row1],
+				ocvrow2,
+				chip->pc_temp_ocv_lut->percent[row2],
+				pc);
+
+	return ocv;
+}
+
 static int interpolate_pc(struct pm8921_bms_chip *chip,
 				int batt_temp, int ocv)
 {
@@ -836,7 +914,7 @@
 #define BMS_MODE_BIT	BIT(6)
 #define EN_VBAT_BIT	BIT(5)
 #define OVERRIDE_MODE_DELAY_MS	20
-int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
+int override_mode_simultaneous_battery_voltage_and_current(int *ibat_ua,
 								int *vbat_uv)
 {
 	int16_t vsense_raw;
@@ -844,11 +922,6 @@
 	int vsense_uv;
 	int usb_chg;
 
-	if (the_chip == NULL) {
-		pr_err("Called to early\n");
-		return -EINVAL;
-	}
-
 	mutex_lock(&the_chip->bms_output_lock);
 
 	pm8xxx_writeb(the_chip->dev->parent, BMS_S1_DELAY, 0x00);
@@ -880,42 +953,6 @@
 			*ibat_ua, *vbat_uv);
 	return 0;
 }
-EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
-
-static int read_rbatt_params_raw(struct pm8921_bms_chip *chip,
-				struct pm8921_rbatt_params *raw)
-{
-	int usb_chg;
-
-	mutex_lock(&chip->bms_output_lock);
-	pm_bms_lock_output_data(chip);
-
-	pm_bms_read_output_data(chip,
-			OCV_FOR_RBATT, &raw->ocv_for_rbatt_raw);
-	pm_bms_read_output_data(chip,
-			VBATT_FOR_RBATT, &raw->vbatt_for_rbatt_raw);
-	pm_bms_read_output_data(chip,
-			VSENSE_FOR_RBATT, &raw->vsense_for_rbatt_raw);
-
-	pm_bms_unlock_output_data(chip);
-	mutex_unlock(&chip->bms_output_lock);
-
-	usb_chg = usb_chg_plugged_in();
-	convert_vbatt_raw_to_uv(chip, usb_chg,
-			raw->vbatt_for_rbatt_raw, &raw->vbatt_for_rbatt_uv);
-	convert_vbatt_raw_to_uv(chip, usb_chg,
-			raw->ocv_for_rbatt_raw, &raw->ocv_for_rbatt_uv);
-	convert_vsense_to_uv(chip, raw->vsense_for_rbatt_raw,
-					&raw->vsense_for_rbatt_uv);
-
-	pr_debug("vbatt_for_rbatt_raw = 0x%x, vbatt_for_rbatt= %duV\n",
-			raw->vbatt_for_rbatt_raw, raw->vbatt_for_rbatt_uv);
-	pr_debug("ocv_for_rbatt_raw = 0x%x, ocv_for_rbatt= %duV\n",
-			raw->ocv_for_rbatt_raw, raw->ocv_for_rbatt_uv);
-	pr_debug("vsense_for_rbatt_raw = 0x%x, vsense_for_rbatt= %duV\n",
-			raw->vsense_for_rbatt_raw, raw->vsense_for_rbatt_uv);
-	return 0;
-}
 
 #define MBG_TRANSIENT_ERROR_RAW 51
 static void adjust_pon_ocv_raw(struct pm8921_bms_chip *chip,
@@ -953,6 +990,7 @@
 		convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
 		chip->last_ocv_uv = raw->last_good_ocv_uv;
+		pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
 	} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
 		chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
 		convert_vbatt_raw_to_uv(chip, usb_chg,
@@ -988,7 +1026,7 @@
 {
 	int rbatt, scalefactor;
 
-	rbatt = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
+	rbatt = chip->default_rbatt_mohm;
 	pr_debug("rbatt before scaling = %d\n", rbatt);
 	if (chip->rbatt_sf_lut == NULL)  {
 		pr_debug("RBATT = %d\n", rbatt);
@@ -1017,27 +1055,6 @@
 	return rbatt;
 }
 
-static int calculate_rbatt_resume(struct pm8921_bms_chip *chip,
-				struct pm8921_rbatt_params *raw)
-{
-	unsigned int  r_batt;
-
-	if (raw->ocv_for_rbatt_uv <= 0
-		|| raw->ocv_for_rbatt_uv <= raw->vbatt_for_rbatt_uv
-		|| raw->vsense_for_rbatt_raw <= 0) {
-		pr_debug("rbatt readings unavailable ocv = %d, vbatt = %d,"
-					"vsen = %d\n",
-					raw->ocv_for_rbatt_uv,
-					raw->vbatt_for_rbatt_uv,
-					raw->vsense_for_rbatt_raw);
-		return -EINVAL;
-	}
-	r_batt = ((raw->ocv_for_rbatt_uv - raw->vbatt_for_rbatt_uv)
-			* chip->r_sense) / raw->vsense_for_rbatt_uv;
-	pr_debug("r_batt = %umilliOhms", r_batt);
-	return r_batt;
-}
-
 static int calculate_fcc_uah(struct pm8921_bms_chip *chip, int batt_temp,
 							int chargecycles)
 {
@@ -1090,7 +1107,7 @@
 		return rc;
 	}
 
-	rbatt = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
+	rbatt = chip->default_rbatt_mohm;
 	*ocv = vbatt + (ibatt_ua * rbatt)/1000;
 	return 0;
 }
@@ -1141,185 +1158,230 @@
 	*val = cc_uah;
 }
 
-static int calculate_uuc_uah_at_given_current(struct pm8921_bms_chip *chip,
+static int calculate_termination_uuc(struct pm8921_bms_chip *chip,
 				 int batt_temp, int chargecycles,
-				int rbatt, int fcc_uah, int i_ma)
+				int fcc_uah, int i_ma,
+				int *ret_pc_unusable)
 {
 	int unusable_uv, pc_unusable, uuc;
+	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 prev_ocv_mv = 0;
+	int uuc_rbatt_uv;
 
-	/* calculate unusable charge with itest */
-	unusable_uv = (rbatt * i_ma) + (chip->v_failure * 1000);
+	for (i = 0; i <= 100; i++) {
+		ocv_mv = interpolate_ocv(chip, batt_temp_degc, i);
+		rbatt_mohm = get_rbatt(chip, i, batt_temp);
+		unusable_uv = (rbatt_mohm * i_ma) + (chip->v_cutoff * 1000);
+		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;
+		prev_ocv_mv = ocv_mv;
+	}
+
+	uuc_rbatt_uv = linear_interpolate(rbatt_mohm, delta_uv,
+					prev_rbatt_mohm, prev_delta_uv,
+					0);
+
+	unusable_uv = (uuc_rbatt_uv * i_ma) + (chip->v_cutoff * 1000);
+
 	pc_unusable = calculate_pc(chip, unusable_uv, batt_temp, chargecycles);
 	uuc = (fcc_uah * pc_unusable) / 100;
-	pr_debug("For i_ma = %d, unusable_uv = %d unusable_pc = %d uuc = %d\n",
-					i_ma, unusable_uv, pc_unusable, uuc);
+	pr_debug("For i_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d uuc = %d\n",
+					i_ma, uuc_rbatt_uv, unusable_uv,
+					pc_unusable, uuc);
+	*ret_pc_unusable = pc_unusable;
 	return uuc;
 }
 
-#define SOC_RBATT_CHG		70
-#define SOC_RBATT_DISCHG	20
-
-static int uuc_iavg_div = 150;
-module_param(uuc_iavg_div, int, 0644);
-
-static int uuc_min_step_size = 120;
-module_param(uuc_min_step_size, int, 0644);
-
-static int uuc_multiplier = 1000;
-module_param(uuc_multiplier, int, 0644);
-
-#define UUC_TIMER_MS		120000
-
-static void uuc_timer_work(struct work_struct *work)
+static int adjust_uuc(struct pm8921_bms_chip *chip, int fcc_uah,
+			int new_pc_unusable,
+			int new_uuc,
+			int batt_temp,
+			int rbatt,
+			int *iavg_ma)
 {
-	struct pm8921_bms_chip *chip = container_of(work,
-				struct pm8921_bms_chip, uuc_timer_work.work);
+	int new_unusable_mv;
+	int batt_temp_degc = batt_temp / 10;
 
-	pr_debug("UUC Timer expired\n");
-	/* indicates the system is done with the high load during bootup */
-	chip->timer_uuc_expired = 1;
+	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;
+	}
+
+	/* 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 = (fcc_uah * chip->prev_pc_unusable) / 100;
+
+	/* also find update the iavg_ma accordingly */
+	new_unusable_mv = interpolate_ocv(chip, batt_temp_degc,
+						chip->prev_pc_unusable);
+	if (new_unusable_mv < chip->v_cutoff)
+		new_unusable_mv = chip->v_cutoff;
+
+	*iavg_ma = (new_unusable_mv - chip->v_cutoff) * 1000 / rbatt;
+	if (*iavg_ma == 0)
+		*iavg_ma = 1;
+	pr_debug("Restricting UUC to %d (%d%%) unusable_mv = %d iavg_ma = %d\n",
+					new_uuc, chip->prev_pc_unusable,
+					new_unusable_mv, *iavg_ma);
+
+	return new_uuc;
 }
 
 static void calculate_iavg_ua(struct pm8921_bms_chip *chip, int cc_uah,
-				int *iavg_ua, int *delta_time_us)
+				int *iavg_ua, int *delta_time_s)
 {
 	int delta_cc_uah;
-	struct timeval now;
+	struct rtc_time tm;
+	struct rtc_device *rtc;
+	unsigned long now_tm_sec = 0;
+	int rc = 0;
 
-	delta_cc_uah = cc_uah - chip->last_cc_uah;
-	do_gettimeofday(&now);
-	if (chip->t.tv_sec != 0) {
-		*delta_time_us = (now.tv_sec - chip->t.tv_sec) * USEC_PER_SEC
-				+ now.tv_usec - chip->t.tv_usec;
-	} else {
-		/* calculation for the first time */
-		*delta_time_us = 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;
 	}
 
-	if (*delta_time_us != 0)
-		*iavg_ua = div_s64((s64)delta_cc_uah * 3600 * 1000000,
-					*delta_time_us);
-	else
-		*iavg_ua = 0;
+	rc = rtc_read_time(rtc, &tm);
+	if (rc) {
+		pr_err("Error reading rtc device (%s) : %d\n",
+			CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto out;
+	}
 
-	pr_debug("t.tv_sec = %d, now.tv_sec = %d delta_us = %d iavg_ua = %d\n",
-				(int)chip->t.tv_sec, (int)now.tv_sec,
-				*delta_time_us, (int)*iavg_ua);
+	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) {
+		*delta_time_s = 0;
+		pm8921_bms_get_battery_current(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->t = now;
+	chip->tm_sec = now_tm_sec;
 }
 
-#define UUC_IAVG_THRESHOLD_UAH	50000
-static int scale_unusable_charge_uah(struct pm8921_bms_chip *chip,
-			bool charging, int uuc_uah_iavg, int uuc_uah_itest,
-			int uuc_uah_iavg_prev)
-{
-	int stepsize = 0;
-	int delta_uuc = 0;
-	int uuc_reported = 0;
-
-	if (charging) {
-		stepsize = max(uuc_min_step_size,
-				uuc_multiplier * (SOC_RBATT_CHG - last_soc));
-		/*
-		 * set the delta only if uuc is decreasing. If it has increased
-		 * simply report the last uuc since we don't want to report a
-		 * higher uuc as charging progresses
-		 */
-		if (chip->last_uuc_uah > uuc_uah_iavg)
-			delta_uuc = (chip->last_uuc_uah - uuc_uah_iavg)
-								/ stepsize;
-		uuc_reported = chip->last_uuc_uah - delta_uuc;
-	} else {
-		stepsize = max(uuc_min_step_size,
-			uuc_multiplier * (last_soc - SOC_RBATT_DISCHG));
-		if (uuc_uah_itest > uuc_uah_iavg) {
-			if ((uuc_uah_iavg > uuc_uah_iavg_prev
-						+ UUC_IAVG_THRESHOLD_UAH)
-				&& chip->timer_uuc_expired)
-				/*
-				 * there is a big jump in iavg current way past
-				 * the bootup increase  uuc to this high iavg
-				 * based uuc in steps
-				 */
-				delta_uuc = (uuc_uah_iavg - uuc_uah_iavg_prev)
-							/ uuc_iavg_div;
-			else
-				/* increase uuc towards itest based uuc */
-				delta_uuc = (uuc_uah_itest - uuc_uah_iavg)
-						/ stepsize;
-		} else {
-			/*
-			 * the iavg based uuc was higher than itest based
-			 * uuc. This means that iavg > itest. Itest represents
-			 * the max current drawn from the device at anytime.
-			 * If we find iavg > itest, ignore iavg and simply step
-			 * up the uuc based on itest
-			 */
-			delta_uuc = uuc_uah_itest / stepsize;
-		}
-		uuc_reported = min(uuc_uah_itest,
-					chip->last_uuc_uah + delta_uuc);
-	}
-	pr_debug("uuc_prev = %d stepsize = %d d_uuc =  %d uuc_reported = %d\n",
-			chip->last_uuc_uah, (int)stepsize, delta_uuc,
-			uuc_reported);
-	return uuc_reported;
-}
-
+#define IAVG_SAMPLES 16
+#define CHARGING_IAVG_MA 250
+#define MIN_SECONDS_FOR_VALID_SAMPLE	20
 static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
 				int rbatt, int fcc_uah, int cc_uah,
 				int soc_rbatt, int batt_temp, int chargecycles,
-				int iavg_ua)
+				int iavg_ua, int delta_time_s)
 {
-	int uuc_uah_itest, uuc_uah_iavg, uuc_reported;
-	static int firsttime = 1;
+	int uuc_uah_iavg;
+	int i;
 	int iavg_ma = iavg_ua / 1000;
+	static int iavg_samples[IAVG_SAMPLES];
+	static int iavg_index;
+	static int iavg_num_samples;
+	static int firsttime = 1;
+	int pc_unusable;
 
-	/* calculate unusable charge with itest */
-	uuc_uah_itest = calculate_uuc_uah_at_given_current(chip,
+	/*
+	 * if we are called first time fill all the
+	 * samples with the the shutdown_iavg_ua
+	 */
+	if (firsttime && chip->shutdown_iavg_ua != 0) {
+		pr_emerg("Using shutdown_iavg_ua = %d in all samples\n",
+				chip->shutdown_iavg_ua);
+		for (i = 0; i < IAVG_SAMPLES; i++)
+			iavg_samples[i] = chip->shutdown_iavg_ua;
+
+		iavg_index = 0;
+		iavg_num_samples = IAVG_SAMPLES;
+	}
+
+	/*
+	 * if we are charging use a nominal avg current so that we keep
+	 * a reasonable UUC while charging
+	 */
+	if (iavg_ma < 0)
+		iavg_ma = CHARGING_IAVG_MA;
+	iavg_samples[iavg_index] = iavg_ma;
+	iavg_index = (iavg_index + 1) % IAVG_SAMPLES;
+	iavg_num_samples++;
+	if (iavg_num_samples >= IAVG_SAMPLES)
+		iavg_num_samples = IAVG_SAMPLES;
+
+	/* now that this sample is added calcualte the average */
+	iavg_ma = 0;
+	if (iavg_num_samples != 0) {
+		for (i = 0; i < iavg_num_samples; i++) {
+			pr_debug("iavg_samples[%d] = %d\n", i, iavg_samples[i]);
+			iavg_ma += iavg_samples[i];
+		}
+
+		iavg_ma = DIV_ROUND_CLOSEST(iavg_ma, iavg_num_samples);
+	}
+
+	uuc_uah_iavg = calculate_termination_uuc(chip,
 					batt_temp, chargecycles,
-					rbatt, fcc_uah, chip->i_test);
-
-	pr_debug("itest = %d uuc_itest = %d\n", chip->i_test, uuc_uah_itest);
-
-	/* calculate unusable charge with iavg */
-	iavg_ma = max(0, iavg_ma);
-	uuc_uah_iavg = calculate_uuc_uah_at_given_current(chip,
-					batt_temp, chargecycles,
-					rbatt, fcc_uah, iavg_ma);
+					fcc_uah, iavg_ma,
+					&pc_unusable);
 	pr_debug("iavg = %d uuc_iavg = %d\n", iavg_ma, uuc_uah_iavg);
 
-	if (firsttime) {
-		chip->uuc_uah_iavg_prev = uuc_uah_iavg;
+	/* restrict the uuc such that it can increase only by one percent */
+	uuc_uah_iavg = adjust_uuc(chip, fcc_uah, pc_unusable, uuc_uah_iavg,
+					batt_temp, rbatt, &iavg_ma);
 
-		if (cc_uah < chip->last_cc_uah)
-			chip->last_uuc_uah = uuc_uah_itest;
-		else
-			chip->last_uuc_uah = uuc_uah_iavg;
-		pr_debug("firsttime uuc_prev = %d\n", chip->last_uuc_uah);
-	}
+	/* find out what the avg current should be for this uuc */
+	chip->prev_uuc_iavg_ma = iavg_ma;
 
-	uuc_reported = scale_unusable_charge_uah(chip,
-				cc_uah < chip->last_cc_uah,
-				uuc_uah_iavg, uuc_uah_itest,
-				chip->uuc_uah_iavg_prev);
-
-	/* remember the last uuc_uah_iavg */
-	chip->uuc_uah_iavg_prev = uuc_uah_iavg;
-
-	/* remember the reported uuc */
-	chip->last_uuc_uah = uuc_reported;
-
-	if (firsttime == 1) {
-		/* uuc calculation for the first time is done */
-		firsttime = 0;
-	}
-
-	return uuc_reported;
+	firsttime = 0;
+	return uuc_uah_iavg;
 }
 
 /* calculate remainging charge at the time of ocv */
@@ -1345,7 +1407,7 @@
 						int *cc_uah,
 						int *rbatt,
 						int *iavg_ua,
-						int *delta_time_us)
+						int *delta_time_s)
 {
 	int soc_rbatt;
 
@@ -1371,11 +1433,12 @@
 		soc_rbatt = 0;
 	*rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
 
-	calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_us);
+	calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_s);
 
 	*unusable_charge_uah = calculate_unusable_charge_uah(chip, *rbatt,
 					*fcc_uah, *cc_uah, soc_rbatt,
-					batt_temp, chargecycles, *iavg_ua);
+					batt_temp, chargecycles, *iavg_ua,
+					*delta_time_s);
 	pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
 }
 
@@ -1390,7 +1453,7 @@
 	int real_fcc_uah;
 	int rbatt;
 	int iavg_ua;
-	int delta_time_us;
+	int delta_time_s;
 
 	calculate_soc_params(chip, raw, batt_temp, chargecycles,
 						&fcc_uah,
@@ -1399,7 +1462,7 @@
 						&cc_uah,
 						&rbatt,
 						&iavg_ua,
-						&delta_time_us);
+						&delta_time_s);
 
 	real_fcc_uah = remaining_charge_uah - cc_uah;
 	*ret_fcc_uah = fcc_uah;
@@ -1408,6 +1471,38 @@
 	return real_fcc_uah;
 }
 
+int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
+								int *vbat_uv)
+{
+	int rc;
+
+	if (the_chip == NULL) {
+		pr_err("Called too early\n");
+		return -EINVAL;
+	}
+
+	if (pm8921_is_batfet_closed()) {
+		return override_mode_simultaneous_battery_voltage_and_current(
+								ibat_ua,
+								vbat_uv);
+	} else {
+		pr_debug("batfet is open using separate vbat and ibat meas\n");
+		rc = get_battery_uvolts(the_chip, vbat_uv);
+		if (rc < 0) {
+			pr_err("adc vbat failed err = %d\n", rc);
+			return rc;
+		}
+		rc = pm8921_bms_get_battery_current(ibat_ua);
+		if (rc < 0) {
+			pr_err("bms ibat failed err = %d\n", rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
+
 static int bound_soc(int soc)
 {
 	soc = max(0, soc);
@@ -1427,12 +1522,23 @@
 	int pc_new = 0;
 	int soc_new = 0;
 	int m = 0;
+	int rc = 0;
+	int delta_ocv_uv_limit = 0;
 
-	pm8921_bms_get_simultaneous_battery_voltage_and_current(&ibat_ua,
-		&vbat_uv);
+	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+							&ibat_ua,
+							&vbat_uv);
+	if (rc < 0) {
+		pr_err("simultaneous vbat ibat failed err = %d\n", rc);
+		goto out;
+	}
+
 
 	if (ibat_ua < 0)
 		goto out;
+
+	delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
+
 	ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000;
 	pc_est = calculate_pc(chip, ocv_est_uv, batt_temp, last_chargecycles);
 	soc_est = div_s64((s64)fcc_uah * pc_est - uuc_uah*100,
@@ -1440,10 +1546,19 @@
 	soc_est = bound_soc(soc_est);
 
 	/*
-	 * do not adjust if soc_est is between 45 and 25 OR soc_est is
-	 * same as what bms calculated
+	 * 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 we might pull it low
+	 * and  cause a bad user experience
 	 */
-	if (is_between(45, 25, soc_est) || soc_est == soc)
+	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 (last_soc_est == -EINVAL)
@@ -1477,6 +1592,18 @@
 
 	delta_ocv_uv = div_s64((soc - soc_est) * (s64)m * 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)
@@ -1509,71 +1636,229 @@
 	return soc;
 }
 
-#define MAX_SHUTDOWN_ADJUST_SECONDS	1800
-static int adjust_for_shutdown_soc(struct pm8921_bms_chip *chip, int soc)
+#define IGNORE_SOC_TEMP_DECIDEG		50
+#define IAVG_STEP_SIZE_MA	50
+#define IAVG_START		600
+#define SOC_ZERO		0xFF
+static void backup_soc_and_iavg(struct pm8921_bms_chip *chip, int batt_temp,
+				int soc)
 {
-	struct timespec uptime;
-	int val;
+	u8 temp;
+	int iavg_ma = chip->prev_uuc_iavg_ma;
 
-	/* value of zero means the shutdown soc should not be used */
-	if (chip->shutdown_soc == 0)
-		return soc;
+	if (iavg_ma > IAVG_START)
+		temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+	else
+		temp = 0;
 
-	if (shutdown_soc_invalid) {
-		chip->shutdown_soc = 0;
-		return soc;
-	}
+	pm_bms_masked_write(chip, TEMP_IAVG_STORAGE,
+			TEMP_IAVG_STORAGE_USE_MASK, temp);
 
-	do_posix_clock_monotonic_gettime(&uptime);
+	/* since only 6 bits are available for SOC, we store half the soc */
+	if (soc == 0)
+		temp = SOC_ZERO;
+	else
+		temp = soc;
 
-	if (uptime.tv_sec >= MAX_SHUTDOWN_ADJUST_SECONDS) {
-		/*
-		 * adjusted for a long time now, switch to reporting the
-		 * calculated soc
-		 */
-		chip->shutdown_soc = 0;
-		return soc;
-	}
-
-	val = ((MAX_SHUTDOWN_ADJUST_SECONDS - uptime.tv_sec)
-		* chip->shutdown_soc
-		+ uptime.tv_sec * soc);
-	val /= MAX_SHUTDOWN_ADJUST_SECONDS;
-	pr_debug("shutdown_soc = %d, adj soc = %d, calc soc = %d\n",
-				chip->shutdown_soc, val, soc);
-
-	return val;
+	/* don't store soc if temperature is below 5degC */
+	if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
+		pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, temp);
 }
 
-static void backup_soc(struct pm8921_bms_chip *chip, int last_soc)
-{
-	/* TODO: if 0x107 is free for all variants 8917, 8038 etc */
-	pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, last_soc);
-}
-
-static void read_shutdown_soc(struct pm8921_bms_chip *chip)
+static void read_shutdown_soc_and_iavg(struct pm8921_bms_chip *chip)
 {
 	int rc;
 	u8 temp;
 
+	rc = pm8xxx_readb(chip->dev->parent, TEMP_IAVG_STORAGE, &temp);
+	if (rc) {
+		pr_err("failed to read addr = %d %d assuming %d\n",
+				TEMP_IAVG_STORAGE, rc, IAVG_START);
+		chip->shutdown_iavg_ua = IAVG_START;
+	} else {
+		temp &= TEMP_IAVG_STORAGE_USE_MASK;
+
+		if (temp == 0) {
+			chip->shutdown_iavg_ua = IAVG_START;
+		} else {
+			chip->shutdown_iavg_ua = IAVG_START
+					+ IAVG_STEP_SIZE_MA * (temp + 1);
+		}
+	}
+
 	rc = pm8xxx_readb(chip->dev->parent, TEMP_SOC_STORAGE, &temp);
-	if (rc)
+	if (rc) {
 		pr_err("failed to read addr = %d %d\n", TEMP_SOC_STORAGE, rc);
-	else
+	} else {
 		chip->shutdown_soc = temp;
 
-	pr_debug("shutdown_soc = %d\n", chip->shutdown_soc);
+		if (chip->shutdown_soc == 0) {
+			pr_debug("No shutdown soc available\n");
+			shutdown_soc_invalid = 1;
+			chip->shutdown_iavg_ua = 0;
+		} else if (chip->shutdown_soc == SOC_ZERO) {
+			chip->shutdown_soc = 0;
+		}
+	}
+
+	if (chip->ignore_shutdown_soc) {
+		shutdown_soc_invalid = 1;
+		chip->shutdown_soc = 0;
+		chip->shutdown_iavg_ua = 0;
+	}
+
+	pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d\n",
+			chip->shutdown_soc,
+			chip->shutdown_iavg_ua,
+			shutdown_soc_invalid);
 }
 
-void pm8921_bms_invalidate_shutdown_soc(void)
+static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
+			int batt_temp,
+			int chargecycles,
+			int fcc_uah,
+			int uuc_uah,
+			int cc_uah,
+			int shutdown_soc,
+			int *rc_uah,
+			int *ocv_uv)
 {
-	pr_debug("Invalidating shutdown soc - the battery was removed\n");
-	shutdown_soc_invalid = 1;
-	if (the_chip)
-		the_chip->shutdown_soc = 0;
-}
-EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
+	s64 rc;
+	int pc, new_pc;
+	int batt_temp_degc = batt_temp / 10;
+	int ocv;
 
+	rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
+	rc = div_s64(rc, 100) + cc_uah + uuc_uah;
+	pc = DIV_ROUND_CLOSEST((int)rc * 100, fcc_uah);
+	pc = clamp(pc, 0, 100);
+
+	ocv = interpolate_ocv(chip, batt_temp_degc, pc);
+
+	pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
+			shutdown_soc, fcc_uah, uuc_uah, (int)rc, pc, ocv);
+	new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+	pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+
+	while (abs(new_pc - pc) > 1) {
+		int delta_mv = 5;
+
+		if (new_pc > pc)
+			delta_mv = -1 * delta_mv;
+
+		ocv = ocv + delta_mv;
+		new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+		pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+	}
+
+	*ocv_uv = ocv * 1000;
+	*rc_uah = (int)rc;
+}
+
+static void adjust_rc_and_uuc_for_specific_soc(
+						struct pm8921_bms_chip *chip,
+						int batt_temp,
+						int chargecycles,
+						int soc,
+						int fcc_uah,
+						int uuc_uah,
+						int cc_uah,
+						int rc_uah,
+						int rbatt,
+						int *ret_ocv,
+						int *ret_rc,
+						int *ret_uuc,
+						int *ret_rbatt)
+{
+	int ocv_uv;
+
+	find_ocv_for_soc(chip, batt_temp, chargecycles,
+					fcc_uah, uuc_uah, cc_uah,
+					soc,
+					&rc_uah, &ocv_uv);
+
+	*ret_ocv = ocv_uv;
+	*ret_rbatt = rbatt;
+	*ret_rc = rc_uah;
+	*ret_uuc = uuc_uah;
+}
+
+#define SOC_CATCHUP_SEC_MAX		600
+#define SOC_CATCHUP_SEC_PER_PERCENT	60
+#define MAX_CATCHUP_SOC	(SOC_CATCHUP_SEC_MAX/SOC_CATCHUP_SEC_PER_PERCENT)
+static int scale_soc_while_chg(struct pm8921_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 we are not charging return last soc */
+	if (the_chip->start_percent == -EINVAL)
+		return prev_soc;
+
+	/* if soc is called in quick succession return the last soc */
+	if (delta_time_us < USEC_PER_SEC)
+		return prev_soc;
+
+	chg_time_sec = DIV_ROUND_UP(the_chip->charge_time_us, USEC_PER_SEC);
+	catch_up_sec = DIV_ROUND_UP(the_chip->catch_up_time_us, USEC_PER_SEC);
+	pr_debug("cts= %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
+
+	/*
+	 * if we have been 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;
+}
+
+#define SHOW_SHUTDOWN_SOC_MS	30000
+static void shutdown_soc_work(struct work_struct *work)
+{
+	struct pm8921_bms_chip *chip = container_of(work,
+				struct pm8921_bms_chip, shutdown_soc_work.work);
+
+	pr_debug("not forcing shutdown soc anymore\n");
+	/* it has been  30 seconds since init, no need to show shutdown soc */
+	chip->shutdown_soc_timer_expired = 1;
+}
+
+static bool is_shutdown_soc_within_limits(struct pm8921_bms_chip *chip, int soc)
+{
+	if (shutdown_soc_invalid) {
+		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);
+		shutdown_soc_invalid = 1;
+		return 0;
+	}
+
+	return 1;
+}
 /*
  * Remaining Usable Charge = remaining_charge (charge at ocv instance)
  *				- coloumb counter charge
@@ -1588,9 +1873,14 @@
 	int remaining_charge_uah, soc;
 	int cc_uah;
 	int rbatt;
-	int shutdown_adjusted_soc;
 	int iavg_ua;
-	int delta_time_us;
+	int delta_time_s;
+	int new_ocv;
+	int new_rc_uah;
+	int new_ucc_uah;
+	int new_rbatt;
+	int shutdown_soc;
+	static int firsttime = 1;
 
 	calculate_soc_params(chip, raw, batt_temp, chargecycles,
 						&fcc_uah,
@@ -1599,7 +1889,7 @@
 						&cc_uah,
 						&rbatt,
 						&iavg_ua,
-						&delta_time_us);
+						&delta_time_s);
 
 	/* calculate remaining usable charge */
 	remaining_usable_charge_uah = remaining_charge_uah
@@ -1612,13 +1902,43 @@
 						fcc_uah, unusable_charge_uah);
 		soc = 0;
 	} else {
-		soc = (remaining_usable_charge_uah * 100)
-			/ (fcc_uah - unusable_charge_uah);
+		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+					(fcc_uah - unusable_charge_uah));
+	}
+
+	if (firsttime && soc < 0) {
+		/*
+		 * first time calcualtion and the pon ocv  is too low resulting
+		 * in a bad soc. Adjust ocv such that we get 0 soc
+		 */
+		pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
+		adjust_rc_and_uuc_for_specific_soc(
+						chip,
+						batt_temp, chargecycles,
+						0,
+						fcc_uah, unusable_charge_uah,
+						cc_uah, remaining_charge_uah,
+						rbatt,
+						&new_ocv,
+						&new_rc_uah, &new_ucc_uah,
+						&new_rbatt);
+		chip->last_ocv_uv = new_ocv;
+		remaining_charge_uah = new_rc_uah;
+		unusable_charge_uah = new_ucc_uah;
+		rbatt = new_rbatt;
+
+		remaining_usable_charge_uah = remaining_charge_uah
+					- cc_uah
+					- unusable_charge_uah;
+
+		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+					(fcc_uah - unusable_charge_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;
-	pr_debug("SOC = %u%%\n", soc);
 
 	if (bms_fake_battery != -EINVAL) {
 		pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
@@ -1640,30 +1960,221 @@
 		soc = 0;
 	}
 
-	soc = adjust_soc(chip, soc, batt_temp, rbatt,
-					fcc_uah, unusable_charge_uah, cc_uah);
+	mutex_lock(&soc_invalidation_mutex);
+	shutdown_soc = chip->shutdown_soc;
 
-	if (last_soc == -EINVAL || soc <= last_soc) {
-		last_soc = soc;
-	} else {
+	if (firsttime && soc != shutdown_soc
+			&& is_shutdown_soc_within_limits(chip, soc)) {
 		/*
-		 * soc > last_soc
-		 * the device must be charging for reporting a higher soc, if
-		 * not ignore this soc and continue reporting the last_soc
+		 * soc for the first time - use shutdown soc
+		 * to adjust pon ocv since it is a small percent away from
+		 * the real soc
 		 */
-		if (the_chip->start_percent != -EINVAL)
-			last_soc = soc;
-		else
-			pr_debug("soc = %d reporting last_soc = %d\n", soc,
-								last_soc);
+		pr_debug("soc = %d before forcing shutdown_soc = %d\n",
+							soc, shutdown_soc);
+		adjust_rc_and_uuc_for_specific_soc(
+						chip,
+						batt_temp, chargecycles,
+						shutdown_soc,
+						fcc_uah, unusable_charge_uah,
+						cc_uah, remaining_charge_uah,
+						rbatt,
+						&new_ocv,
+						&new_rc_uah, &new_ucc_uah,
+						&new_rbatt);
+
+		chip->pon_ocv_uv = chip->last_ocv_uv;
+		chip->last_ocv_uv = new_ocv;
+		remaining_charge_uah = new_rc_uah;
+		unusable_charge_uah = new_ucc_uah;
+		rbatt = new_rbatt;
+
+		remaining_usable_charge_uah = remaining_charge_uah
+					- cc_uah
+					- unusable_charge_uah;
+
+		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+					(fcc_uah - unusable_charge_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(&soc_invalidation_mutex);
+
+	calculated_soc = adjust_soc(chip, soc, batt_temp,
+			rbatt, fcc_uah, unusable_charge_uah, cc_uah);
+
+	pr_debug("calculated SOC = %d\n", calculated_soc);
+	firsttime = 0;
+	return calculated_soc;
+}
+
+#define CALCULATE_SOC_MS	20000
+static void calculate_soc_work(struct work_struct *work)
+{
+	struct pm8921_bms_chip *chip = container_of(work,
+				struct pm8921_bms_chip,
+				calculate_soc_delayed_work.work);
+	int batt_temp, rc;
+	struct pm8xxx_adc_chan_result result;
+	struct pm8921_soc_params raw;
+	int soc;
+
+	rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					chip->batt_temp_channel, 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, last_chargecycles);
+	mutex_unlock(&chip->last_ocv_uv_mutex);
+
+	schedule_delayed_work(&chip->calculate_soc_delayed_work,
+			round_jiffies_relative(msecs_to_jiffies
+			(CALCULATE_SOC_MS)));
+}
+
+static int report_state_of_charge(struct pm8921_bms_chip *chip)
+{
+	int soc = calculated_soc;
+	int delta_time_us;
+	struct timespec now;
+	struct pm8xxx_adc_chan_result result;
+	int batt_temp;
+	int rc;
+
+	rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					the_chip->batt_temp_channel, 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;
 	}
 
-	shutdown_adjusted_soc = adjust_for_shutdown_soc(chip, last_soc);
-	backup_soc(chip, shutdown_adjusted_soc);
+	/*
+	 * account for charge time - limit it to SOC_CATCHUP_SEC to
+	 * avoid overflows when charging continues for extended periods
+	 */
+	if (the_chip->start_percent != -EINVAL) {
+		if (the_chip->charge_time_us == 0) {
+			/*
+			 * calculating soc for the first time
+			 * after start of chg. Initialize catchup time
+			 */
+			if (abs(soc - last_soc) < MAX_CATCHUP_SOC)
+				the_chip->catch_up_time_us =
+				(soc - last_soc) * SOC_CATCHUP_SEC_PER_PERCENT
+					 * USEC_PER_SEC;
+			else
+				the_chip->catch_up_time_us =
+				SOC_CATCHUP_SEC_MAX * USEC_PER_SEC;
 
-	return shutdown_adjusted_soc;
+			if (the_chip->catch_up_time_us < 0)
+				the_chip->catch_up_time_us = 0;
+		}
+
+		/* add charge time */
+		if (the_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 (last_soc == soc)
+			the_chip->catch_up_time_us = 0;
+	}
+
+	/* last_soc < soc  ... scale and catch up */
+	if (last_soc != -EINVAL && last_soc < soc && soc != 100)
+		soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
+
+	if (chip->shutdown_soc != 0
+			&& !shutdown_soc_invalid
+			&& !chip->shutdown_soc_timer_expired) {
+		/*
+		 * force shutdown soc if it is valid and the shutdown soc show
+		 * timer has not expired
+		 */
+		soc = chip->shutdown_soc;
+
+		pr_debug("Forcing SHUTDOWN_SOC = %d\n", soc);
+	}
+
+	last_soc = soc;
+	backup_soc_and_iavg(chip, batt_temp, last_soc);
+	pr_debug("Reported SOC = %d\n", last_soc);
+	chip->t_soc_queried = now;
+
+	return last_soc;
 }
 
+void pm8921_bms_invalidate_shutdown_soc(void)
+{
+	int calculate_soc = 0;
+	struct pm8921_bms_chip *chip = the_chip;
+	int batt_temp, rc;
+	struct pm8xxx_adc_chan_result result;
+	struct pm8921_soc_params raw;
+	int soc;
+
+	pr_debug("Invalidating shutdown soc - the battery was removed\n");
+	if (shutdown_soc_invalid)
+		return;
+
+	mutex_lock(&soc_invalidation_mutex);
+	shutdown_soc_invalid = 1;
+	last_soc = -EINVAL;
+	if (the_chip) {
+		/* reset to pon ocv undoing what the adjusting did */
+		if (the_chip->pon_ocv_uv) {
+			the_chip->last_ocv_uv = the_chip->pon_ocv_uv;
+			calculate_soc = 1;
+			pr_debug("resetting ocv to pon_ocv = %d\n",
+						the_chip->pon_ocv_uv);
+		}
+	}
+	mutex_unlock(&soc_invalidation_mutex);
+	if (!calculate_soc)
+		return;
+
+	rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+	if (rc) {
+		pr_err("error reading adc channel = %d, rc = %d\n",
+					chip->batt_temp_channel, 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, last_chargecycles);
+	mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
+
 #define MIN_DELTA_625_UV	1000
 static void calib_hkadc(struct pm8921_bms_chip *chip)
 {
@@ -1672,10 +2183,11 @@
 	int usb_chg;
 	int this_delta;
 
+	mutex_lock(&chip->calib_mutex);
 	rc = pm8xxx_adc_read(the_chip->ref1p25v_channel, &result);
 	if (rc) {
 		pr_err("ADC failed for 1.25volts rc = %d\n", rc);
-		return;
+		goto out;
 	}
 	voltage = xoadc_reading_to_microvolt(result.adc_code);
 
@@ -1687,7 +2199,7 @@
 	rc = pm8xxx_adc_read(the_chip->ref625mv_channel, &result);
 	if (rc) {
 		pr_err("ADC failed for 1.25volts rc = %d\n", rc);
-		return;
+		goto out;
 	}
 	voltage = xoadc_reading_to_microvolt(result.adc_code);
 
@@ -1714,6 +2226,8 @@
 			chip->xoadc_v0625_usb_absent,
 			last_usb_cal_delta_uv);
 	}
+out:
+	mutex_unlock(&chip->calib_mutex);
 }
 
 static void calibrate_hkadc_work(struct work_struct *work)
@@ -1729,6 +2243,19 @@
 	schedule_work(&the_chip->calib_hkadc_work);
 }
 
+#define HKADC_CALIB_DELAY_MS	600000
+static void calibrate_hkadc_delayed_work(struct work_struct *work)
+{
+	struct pm8921_bms_chip *chip = container_of(work,
+				struct pm8921_bms_chip,
+				calib_hkadc_delayed_work.work);
+
+	calib_hkadc(chip);
+	schedule_delayed_work(&chip->calib_hkadc_delayed_work,
+			round_jiffies_relative(msecs_to_jiffies
+			(HKADC_CALIB_DELAY_MS)));
+}
+
 int pm8921_bms_get_vsense_avg(int *result)
 {
 	int rc = -EINVAL;
@@ -1774,33 +2301,12 @@
 
 int pm8921_bms_get_percent_charge(void)
 {
-	int batt_temp, rc;
-	struct pm8xxx_adc_chan_result result;
-	struct pm8921_soc_params raw;
-	int soc;
-
 	if (!the_chip) {
 		pr_err("called before initialization\n");
 		return -EINVAL;
 	}
 
-	rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
-	if (rc) {
-		pr_err("error reading adc channel = %d, rc = %d\n",
-					the_chip->batt_temp_channel, rc);
-		return rc;
-	}
-	pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
-						result.measurement);
-	batt_temp = (int)result.physical;
-
-	mutex_lock(&the_chip->last_ocv_uv_mutex);
-	read_soc_params_raw(the_chip, &raw);
-
-	soc = calculate_state_of_charge(the_chip, &raw,
-					batt_temp, last_chargecycles);
-	mutex_unlock(&the_chip->last_ocv_uv_mutex);
-	return soc;
+	return report_state_of_charge(the_chip);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_get_percent_charge);
 
@@ -1815,7 +2321,7 @@
 	int cc_uah;
 	int rbatt;
 	int iavg_ua;
-	int delta_time_us;
+	int delta_time_s;
 
 	if (!the_chip) {
 		pr_err("called before initialization\n");
@@ -1843,7 +2349,7 @@
 						&cc_uah,
 						&rbatt,
 						&iavg_ua,
-						&delta_time_us);
+						&delta_time_s);
 	mutex_unlock(&the_chip->last_ocv_uv_mutex);
 
 	return rbatt;
@@ -1881,32 +2387,21 @@
 #define OCV_TOL_NO_OCV		0x00
 void pm8921_bms_charging_began(void)
 {
-	int batt_temp, rc;
-	struct pm8xxx_adc_chan_result result;
 	struct pm8921_soc_params raw;
 
-	rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
-	if (rc) {
-		pr_err("error reading adc channel = %d, rc = %d\n",
-				the_chip->batt_temp_channel, rc);
-		return;
-	}
-	pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
-						result.measurement);
-	batt_temp = (int)result.physical;
-
 	mutex_lock(&the_chip->last_ocv_uv_mutex);
 	read_soc_params_raw(the_chip, &raw);
-
-	the_chip->start_percent = calculate_state_of_charge(the_chip, &raw,
-					batt_temp, last_chargecycles);
 	mutex_unlock(&the_chip->last_ocv_uv_mutex);
 
+	the_chip->start_percent = report_state_of_charge(the_chip);
+
 	bms_start_percent = the_chip->start_percent;
 	bms_start_ocv_uv = raw.last_good_ocv_uv;
 	calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah);
 	pm_bms_masked_write(the_chip, BMS_TOLERANCES,
 			IBAT_TOL_MASK, IBAT_TOL_DEFAULT);
+	the_chip->charge_time_us = 0;
+	the_chip->catch_up_time_us = 0;
 	pr_debug("start_percent = %u%%\n", the_chip->start_percent);
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
@@ -1971,7 +2466,6 @@
 		last_real_fcc_mah = new_fcc_uah/1000;
 		last_real_fcc_batt_temp = batt_temp;
 		readjust_fcc_table();
-
 	}
 
 	if (is_battery_full) {
@@ -1985,7 +2479,7 @@
 		 * forget the old cc value
 		 */
 		the_chip->last_cc_uah = 0;
-		pr_debug("EOC ocv_reading = 0x%x cc = 0x%x\n",
+		pr_debug("EOC BATT_FULL ocv_reading = 0x%x cc = 0x%x\n",
 				the_chip->ocv_reading_at_100,
 				the_chip->cc_reading_at_100);
 	}
@@ -2011,6 +2505,8 @@
 			last_chargecycles);
 	the_chip->start_percent = -EINVAL;
 	the_chip->end_percent = -EINVAL;
+	the_chip->charge_time_us = 0;
+	the_chip->catch_up_time_us = 0;
 	pm_bms_masked_write(the_chip, BMS_TOLERANCES,
 				IBAT_TOL_MASK, IBAT_TOL_NOCHG);
 }
@@ -2157,94 +2653,6 @@
 	return -EINVAL;
 }
 
-static int pm8921_bms_suspend(struct device *dev)
-{
-	int rc;
-	struct pm8xxx_adc_chan_result result;
-	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
-	struct pm8921_soc_params raw;
-	int fcc_uah;
-	int remaining_charge_uah;
-	int cc_uah;
-
-	chip->batt_temp_suspend = 0;
-	rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
-	if (rc) {
-		pr_err("error reading adc channel = %d, rc = %d\n",
-					chip->batt_temp_channel, rc);
-	}
-	chip->batt_temp_suspend = (int)result.physical;
-
-	mutex_lock(&chip->last_ocv_uv_mutex);
-	read_soc_params_raw(chip, &raw);
-
-	fcc_uah = calculate_fcc_uah(chip,
-			chip->batt_temp_suspend, last_chargecycles);
-	pr_debug("FCC = %uuAh batt_temp = %d, cycles = %d\n",
-			fcc_uah, chip->batt_temp_suspend, last_chargecycles);
-	/* calculate remainging charge */
-	remaining_charge_uah = calculate_remaining_charge_uah(chip, &raw,
-					fcc_uah, chip->batt_temp_suspend,
-					last_chargecycles);
-	pr_debug("RC = %uuAh\n", remaining_charge_uah);
-
-	/* calculate cc micro_volt_hour */
-	calculate_cc_uah(chip, raw.cc, &cc_uah);
-	pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n",
-				cc_uah, raw.cc,
-				(int64_t)raw.cc - chip->cc_reading_at_100,
-				chip->cc_reading_at_100);
-	chip->soc_rbatt_suspend = ((remaining_charge_uah - cc_uah) * 100)
-						/ fcc_uah;
-	mutex_unlock(&chip->last_ocv_uv_mutex);
-
-	return 0;
-}
-
-#define DELTA_RBATT_PERCENT	10
-static int pm8921_bms_resume(struct device *dev)
-{
-	struct pm8921_rbatt_params raw;
-	struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
-	int rbatt;
-	int expected_rbatt;
-	int scalefactor;
-	int delta_rbatt;
-
-	read_rbatt_params_raw(chip, &raw);
-	rbatt = calculate_rbatt_resume(chip, &raw);
-
-	if (rbatt < 0)
-		return 0;
-
-	expected_rbatt
-		= (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
-
-	if (chip->rbatt_sf_lut) {
-		scalefactor = interpolate_scalingfactor(chip,
-						chip->rbatt_sf_lut,
-						chip->batt_temp_suspend / 10,
-						chip->soc_rbatt_suspend);
-		rbatt = rbatt * 100 / scalefactor;
-	}
-
-	delta_rbatt = expected_rbatt - rbatt;
-	if (delta_rbatt)
-		delta_rbatt = -delta_rbatt;
-	/*
-	 * only update last_rbatt if rbatt is within some
-	 * percent of expected_rbatt
-	 */
-	if (delta_rbatt * 100 <= DELTA_RBATT_PERCENT * expected_rbatt)
-		last_rbatt = rbatt;
-
-	return 0;
-}
-
-static const struct dev_pm_ops pm8921_pm_ops = {
-	.suspend	= pm8921_bms_suspend,
-	.resume		= pm8921_bms_resume,
-};
 #define EN_BMS_BIT	BIT(7)
 #define EN_PON_HS_BIT	BIT(0)
 static int __devinit pm8921_bms_hw_init(struct pm8921_bms_chip *chip)
@@ -2359,7 +2767,6 @@
 }
 
 enum bms_request_operation {
-	CALC_RBATT,
 	CALC_FCC,
 	CALC_PC,
 	CALC_SOC,
@@ -2420,18 +2827,13 @@
 	int ret = 0;
 	int ibat_ua, vbat_uv;
 	struct pm8921_soc_params raw;
-	struct pm8921_rbatt_params rraw;
 
 	read_soc_params_raw(the_chip, &raw);
-	read_rbatt_params_raw(the_chip, &rraw);
 
 	*val = 0;
 
 	/* global irq number passed in via data */
 	switch (param) {
-	case CALC_RBATT:
-		*val = calculate_rbatt_resume(the_chip, &rraw);
-		break;
 	case CALC_FCC:
 		*val = calculate_fcc_uah(the_chip, test_batt_temp,
 							test_chargecycle);
@@ -2490,10 +2892,8 @@
 	int param = (int)data;
 	int ret = 0;
 	struct pm8921_soc_params raw;
-	struct pm8921_rbatt_params rraw;
 
 	read_soc_params_raw(the_chip, &raw);
-	read_rbatt_params_raw(the_chip, &rraw);
 
 	*val = 0;
 
@@ -2505,15 +2905,6 @@
 	case LAST_GOOD_OCV_VALUE:
 		*val = raw.last_good_ocv_uv;
 		break;
-	case VBATT_FOR_RBATT:
-		*val = rraw.vbatt_for_rbatt_uv;
-		break;
-	case VSENSE_FOR_RBATT:
-		*val = rraw.vsense_for_rbatt_uv;
-		break;
-	case OCV_FOR_RBATT:
-		*val = rraw.ocv_for_rbatt_uv;
-		break;
 	case VSENSE_AVG:
 		read_vsense_avg(the_chip, (uint *)val);
 		break;
@@ -2609,8 +3000,6 @@
 	debugfs_create_file("read_vsense_avg", 0644, chip->dent,
 				(void *)VSENSE_AVG, &reading_fops);
 
-	debugfs_create_file("show_rbatt", 0644, chip->dent,
-				(void *)CALC_RBATT, &calc_fops);
 	debugfs_create_file("show_fcc", 0644, chip->dent,
 				(void *)CALC_FCC, &calc_fops);
 	debugfs_create_file("show_pc", 0644, chip->dent,
@@ -2716,13 +3105,20 @@
 	mutex_init(&chip->last_ocv_uv_mutex);
 	chip->dev = &pdev->dev;
 	chip->r_sense = pdata->r_sense;
-	chip->i_test = pdata->i_test;
-	chip->v_failure = pdata->v_failure;
+	chip->v_cutoff = pdata->v_cutoff;
 	chip->max_voltage_uv = pdata->max_voltage_uv;
 	chip->batt_type = pdata->battery_type;
 	chip->rconn_mohm = pdata->rconn_mohm;
 	chip->start_percent = -EINVAL;
 	chip->end_percent = -EINVAL;
+	chip->shutdown_soc_valid_limit = pdata->shutdown_soc_valid_limit;
+	chip->adjust_soc_low_threshold = pdata->adjust_soc_low_threshold;
+	if (chip->adjust_soc_low_threshold >= 45)
+		chip->adjust_soc_low_threshold = 45;
+
+	chip->prev_pc_unusable = -EINVAL;
+
+	chip->ignore_shutdown_soc = pdata->ignore_shutdown_soc;
 	rc = set_battery_data(chip);
 	if (rc) {
 		pr_err("%s bad battery data %d\n", __func__, rc);
@@ -2746,7 +3142,14 @@
 	chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
 	chip->revision = pm8xxx_get_revision(chip->dev->parent);
 	chip->enable_fcc_learning = pdata->enable_fcc_learning;
+
+	mutex_init(&chip->calib_mutex);
 	INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
+	INIT_DELAYED_WORK(&chip->calib_hkadc_delayed_work,
+				calibrate_hkadc_delayed_work);
+
+	INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
+			calculate_soc_work);
 
 	rc = request_irqs(chip, pdev);
 	if (rc) {
@@ -2760,7 +3163,7 @@
 		goto free_irqs;
 	}
 
-	read_shutdown_soc(chip);
+	read_shutdown_soc_and_iavg(chip);
 
 	platform_set_drvdata(pdev, chip);
 	the_chip = chip;
@@ -2773,20 +3176,25 @@
 	}
 	check_initial_ocv(chip);
 
-	/* initial hkadc calibration */
-	schedule_work(&chip->calib_hkadc_work);
+	/* start periodic hkadc calibration */
+	schedule_delayed_work(&chip->calib_hkadc_delayed_work, 0);
+
 	/* enable the vbatt reading interrupts for scheduling hkadc calib */
 	pm8921_bms_enable_irq(chip, PM8921_BMS_GOOD_OCV);
 	pm8921_bms_enable_irq(chip, PM8921_BMS_OCV_FOR_R);
 
-	INIT_DELAYED_WORK(&chip->uuc_timer_work, uuc_timer_work);
-	schedule_delayed_work(&chip->uuc_timer_work,
-					msecs_to_jiffies(UUC_TIMER_MS));
+	calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
 
 	get_battery_uvolts(chip, &vbatt);
 	pr_info("OK battery_capacity_at_boot=%d volt = %d ocv = %d\n",
 				pm8921_bms_get_percent_charge(),
 				vbatt, chip->last_ocv_uv);
+
+	INIT_DELAYED_WORK(&chip->shutdown_soc_work, shutdown_soc_work);
+	schedule_delayed_work(&chip->shutdown_soc_work,
+			round_jiffies_relative(msecs_to_jiffies
+			(SHOW_SHUTDOWN_SOC_MS)));
+
 	return 0;
 
 free_irqs:
@@ -2814,7 +3222,6 @@
 	.driver	= {
 		.name	= PM8921_BMS_DEV_NAME,
 		.owner	= THIS_MODULE,
-		.pm	= &pm8921_pm_ops
 	},
 };
 
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 85b653d..6330883 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -271,6 +271,7 @@
 	enum pm8921_chg_led_src_config	led_src_config;
 	bool				host_mode;
 	u8				active_path;
+	int				recent_reported_soc;
 };
 
 /* user space parameter to limit usb current */
@@ -327,6 +328,10 @@
 	return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
 }
 
+static int is_batfet_closed(struct pm8921_chg_chip *chip)
+{
+	return pm_chg_get_rt_status(chip, BATFET_IRQ);
+}
 #define CAPTURE_FSM_STATE_CMD	0xC2
 #define READ_BANK_7		0x70
 #define READ_BANK_4		0x40
@@ -1400,6 +1405,7 @@
 	if (percent_soc <= 10)
 		pr_warn("low battery charge = %d%%\n", percent_soc);
 
+	chip->recent_reported_soc = percent_soc;
 	return percent_soc;
 }
 
@@ -1741,6 +1747,15 @@
 }
 EXPORT_SYMBOL(pm8921_is_battery_present);
 
+int pm8921_is_batfet_closed(void)
+{
+	if (!the_chip) {
+		pr_err("called before init\n");
+		return -EINVAL;
+	}
+	return is_batfet_closed(the_chip);
+}
+EXPORT_SYMBOL(pm8921_is_batfet_closed);
 /*
  * Disabling the charge current limit causes current
  * current limits to have no monitoring. An adequate charger
@@ -2768,6 +2783,7 @@
  *		per update_time minutes
  *
  */
+#define LOW_SOC_HEARTBEAT_MS	20000
 static void update_heartbeat(struct work_struct *work)
 {
 	struct delayed_work *dwork = to_delayed_work(work);
@@ -2776,7 +2792,12 @@
 
 	pm_chg_failed_clear(chip, 1);
 	power_supply_changed(&chip->batt_psy);
-	schedule_delayed_work(&chip->update_heartbeat_work,
+	if (chip->recent_reported_soc <= 20)
+		schedule_delayed_work(&chip->update_heartbeat_work,
+			      round_jiffies_relative(msecs_to_jiffies
+						     (LOW_SOC_HEARTBEAT_MS)));
+	else
+		schedule_delayed_work(&chip->update_heartbeat_work,
 			      round_jiffies_relative(msecs_to_jiffies
 						     (chip->update_time)));
 }
@@ -2787,6 +2808,8 @@
 
 static int ichg_threshold_ua = -400000;
 module_param(ichg_threshold_ua, int, 0644);
+
+#define PM8921_CHG_VDDMAX_RES_MV	10
 static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
 {
 	int ichg_meas_ua, vbat_uv;
@@ -2846,9 +2869,11 @@
 		return;
 	}
 
+	adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
+					* PM8921_CHG_VDDMAX_RES_MV;
+
 	if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
 		adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
-
 	pr_debug("adjusting vdd_max_mv to %d to make "
 		"vbat_batt_termial_uv = %d to %d\n",
 		adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index 861bac8..e48257a 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -685,13 +685,13 @@
 		goto free_chip;
 	}
 
-	INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
-	schedule_delayed_work(&chip->calib_ccadc_work, 0);
 
 	disable_irq_nosync(chip->eoc_irq);
 
 	platform_set_drvdata(pdev, chip);
 	the_chip = chip;
+	INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
+	schedule_delayed_work(&chip->calib_ccadc_work, 0);
 
 	create_debugfs_entries(chip);
 
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 4dd6d68..465e512 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -47,6 +47,8 @@
 #define USB_REG_START_OFFSET 0x90
 #define USB_REG_END_OFFSET 0x250
 
+static struct workqueue_struct  *ehci_wq;
+
 struct msm_hsic_hcd {
 	struct ehci_hcd		ehci;
 	struct device		*dev;
@@ -66,6 +68,9 @@
 	uint32_t		bus_perf_client;
 	uint32_t		wakeup_int_cnt;
 	enum usb_vdd_type	vdd_type;
+
+	struct work_struct	bus_vote_w;
+	bool			bus_vote;
 };
 
 struct msm_hsic_hcd *__mehci;
@@ -658,11 +663,8 @@
 		dev_err(mehci->dev, "unable to set vddcx voltage for VDD MIN\n");
 
 	if (mehci->bus_perf_client && debug_bus_voting_enabled) {
-		ret = msm_bus_scale_client_update_request(
-				mehci->bus_perf_client, 0);
-		if (ret)
-			dev_err(mehci->dev, "%s: Failed to dvote for "
-				   "bus bandwidth %d\n", __func__, ret);
+		mehci->bus_vote = false;
+		queue_work(ehci_wq, &mehci->bus_vote_w);
 	}
 
 	atomic_set(&mehci->in_lpm, 1);
@@ -697,11 +699,8 @@
 	}
 
 	if (mehci->bus_perf_client && debug_bus_voting_enabled) {
-		ret = msm_bus_scale_client_update_request(
-				mehci->bus_perf_client, 1);
-		if (ret)
-			dev_err(mehci->dev, "%s: Failed to vote for "
-				   "bus bandwidth %d\n", __func__, ret);
+		mehci->bus_vote = true;
+		queue_work(ehci_wq, &mehci->bus_vote_w);
 	}
 
 	min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
@@ -769,6 +768,19 @@
 }
 #endif
 
+static void ehci_hsic_bus_vote_w(struct work_struct *w)
+{
+	struct msm_hsic_hcd *mehci =
+			container_of(w, struct msm_hsic_hcd, bus_vote_w);
+	int ret;
+
+	ret = msm_bus_scale_client_update_request(mehci->bus_perf_client,
+			mehci->bus_vote);
+	if (ret)
+		dev_err(mehci->dev, "%s: Failed to vote for bus bandwidth %d\n",
+				__func__, ret);
+}
+
 static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
 {
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -1294,6 +1306,15 @@
 		goto deinit_vddcx;
 	}
 
+	ehci_wq = create_singlethread_workqueue("ehci_wq");
+	if (!ehci_wq) {
+		dev_err(&pdev->dev, "unable to create workqueue\n");
+		ret = -ENOMEM;
+		goto deinit_vddcx;
+	}
+
+	INIT_WORK(&mehci->bus_vote_w, ehci_hsic_bus_vote_w);
+
 	ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to register HCD\n");
@@ -1339,11 +1360,8 @@
 		    msm_bus_scale_register_client(pdata->bus_scale_table);
 		/* Configure BUS performance parameters for MAX bandwidth */
 		if (mehci->bus_perf_client) {
-			ret = msm_bus_scale_client_update_request(
-					mehci->bus_perf_client, 1);
-			if (ret)
-				dev_err(&pdev->dev, "%s: Failed to vote for "
-					   "bus bandwidth %d\n", __func__, ret);
+			mehci->bus_vote = true;
+			queue_work(ehci_wq, &mehci->bus_vote_w);
 		} else {
 			dev_err(&pdev->dev, "%s: Failed to register BUS "
 						"scaling client!!\n", __func__);
@@ -1369,6 +1387,7 @@
 	return 0;
 
 unconfig_gpio:
+	destroy_workqueue(ehci_wq);
 	msm_hsic_config_gpios(mehci, 0);
 deinit_vddcx:
 	msm_hsic_init_vddcx(mehci, 0);
@@ -1396,6 +1415,14 @@
 		free_irq(mehci->wakeup_irq, mehci);
 	}
 
+	/*
+	 * If the update request is called after unregister, the request will
+	 * fail. Results are undefined if unregister is called in the middle of
+	 * update request.
+	 */
+	mehci->bus_vote = false;
+	cancel_work_sync(&mehci->bus_vote_w);
+
 	if (mehci->bus_perf_client)
 		msm_bus_scale_unregister_client(mehci->bus_perf_client);
 
@@ -1403,6 +1430,8 @@
 	device_init_wakeup(&pdev->dev, 0);
 	pm_runtime_set_suspended(&pdev->dev);
 
+	destroy_workqueue(ehci_wq);
+
 	usb_remove_hcd(hcd);
 	msm_hsic_config_gpios(mehci, 0);
 	msm_hsic_init_vddcx(mehci, 0);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index d911b62..6d14ec1 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -50,6 +50,7 @@
 static struct clk *mdp_lut_clk;
 int mdp_rev;
 int mdp_iommu_split_domain;
+u32 mdp_max_clk = 200000000;
 
 static struct platform_device *mdp_init_pdev;
 static struct regulator *footswitch;
@@ -2178,33 +2179,6 @@
 				__func__, mdp_hw_revision);
 }
 
-#ifdef CONFIG_FB_MSM_MDP40
-static void configure_mdp_core_clk_table(uint32 min_clk_rate)
-{
-	uint8 count;
-	uint32 current_rate;
-	if (mdp_clk && mdp_pdata && mdp_pdata->mdp_core_clk_table) {
-		min_clk_rate = clk_round_rate(mdp_clk, min_clk_rate);
-		if (clk_set_rate(mdp_clk, min_clk_rate) < 0)
-			printk(KERN_ERR "%s: clk_set_rate failed\n",
-							 __func__);
-		else {
-			count = 0;
-			current_rate = clk_get_rate(mdp_clk);
-			while (count < mdp_pdata->num_mdp_clk) {
-				if (mdp_pdata->mdp_core_clk_table[count]
-						< current_rate) {
-					mdp_pdata->
-					mdp_core_clk_table[count] =
-							current_rate;
-				}
-				count++;
-			}
-		}
-	}
-}
-#endif
-
 #ifdef CONFIG_MSM_BUS_SCALING
 static uint32_t mdp_bus_scale_handle;
 int mdp_bus_scale_update_request(uint32_t index)
@@ -2223,29 +2197,24 @@
 }
 #endif
 DEFINE_MUTEX(mdp_clk_lock);
-int mdp_set_core_clk(uint16 perf_level)
+int mdp_set_core_clk(u32 rate)
 {
 	int ret = -EINVAL;
-	if (mdp_clk && mdp_pdata
-		 && mdp_pdata->mdp_core_clk_table) {
-		if (perf_level > mdp_pdata->num_mdp_clk)
-			printk(KERN_ERR "%s invalid perf level\n", __func__);
-		else {
-			mutex_lock(&mdp_clk_lock);
-			ret = clk_set_rate(mdp_clk,
-				mdp_pdata->
-				mdp_core_clk_table[mdp_pdata->num_mdp_clk
-						 - perf_level]);
-			mutex_unlock(&mdp_clk_lock);
-			if (ret) {
-				printk(KERN_ERR "%s unable to set mdp_core_clk rate\n",
-					__func__);
-			}
-		}
-	}
+	if (mdp_clk)
+		ret = clk_set_rate(mdp_clk, rate);
+	if (ret)
+		pr_err("%s unable to set mdp clk rate", __func__);
+	else
+		pr_debug("%s mdp clk rate to be set %d: actual rate %ld\n",
+			__func__, rate, clk_get_rate(mdp_clk));
 	return ret;
 }
 
+int mdp_clk_round_rate(u32 rate)
+{
+	return clk_round_rate(mdp_clk, rate);
+}
+
 unsigned long mdp_get_core_clk(void)
 {
 	unsigned long clk_rate = 0;
@@ -2258,25 +2227,6 @@
 	return clk_rate;
 }
 
-unsigned long mdp_perf_level2clk_rate(uint32 perf_level)
-{
-	unsigned long clk_rate = 0;
-
-	if (mdp_pdata && mdp_pdata->mdp_core_clk_table) {
-		if (perf_level > mdp_pdata->num_mdp_clk) {
-			printk(KERN_ERR "%s invalid perf level\n", __func__);
-			clk_rate = mdp_get_core_clk();
-		} else {
-			clk_rate = mdp_pdata->
-				mdp_core_clk_table[mdp_pdata->num_mdp_clk
-					- perf_level];
-		}
-	} else
-		clk_rate = mdp_get_core_clk();
-
-	return clk_rate;
-}
-
 static int mdp_irq_clk_setup(struct platform_device *pdev,
 	char cont_splashScreen)
 {
@@ -2333,21 +2283,25 @@
 	}
 
 #ifdef CONFIG_FB_MSM_MDP40
-	/*
-	 * mdp_clk should greater than mdp_pclk always
-	 */
-	if (mdp_pdata && mdp_pdata->mdp_core_clk_rate) {
-		if (cont_splashScreen)
-			mdp_clk_rate = clk_get_rate(mdp_clk);
-		else
-			mdp_clk_rate = mdp_pdata->mdp_core_clk_rate;
 
-		mutex_lock(&mdp_clk_lock);
-		clk_set_rate(mdp_clk, mdp_clk_rate);
-		if (mdp_lut_clk != NULL)
-			clk_set_rate(mdp_lut_clk, mdp_clk_rate);
-		mutex_unlock(&mdp_clk_lock);
-	}
+	if (mdp_pdata)
+		mdp_max_clk = mdp_pdata->mdp_max_clk;
+	else
+		pr_err("%s cannot get mdp max clk!\n", __func__);
+
+	if (!mdp_max_clk)
+		pr_err("%s mdp max clk is zero!\n", __func__);
+
+	if (cont_splashScreen)
+		mdp_clk_rate = clk_get_rate(mdp_clk);
+	else
+		mdp_clk_rate = mdp_max_clk;
+
+	mutex_lock(&mdp_clk_lock);
+	clk_set_rate(mdp_clk, mdp_clk_rate);
+	if (mdp_lut_clk != NULL)
+		clk_set_rate(mdp_lut_clk, mdp_clk_rate);
+	mutex_unlock(&mdp_clk_lock);
 
 	MSM_FB_DEBUG("mdp_clk: mdp_clk=%d\n", (int)clk_get_rate(mdp_clk));
 #endif
@@ -2468,8 +2422,6 @@
 		mfd->ov1_wb_buf->size = 0;
 		mfd->mem_hid = 0;
 	}
-	mfd->ov0_blt_state  = 0;
-	mfd->use_ov0_blt = 0 ;
 
 	/* initialize Post Processing data*/
 	mdp_hist_lut_init();
@@ -2568,7 +2520,6 @@
 	case MIPI_VIDEO_PANEL:
 #ifndef CONFIG_FB_MSM_MDP303
 		mipi = &mfd->panel_info.mipi;
-		configure_mdp_core_clk_table((mipi->dsi_pclk_rate) * 23 / 20);
 		mdp4_dsi_vsync_init(0);
 		mfd->hw_refresh = TRUE;
 		mfd->dma_fnc = mdp4_dsi_video_overlay;
@@ -2613,7 +2564,6 @@
 #ifndef CONFIG_FB_MSM_MDP303
 		mfd->dma_fnc = mdp4_dsi_cmd_overlay;
 		mipi = &mfd->panel_info.mipi;
-		configure_mdp_core_clk_table((mipi->dsi_pclk_rate) * 3 / 2);
 		mdp4_dsi_rdptr_init(0);
 		if (mfd->panel_info.pdest == DISPLAY_1) {
 			if_no = PRIMARY_INTF_SEL;
@@ -2698,8 +2648,6 @@
 
 #ifdef CONFIG_FB_MSM_MDP40
 		mdp4_lcdc_vsync_init(0);
-		configure_mdp_core_clk_table((mfd->panel_info.clk_rate)
-								* 23 / 20);
 		if (mfd->panel.type == HDMI_PANEL) {
 			mfd->dma = &dma_e_data;
 			mdp4_display_intf_sel(EXTERNAL_INTF_SEL, LCDC_RGB_INTF);
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 76d06a0..293bd9b 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -812,7 +812,9 @@
 void mdp_disable_irq_nosync(uint32 term);
 int mdp_get_bytes_per_pixel(uint32_t format,
 				 struct msm_fb_data_type *mfd);
-int mdp_set_core_clk(uint16 perf_level);
+int mdp_set_core_clk(u32 rate);
+int mdp_clk_round_rate(u32 rate);
+
 unsigned long mdp_get_core_clk(void);
 unsigned long mdp_perf_level2clk_rate(uint32 perf_level);
 
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index cf8a9b2..cc4eae5 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -27,6 +27,7 @@
 extern uint32 mdp4_extn_disp;
 extern char *mmss_cc_base;	/* mutimedia sub system clock control */
 extern spinlock_t dsi_clk_lock;
+extern u32 mdp_max_clk;
 
 #define MDP4_OVERLAYPROC0_BASE	0x10000
 #define MDP4_OVERLAYPROC1_BASE	0x18000
@@ -361,6 +362,8 @@
 	uint32 blt_ov_done;
 	uint32 blt_dmap_koff;
 	uint32 blt_dmap_done;
+	uint32 req_clk;
+	uint32 req_bw;
 	uint32 luma_align_size;
 	struct mdp_overlay_pp_params pp_cfg;
 	struct mdp_overlay req_data;
@@ -610,9 +613,6 @@
 void mdp4_lcdc_wait4vsync(int cndx, long long *vtime);
 void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe);
-void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd);
-void mdp4_update_perf_level(u32 perf_level);
-void mdp4_set_perf_level(void);
 void mdp4_mddi_overlay_dmas_restore(void);
 
 #ifndef CONFIG_FB_MSM_MIPI_DSI
@@ -728,6 +728,12 @@
 {
 	/* empty */
 }
+static inline void mdp4_dsi_cmd_blt_start(struct msm_fb_data_type *mfd)
+{
+}
+static inline void mdp4_dsi_cmd_blt_stop(struct msm_fb_data_type *mfd)
+{
+}
 #endif  /* CONFIG_FB_MSM_MIPI_DSI */
 
 void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd,
@@ -914,6 +920,11 @@
 int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe,
 	unsigned long srcp0_addr, unsigned long srcp1_addr,
 	unsigned long srcp2_addr);
+int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe,
+				struct msm_fb_data_type *mfd);
+int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd,
+				struct mdp4_overlay_pipe *plist);
+void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, int flag);
 
 #ifndef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
 static inline void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index a6ffe82..f0a3639 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -104,7 +104,21 @@
 
 static DEFINE_MUTEX(iommu_mutex);
 static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db;
-static int new_perf_level;
+
+struct mdp4_overlay_perf {
+	u32 mdp_clk_rate;
+	u32 use_ov0_blt;
+	u32 use_ov1_blt;
+	u32 mdp_bw;
+};
+
+struct mdp4_overlay_perf perf_request = {
+	.mdp_bw = OVERLAY_PERF_LEVEL4,
+};
+struct mdp4_overlay_perf perf_current = {
+	.mdp_bw = OVERLAY_PERF_LEVEL4,
+};
+
 static struct ion_client *display_iclient;
 
 
@@ -2114,79 +2128,6 @@
 
 }
 
-static int mdp4_overlay_validate_downscale(struct mdp_overlay *req,
-	struct msm_fb_data_type *mfd, uint32 perf_level, uint32 pclk_rate)
-{
-	__u32 panel_clk_khz, mdp_clk_khz;
-	__u32 num_hsync_pix_clks, mdp_clks_per_hsync, src_wh;
-	__u32 hsync_period_ps, mdp_period_ps, total_hsync_period_ps;
-	unsigned long fill_rate_y_dir, fill_rate_x_dir;
-	unsigned long fillratex100, mdp_pixels_produced;
-	unsigned long mdp_clk_hz;
-
-	pr_debug("%s: LCDC Mode Downscale validation with MDP Core"
-		" Clk rate\n", __func__);
-	pr_debug("src_w %u, src_h %u, dst_w %u, dst_h %u\n",
-		req->src_rect.w, req->src_rect.h, req->dst_rect.w,
-		req->dst_rect.h);
-
-
-	panel_clk_khz = pclk_rate/1000;
-	mdp_clk_hz = mdp_perf_level2clk_rate(perf_level);
-
-	if (!mdp_clk_hz || !req->dst_rect.w || !req->dst_rect.h) {
-		pr_debug("mdp_perf_level2clk_rate returned 0,"
-			 "or dst_rect height/width is 0,"
-			 "Downscale Validation incomplete\n");
-		return 0;
-	}
-
-	mdp_clk_khz = mdp_clk_hz/1000;
-
-	num_hsync_pix_clks = mfd->panel_info.lcdc.h_back_porch +
-		mfd->panel_info.lcdc.h_front_porch +
-		mfd->panel_info.lcdc.h_pulse_width +
-		mfd->panel_info.xres;
-
-	hsync_period_ps = 1000000000/panel_clk_khz;
-	mdp_period_ps = 1000000000/mdp_clk_khz;
-
-	total_hsync_period_ps = num_hsync_pix_clks * hsync_period_ps;
-	mdp_clks_per_hsync = total_hsync_period_ps/mdp_period_ps;
-
-	pr_debug("hsync_period_ps %u, mdp_period_ps %u,"
-		"total_hsync_period_ps %u\n", hsync_period_ps,
-		mdp_period_ps, total_hsync_period_ps);
-
-	src_wh = req->src_rect.w * req->src_rect.h;
-	if (src_wh % req->dst_rect.h)
-		fill_rate_y_dir = (src_wh / req->dst_rect.h) + 1;
-	else
-		fill_rate_y_dir = (src_wh / req->dst_rect.h);
-
-	fill_rate_x_dir = (mfd->panel_info.xres - req->dst_rect.w)
-		+ req->src_rect.w;
-
-	if (fill_rate_y_dir >= fill_rate_x_dir)
-		fillratex100 = 100 * fill_rate_y_dir / mfd->panel_info.xres;
-	else
-		fillratex100 = 100 * fill_rate_x_dir / mfd->panel_info.xres;
-
-	pr_debug("mdp_clks_per_hsync %u, fill_rate_y_dir %lu,"
-		"fill_rate_x_dir %lu\n", mdp_clks_per_hsync,
-		fill_rate_y_dir, fill_rate_x_dir);
-
-	mdp_pixels_produced = 100 * mdp_clks_per_hsync/fillratex100;
-	pr_debug("fillratex100 %lu, mdp_pixels_produced %lu\n",
-		fillratex100, mdp_pixels_produced);
-	if (mdp_pixels_produced <= mfd->panel_info.xres) {
-		mdp4_stat.err_underflow++;
-		return -ERANGE;
-	}
-
-	return 0;
-}
-
 static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer,
 			struct mdp4_overlay_pipe **ppipe,
 			struct msm_fb_data_type *mfd)
@@ -2428,11 +2369,451 @@
 
 	pipe->transp = req->transp_mask;
 
+	pipe->flags = req->flags;
+
 	*ppipe = pipe;
 
 	return 0;
 }
 
+static int mdp4_calc_pipe_mdp_clk(struct msm_fb_data_type *mfd,
+				  struct mdp4_overlay_pipe *pipe)
+{
+	u32 pclk;
+	u32 xscale, yscale;
+	u32 hsync = 0;
+	u32 shift = 16;
+	u64 rst;
+	int ret = -EINVAL;
+
+	if (!pipe) {
+		pr_err("%s: pipe is null!\n", __func__);
+		pipe->req_bw = OVERLAY_PERF_LEVEL4;
+		return ret;
+	}
+	if (!mfd) {
+		pr_err("%s: mfd is null!\n", __func__);
+		pipe->req_bw = OVERLAY_PERF_LEVEL4;
+		return ret;
+	}
+
+	/*
+	 * Serveral special cases require the max mdp clk but cannot
+	 * be explained by mdp clk equation.
+	 */
+	if (pipe->flags & MDP_DEINTERLACE) {
+		pr_info("%s deinterlace requires max mdp clk.\n",
+			__func__);
+		pipe->req_clk = mdp_max_clk;
+		return 0;
+	}
+
+	pr_debug("%s: pipe sets: panel res(x,y)=(%d,%d)\n",
+		 __func__,  mfd->panel_info.xres, mfd->panel_info.yres);
+	pr_debug("%s: src(w,h)(%d,%d),src(x,y)(%d,%d)\n",
+		 __func__,  pipe->src_w, pipe->src_h, pipe->src_x, pipe->src_y);
+	pr_debug("%s: dst(w,h)(%d,%d),dst(x,y)(%d,%d)\n",
+		 __func__, pipe->dst_w, pipe->dst_h, pipe->dst_x, pipe->dst_y);
+
+	pclk = (mfd->panel_info.type == MIPI_VIDEO_PANEL ||
+		mfd->panel_info.type == MIPI_CMD_PANEL) ?
+		mfd->panel_info.mipi.dsi_pclk_rate :
+		mfd->panel_info.clk_rate;
+	if (!pclk) {
+		pipe->req_clk = mdp_max_clk;
+		pr_err("%s panel pixel clk is zero!\n", __func__);
+		return ret;
+	}
+	pr_debug("%s: mdp panel pixel clk is %d.\n",
+		 __func__, pclk);
+
+	if (!pipe->dst_h) {
+		pr_err("%s: pipe dst_h is zero!\n", __func__);
+		pipe->req_clk = mdp_max_clk;
+		return ret;
+	}
+
+	if (!pipe->src_h) {
+		pr_err("%s: pipe src_h is zero!\n", __func__);
+		pipe->req_clk = mdp_max_clk;
+		return ret;
+	}
+
+	if (!pipe->dst_w) {
+		pr_err("%s: pipe dst_w is zero!\n", __func__);
+		pipe->req_clk = mdp_max_clk;
+		return ret;
+	}
+
+	if (!pipe->dst_h) {
+		pr_err("%s: pipe dst_h is zero!\n", __func__);
+		pipe->req_clk = mdp_max_clk;
+		return ret;
+	}
+
+	/*
+	 * For the scaling cases, make more margin by removing porch
+	 * values and adding extra 20%.
+	 */
+	if ((pipe->src_h != pipe->dst_h) ||
+	    (pipe->src_w != pipe->dst_w)) {
+		hsync = mfd->panel_info.xres;
+		hsync *= 100;
+		hsync /= 120;
+		pr_debug("%s: panel hsync is %d. with scaling\n",
+			__func__, hsync);
+
+	} else {
+		hsync = mfd->panel_info.lcdc.h_back_porch +
+			mfd->panel_info.lcdc.h_front_porch +
+			mfd->panel_info.lcdc.h_pulse_width +
+			mfd->panel_info.xres;
+		pr_debug("%s: panel hsync is %d.\n",
+			__func__, hsync);
+	}
+
+	if (!hsync) {
+		pipe->req_clk = mdp_max_clk;
+		pr_err("%s: panel hsync is zero!\n", __func__);
+		return 0;
+	}
+
+	xscale = mfd->panel_info.xres;
+	xscale += pipe->src_w;
+
+	if (xscale < pipe->dst_w) {
+		pipe->req_clk = mdp_max_clk;
+		pr_err("%s: xres+src_w cannot be less than dst_w!\n",
+		       __func__);
+		return ret;
+	}
+
+	xscale -= pipe->dst_w;
+	xscale <<= shift;
+	xscale /= hsync;
+	pr_debug("%s: the right %d shifted xscale is %d.\n",
+		 __func__, shift, xscale);
+
+	if (pipe->src_h > pipe->dst_h) {
+		yscale = pipe->src_h;
+		yscale <<= shift;
+		yscale /= pipe->dst_h;
+	} else {		/* upscale */
+		yscale = pipe->dst_h;
+		yscale <<= shift;
+		yscale /= pipe->src_h;
+	}
+
+	yscale *= pipe->src_w;
+	yscale /= hsync;
+
+	pr_debug("%s: the right %d shifted yscale is %d.\n",
+		 __func__, shift, yscale);
+
+	rst = pclk;
+	if (yscale > xscale)
+		rst *= yscale;
+	else
+		rst *= xscale;
+
+	rst >>= shift;
+
+	/*
+	 * If the calculated mdp clk is less than panel pixel clk,
+	 * most likely due to upscaling, mdp clk rate will be set to
+	 * greater than pclk. Now the driver uses 1.15 as the
+	 * factor. Ideally this factor is passed from board file.
+	 */
+	if (rst < pclk) {
+		rst = ((pclk >> shift) * 23 / 20) << shift;
+		pr_debug("%s calculated mdp clk is less than pclk.\n",
+			__func__);
+	}
+
+	pipe->req_clk = (u32) rst;
+
+	pr_debug("%s: required mdp clk %d mixer %d pipe ndx %d\n",
+		 __func__, pipe->req_clk, pipe->mixer_num, pipe->pipe_ndx);
+
+	return 0;
+}
+
+#define OVERLAY_VGA_SIZE	0x04B000
+#define OVERLAY_720P_TILE_SIZE  0x0E6000
+#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
+
+#define OVERLAY_BUS_SCALE_TABLE_BASE	6
+
+
+static int mdp4_calc_pipe_mdp_bw(struct msm_fb_data_type *mfd,
+			  struct mdp4_overlay_pipe *pipe)
+{
+	u32 res;
+	int ret = -EINVAL;
+
+	if (!pipe) {
+		pr_err("%s: pipe is null!\n", __func__);
+		return ret;
+	}
+	if (!mfd) {
+		pr_err("%s: mfd is null!\n", __func__);
+		return ret;
+	}
+
+	if (pipe->flags & MDP_DEINTERLACE) {
+		pr_info("%s deinterlace requires max mdp bw.\n",
+			__func__);
+		pipe->req_bw = OVERLAY_PERF_LEVEL1;
+		return 0;
+	}
+
+	if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+		pipe->req_bw = OVERLAY_PERF_LEVEL4;
+		return 0;
+	}
+
+	res = pipe->src_w * pipe->src_h;
+
+	if (res <= OVERLAY_WSVGA_SIZE)
+		pipe->req_bw = OVERLAY_PERF_LEVEL4;
+	else if (res <= OVERLAY_VGA_SIZE)
+		pipe->req_bw = OVERLAY_PERF_LEVEL3;
+	else if (res <= OVERLAY_720P_TILE_SIZE)
+		pipe->req_bw = OVERLAY_PERF_LEVEL2;
+	else
+		pipe->req_bw = OVERLAY_PERF_LEVEL1;
+
+	return 0;
+}
+
+int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd,
+			      struct mdp4_overlay_pipe *plist)
+{
+	u32 worst_mdp_clk = 0;
+	u32 worst_mdp_bw = OVERLAY_PERF_LEVEL4;
+	int i;
+	struct mdp4_overlay_perf *perf_req = &perf_request;
+	struct mdp4_overlay_pipe *pipe = plist;
+	u32 cnt = 0;
+	int ret = -EINVAL;
+
+	if (!mfd) {
+		pr_err("%s: mfd is null!\n", __func__);
+		return ret;
+	}
+
+	if (!plist) {
+		pr_err("%s: plist is null!\n", __func__);
+		return ret;
+	}
+
+	perf_req->use_ov0_blt = 0;
+	perf_req->use_ov1_blt = 0;
+
+	for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
+
+		if (!pipe)
+			return ret;
+
+		if (!pipe->pipe_used)
+			continue;
+		cnt++;
+		if (worst_mdp_clk < pipe->req_clk)
+			worst_mdp_clk = pipe->req_clk;
+		if (pipe->req_clk > mdp_max_clk) {
+			if (pipe->mixer_num == MDP4_MIXER0)
+				perf_req->use_ov0_blt = 1;
+			if (pipe->mixer_num == MDP4_MIXER1)
+				perf_req->use_ov1_blt = 1;
+		}
+
+		if (!pipe->req_bw) {
+			pr_err("%s mdp pipe bw request should not be zero!\n",
+			       __func__);
+			pr_debug("%s %d pid %d num %d idx %d mix %d bw %d\n",
+				 __func__, __LINE__, current->pid,
+				 pipe->pipe_num, pipe->pipe_ndx,
+				 pipe->mixer_num, pipe->req_bw);
+			pipe->req_bw = OVERLAY_PERF_LEVEL4;
+		}
+
+		if (pipe->req_bw < worst_mdp_bw)
+			worst_mdp_bw = pipe->req_bw;
+
+		if (mfd->mdp_rev == MDP_REV_41) {
+			/*
+			 * writeback (blt) mode to provide work around
+			 * for dsi cmd mode interface hardware bug.
+			 */
+			if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+				if (pipe->dst_x != 0)
+					perf_req->use_ov0_blt = 1;
+			}
+			if ((mfd->panel_info.xres > 1280) &&
+			    (mfd->panel_info.type != DTV_PANEL)) {
+				perf_req->use_ov0_blt = 1;
+			}
+		}
+	}
+
+	perf_req->mdp_clk_rate = worst_mdp_clk;
+	if (perf_req->mdp_clk_rate > mdp_max_clk)
+		perf_req->mdp_clk_rate = mdp_max_clk;
+
+	perf_req->mdp_clk_rate = mdp_clk_round_rate(perf_req->mdp_clk_rate);
+
+	perf_req->mdp_bw = worst_mdp_bw;
+
+	if (cnt >= 3)
+		perf_req->mdp_bw = OVERLAY_PERF_LEVEL1;
+
+	pr_debug("%s %d pid %d cnt %d clk %d ov0_blt %d, ov1_blt %d bw %d\n",
+		 __func__, __LINE__, current->pid, cnt,
+		 perf_req->mdp_clk_rate,
+		 perf_req->use_ov0_blt,
+		 perf_req->use_ov1_blt,
+		 perf_req->mdp_bw);
+
+	return 0;
+}
+
+int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe,
+				  struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+
+	if (mdp4_calc_pipe_mdp_clk(mfd, pipe)) {
+		pr_err("%s unable to calc mdp pipe clk rate ret=%d\n",
+		       __func__, ret);
+		ret = -EINVAL;
+	}
+	if (mdp4_calc_pipe_mdp_bw(mfd, pipe)) {
+		pr_err("%s unable to calc mdp pipe bandwidth ret=%d\n",
+		       __func__, ret);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd,
+				  int flag)
+{
+	struct mdp4_overlay_perf *perf_req = &perf_request;
+	struct mdp4_overlay_perf *perf_cur = &perf_current;
+
+	pr_debug("%s %d: req mdp clk %d, cur mdp clk %d flag %d\n",
+		 __func__, __LINE__,
+		 perf_req->mdp_clk_rate,
+		 perf_cur->mdp_clk_rate,
+		 flag);
+
+	if (!mdp4_extn_disp)
+		perf_cur->use_ov1_blt = 0;
+
+	if (flag) {
+		if (perf_req->mdp_clk_rate > perf_cur->mdp_clk_rate) {
+			mdp_set_core_clk(perf_req->mdp_clk_rate);
+			pr_info("%s mdp clk is changed [%d] from %d to %d\n",
+				__func__,
+				flag,
+				perf_cur->mdp_clk_rate,
+				perf_req->mdp_clk_rate);
+			perf_cur->mdp_clk_rate =
+				perf_req->mdp_clk_rate;
+		}
+		if (perf_req->mdp_bw < perf_cur->mdp_bw) {
+			mdp_bus_scale_update_request
+				(OVERLAY_BUS_SCALE_TABLE_BASE -
+				 perf_req->mdp_bw);
+			pr_info("%s mdp bw is changed [%d] from %d to %d\n",
+				__func__,
+				flag,
+				perf_cur->mdp_bw,
+				perf_req->mdp_bw);
+			perf_cur->mdp_bw = perf_req->mdp_bw;
+		}
+		if (mfd->panel_info.pdest == DISPLAY_1 &&
+		    perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) {
+			mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+			if (mfd->panel_info.type == LCDC_PANEL ||
+			    mfd->panel_info.type == LVDS_PANEL)
+				mdp4_lcdc_overlay_blt_start(mfd);
+			else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+				mdp4_dsi_video_blt_start(mfd);
+			else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
+				mdp4_dsi_cmd_blt_start(mfd);
+			pr_info("%s mixer0 start blt [%d] from %d to %d.\n",
+				__func__,
+				flag,
+				perf_cur->use_ov0_blt,
+				perf_req->use_ov0_blt);
+			perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
+		}
+		if (mfd->panel_info.pdest == DISPLAY_2 &&
+		    perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) {
+			mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
+			mdp4_dtv_overlay_blt_start(mfd);
+			pr_info("%s mixer1 start blt [%d] from %d to %d.\n",
+				__func__,
+				flag,
+				perf_cur->use_ov1_blt,
+				perf_req->use_ov1_blt);
+			perf_cur->use_ov1_blt = perf_req->use_ov1_blt;
+		}
+	} else {
+		if (perf_req->mdp_clk_rate < perf_cur->mdp_clk_rate) {
+			pr_info("%s mdp clk is changed [%d] from %d to %d\n",
+				__func__,
+				flag,
+				perf_cur->mdp_clk_rate,
+				perf_req->mdp_clk_rate);
+			mdp_set_core_clk(perf_req->mdp_clk_rate);
+			perf_cur->mdp_clk_rate =
+				perf_req->mdp_clk_rate;
+		}
+		if (perf_req->mdp_bw > perf_cur->mdp_bw) {
+			pr_info("%s mdp bw is changed [%d] from %d to %d\n",
+				__func__,
+				flag,
+				perf_cur->mdp_bw,
+				perf_req->mdp_bw);
+			mdp_bus_scale_update_request
+				(OVERLAY_BUS_SCALE_TABLE_BASE -
+				 perf_req->mdp_bw);
+			perf_cur->mdp_bw = perf_req->mdp_bw;
+		}
+		if (mfd->panel_info.pdest == DISPLAY_1 &&
+		    !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) {
+			if (mfd->panel_info.type == LCDC_PANEL ||
+			    mfd->panel_info.type == LVDS_PANEL)
+				mdp4_lcdc_overlay_blt_stop(mfd);
+			else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+				mdp4_dsi_video_blt_stop(mfd);
+			else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
+				mdp4_dsi_cmd_blt_stop(mfd);
+			mdp4_free_writeback_buf(mfd, MDP4_MIXER0);
+			pr_info("%s mixer0 stop blt [%d] from %d to %d.\n",
+				__func__,
+				flag,
+				perf_cur->use_ov0_blt,
+				perf_req->use_ov0_blt);
+			perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
+		}
+		if (mfd->panel_info.pdest == DISPLAY_2 &&
+		    !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) {
+			mdp4_dtv_overlay_blt_stop(mfd);
+			mdp4_free_writeback_buf(mfd, MDP4_MIXER1);
+			pr_info("%s mixer1 stop blt [%d] from %d to %d.\n",
+				__func__,
+				flag,
+				perf_cur->use_ov1_blt,
+				perf_req->use_ov1_blt);
+			perf_cur->use_ov1_blt = perf_req->use_ov1_blt;
+		}
+	}
+	return;
+}
+
 static int get_img(struct msmfb_data *img, struct fb_info *info,
 	struct mdp4_overlay_pipe *pipe, unsigned int plane,
 	unsigned long *start, unsigned long *len, struct file **srcp_file,
@@ -2555,154 +2936,10 @@
 	return 0;
 }
 
-#define OVERLAY_VGA_SIZE	0x04B000
-#define OVERLAY_720P_TILE_SIZE  0x0E6000
-#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
-
-#define OVERLAY_BUS_SCALE_TABLE_BASE	6
-
-static int mdp4_overlay_is_rgb_type(int format)
-{
-	switch (format) {
-	case MDP_RGB_565:
-	case MDP_RGB_888:
-	case MDP_BGR_565:
-	case MDP_XRGB_8888:
-	case MDP_ARGB_8888:
-	case MDP_RGBA_8888:
-	case MDP_BGRA_8888:
-	case MDP_RGBX_8888:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req,
-					  struct msm_fb_data_type *mfd)
-{
-	int is_fg = 0, i, cnt;
-
-	if (req->is_fg && ((req->alpha & 0x0ff) == 0xff))
-		is_fg = 1;
-
-	if (mdp4_extn_disp)
-		return OVERLAY_PERF_LEVEL1;
-
-	if (req->flags & (MDP_DEINTERLACE | MDP_BACKEND_COMPOSITION))
-		return OVERLAY_PERF_LEVEL1;
-
-	for (i = 0, cnt = 0; i < OVERLAY_PIPE_MAX; i++) {
-		if (ctrl->plist[i].pipe_used && ++cnt > 2)
-			return OVERLAY_PERF_LEVEL1;
-	}
-
-	if (mdp4_overlay_is_rgb_type(req->src.format) && is_fg &&
-		((req->src.width * req->src.height) <= OVERLAY_WSVGA_SIZE))
-		return OVERLAY_PERF_LEVEL4;
-	else if (mdp4_overlay_is_rgb_type(req->src.format))
-		return OVERLAY_PERF_LEVEL1;
-
-	if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE) {
-		if (mfd->mdp_rev >= MDP_REV_42)
-			return OVERLAY_PERF_LEVEL4;
-		else
-			return OVERLAY_PERF_LEVEL3;
-
-	} else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE) {
-		u32 max, min;
-		max = (req->dst_rect.h > req->dst_rect.w) ?
-			req->dst_rect.h : req->dst_rect.w;
-		min = (mfd->panel_info.yres > mfd->panel_info.xres) ?
-			mfd->panel_info.xres : mfd->panel_info.yres;
-		if (max > min)	/* landscape mode */
-			return OVERLAY_PERF_LEVEL3;
-		else		/* potrait mode */
-			return OVERLAY_PERF_LEVEL2;
-	}
-	else
-		return OVERLAY_PERF_LEVEL1;
-}
-
-void mdp4_update_perf_level(u32 perf_level)
-{
-	static int first = 1;
-
-	new_perf_level = perf_level;
-
-	if (first) {
-		first = 0;
-		mdp4_set_perf_level();
-	}
-}
-
-void mdp4_set_perf_level(void)
-{
-	static int old_perf_level;
-	int cur_perf_level;
-
-	if (mdp4_extn_disp)
-		cur_perf_level = OVERLAY_PERF_LEVEL1;
-	else
-		cur_perf_level = new_perf_level;
-
-	if (old_perf_level != cur_perf_level) {
-		mdp_set_core_clk(cur_perf_level);
-		old_perf_level = cur_perf_level;
-		mdp_bus_scale_update_request(OVERLAY_BUS_SCALE_TABLE_BASE
-					     - cur_perf_level);
-	}
-}
-
-static u32 mdp4_overlay_blt_enable(struct mdp_overlay *req,
-	struct msm_fb_data_type *mfd, uint32 perf_level)
-{
-	u32 clk_rate = mfd->panel_info.clk_rate;
-	u32 blt_chq_req  = 0, use_blt = 0;
-
-	if ((mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
-		 (mfd->panel_info.type == MIPI_CMD_PANEL))
-		clk_rate = (&mfd->panel_info.mipi)->dsi_pclk_rate;
-
-	if ((mfd->panel_info.type == LCDC_PANEL) ||
-	    (mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
-	    (mfd->panel_info.type == DTV_PANEL) ||
-	    (mfd->panel_info.type == MIPI_CMD_PANEL))
-		blt_chq_req = 1;
-
-	if (blt_chq_req && (req->src_rect.h > req->dst_rect.h ||
-		req->src_rect.w > req->dst_rect.w)) {
-		if (mdp4_overlay_validate_downscale(req, mfd, perf_level,
-			clk_rate))
-			use_blt = 1;
-	}
-
-	if (mfd->panel_info.type == MDDI_PANEL) {
-		if ((req->src_rect.h/2) >= req->dst_rect.h ||
-			(req->src_rect.w/2) >= req->dst_rect.w)
-				use_blt = 1;
-	}
-
-	if (mfd->mdp_rev == MDP_REV_41) {
-		/*
-		* writeback (blt) mode to provide work around for
-		* dsi cmd mode interface hardware bug.
-		*/
-		if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
-			if (req->dst_rect.x != 0)
-				use_blt = 1;
-		}
-		if ((mfd->panel_info.xres > 1280) &&
-		    (mfd->panel_info.type != DTV_PANEL))
-			use_blt = 1;
-	}
-	return use_blt;
-}
-
 int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-	int ret, mixer, perf_level;
+	int ret, mixer;
 	struct mdp4_overlay_pipe *pipe;
 
 	if (mfd == NULL) {
@@ -2732,20 +2969,10 @@
 		return ret;
 	}
 
-	perf_level = mdp4_overlay_get_perf_level(req, mfd);
-
-	if (mixer == MDP4_MIXER0) {
-		u32 use_blt = mdp4_overlay_blt_enable(req, mfd,	perf_level);
-		mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
-		mfd->use_ov0_blt |= (use_blt << (pipe->pipe_ndx-1));
-	}
-
 	/* return id back to user */
 	req->id = pipe->pipe_ndx;	/* pipe_ndx start from 1 */
 	pipe->req_data = *req;		/* keep original req */
 
-	pipe->flags = req->flags;
-
 	if (!IS_ERR_OR_NULL(mfd->iclient)) {
 		pr_debug("pipe->flags 0x%x\n", pipe->flags);
 		if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) {
@@ -2768,47 +2995,8 @@
 								__func__);
 	}
 
-	if (ctrl->panel_mode & MDP4_PANEL_DTV &&
-	    pipe->mixer_num == MDP4_MIXER1) {
-		u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
+	mdp4_overlay_mdp_pipe_req(pipe, mfd);
 
-		if (hdmi_prim_display) {
-			if (!mdp4_overlay_is_rgb_type(req->src.format) &&
-				pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
-				(req->src_rect.h > req->dst_rect.h ||
-				req->src_rect.w > req->dst_rect.w))
-				use_blt = 1;
-		}
-
-		mdp4_overlay_dtv_set(mfd, pipe);
-		mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
-		mfd->use_ov1_blt |= (use_blt << (pipe->pipe_ndx-1));
-	}
-
-	if (new_perf_level != perf_level) {
-		u32 old_level = new_perf_level;
-		mdp4_update_perf_level(perf_level);
-
-		/* change clck base on perf level */
-		if (pipe->mixer_num == MDP4_MIXER0) {
-			if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
-				if (old_level > perf_level)
-					mdp4_set_perf_level();
-			} else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
-				mdp4_set_perf_level();
-			} else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
-				if (old_level > perf_level)
-					mdp4_set_perf_level();
-			} else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
-				mdp4_mddi_dma_busy_wait(mfd);
-				mdp4_mddi_blt_dmap_busy_wait(mfd);
-				mdp4_set_perf_level();
-			}
-		} else {
-			if (ctrl->panel_mode & MDP4_PANEL_DTV)
-				mdp4_overlay_dtv_set_perf(mfd);
-		}
-	}
 	mutex_unlock(&mfd->dma->ov_mutex);
 
 	return 0;
@@ -2864,7 +3052,6 @@
 	else {
 		/* mixer 0 */
 		ctrl->mixer0_played = 0;
-
 		if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
 			if (mfd->panel_power_on)
 				mdp4_mddi_blt_dmap_busy_wait(mfd);
@@ -2879,13 +3066,9 @@
 			if (mfd->panel_power_on)
 				mdp4_mddi_overlay_restore();
 		}
-
-		mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
 	} else {	/* mixer1, DTV, ATV */
-		if (ctrl->panel_mode & MDP4_PANEL_DTV) {
+		if (ctrl->panel_mode & MDP4_PANEL_DTV)
 			mdp4_overlay_dtv_unset(mfd, pipe);
-			mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
-		}
 	}
 
 	mdp4_stat.overlay_unset[pipe->mixer_num]++;
@@ -3002,7 +3185,6 @@
 
 	pr_debug("%s: pipe=%x ndx=%d num=%d used=%d\n", __func__,
 		(int) pipe, pipe->pipe_ndx, pipe->pipe_num, pipe->pipe_used);
-
 	mdp4_overlay_reg_flush(pipe, 1);
 	mdp4_mixer_stage_up(pipe);
 }
@@ -3148,6 +3330,7 @@
 		}
 	}
 
+	mdp4_overlay_mdp_perf_req(mfd, ctrl->plist);
 
 	if (pipe->mixer_num == MDP4_MIXER2 ||
 				ctrl->panel_mode & MDP4_PANEL_MDDI)
@@ -3173,7 +3356,6 @@
 	return ret;
 
 mddi:
-
 	if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
 		mdp4_overlay_vg_setup(pipe);    /* video/graphic pipe */
 	} else {
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index 753ff23..3fe00ed 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -110,7 +110,6 @@
 
 	mdp4_overlay_dmae_xy(pipe);	/* dma_e */
 	mdp4_overlay_dmae_cfg(mfd, 1);
-
 	mdp4_overlay_rgb_setup(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
@@ -183,6 +182,8 @@
 	} else {
 		pipe->srcp0_addr = (uint32)(buf + buf_offset);
 	}
+	mdp4_overlay_mdp_perf_req(pipe, mfd);
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
 	mdp4_overlay_rgb_setup(pipe);
 	mdp4_overlay_reg_flush(pipe, 0);
 	mdp4_mixer_stage_up(pipe);
@@ -201,10 +202,7 @@
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 	wait_for_completion_killable(&atv_pipe->comp);
 	mdp_disable_irq(MDP_OVERLAY1_TERM);
-
-	/* change mdp clk while mdp is idle` */
-	mdp4_set_perf_level();
-
+	mdp4_overlay_mdp_perf_upd(mfd, 0);
 	mdp4_stat.kickoff_atv++;
 	mutex_unlock(&mfd->dma->ov_mutex);
 }
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index e1fa02e..05a89b8 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -864,6 +864,7 @@
 	/* disable dsi trigger */
 	MDP_OUTP(MDP_BASE + 0x000a4, 0x00);
 
+
 	mdp4_overlay_setup_pipe_addr(mfd, pipe);
 
 	mdp4_overlay_rgb_setup(pipe);
@@ -1098,18 +1099,12 @@
 		mdp4_dsi_cmd_pipe_queue(0, pipe);
 	}
 
-	if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
-
-		if (mfd->use_ov0_blt)
-			mdp4_dsi_cmd_do_blt(mfd, 1);
-		else
-			mdp4_dsi_cmd_do_blt(mfd, 0);
-
-		mfd->ov0_blt_state = mfd->use_ov0_blt;
-	}
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
 	mdp4_dsi_cmd_pipe_commit();
 	mdp4_dsi_cmd_wait4vsync(0, &xx);
 	vctrl->expire_tick = VSYNC_EXPIRE_TICK;
 	vctrl->clk_control = 1;
+
+	mdp4_overlay_mdp_perf_upd(mfd, 0);
 }
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 851a9ad..a8b906a 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -122,9 +122,6 @@
 		return;
 	}
 
-	/* start timing generator & mmu if they are not started yet */
-	mdp4_overlay_dsi_video_start();
-
 	vctrl = &vsync_ctrl_db[cndx];
 
 	if (atomic_read(&vctrl->suspend) > 0)
@@ -196,6 +193,8 @@
 	}
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 
+	mdp4_overlay_mdp_perf_upd(vctrl->mfd, 1);
+
 	if (vctrl->blt_change) {
 		pipe = vctrl->base_pipe;
 		spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -209,6 +208,7 @@
 	}
 
 	pipe = vp->plist;
+
 	for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
 		if (pipe->pipe_used) {
 			cnt++;
@@ -224,6 +224,9 @@
 
 	mdp4_mixer_stage_commit(mixer);
 
+	/* start timing generator & mmu if they are not started yet */
+	mdp4_overlay_dsi_video_start();
+
 	pipe = vctrl->base_pipe;
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	if (pipe->ov_blt_addr) {
@@ -539,6 +542,8 @@
 	pipe->dst_h = fbi->var.yres;
 	pipe->dst_w = fbi->var.xres;
 
+	mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
 	atomic_set(&vctrl->suspend, 0);
 
 	mdp4_overlay_dmap_xy(pipe);	/* dma_p */
@@ -820,13 +825,6 @@
 	MDP_OUTP(MDP_BASE + 0x90008, addr);
 }
 
-void mdp4_overlay_dsi_video_set_perf(struct msm_fb_data_type *mfd)
-{
-	/* change mdp clk while mdp is idle */
-	mdp4_set_perf_level();
-}
-
-
 /*
  * mdp4_primary_vsync_dsi_video: called from isr
  */
@@ -928,8 +926,6 @@
 	vctrl = &vsync_ctrl_db[cndx];
 	pipe = vctrl->base_pipe;
 
-	mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
-
 	if (mfd->ov0_wb_buf->write_addr == 0) {
 		pr_info("%s: no blt_base assigned\n", __func__);
 		return;
@@ -1011,15 +1007,7 @@
 		mdp4_dsi_video_pipe_queue(0, pipe);
 	}
 
-	if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
-
-		if (mfd->use_ov0_blt)
-			mdp4_dsi_video_do_blt(mfd, 1);
-		else
-			mdp4_dsi_video_do_blt(mfd, 0);
-
-		mfd->ov0_blt_state = mfd->use_ov0_blt;
-	}
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
 	mdp4_dsi_video_pipe_commit();
 
@@ -1027,5 +1015,7 @@
 		mdp4_dsi_video_wait4ov(0);
 	else
 		mdp4_dsi_video_wait4dmap(0);
+
+	mdp4_overlay_mdp_perf_upd(mfd, 0);
 }
 
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index d0d4f40..d22de54 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -141,9 +141,6 @@
 		return;
 	}
 
-	/* start timing generator & mmu if they are not started yet */
-	mdp4_overlay_dtv_start();
-
 	vctrl = &vsync_ctrl_db[cndx];
 
 	if (atomic_read(&vctrl->suspend) > 0)
@@ -210,6 +207,9 @@
 	}
 	mdp4_mixer_stage_commit(mixer);
 
+	 /* start timing generator & mmu if they are not started yet */
+	mdp4_overlay_dtv_start();
+
 	pipe = vctrl->base_pipe;
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	if (pipe->ov_blt_addr) {
@@ -647,8 +647,7 @@
 
 void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd)
 {
-	/* change mdp clk while mdp is idle` */
-	mdp4_set_perf_level();
+
 }
 
 static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd,
@@ -701,12 +700,16 @@
 	pipe->src_width = fbi->var.xres;
 	pipe->src_h = fbi->var.yres;
 	pipe->src_w = fbi->var.xres;
+	pipe->dst_h = fbi->var.yres;
+	pipe->dst_w = fbi->var.xres;
 	pipe->src_y = 0;
 	pipe->src_x = 0;
 	pipe->dst_h = fbi->var.yres;
 	pipe->dst_w = fbi->var.xres;
 	pipe->srcp0_ystride = fbi->fix.line_length;
 
+	mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
 	ret = mdp4_overlay_format2pipe(pipe);
 	if (ret < 0)
 		pr_warn("%s: format2type failed\n", __func__);
@@ -838,6 +841,7 @@
 	} else  {
 		mdp4_overlay_dma_commit(MDP4_MIXER1);
 	}
+
 	vsync_irq_disable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
 	spin_unlock(&vctrl->spin_lock);
 }
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index feba8b8..4a478cd 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -128,9 +128,6 @@
 		return;
 	}
 
-       /* start timing generator & mmu if they are not started yet */
-	mdp4_overlay_lcdc_start();
-
 	vctrl = &vsync_ctrl_db[cndx];
 
 	if (atomic_read(&vctrl->suspend) > 0)
@@ -201,6 +198,8 @@
 	}
 	spin_unlock_irqrestore(&vctrl->spin_lock, flags);
 
+	mdp4_overlay_mdp_perf_upd(vctrl->mfd, 1);
+
 	if (vctrl->blt_change) {
 		pipe = vctrl->base_pipe;
 		spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -229,6 +228,9 @@
 
 	mdp4_mixer_stage_commit(mixer);
 
+	/* start timing generator & mmu if they are not started yet */
+	mdp4_overlay_lcdc_start();
+
 	pipe = vctrl->base_pipe;
 	spin_lock_irqsave(&vctrl->spin_lock, flags);
 	if (pipe->ov_blt_addr) {
@@ -513,6 +515,8 @@
 	pipe->srcp0_ystride = fbi->fix.line_length;
 	pipe->bpp = bpp;
 
+	mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
 	atomic_set(&vctrl->suspend, 0);
 
 	mdp4_overlay_dmap_xy(pipe);
@@ -714,12 +718,6 @@
 	MDP_OUTP(MDP_BASE + 0x90008, addr);
 }
 
-void mdp4_overlay_lcdc_set_perf(struct msm_fb_data_type *mfd)
-{
-	/* change mdp clk while mdp is idle */
-	mdp4_set_perf_level();
-}
-
 /*
  * mdp4_primary_vsync_lcdc: called from isr
  */
@@ -900,15 +898,7 @@
 		mdp4_lcdc_pipe_queue(0, pipe);
 	}
 
-	if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
-
-		if (mfd->use_ov0_blt)
-			mdp4_lcdc_do_blt(mfd, 1);
-		else
-			mdp4_lcdc_do_blt(mfd, 0);
-
-		mfd->ov0_blt_state = mfd->use_ov0_blt;
-	}
+	mdp4_overlay_mdp_perf_upd(mfd, 1);
 
 	mdp4_lcdc_pipe_commit();
 
@@ -916,4 +906,6 @@
 		mdp4_lcdc_wait4ov(0);
 	else
 		mdp4_lcdc_wait4dmap(0);
+
+	mdp4_overlay_mdp_perf_upd(mfd, 0);
 }
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index 103419e..d10e669 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -574,8 +574,6 @@
 				struct mdp4_overlay_pipe *pipe)
 {
 	unsigned long flag;
-	/* change mdp clk while mdp is idle` */
-	mdp4_set_perf_level();
 
 	mdp_enable_irq(MDP_OVERLAY0_TERM);
 	spin_lock_irqsave(&mdp_spin_lock, flag);
@@ -660,9 +658,6 @@
 void mdp4_mddi_dma_s_kickoff(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe)
 {
-	/* change mdp clk while mdp is idle` */
-	mdp4_set_perf_level();
-
 	mdp_enable_irq(MDP_DMA_S_TERM);
 
 	if (mddi_pipe->ov_blt_addr == 0)
@@ -698,9 +693,10 @@
 
 		if (mddi_pipe && mddi_pipe->ov_blt_addr)
 			mdp4_mddi_blt_dmap_busy_wait(mfd);
-
+		mdp4_overlay_mdp_perf_upd(mfd, 0);
 		mdp4_overlay_update_lcd(mfd);
 
+		mdp4_overlay_mdp_perf_upd(mfd, 1);
 		if (mdp_hw_revision < MDP4_REVISION_V2_1) {
 			/* dmas dmap switch */
 			if (mdp4_overlay_mixer_play(mddi_pipe->mixer_num)
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 9c06992..d8e4be4 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -174,6 +174,8 @@
 	pipe->dst_y = 0;
 	pipe->dst_x = 0;
 
+	mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
 	if (mfd->display_iova)
 		pipe->srcp0_addr = mfd->display_iova + buf_offset;
 	else
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index e76b8ba..ca73a70 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -249,7 +249,7 @@
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
-	mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
+	mdp_bus_scale_update_request(5);
 
 #ifdef MDP4_ERROR
 	/*
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 2f0a1f5..bc64d2e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -304,7 +304,7 @@
 	itp.h_back_porch =  pinfo->lcdc.h_back_porch;
 	itp.h_front_porch =  pinfo->lcdc.h_front_porch;
 	itp.v_back_porch =  pinfo->lcdc.v_back_porch;
-	itp.v_front_porch = pinfo->lcdc.h_front_porch;
+	itp.v_front_porch = pinfo->lcdc.v_front_porch;
 	itp.hsync_pulse_width = pinfo->lcdc.h_pulse_width;
 	itp.vsync_pulse_width = pinfo->lcdc.v_pulse_width;
 
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index efe6160..ae5acf4 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -184,8 +184,6 @@
 	u32 ov_start;
 	u32 mem_hid;
 	u32 mdp_rev;
-	u32 use_ov0_blt, ov0_blt_state;
-	u32 use_ov1_blt, ov1_blt_state;
 	u32 writeback_state;
 	bool writeback_active_cnt;
 	int cont_splash_done;
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index bbd032d..d1438d1 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -116,7 +116,8 @@
  * @r_sense:		sense resistor value in (mOhms)
  * @i_test:		current at which the unusable charger cutoff is to be
  *			calculated or the peak system current (mA)
- * @v_failure:		the voltage at which the battery is considered empty(mV)
+ * @v_cutoff:		the loaded voltage at which the battery
+ *			is considered empty(mV)
  * @enable_fcc_learning:	if set the driver will learn full charge
  *				capacity of the battery upon end of charge
  */
@@ -125,10 +126,13 @@
 	enum battery_type		battery_type;
 	unsigned int			r_sense;
 	unsigned int			i_test;
-	unsigned int			v_failure;
+	unsigned int			v_cutoff;
 	unsigned int			max_voltage_uv;
 	unsigned int			rconn_mohm;
 	int				enable_fcc_learning;
+	int				shutdown_soc_valid_limit;
+	int				ignore_shutdown_soc;
+	int				adjust_soc_low_threshold;
 };
 
 #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index b00e050..6bd4cb2 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -281,6 +281,13 @@
  *
  */
 int pm8921_usb_ovp_disable(int disable);
+/**
+ * pm8921_is_batfet_closed - battery fet status
+ *
+ * Returns 1 if batfet is closed 0 if open. On configurations without
+ * batfet this will return 0.
+ */
+int pm8921_is_batfet_closed(void);
 #else
 static inline void pm8921_charger_vbus_draw(unsigned int mA)
 {
@@ -353,6 +360,10 @@
 {
 	return -ENXIO;
 }
+static inline int pm8921_is_batfet_closed(void)
+{
+	return 1;
+}
 #endif
 
 #endif
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
index 1f85952..eb1c3fd 100644
--- a/include/linux/regulator/krait-regulator.h
+++ b/include/linux/regulator/krait-regulator.h
@@ -23,5 +23,6 @@
  * success and error on failure.
  */
 int __init krait_power_init(void);
+void secondary_cpu_hs_init(void *base_ptr);
 
 #endif
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 36b7794..5c5ee30 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -2474,19 +2474,6 @@
 	return 0;
 }
 
-static void sitar_shutdown(struct snd_pcm_substream *substream,
-		struct snd_soc_dai *dai)
-{
-	struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
-	if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
-			(wcd9xxx->dev->parent != NULL)) {
-		pm_runtime_mark_last_busy(wcd9xxx->dev->parent);
-		pm_runtime_put(wcd9xxx->dev->parent);
-	}
-	pr_debug("%s(): substream = %s  stream = %d\n" , __func__,
-		substream->name, substream->stream);
-}
-
 int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
 {
 	struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
@@ -2782,7 +2769,6 @@
 
 static struct snd_soc_dai_ops sitar_dai_ops = {
 	.startup = sitar_startup,
-	.shutdown = sitar_shutdown,
 	.hw_params = sitar_hw_params,
 	.set_sysclk = sitar_set_dai_sysclk,
 	.set_fmt = sitar_set_dai_fmt,
@@ -2887,6 +2873,15 @@
 	return ret;
 }
 
+static void sitar_codec_pm_runtime_put(struct wcd9xxx *sitar)
+{
+	if (sitar->dev != NULL &&
+			sitar->dev->parent != NULL) {
+		pm_runtime_mark_last_busy(sitar->dev->parent);
+		pm_runtime_put(sitar->dev->parent);
+	}
+}
+
 static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -2896,9 +2891,14 @@
 	u32  j = 0, ret = 0;
 	codec->control_data = dev_get_drvdata(codec->dev->parent);
 	sitar = codec->control_data;
+
 	/* Execute the callback only if interface type is slimbus */
-	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		if (event == SND_SOC_DAPM_POST_PMD && (sitar != NULL))
+			sitar_codec_pm_runtime_put(sitar);
 		return 0;
+	}
+
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
@@ -2937,6 +2937,8 @@
 					sitar_p->dai[j].ch_tot));
 			sitar_p->dai[j].ch_tot = 0;
 			ret = sitar_codec_enable_chmask(sitar_p, event, j);
+			if (sitar != NULL)
+				sitar_codec_pm_runtime_put(sitar);
 		}
 	}
 	return ret;
@@ -2955,8 +2957,12 @@
 	sitar = codec->control_data;
 
 	/* Execute the callback only if interface type is slimbus */
-	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+	if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+		if (event == SND_SOC_DAPM_POST_PMD && (sitar != NULL))
+			sitar_codec_pm_runtime_put(sitar);
 		return 0;
+	}
+
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
@@ -2995,6 +3001,8 @@
 					sitar_p->dai[j].ch_tot));
 			sitar_p->dai[j].ch_tot = 0;
 			ret = sitar_codec_enable_chmask(sitar_p, event, j);
+			if (sitar != NULL)
+				sitar_codec_pm_runtime_put(sitar);
 		}
 	}
 	return ret;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 3516022..f50b915 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -837,6 +837,21 @@
 		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
 	},
+	/* Hostless PCM purpose */
+	{
+		.name = "SLIMBUS_0 Hostless",
+		.stream_name = "SLIMBUS_0 Hostless",
+		.cpu_dai_name = "SLIMBUS0_HOSTLESS",
+		.platform_name = "msm-pcm-hostless",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1, /* dai link has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+	},
 	{
 		.name = "MSM8974 Compr",
 		.stream_name = "COMPR",
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 756cb18..2e58e1b 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -586,25 +586,23 @@
 						sizeof(lb_cmd) - APR_HDR_SIZE);
 	lb_cmd.hdr.src_port = 0;
 	lb_cmd.hdr.dest_port = 0;
-	lb_cmd.hdr.token = 0;
+	lb_cmd.hdr.token = index;
 	lb_cmd.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
 	lb_cmd.param.port_id = tx_port;
-	lb_cmd.param.payload_size = (sizeof(lb_cmd) -
-			sizeof(struct apr_hdr) -
-			sizeof(struct afe_port_cmd_set_param_v2));
+	lb_cmd.param.payload_size = (sizeof(lb_cmd) - sizeof(struct apr_hdr) -
+				     sizeof(struct afe_port_cmd_set_param_v2));
 	lb_cmd.param.payload_address_lsw = 0x00;
 	lb_cmd.param.payload_address_msw = 0x00;
 	lb_cmd.param.mem_map_handle = 0x00;
 	lb_cmd.pdata.module_id = AFE_MODULE_LOOPBACK;
 	lb_cmd.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
-	lb_cmd.pdata.param_size =  lb_cmd.param.payload_size -
-				sizeof(struct afe_port_param_data_v2);
+	lb_cmd.pdata.param_size = lb_cmd.param.payload_size -
+				  sizeof(struct afe_port_param_data_v2);
 
 	lb_cmd.dst_port_id = rx_port;
 	lb_cmd.routing_mode = LB_MODE_DEFAULT;
 	lb_cmd.enable = (enable ? 1 : 0);
-	lb_cmd.loopback_cfg_minor_version =
-					AFE_API_VERSION_LOOPBACK_CONFIG;
+	lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
 	atomic_set(&this_afe.state, 1);
 
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
@@ -613,9 +611,10 @@
 		ret = -EINVAL;
 		goto done;
 	}
+	pr_debug("%s: waiting for this_afe.wait[%d]\n", __func__, index);
 	ret = wait_event_timeout(this_afe.wait[index],
-		(atomic_read(&this_afe.state) == 0),
-				msecs_to_jiffies(TIMEOUT_MS));
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: wait_event timeout\n", __func__);
 		ret = -EINVAL;
@@ -667,26 +666,24 @@
 	set_param.hdr.pkt_size = sizeof(set_param);
 	set_param.hdr.src_port = 0;
 	set_param.hdr.dest_port = 0;
-	set_param.hdr.token = 0;
+	set_param.hdr.token = index;
 	set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
 
-	set_param.param.port_id		= port_id;
-	set_param.param.payload_size		=
-		(sizeof(struct afe_loopback_gain_per_path_param) -
-		 sizeof(struct apr_hdr) -
-		sizeof(struct afe_port_cmd_set_param_v2));
+	set_param.param.port_id	= port_id;
+	set_param.param.payload_size =
+	    (sizeof(struct afe_loopback_gain_per_path_param) -
+	     sizeof(struct apr_hdr) - sizeof(struct afe_port_cmd_set_param_v2));
 	set_param.param.payload_address_lsw	= 0;
 	set_param.param.payload_address_msw	= 0;
 	set_param.param.mem_map_handle        = 0;
 
-	set_param.pdata.module_id	= AFE_MODULE_LOOPBACK;
-	set_param.pdata.param_id	= AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
-	set_param.pdata.param_size = (set_param.param.payload_size -
-				sizeof(struct afe_port_param_data_v2));
+	set_param.pdata.module_id = AFE_MODULE_LOOPBACK;
+	set_param.pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
+	set_param.pdata.param_size =
+	    (set_param.param.payload_size -
+	     sizeof(struct afe_port_param_data_v2));
 	set_param.rx_port_id = port_id;
-	set_param.gain	= volume;
-
-	set_param.hdr.token = index;
+	set_param.gain = volume;
 
 	atomic_set(&this_afe.state, 1);
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
@@ -698,8 +695,8 @@
 	}
 
 	ret = wait_event_timeout(this_afe.wait[index],
-		(atomic_read(&this_afe.state) == 0),
-			msecs_to_jiffies(TIMEOUT_MS));
+				 (atomic_read(&this_afe.state) == 0),
+				 msecs_to_jiffies(TIMEOUT_MS));
 	if (ret < 0) {
 		pr_err("%s: wait_event timeout\n", __func__);
 		ret = -EINVAL;