Merge "msm: ocmem: Add clock management support" into msm-3.4
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
index 323fac4..5d93fa3 100644
--- a/arch/arm/boot/dts/msm8974-gpio.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpio.dtsi
@@ -25,14 +25,26 @@
 			};
 
 			gpio@c200 {
+				qcom,mode = <0>;
+				qcom,pull = <0>;
+				qcom,vin-sel = <2>;
+				qcom,select = <0>;
 				status = "ok";
 			};
 
 			gpio@c300 {
+				qcom,mode = <0>;
+				qcom,pull = <0>;
+				qcom,vin-sel = <2>;
+				qcom,select = <0>;
 				status = "ok";
 			};
 
 			gpio@c400 {
+				qcom,mode = <0>;
+				qcom,pull = <0>;
+				qcom,vin-sel = <2>;
+				qcom,select = <0>;
 				status = "ok";
 			};
 
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c5b53d7..194717c 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -788,6 +788,37 @@
 		qcom,temp-hysteresis = <10>;
 		qcom,freq-step = <2>;
 	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+
+		camera_snapshot {
+			label = "camera_snapshot";
+			gpios = <&pm8941_gpios 3 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x2fe>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		camera_focus {
+			label = "camera_focus";
+			gpios = <&pm8941_gpios 4 0x1>;
+			linux,input-type = <1>;
+			linux,code = <0x210>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8941_gpios 5 0x1>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+		};
+	};
 };
 
 /include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index e231db6..0405d1b 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -126,6 +126,7 @@
 # CONFIG_MSM_RMNET is not set
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 518579a..1f39d3f 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -394,6 +394,7 @@
 	.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-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 384b1cf..c16f55d 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -345,6 +345,7 @@
 	.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-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 98140b4..46d317b 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -426,6 +426,7 @@
 	.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/dal_axi.c b/arch/arm/mach-msm/dal_axi.c
index 739b7dc..1d873ca 100644
--- a/arch/arm/mach-msm/dal_axi.c
+++ b/arch/arm/mach-msm/dal_axi.c
@@ -17,6 +17,8 @@
 #define DALRPC_PORT_NAME  "DAL00"
 
 enum {
+	DALRPC_AXI_ALLOCATE = DALDEVICE_FIRST_DEVICE_API_IDX + 1,
+	DALRPC_AXI_FREE = DALDEVICE_FIRST_DEVICE_API_IDX + 2,
 	DALRPC_AXI_CONFIGURE_BRIDGE = DALDEVICE_FIRST_DEVICE_API_IDX + 11
 };
 
@@ -38,6 +40,67 @@
 
 };
 
+static void *cam_dev_handle;
+static int __axi_free(int mode)
+{
+	int rc = 0;
+
+	if (!cam_dev_handle)
+		return rc;
+
+	rc = dalrpc_fcn_0(DALRPC_AXI_FREE, cam_dev_handle, mode);
+	if (rc) {
+		printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+			__func__, rc);
+		goto fail_dal_fcn_0;
+	}
+
+	/* close device handle */
+	rc = daldevice_detach(cam_dev_handle);
+	if (rc) {
+		printk(KERN_ERR "%s: failed to detach AXI bus device (%d)\n",
+			__func__, rc);
+		goto fail_dal_attach_detach;
+	}
+	cam_dev_handle = NULL;
+	return 0;
+
+fail_dal_fcn_0:
+	(void)daldevice_detach(cam_dev_handle);
+	cam_dev_handle = NULL;
+fail_dal_attach_detach:
+	return rc;
+}
+
+static int __axi_allocate(int mode)
+{
+	int rc;
+
+	/* get device handle */
+	rc = daldevice_attach(DALDEVICEID_AXI, DALRPC_PORT_NAME,
+				DALRPC_DEST_MODEM, &cam_dev_handle);
+	if (rc) {
+		printk(KERN_ERR "%s: failed to attach AXI bus device (%d)\n",
+			__func__, rc);
+		goto fail_dal_attach_detach;
+	}
+
+	rc = dalrpc_fcn_0(DALRPC_AXI_ALLOCATE, cam_dev_handle, mode);
+	if (rc) {
+		printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+			__func__, rc);
+		goto fail_dal_fcn_0;
+	}
+
+	return 0;
+
+fail_dal_fcn_0:
+	(void)daldevice_detach(cam_dev_handle);
+	cam_dev_handle = NULL;
+fail_dal_attach_detach:
+	return rc;
+}
+
 static int axi_configure_bridge_grfx_sync_mode(int bridge_mode)
 {
 	int rc;
@@ -82,7 +145,15 @@
 	return rc;
 }
 
+int axi_free(mode)
+{
+	return __axi_free(mode);
+}
 
+int axi_allocate(mode)
+{
+	return __axi_allocate(mode);
+}
 
 int set_grp2d_async(void)
 {
diff --git a/arch/arm/mach-msm/include/mach/dal_axi.h b/arch/arm/mach-msm/include/mach/dal_axi.h
index 4e32aa3..84cd37f 100644
--- a/arch/arm/mach-msm/include/mach/dal_axi.h
+++ b/arch/arm/mach-msm/include/mach/dal_axi.h
@@ -17,5 +17,7 @@
 int set_grp2d_async(void);
 int set_grp3d_async(void);
 int set_grp_xbar_async(void);
-
+int axi_allocate(int mode);
+int axi_free(int mode);
+#define AXI_FLOW_VIEWFINDER_HI	243
 #endif  /* _DAL_AXI_H */
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 2d1fa80..3040a31 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -228,18 +228,6 @@
 
 static int pil_riva_shutdown(struct pil_desc *pil)
 {
-	struct riva_data *drv = dev_get_drvdata(pil->dev);
-	u32 reg;
-
-	/* Put cCPU and cCPU clock into reset */
-	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
-	reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
-	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_VAL);
-	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_EN);
-	reg |= RIVA_PMU_OVRD_EN_CCPU_RESET | RIVA_PMU_OVRD_EN_CCPU_CLK;
-	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_EN);
-	mb();
-
 	/* Assert reset to Riva */
 	writel_relaxed(1, RIVA_RESET);
 	mb();
diff --git a/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/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/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index 7e80145..9549dcc 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -21,7 +21,7 @@
 #include <mach/clk.h>
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
-
+#include <mach/dal_axi.h>
 
 #define MSM_AXI_QOS_PREVIEW 200000
 #define MSM_AXI_QOS_SNAPSHOT 200000
@@ -142,6 +142,7 @@
 		break;
 	case S_PREVIEW:
 		update_axi_qos(MSM_AXI_QOS_PREVIEW);
+		axi_allocate(AXI_FLOW_VIEWFINDER_HI);
 		break;
 	case S_VIDEO:
 		update_axi_qos(MSM_AXI_QOS_RECORDING);
@@ -153,6 +154,7 @@
 		update_axi_qos(PM_QOS_DEFAULT_VALUE);
 		break;
 	case S_EXIT:
+		axi_free(AXI_FLOW_VIEWFINDER_HI);
 		release_axi_qos();
 		break;
 	default:
diff --git a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
index e1d8b48..460eb07 100644
--- a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
@@ -696,7 +696,6 @@
 
 		switch (id) {
 		case MSG_SNAPSHOT:
-			msm_camio_set_perf_lvl(S_PREVIEW);
 			while (vfe2x_ctrl->snap.frame_cnt <
 				vfe2x_ctrl->num_snap) {
 				vfe_7x_ops(driver_data, MSG_OUTPUT_S, len,
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 282da64..a1d796f 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -26,9 +26,9 @@
 #define MAX_BIT_RATE 160000
 #define DEFAULT_BIT_RATE 64
 #define BIT_RATE_STEP 1
-#define MIN_FRAME_RATE 1
-#define MAX_FRAME_RATE 240
-#define DEFAULT_FRAME_RATE 30
+#define MIN_FRAME_RATE 65536
+#define MAX_FRAME_RATE 15728640
+#define DEFAULT_FRAME_RATE 1966080
 #define DEFAULT_IR_MBS 30
 #define MAX_SLICE_BYTE_SIZE 1024
 #define MIN_SLICE_BYTE_SIZE 1024
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 4de5752..88e0948 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -28,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
@@ -50,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,
@@ -126,14 +130,20 @@
 	int			last_ocv_uv;
 	int			pon_ocv_uv;
 	int			last_cc_uah;
-	struct timeval		t;
+	unsigned long		tm_sec;
 	int			enable_fcc_learning;
 	int			shutdown_soc;
+	int			shutdown_iavg_ua;
 	int			shutdown_soc_timer_expired;
 	struct delayed_work	shutdown_soc_work;
 	struct delayed_work	calculate_soc_delayed_work;
 	struct timespec		t_soc_queried;
 	int			shutdown_soc_valid_limit;
+	int			ignore_shutdown_soc;
+	int			prev_iavg_ua;
+	int			prev_uuc_iavg_ma;
+	int			prev_pc_unusable;
+	int			adjust_soc_low_threshold;
 };
 
 /*
@@ -475,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 -
@@ -1148,59 +1158,168 @@
 	*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_cutoff * 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;
 }
 
-static void calculate_iavg_ua(struct pm8921_bms_chip *chip, int cc_uah,
-				int *iavg_ua, int *delta_time_us)
+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)
 {
-	int delta_cc_uah;
-	struct timeval now;
+	int new_unusable_mv;
+	int batt_temp_degc = batt_temp / 10;
 
-	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 (chip->prev_pc_unusable == -EINVAL
+		|| abs(chip->prev_pc_unusable - new_pc_unusable) <= 1) {
+		chip->prev_pc_unusable = new_pc_unusable;
+		return new_uuc;
 	}
 
-	if (*delta_time_us != 0)
-		*iavg_ua = div_s64((s64)delta_cc_uah * 3600 * 1000000,
-					*delta_time_us);
+	/* the uuc is trying to change more than 1% restrict it */
+	if (new_pc_unusable > chip->prev_pc_unusable)
+		chip->prev_pc_unusable++;
 	else
-		*iavg_ua = 0;
+		chip->prev_pc_unusable--;
 
-	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);
+	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_s)
+{
+	int delta_cc_uah;
+	struct rtc_time tm;
+	struct rtc_device *rtc;
+	unsigned long now_tm_sec = 0;
+	int rc = 0;
+
+	/* if anything fails report the previous iavg_ua */
+	*iavg_ua = chip->prev_iavg_ua;
+
+	rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+	if (rtc == NULL) {
+		pr_err("%s: unable to open rtc device (%s)\n",
+			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+		goto out;
+	}
+
+	rc = rtc_read_time(rtc, &tm);
+	if (rc) {
+		pr_err("Error reading rtc device (%s) : %d\n",
+			CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto out;
+	}
+
+	rc = rtc_valid_tm(&tm);
+	if (rc) {
+		pr_err("Invalid RTC time (%s): %d\n",
+			CONFIG_RTC_HCTOSYS_DEVICE, rc);
+		goto out;
+	}
+	rtc_tm_to_time(&tm, &now_tm_sec);
+
+	if (chip->tm_sec == 0) {
+		*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 IAVG_SAMPLES 16
-#define CHARGING_IAVG_MA 300
+#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 delta_time_us)
+				int iavg_ua, int delta_time_s)
 {
 	int uuc_uah_iavg;
 	int i;
@@ -1208,32 +1327,34 @@
 	static int iavg_samples[IAVG_SAMPLES];
 	static int iavg_index;
 	static int iavg_num_samples;
+	static int firsttime = 1;
+	int pc_unusable;
 
-	if (delta_time_us == 0) {
-		/*
-		 * this means uuc is being for the first time,
-		 * iavg_ua will be 0 which will lead to unreasonably low uuc
-		 * hence use the instantenous current instead of iavg_ua
-		 * value for the first time
-		 */
-		pm8921_bms_get_battery_current(&iavg_ua);
-		iavg_ma = iavg_ua / 1000;
+	/*
+	 * 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 the time since last sample is small ignore it */
-	if (delta_time_us == 0 || delta_time_us > USEC_PER_SEC) {
-		/*
-		 * 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;
-	}
+	/*
+	 * 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;
@@ -1246,11 +1367,20 @@
 		iavg_ma = DIV_ROUND_CLOSEST(iavg_ma, iavg_num_samples);
 	}
 
-	uuc_uah_iavg = calculate_uuc_uah_at_given_current(chip,
+	uuc_uah_iavg = calculate_termination_uuc(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);
 
+	/* 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);
+
+	/* find out what the avg current should be for this uuc */
+	chip->prev_uuc_iavg_ma = iavg_ma;
+
+	firsttime = 0;
 	return uuc_uah_iavg;
 }
 
@@ -1277,7 +1407,7 @@
 						int *cc_uah,
 						int *rbatt,
 						int *iavg_ua,
-						int *delta_time_us)
+						int *delta_time_s)
 {
 	int soc_rbatt;
 
@@ -1303,12 +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,
-					*delta_time_us);
+					*delta_time_s);
 	pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
 }
 
@@ -1323,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,
@@ -1332,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;
@@ -1393,6 +1523,7 @@
 	int soc_new = 0;
 	int m = 0;
 	int rc = 0;
+	int delta_ocv_uv_limit = 0;
 
 	rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
 							&ibat_ua,
@@ -1405,6 +1536,9 @@
 
 	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,
@@ -1422,7 +1556,8 @@
 	 * and  cause a bad user experience
 	 */
 	if (soc_est == soc
-		|| (is_between(45, 25, soc_est) && is_between(50, 20, 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;
 
@@ -1457,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)
@@ -1490,48 +1637,81 @@
 }
 
 #define IGNORE_SOC_TEMP_DECIDEG		50
-static void backup_soc(struct pm8921_bms_chip *chip, int batt_temp, int soc)
+#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)
 {
+	u8 temp;
+	int iavg_ma = chip->prev_uuc_iavg_ma;
+
+	if (iavg_ma > IAVG_START)
+		temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+	else
+		temp = 0;
+
+	pm_bms_masked_write(chip, TEMP_IAVG_STORAGE,
+			TEMP_IAVG_STORAGE_USE_MASK, temp);
+
+	/* since only 6 bits are available for SOC, we store half the soc */
 	if (soc == 0)
-		soc = 0xFF;
+		temp = SOC_ZERO;
+	else
+		temp = soc;
 
-	if (batt_temp < IGNORE_SOC_TEMP_DECIDEG)
-		soc = 0;
-
-	pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, soc);
+	/* 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 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_SOC_STORAGE, &temp);
-	if (rc)
-		pr_err("failed to read addr = %d %d\n", TEMP_SOC_STORAGE, rc);
-	else
-		chip->shutdown_soc = 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;
 
-	pr_debug("shutdown_soc = %d\n", chip->shutdown_soc);
-}
-
-void pm8921_bms_invalidate_shutdown_soc(void)
-{
-	pr_debug("Invalidating shutdown soc - the battery was removed\n");
-	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;
-			pr_debug("resetting ocv to pon_ocv = %d\n",
-						the_chip->pon_ocv_uv);
+		if (temp == 0) {
+			chip->shutdown_iavg_ua = IAVG_START;
+		} else {
+			chip->shutdown_iavg_ua = IAVG_START
+					+ IAVG_STEP_SIZE_MA * (temp + 1);
 		}
 	}
-	mutex_unlock(&soc_invalidation_mutex);
+
+	rc = pm8xxx_readb(chip->dev->parent, TEMP_SOC_STORAGE, &temp);
+	if (rc) {
+		pr_err("failed to read addr = %d %d\n", TEMP_SOC_STORAGE, rc);
+	} else {
+		chip->shutdown_soc = temp;
+
+		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);
 }
-EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
 
 static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
 			int batt_temp,
@@ -1575,82 +1755,32 @@
 	*rc_uah = (int)rc;
 }
 
-static void adjust_rc_and_uuc_for_shutdown_soc(
+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 remaining_charge_uah,
+						int rc_uah,
 						int rbatt,
+						int *ret_ocv,
 						int *ret_rc,
 						int *ret_uuc,
 						int *ret_rbatt)
 {
-	int new_rbatt;
 	int ocv_uv;
-	int shutdown_soc;
-	int rc_uah;
-	int soc_rbatt;
-	int iavg_ua, iavg_ma;
-	int num_tries = 0;
-
-	mutex_lock(&soc_invalidation_mutex);
-	shutdown_soc = chip->shutdown_soc;
-	/*
-	 * value of zero means the shutdown soc should not be used, the battery
-	 * was removed for extended period, the coincell capacitor could have
-	 * drained
-	 * shutdown_soc_invalid means the shutdown soc should not be used,
-	 * the battery was removed for a small period
-	 */
-	if (shutdown_soc == 0 || shutdown_soc_invalid) {
-		rc_uah = remaining_charge_uah;
-		goto out;
-	}
-
-	/* value of 0xFF means shutdown soc was 0% */
-	if (shutdown_soc == 0xFF)
-		shutdown_soc = 0;
-
-	pm8921_bms_get_battery_current(&iavg_ua);
-	iavg_ma = iavg_ua / 1000;
-	if (iavg_ma < 0)
-		iavg_ma = CHARGING_IAVG_MA;
-
-recalculate_ocv:
 
 	find_ocv_for_soc(chip, batt_temp, chargecycles,
 					fcc_uah, uuc_uah, cc_uah,
-					shutdown_soc,
+					soc,
 					&rc_uah, &ocv_uv);
 
-	soc_rbatt = div_s64((rc_uah - cc_uah) * 100,  fcc_uah);
-	new_rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
-	pr_debug("for s_soc = %d rc_uah = %d ocv_uv = %d, soc_rbatt = %d rbatt = %d\n",
-			shutdown_soc, rc_uah, ocv_uv, soc_rbatt, new_rbatt);
-	if (abs(new_rbatt - rbatt) > 20 && num_tries < 10) {
-		rbatt = new_rbatt;
-		uuc_uah = calculate_uuc_uah_at_given_current(chip,
-					batt_temp, chargecycles,
-					new_rbatt, fcc_uah, iavg_ma);
-
-		pr_debug("rbatt not settled uuc = %d for rbatt = %d iavg_ma = %d num_tries = %d\n",
-					uuc_uah, rbatt, iavg_ma, num_tries);
-		num_tries++;
-		goto recalculate_ocv;
-	}
-	pr_debug("DONE for s_soc = %d rc_uah = %d ocv_uv = %d, rbatt = %d\n",
-			shutdown_soc, rc_uah, ocv_uv, new_rbatt);
-
-	chip->pon_ocv_uv = chip->last_ocv_uv;
-	chip->last_ocv_uv = ocv_uv;
-out:
+	*ret_ocv = ocv_uv;
 	*ret_rbatt = rbatt;
 	*ret_rc = rc_uah;
 	*ret_uuc = uuc_uah;
-	mutex_unlock(&soc_invalidation_mutex);
 }
 
 #define SOC_CATCHUP_SEC_MAX		600
@@ -1714,20 +1844,15 @@
 
 static bool is_shutdown_soc_within_limits(struct pm8921_bms_chip *chip, int soc)
 {
-	int shutdown_soc;
-
-	if (chip->shutdown_soc == 0 || shutdown_soc_invalid) {
+	if (shutdown_soc_invalid) {
 		pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
 		return 0;
 	}
 
-	shutdown_soc = chip->shutdown_soc;
-	if (shutdown_soc == 0xFF)
-		shutdown_soc = 0;
-
-	if (abs(shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
-		pr_debug("rejecting shutdown soc = %d, soc = %d, limit = %d\n",
-			shutdown_soc, soc, chip->shutdown_soc_valid_limit);
+	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;
 	}
@@ -1749,10 +1874,13 @@
 	int cc_uah;
 	int rbatt;
 	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,
@@ -1761,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
@@ -1778,9 +1906,39 @@
 					(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("before adjusting calculated SOC = %d%%\n", soc);
 
 	if (bms_fake_battery != -EINVAL) {
 		pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
@@ -1802,33 +1960,52 @@
 		soc = 0;
 	}
 
-	if (delta_time_us == 0 && is_shutdown_soc_within_limits(chip, soc)) {
+	mutex_lock(&soc_invalidation_mutex);
+	shutdown_soc = chip->shutdown_soc;
+
+	if (firsttime && soc != shutdown_soc
+			&& is_shutdown_soc_within_limits(chip, soc)) {
 		/*
 		 * soc for the first time - use shutdown soc
 		 * to adjust pon ocv since it is a small percent away from
 		 * the real soc
 		 */
-		adjust_rc_and_uuc_for_shutdown_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;
 }
 
@@ -1937,22 +2114,67 @@
 		 * force shutdown soc if it is valid and the shutdown soc show
 		 * timer has not expired
 		 */
-		if (chip->shutdown_soc != 0xFF)
-			soc = chip->shutdown_soc;
-		else
-			soc = 0;
+		soc = chip->shutdown_soc;
 
 		pr_debug("Forcing SHUTDOWN_SOC = %d\n", soc);
 	}
 
 	last_soc = soc;
-	backup_soc(chip, batt_temp, last_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)
 {
@@ -2099,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");
@@ -2127,7 +2349,7 @@
 						&cc_uah,
 						&rbatt,
 						&iavg_ua,
-						&delta_time_us);
+						&delta_time_s);
 	mutex_unlock(&the_chip->last_ocv_uv_mutex);
 
 	return rbatt;
@@ -2244,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) {
@@ -2258,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);
 	}
@@ -2891,6 +3112,13 @@
 	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);
@@ -2935,7 +3163,7 @@
 		goto free_irqs;
 	}
 
-	read_shutdown_soc(chip);
+	read_shutdown_soc_and_iavg(chip);
 
 	platform_set_drvdata(pdev, chip);
 	the_chip = chip;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 4e15e77..6330883 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -2808,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;
@@ -2867,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/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 7d0583c..3366bba 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -60,19 +60,40 @@
 #define TSENS2_POINT1_MASK		0x3f00000
 #define TSENS3_POINT1_MASK		0xfc000000
 #define TSENS4_POINT1_MASK		0x3f
-#define TSENS5_POINT1_MASK		0xfc00
+#define TSENS5_POINT1_MASK		0xfc0
 #define TSENS6_POINT1_MASK		0x3f000
 #define TSENS7_POINT1_MASK		0xfc0000
 #define TSENS8_POINT1_MASK		0x3f000000
 #define TSENS9_POINT1_MASK		0x3f
 #define TSENS10_POINT1_MASK		0xfc00
 #define TSENS_CAL_SEL_0_1		0xc0000000
-#define TSENS_CAL_SEL_2			BIT(30)
+#define TSENS_CAL_SEL_2			0x40000000
 #define TSENS_CAL_SEL_SHIFT		30
 #define TSENS_CAL_SEL_SHIFT_2		28
-#define TSENS_ONE_POINT_CALIB		0x3
+#define TSENS_ONE_POINT_CALIB		0x1
 #define TSENS_TWO_POINT_CALIB		0x2
 
+#define TSENS0_POINT1_SHIFT		8
+#define TSENS1_POINT1_SHIFT		14
+#define TSENS2_POINT1_SHIFT		20
+#define TSENS3_POINT1_SHIFT		26
+#define TSENS5_POINT1_SHIFT		6
+#define TSENS6_POINT1_SHIFT		12
+#define TSENS7_POINT1_SHIFT		18
+#define TSENS8_POINT1_SHIFT		24
+#define TSENS10_POINT1_SHIFT		6
+
+#define TSENS_POINT2_BASE_SHIFT		12
+#define TSENS0_POINT2_SHIFT		20
+#define TSENS1_POINT2_SHIFT		26
+#define TSENS3_POINT2_SHIFT		6
+#define TSENS4_POINT2_SHIFT		12
+#define TSENS5_POINT2_SHIFT		18
+#define TSENS6_POINT2_SHIFT		24
+#define TSENS8_POINT2_SHIFT		6
+#define TSENS9_POINT2_SHIFT		12
+#define TSENS10_POINT2_SHIFT		18
+
 #define TSENS_BASE2_MASK		0xff000
 #define TSENS0_POINT2_MASK		0x3f00000
 #define TSENS1_POINT2_MASK		0xfc000000
@@ -148,9 +169,11 @@
 	if (degcbeforefactor == 0)
 		degc = degcbeforefactor;
 	else if (degcbeforefactor > 0)
-		degc = degcbeforefactor;
+		degc = ((degcbeforefactor * tmdev->tsens_factor) +
+				tmdev->tsens_factor/2)/tmdev->tsens_factor;
 	else
-		degc = degcbeforefactor;
+		degc = ((degcbeforefactor * tmdev->tsens_factor) -
+				tmdev->tsens_factor/2)/tmdev->tsens_factor;
 
 	return degc;
 }
@@ -479,20 +502,20 @@
 	int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
 	int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
 	int tsens9_point2 = 0, tsens10_point2 = 0;
-	int tsens_base2_data = 0, tsens_calibration_mode = 0, temp;
+	int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
 	uint32_t calib_data[5];
 
 	for (i = 0; i < 5; i++)
 		calib_data[i] = readl_relaxed(tmdev->tsens_calib_addr
 					+ (i * TSENS_SN_ADDR_OFFSET));
 
-	tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1
-			>> TSENS_CAL_SEL_SHIFT);
-	temp = (calib_data[3] & TSENS_CAL_SEL_2
-			>> TSENS_CAL_SEL_SHIFT_2);
+	tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
+			>> TSENS_CAL_SEL_SHIFT;
+	temp = (calib_data[3] & TSENS_CAL_SEL_2)
+			>> TSENS_CAL_SEL_SHIFT_2;
 	tsens_calibration_mode |= temp;
 
-	if (!tsens_calibration_mode) {
+	if (tsens_calibration_mode == 0) {
 		pr_debug("TSENS is calibrationless mode\n");
 		for (i = 0; i < tmdev->tsens_num_sensor; i++) {
 			tmdev->sensor[i].calib_data_point2 = 780;
@@ -501,38 +524,58 @@
 		goto compute_intercept_slope;
 	} else if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
 				TSENS_TWO_POINT_CALIB) {
-		tsens_base1_data = calib_data[0] & TSENS_BASE1_MASK;
-		tsens0_point1 = calib_data[0] & TSENS0_POINT1_MASK;
-		tsens1_point1 = calib_data[0] & TSENS1_POINT1_MASK;
-		tsens2_point1 = calib_data[0] & TSENS2_POINT1_MASK;
-		tsens3_point1 = calib_data[0] & TSENS3_POINT1_MASK;
-		tsens4_point1 = calib_data[1] & TSENS4_POINT1_MASK;
-		tsens5_point1 = calib_data[1] & TSENS5_POINT1_MASK;
-		tsens6_point1 = calib_data[1] & TSENS6_POINT1_MASK;
-		tsens7_point1 = calib_data[1] & TSENS7_POINT1_MASK;
-		tsens8_point1 = calib_data[1] & TSENS8_POINT1_MASK;
-		tsens9_point1 = calib_data[2] & TSENS9_POINT1_MASK;
-		tsens10_point1 = calib_data[2] & TSENS10_POINT1_MASK;
+		tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
+		tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
+							TSENS0_POINT1_SHIFT;
+		tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
+							TSENS1_POINT1_SHIFT;
+		tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
+							TSENS2_POINT1_SHIFT;
+		tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
+							TSENS3_POINT1_SHIFT;
+		tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
+		tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
+							TSENS5_POINT1_SHIFT;
+		tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
+							TSENS6_POINT1_SHIFT;
+		tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
+							TSENS7_POINT1_SHIFT;
+		tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
+							TSENS8_POINT1_SHIFT;
+		tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
+		tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK) >>
+							TSENS10_POINT1_SHIFT;
 	} else if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
-		tsens_base2_data = calib_data[2] & TSENS_BASE2_MASK;
-		tsens0_point2 = calib_data[2] & TSENS0_POINT2_MASK;
-		tsens1_point2 = calib_data[2] & TSENS1_POINT2_MASK;
-		tsens2_point2 = calib_data[3] & TSENS2_POINT2_MASK;
-		tsens3_point2 = calib_data[3] & TSENS3_POINT2_MASK;
-		tsens4_point2 = calib_data[3] & TSENS4_POINT2_MASK;
-		tsens5_point2 = calib_data[3] & TSENS5_POINT2_MASK;
-		tsens6_point2 = calib_data[3] & TSENS6_POINT2_MASK;
-		tsens7_point2 = calib_data[4] & TSENS7_POINT2_MASK;
-		tsens8_point2 = calib_data[4] & TSENS8_POINT2_MASK;
-		tsens9_point2 = calib_data[4] & TSENS9_POINT2_MASK;
-		tsens10_point2 = calib_data[4] & TSENS10_POINT2_MASK;
+		tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
+						TSENS_POINT2_BASE_SHIFT;
+		tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
+						TSENS0_POINT2_SHIFT;
+		tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
+						TSENS1_POINT2_SHIFT;
+		tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
+		tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
+						TSENS3_POINT2_SHIFT;
+		tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
+						TSENS4_POINT2_SHIFT;
+		tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
+						TSENS5_POINT2_SHIFT;
+		tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
+						TSENS6_POINT2_SHIFT;
+		tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
+		tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
+						TSENS8_POINT2_SHIFT;
+		tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
+						TSENS9_POINT2_SHIFT;
+		tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK) >>
+						TSENS10_POINT2_SHIFT;
 	} else {
 		pr_debug("Calibration mode is unknown: %d\n",
 						tsens_calibration_mode);
 		return -ENODEV;
 	}
 
-	if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
+	if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
+					TSENS_TWO_POINT_CALIB) {
 		tmdev->sensor[0].calib_data_point1 =
 		(((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
 		tmdev->sensor[1].calib_data_point1 =
@@ -577,7 +620,7 @@
 		tmdev->sensor[8].calib_data_point2 =
 		(((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
 		tmdev->sensor[9].calib_data_point2 =
-		(((tsens_base2_data + tsens9_point2) < 2) | TSENS_BIT_APPEND);
+		(((tsens_base2_data + tsens9_point2) << 2) | TSENS_BIT_APPEND);
 		tmdev->sensor[10].calib_data_point2 =
 		(((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
 	}
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 465e512..eebda9e 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1465,12 +1465,26 @@
 	return ret;
 }
 
+static int msm_hsic_pm_suspend_noirq(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+
+	if (mehci->async_int) {
+		dev_dbg(dev, "suspend_noirq: Aborting due to pending interrupt\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
 static int msm_hsic_pm_resume(struct device *dev)
 {
 	int ret;
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 
+	dev_dbg(dev, "ehci-msm-hsic PM resume\n");
 	dbg_log_event(NULL, "PM Resume", 0);
 
 	if (device_may_wakeup(dev))
@@ -1524,6 +1538,7 @@
 #ifdef CONFIG_PM
 static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
+	.suspend_noirq = msm_hsic_pm_suspend_noirq,
 	SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
 				msm_hsic_runtime_idle)
 };
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index d17125a..d1438d1 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -131,6 +131,8 @@
 	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/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;