Merge "ngd_slim: Ignore pm_runtime_get error when runtime-pm is not enabled"
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index 2cb528c..6ef897a 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -39,7 +39,7 @@
         1200   -  WCN XO settling time (usec)
         1      -  WCN RPM power collapse enabled
         1      -  WCN standalone power collapse enabled
-
+        6      -  GPIO strength value
 
 Example:
 
@@ -64,5 +64,5 @@
         qcom,has-48mhz-xo;
         qcom,has-pronto-hw;
         qcom,wcnss-adc_tm = <&pm8226_adc_tm>;
-	qcom,wcnss-pm = <11 21 1200 1 1>;
+	qcom,wcnss-pm = <11 21 1200 1 1 6>;
     };
diff --git a/arch/arm/boot/compressed/libfdt_env.h b/arch/arm/boot/compressed/libfdt_env.h
index 1f4e718..799b575 100644
--- a/arch/arm/boot/compressed/libfdt_env.h
+++ b/arch/arm/boot/compressed/libfdt_env.h
@@ -1,6 +1,7 @@
 #ifndef _ARM_LIBFDT_ENV_H
 #define _ARM_LIBFDT_ENV_H
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <asm/byteorder.h>
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 525def5..ae3e19d 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -527,3 +527,4 @@
 CONFIG_MOBICORE_API=m
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_MSM_RDBG=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 6874b28..b239bcb 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -504,3 +504,4 @@
 CONFIG_MSM_RDBG=m
 CONFIG_MOBICORE_SUPPORT=m
 CONFIG_MOBICORE_API=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 7c299d7..2711278 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -459,6 +459,7 @@
 CONFIG_QPNP_CLKDIV=y
 CONFIG_QPNP_REVID=y
 CONFIG_QPNP_COINCELL=y
+CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_IOMMU_V1=y
 CONFIG_IOMMU_PGTABLES_L2=y
 CONFIG_MSM_IOMMU_VBIF_CHECK=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index e8a1cde..52f3598 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -483,6 +483,7 @@
 CONFIG_QPNP_CLKDIV=y
 CONFIG_QPNP_REVID=y
 CONFIG_QPNP_COINCELL=y
+CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_IOMMU_V1=y
 CONFIG_MSM_IOMMU_PMON=y
 CONFIG_IOMMU_PGTABLES_L2=y
@@ -568,3 +569,4 @@
 CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
 CONFIG_MSM_RDBG=m
 CONFIG_MSM_AVTIMER=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index 28b2195..6a71e36 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,7 +23,7 @@
 #include <linux/string.h>
 #include <linux/atomic.h>
 #include <linux/of.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm-generic/sizes.h>
 #include <mach/memory.h>
 #include <mach/msm_rtb.h>
@@ -38,18 +38,20 @@
 /* Write
  * 1) 3 bytes sentinel
  * 2) 1 bytes of log type
- * 3) 4 bytes of where the caller came from
+ * 3) 8 bytes of where the caller came from
  * 4) 4 bytes index
- * 4) 4 bytes extra data from the caller
+ * 4) 8 bytes extra data from the caller
+ * 5) 8 bytes for timestamp
  *
- * Total = 16 bytes.
+ * Total = 32 bytes.
  */
 struct msm_rtb_layout {
 	unsigned char sentinel[3];
 	unsigned char log_type;
-	void *caller;
-	unsigned long idx;
-	void *data;
+	uint32_t idx;
+	uint64_t caller;
+	uint64_t data;
+	uint64_t timestamp;
 } __attribute__ ((__packed__));
 
 
@@ -70,7 +72,7 @@
 static atomic_t msm_rtb_idx;
 #endif
 
-struct msm_rtb_state msm_rtb = {
+static struct msm_rtb_state msm_rtb = {
 	.filter = 1 << LOGK_LOGBUF,
 	.enabled = 1,
 };
@@ -109,24 +111,29 @@
 	start->log_type = (char)log_type;
 }
 
-static void msm_rtb_write_caller(void *caller, struct msm_rtb_layout *start)
+static void msm_rtb_write_caller(uint64_t caller, struct msm_rtb_layout *start)
 {
 	start->caller = caller;
 }
 
-static void msm_rtb_write_idx(unsigned long idx,
+static void msm_rtb_write_idx(uint32_t idx,
 				struct msm_rtb_layout *start)
 {
 	start->idx = idx;
 }
 
-static void msm_rtb_write_data(void *data, struct msm_rtb_layout *start)
+static void msm_rtb_write_data(uint64_t data, struct msm_rtb_layout *start)
 {
 	start->data = data;
 }
 
-static void uncached_logk_pc_idx(enum logk_event_type log_type, void *caller,
-				 void *data, int idx)
+static void msm_rtb_write_timestamp(struct msm_rtb_layout *start)
+{
+	start->timestamp = sched_clock();
+}
+
+static void uncached_logk_pc_idx(enum logk_event_type log_type, uint64_t caller,
+				 uint64_t data, int idx)
 {
 	struct msm_rtb_layout *start;
 
@@ -137,6 +144,7 @@
 	msm_rtb_write_caller(caller, start);
 	msm_rtb_write_idx(idx, start);
 	msm_rtb_write_data(data, start);
+	msm_rtb_write_timestamp(start);
 	mb();
 
 	return;
@@ -145,13 +153,10 @@
 static void uncached_logk_timestamp(int idx)
 {
 	unsigned long long timestamp;
-	void *timestamp_upper, *timestamp_lower;
 	timestamp = sched_clock();
-	timestamp_lower = (void *)lower_32_bits(timestamp);
-	timestamp_upper = (void *)upper_32_bits(timestamp);
-
-	uncached_logk_pc_idx(LOGK_TIMESTAMP|LOGTYPE_NOPC, timestamp_lower,
-			     timestamp_upper, idx);
+	uncached_logk_pc_idx(LOGK_TIMESTAMP|LOGTYPE_NOPC,
+			(uint64_t)lower_32_bits(timestamp),
+			(uint64_t)upper_32_bits(timestamp), idx);
 }
 
 #if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
@@ -213,7 +218,8 @@
 
 	i = msm_rtb_get_idx();
 
-	uncached_logk_pc_idx(log_type, caller, data, i);
+	uncached_logk_pc_idx(log_type, (uint64_t)((unsigned long) caller),
+				(uint64_t)((unsigned long) data), i);
 
 	return 1;
 }
@@ -225,7 +231,7 @@
 }
 EXPORT_SYMBOL(uncached_logk);
 
-int msm_rtb_probe(struct platform_device *pdev)
+static int msm_rtb_probe(struct platform_device *pdev)
 {
 	struct msm_rtb_platform_data *d = pdev->dev.platform_data;
 #if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
@@ -297,7 +303,6 @@
 	{.compatible = RTB_COMPAT_STR},
 	{},
 };
-EXPORT_COMPAT(RTB_COMPAT_STR);
 
 static struct platform_driver msm_rtb_driver = {
 	.driver         = {
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index 9f5765d..c8f0101 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -463,14 +463,23 @@
 	size = (adreno_is_a330(adreno_dev) ||
 		adreno_is_a305b(adreno_dev)) ? 0x2E : 0x14;
 
-	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
-			remain, REG_CP_STATE_DEBUG_INDEX,
-			REG_CP_STATE_DEBUG_DATA, 0x0, size);
+	/* Skip indexed register dump for these chipsets 8974, 8x26, 8x10 */
+	if (adreno_is_a330(adreno_dev) ||
+		adreno_is_a330v2(adreno_dev) ||
+		adreno_is_a305b(adreno_dev) ||
+		adreno_is_a305c(adreno_dev)	) {
+		KGSL_DRV_ERR(device,
+		"Skipping indexed register dump\n");
+	} else {
+		snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
+				remain, REG_CP_STATE_DEBUG_INDEX,
+				REG_CP_STATE_DEBUG_DATA, 0x0, size);
 
-	/* CP_ME indexed registers */
-	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
-			remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS,
-			64, 44);
+		/* CP_ME indexed registers */
+		snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
+				remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS,
+				64, 44);
+	}
 
 	/* VPC memory */
 	snapshot = kgsl_snapshot_add_section(device,
@@ -482,10 +491,19 @@
 			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
 			a3xx_snapshot_cp_meq, NULL);
 
-	/* Shader working/shadow memory */
-	snapshot = kgsl_snapshot_add_section(device,
+	/* Skip shader memory dump for these chipsets: 8974, 8x26, 8x10 */
+	if (adreno_is_a330(adreno_dev) ||
+		adreno_is_a330v2(adreno_dev) ||
+		adreno_is_a305b(adreno_dev) ||
+		adreno_is_a305c(adreno_dev)	) {
+		KGSL_DRV_ERR(device,
+		"Skipping shader memory dump\n");
+	} else {
+		/* Shader working/shadow memory */
+		snapshot = kgsl_snapshot_add_section(device,
 			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
 			a3xx_snapshot_shader_memory, NULL);
+	}
 
 
 	/* CP PFP and PM4 */
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index bcab791..d79a169 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -221,13 +221,17 @@
 		struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch)
 {
 	unsigned int prev;
+	struct kgsl_device *device;
 	spin_lock(&drawctxt->lock);
 
 	if (kgsl_context_detached(&drawctxt->base) ||
 		drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
 		spin_unlock(&drawctxt->lock);
+		device = cmdbatch->device;
 		/* get rid of this cmdbatch since the context is bad */
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		kgsl_cmdbatch_destroy(cmdbatch);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		return -EINVAL;
 	}
 
@@ -414,7 +418,10 @@
 		 */
 
 		if (cmdbatch->flags & KGSL_CONTEXT_SYNC) {
+			struct kgsl_device *device = cmdbatch->device;
+			kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 			kgsl_cmdbatch_destroy(cmdbatch);
+			kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 			continue;
 		}
 
@@ -931,11 +938,8 @@
 			drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
 			replay[i] = NULL;
 
-			kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 			kgsl_cancel_events_timestamp(device, cmd->context,
 				cmd->timestamp);
-			kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
-
 			kgsl_cmdbatch_destroy(cmd);
 		}
 	}
@@ -1084,7 +1088,8 @@
 		kgsl_device_snapshot(device, 1);
 	}
 
-	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+    kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+
 
 	/* Allocate memory to store the inflight commands */
 	replay = kzalloc(sizeof(*replay) * dispatcher->inflight, GFP_KERNEL);
@@ -1092,6 +1097,7 @@
 	if (replay == NULL) {
 		unsigned int ptr = dispatcher->head;
 
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		/* Recovery failed - mark everybody guilty */
 		mark_guilty_context(device, 0);
 
@@ -1111,6 +1117,7 @@
 		 */
 
 		count = 0;
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		goto replay;
 	}
 
@@ -1168,7 +1175,9 @@
 			cmdbatch->context->id, cmdbatch->timestamp);
 
 		mark_guilty_context(device, cmdbatch->context->id);
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		adreno_drawctxt_invalidate(device, cmdbatch->context);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 	}
 
 	/*
@@ -1277,7 +1286,9 @@
 	mark_guilty_context(device, cmdbatch->context->id);
 
 	/* Invalidate the context */
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	adreno_drawctxt_invalidate(device, cmdbatch->context);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 
 replay:
@@ -1296,8 +1307,10 @@
 	/* If adreno_reset() fails then what hope do we have for the future? */
 	BUG_ON(ret);
 
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	/* Remove any pending command batches that have been invalidated */
 	remove_invalidated_cmdbatches(device, replay, count);
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	/* Replay the pending command buffers */
 	for (i = 0; i < count; i++) {
@@ -1339,9 +1352,11 @@
 			/* Mark this context as guilty (failed recovery) */
 			mark_guilty_context(device, replay[i]->context->id);
 
+			kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 			adreno_drawctxt_invalidate(device, replay[i]->context);
 			remove_invalidated_cmdbatches(device, &replay[i],
 				count - i);
+			kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 		}
 	}
 
@@ -1449,8 +1464,10 @@
 			dispatcher->head = CMDQUEUE_NEXT(dispatcher->head,
 				ADRENO_DISPATCH_CMDQUEUE_SIZE);
 
+			kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 			/* Destroy the retired command batch */
 			kgsl_cmdbatch_destroy(cmdbatch);
+			kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 			/* Update the expire time for the next command batch */
 
@@ -1695,16 +1712,19 @@
 void adreno_dispatcher_close(struct adreno_device *adreno_dev)
 {
 	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
+	struct kgsl_device *device = &adreno_dev->dev;
 
 	mutex_lock(&dispatcher->mutex);
 	del_timer_sync(&dispatcher->timer);
 	del_timer_sync(&dispatcher->fault_timer);
 
+	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 	while (dispatcher->head != dispatcher->tail) {
 		kgsl_cmdbatch_destroy(dispatcher->cmdqueue[dispatcher->head]);
 		dispatcher->head = (dispatcher->head + 1)
 			% ADRENO_DISPATCH_CMDQUEUE_SIZE;
 	}
+	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	mutex_unlock(&dispatcher->mutex);
 
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index db4aa6a..df9d6ec 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -367,14 +367,10 @@
 	kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
 
 	if (timeout) {
-		ret = (int) wait_event_timeout(drawctxt->waiting,
+		if (0 == (int) wait_event_timeout(drawctxt->waiting,
 			_check_global_timestamp(device, drawctxt, timestamp),
-			msecs_to_jiffies(timeout));
-
-		if (ret == 0)
+			msecs_to_jiffies(timeout)))
 			ret = -ETIMEDOUT;
-		else if (ret > 0)
-			ret = 0;
 	} else {
 		wait_event(drawctxt->waiting,
 			_check_global_timestamp(device, drawctxt, timestamp));
@@ -598,9 +594,14 @@
 	 */
 	BUG_ON(!mutex_is_locked(&device->mutex));
 
-	/* Wait for the last global timestamp to pass before continuing */
+	/* Wait for the last global timestamp to pass before continuing.
+	 * The maxumum wait time is 30s, some large IB's can take longer
+	 * than 10s and if hang happens then the time for the context's
+	 * commands to retire will be greater than 10s. 30s should be sufficient
+	 * time to wait for the commands even if a hang happens.
+	 */
 	ret = adreno_drawctxt_wait_global(adreno_dev, context,
-		drawctxt->internal_timestamp, 10 * 1000);
+		drawctxt->internal_timestamp, 30 * 1000);
 
 	/*
 	 * If the wait for global fails then nothing after this point is likely
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 060dbd2..a5b25a0 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2311,8 +2311,11 @@
 	 * -EPROTO is a "success" error - it just tells the user that the
 	 * context had previously faulted
 	 */
-	if (result && result != -EPROTO)
+	if (result && result != -EPROTO) {
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		kgsl_cmdbatch_destroy(cmdbatch);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+	}
 
 done:
 	kgsl_context_put(context);
@@ -2363,8 +2366,11 @@
 	 * -EPROTO is a "success" error - it just tells the user that the
 	 * context had previously faulted
 	 */
-	if (result && result != -EPROTO)
+	if (result && result != -EPROTO) {
+		kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
 		kgsl_cmdbatch_destroy(cmdbatch);
+		kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
+	}
 
 done:
 	kgsl_context_put(context);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index ba1e58c..263d54d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -403,8 +403,8 @@
 		reset_type = ISP_RST_HARD;
 	}
 	rst_val = msm_vfe32_reset_values[reset_type];
-	init_completion(&vfe_dev->reset_complete);
 	if (blocking) {
+		init_completion(&vfe_dev->reset_complete);
 		msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0x4);
 		rc = wait_for_completion_timeout(
 		   &vfe_dev->reset_complete, msecs_to_jiffies(50));
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 270fb38..e5d82fd 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -211,13 +211,23 @@
 		pr_err("%s failed line %d\n", __func__, __LINE__);
 		return -EINVAL;
 	}
-	/* assume total size within the max queue */
+
+	reg_addr = i2c_cmd->reg_addr;
 	while (cmd_size) {
-		CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__,
+		CDBG("%s cmd_size %d addr 0x%x data 0x%x\n", __func__,
 			cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data);
 		delay = i2c_cmd->delay;
 		data[i++] = CCI_I2C_WRITE_CMD;
-		reg_addr = i2c_cmd->reg_addr;
+
+		/* in case of multiple command
+		* MSM_CCI_I2C_WRITE : address is not continuous, so update
+		*			address for a new packet.
+		* MSM_CCI_I2C_WRITE_SEQ : address is continuous, need to keep
+		*			the incremented address for a
+		*			new packet */
+		if (c_ctrl->cmd == MSM_CCI_I2C_WRITE)
+			reg_addr = i2c_cmd->reg_addr;
+
 		/* either byte or word addr */
 		if (i2c_msg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
 			data[i++] = reg_addr;
@@ -226,21 +236,25 @@
 			data[i++] = reg_addr & 0x00FF;
 		}
 		/* max of 10 data bytes */
-		if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) {
-			data[i++] = i2c_cmd->reg_data;
-			reg_addr++;
-		} else {
-			if ((i + 1) <= 10) {
-				data[i++] = (i2c_cmd->reg_data &
-					0xFF00) >> 8; /* MSB */
-				data[i++] = i2c_cmd->reg_data &
-					0x00FF; /* LSB */
-				reg_addr += 2;
-			} else
-				break;
-		}
-		i2c_cmd++;
-		--cmd_size;
+		do {
+			if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) {
+				data[i++] = i2c_cmd->reg_data;
+				reg_addr++;
+			} else {
+				if ((i + 1) <= 10) {
+					data[i++] = (i2c_cmd->reg_data &
+						0xFF00) >> 8; /* MSB */
+					data[i++] = i2c_cmd->reg_data &
+						0x00FF; /* LSB */
+					reg_addr += 2;
+				} else
+					break;
+			}
+			i2c_cmd++;
+			--cmd_size;
+		} while ((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) &&
+				(cmd_size > 0) && (i <= 10));
+
 		data[0] |= ((i-1) << 4);
 		len = ((i-1)/4) + 1;
 		rc = msm_cci_validate_queue(cci_dev, len, master, queue);
@@ -789,6 +803,7 @@
 		rc = msm_cci_i2c_read_bytes(sd, cci_ctrl);
 		break;
 	case MSM_CCI_I2C_WRITE:
+	case MSM_CCI_I2C_WRITE_SEQ:
 		rc = msm_cci_i2c_write(sd, cci_ctrl);
 		break;
 	case MSM_CCI_GPIO_WRITE:
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
index 44c134e..283bd28 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
@@ -53,6 +53,7 @@
 	MSM_CCI_SET_SYNC_CID,
 	MSM_CCI_I2C_READ,
 	MSM_CCI_I2C_WRITE,
+	MSM_CCI_I2C_WRITE_SEQ,
 	MSM_CCI_GPIO_WRITE,
 };
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
index 8d9274b..6af0cea 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
@@ -158,7 +158,7 @@
 		reg_conf_tbl[i].reg_data = data[i];
 		reg_conf_tbl[i].delay = 0;
 	}
-	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
+	cci_ctrl.cmd = MSM_CCI_I2C_WRITE_SEQ;
 	cci_ctrl.cci_info = client->cci_client;
 	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl;
 	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 0eee530..032cca4 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -215,6 +215,7 @@
 	cmd_done.device_id = device_id;
 	cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
 		session_id;
+	cmd_done.status = hfi_map_err_status(pkt->event_data1);
 	dprintk(VIDC_INFO, "Received : SESSION_ERROR with event id : %d\n",
 		pkt->event_data1);
 	switch (pkt->event_data1) {
@@ -222,6 +223,7 @@
 	case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
 	case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
 	case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
+		cmd_done.status = VIDC_ERR_NONE;
 		dprintk(VIDC_INFO, "Non Fatal : HFI_EVENT_SESSION_ERROR\n");
 		break;
 	default:
@@ -834,12 +836,9 @@
 	} else {
 		sess_close = (struct hal_session *)pkt->session_id;
 		if (sess_close) {
-			dprintk(VIDC_INFO,
-				"Sess init failed: Deleting session: 0x%x 0x%p",
+			dprintk(VIDC_WARN,
+				"Sess init failed: 0x%x, 0x%p",
 				sess_close->session_id, sess_close);
-			list_del(&sess_close->list);
-			kfree(sess_close);
-			sess_close = NULL;
 		}
 	}
 	cmd_done.size = sizeof(struct vidc_hal_session_init_done);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 30ca194..7830db7 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -1400,7 +1400,7 @@
 	case V4L2_DEC_QCOM_CMD_FLUSH:
 		if (core->state != VIDC_CORE_INVALID &&
 			inst->state ==  MSM_VIDC_CORE_INVALID) {
-			rc = msm_comm_recover_from_session_error(inst);
+			rc = msm_comm_kill_session(inst);
 			if (rc)
 				dprintk(VIDC_ERR,
 					"Failed to recover from session_error: %d\n",
@@ -1415,7 +1415,7 @@
 	case V4L2_DEC_CMD_STOP:
 		if (core->state != VIDC_CORE_INVALID &&
 			inst->state ==  MSM_VIDC_CORE_INVALID) {
-			rc = msm_comm_recover_from_session_error(inst);
+			rc = msm_comm_kill_session(inst);
 			if (rc)
 				dprintk(VIDC_ERR,
 					"Failed to recover from session_error: %d\n",
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index ba17820..794d116 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -46,6 +46,10 @@
 	u32 __mbs = (__h >> 4) * (__w >> 4);\
 	__mbs;\
 })
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst);
+static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst);
+static void handle_session_error(enum command_response cmd, void *data);
+
 static bool is_turbo_requested(struct msm_vidc_core *core,
 		enum session_type type)
 {
@@ -398,7 +402,7 @@
 		dprintk(VIDC_ERR,
 			"%s: Wait interrupted or timeout[%u]: %d\n",
 			__func__, (u32)inst->session, SESSION_MSG_INDEX(cmd));
-		msm_comm_recover_from_session_error(inst);
+		msm_comm_kill_session(inst);
 		rc = -EIO;
 	} else {
 		rc = 0;
@@ -432,32 +436,19 @@
 	wake_up(&inst->kernel_event_queue);
 }
 
-static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
-{
-	if (!inst) {
-		dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
-		return;
-	}
-	mutex_lock(&inst->lock);
-	inst->session = NULL;
-	inst->state = MSM_VIDC_CORE_INVALID;
-	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
-	mutex_unlock(&inst->lock);
-}
-
 static void msm_comm_generate_max_clients_error(struct msm_vidc_inst *inst)
 {
+	enum command_response cmd = SESSION_ERROR;
+	struct msm_vidc_cb_cmd_done response = {0};
+
 	if (!inst) {
 		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
 		return;
 	}
-	mutex_lock(&inst->sync_lock);
-	inst->session = NULL;
-	inst->state = MSM_VIDC_CORE_INVALID;
-	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_MAX_CLIENTS);
-	dprintk(VIDC_WARN,
-			"%s: Too many clients\n", __func__);
-	mutex_unlock(&inst->sync_lock);
+	dprintk(VIDC_ERR, "%s: Too many clients\n", __func__);
+	response.session_id = (u32) inst;
+	response.status = VIDC_ERR_MAX_CLIENTS;
+	handle_session_error(cmd, (void *)&response);
 }
 
 static void handle_session_init_done(enum command_response cmd, void *data)
@@ -834,21 +825,50 @@
 static void handle_session_error(enum command_response cmd, void *data)
 {
 	struct msm_vidc_cb_cmd_done *response = data;
+	int rc;
+	struct hfi_device *hdev = NULL;
 	struct msm_vidc_inst *inst = NULL;
-	if (response) {
-		inst = (struct msm_vidc_inst *)response->session_id;
-		if (inst) {
-			dprintk(VIDC_WARN,
-				"Session error receivd for session %p\n", inst);
-			mutex_lock(&inst->sync_lock);
-			inst->state = MSM_VIDC_CORE_INVALID;
-			mutex_unlock(&inst->sync_lock);
-			msm_vidc_queue_v4l2_event(inst,
-					V4L2_EVENT_MSM_VIDC_SYS_ERROR);
-		}
-	} else {
+
+	if (!response) {
 		dprintk(VIDC_ERR,
 			"Failed to get valid response for session error\n");
+		return;
+	}
+
+	inst = (struct msm_vidc_inst *)response->session_id;
+
+	if (!inst || !inst->session || !inst->core->device) {
+		dprintk(VIDC_ERR,
+				"Session (%p) not in a stable enough state to handle session error\n",
+				inst);
+		return;
+	}
+
+	hdev = inst->core->device;
+	dprintk(VIDC_WARN, "Session error received for session %p\n", inst);
+	change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+
+	mutex_lock(&inst->lock);
+	dprintk(VIDC_DBG, "cleaning up inst: %p\n", inst);
+	rc = call_hfi_op(hdev, session_clean, inst->session);
+	if (rc)
+		dprintk(VIDC_ERR, "Session (%p) clean failed: %d\n", inst, rc);
+
+	inst->session = NULL;
+	mutex_unlock(&inst->lock);
+
+	if (response->status == VIDC_ERR_MAX_CLIENTS) {
+		dprintk(VIDC_WARN,
+			"send max clients reached error to client: %p\n",
+			inst);
+		msm_vidc_queue_v4l2_event(inst,
+			V4L2_EVENT_MSM_VIDC_MAX_CLIENTS);
+	} else {
+		dprintk(VIDC_ERR,
+			"send session error to client: %p\n",
+			inst);
+		msm_vidc_queue_v4l2_event(inst,
+			V4L2_EVENT_MSM_VIDC_SYS_ERROR);
 	}
 }
 
@@ -1249,10 +1269,10 @@
 	inst = (struct msm_vidc_inst *)response->session_id;
 	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
 	buffer_type = msm_comm_get_hal_output_buffer(inst);
-	if (fill_buf_done->buffer_type == buffer_type)
+	if (fill_buf_done->buffer_type == buffer_type) {
 		vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
 			(u32)fill_buf_done->packet_buffer1);
-	else {
+	} else {
 		if (handle_multi_stream_buffers(inst,
 			(u32)fill_buf_done->packet_buffer1))
 			dprintk(VIDC_ERR,
@@ -1881,7 +1901,7 @@
 			num_mbs_per_sec, inst->core->resources.max_load);
 		msm_vidc_print_running_insts(inst->core);
 		inst->state = MSM_VIDC_CORE_INVALID;
-		msm_comm_recover_from_session_error(inst);
+		msm_comm_kill_session(inst);
 		return -EBUSY;
 	}
 
@@ -2672,7 +2692,7 @@
 			__func__, (u32)inst->session,
 			SESSION_MSG_INDEX(SESSION_PROPERTY_INFO));
 		inst->state = MSM_VIDC_CORE_INVALID;
-		msm_comm_recover_from_session_error(inst);
+		msm_comm_kill_session(inst);
 		rc = -EIO;
 		goto exit;
 	}
@@ -2790,11 +2810,9 @@
 				rc = wait_for_sess_signal_receipt(inst,
 					SESSION_RELEASE_BUFFER_DONE);
 				if (rc) {
-					mutex_lock(&inst->sync_lock);
-					inst->state = MSM_VIDC_CORE_INVALID;
-					mutex_unlock(&inst->sync_lock);
-					msm_comm_recover_from_session_error(
-						inst);
+					change_inst_state(inst,
+						MSM_VIDC_CORE_INVALID);
+					msm_comm_kill_session(inst);
 				}
 				mutex_lock(&inst->lock);
 			}
@@ -2861,11 +2879,9 @@
 				rc = wait_for_sess_signal_receipt(inst,
 					SESSION_RELEASE_BUFFER_DONE);
 				if (rc) {
-					mutex_lock(&inst->sync_lock);
-					inst->state = MSM_VIDC_CORE_INVALID;
-					mutex_unlock(&inst->sync_lock);
-					msm_comm_recover_from_session_error(
-						inst);
+					change_inst_state(inst,
+						MSM_VIDC_CORE_INVALID);
+					msm_comm_kill_session(inst);
 				}
 				mutex_lock(&inst->lock);
 			}
@@ -3472,9 +3488,7 @@
 		}
 	}
 	if (rc) {
-		mutex_lock(&inst->sync_lock);
-		inst->state = MSM_VIDC_CORE_INVALID;
-		mutex_unlock(&inst->sync_lock);
+		change_inst_state(inst, MSM_VIDC_CORE_INVALID);
 		msm_vidc_queue_v4l2_event(inst,
 					V4L2_EVENT_MSM_VIDC_HW_OVERLOAD);
 		dprintk(VIDC_WARN,
@@ -3484,6 +3498,22 @@
 	return rc;
 }
 
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
+{
+	enum command_response cmd = SESSION_ERROR;
+	struct msm_vidc_cb_cmd_done response = {0};
+
+	dprintk(VIDC_WARN, "msm_comm_generate_session_error\n");
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+		return;
+	}
+
+	response.session_id = (u32)inst;
+	response.status = VIDC_ERR_FAIL;
+	handle_session_error(cmd, (void *)&response);
+}
+
 static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
 {
 	struct msm_vidc_core *core;
@@ -3498,43 +3528,55 @@
 	handle_sys_error(cmd, (void *) &response);
 
 }
-int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst)
+
+int msm_comm_kill_session(struct msm_vidc_inst *inst)
 {
-	struct hfi_device *hdev;
 	int rc = 0;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
 		return -EINVAL;
+	} else if (!inst->session) {
+		/* There's no hfi session to kill */
+		return 0;
 	}
-	if (!inst->session || inst->state < MSM_VIDC_OPEN_DONE) {
-		dprintk(VIDC_WARN,
-			"No corresponding FW session. No need to send Abort");
-		return rc;
-	}
-	hdev = inst->core->device;
 
-	init_completion(&inst->completions[SESSION_MSG_INDEX
-		(SESSION_ABORT_DONE)]);
-
-	/* We have received session_error. Send session_abort to firmware
-	 *  to clean up and release the session
+	/*
+	 * We're internally forcibly killing the session, if fw is aware of
+	 * the session send session_abort to firmware to clean up and release
+	 * the session, else just kill the session inside the driver.
 	 */
-	rc = call_hfi_op(hdev, session_abort, (void *) inst->session);
-	if (rc) {
-		dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc);
-		return rc;
+	if (inst->state >= MSM_VIDC_OPEN_DONE &&
+			inst->state < MSM_VIDC_CLOSE_DONE) {
+		struct hfi_device *hdev = inst->core->device;
+		int abort_completion = SESSION_MSG_INDEX(SESSION_ABORT_DONE);
+
+		rc = call_hfi_op(hdev, session_abort, (void *) inst->session);
+		if (rc) {
+			dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc);
+			return rc;
+		}
+
+		init_completion(&inst->completions[abort_completion]);
+		rc = wait_for_completion_timeout(
+				&inst->completions[abort_completion],
+				msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+		if (!rc) {
+			dprintk(VIDC_ERR,
+					"%s: Wait interrupted or timed out [%p]: %d\n",
+					__func__, inst, abort_completion);
+			msm_comm_generate_sys_error(inst);
+		} else {
+			change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
+		}
+	} else {
+		dprintk(VIDC_WARN,
+				"Inactive session %p, triggering an internal session error\n",
+				inst);
+		msm_comm_generate_session_error(inst);
+
 	}
-	rc = wait_for_completion_timeout(
-		&inst->completions[SESSION_MSG_INDEX(SESSION_ABORT_DONE)],
-		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
-	if (!rc) {
-		dprintk(VIDC_ERR, "%s: Wait interrupted or timeout[%u]: %d\n",
-			__func__, (u32)inst->session,
-			SESSION_MSG_INDEX(SESSION_ABORT_DONE));
-		msm_comm_generate_sys_error(inst);
-	} else
-		change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
+
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index f4e2cd5..1e86278 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -52,7 +52,7 @@
 		V4L2_CTRL_DRIVER_PRIV(idx))
 
 int msm_comm_check_scaling_supported(struct msm_vidc_inst *inst);
-int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
+int msm_comm_kill_session(struct msm_vidc_inst *inst);
 enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
 enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
 struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index e43a563..399cea9 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -648,7 +648,7 @@
 	}
 	if (req_mode > HIGH) {
 		pr_err("Invalid bandwidth mode (%d)\n", req_mode);
-		return ret;
+		return -EINVAL;
 	}
 
 	/*
@@ -1115,8 +1115,8 @@
 	bool found_dead_app = false;
 
 	if (!memcmp(data->client.app_name, "keymaste", strlen("keymaste"))) {
-		pr_warn("Do not unload keymaster app from tz\n");
-		return 0;
+		pr_debug("Do not unload keymaster app from tz\n");
+		goto unload_exit;
 	}
 
 	if (data->client.app_id > 0) {
@@ -1211,6 +1211,7 @@
 		spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
 								flags1);
 	}
+unload_exit:
 	qseecom_unmap_ion_allocated_memory(data);
 	data->released = true;
 	return ret;
@@ -1392,6 +1393,74 @@
 	return ret;
 }
 
+static int __validate_send_cmd_inputs(struct qseecom_dev_handle *data,
+				struct qseecom_send_cmd_req *req)
+{
+	if (!data || !data->client.ihandle) {
+		pr_err("Client or client handle is not initialized\n");
+		return -EINVAL;
+	}
+	if (((req->resp_buf == NULL) && (req->resp_len != 0)) ||
+						(req->cmd_req_buf == NULL)) {
+		pr_err("cmd buffer or response buffer is null\n");
+		return -EINVAL;
+	}
+	if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
+		((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
+					data->client.sb_length))) {
+		pr_err("cmd buffer address not within shared bufffer\n");
+		return -EINVAL;
+	}
+	if (((uintptr_t)req->resp_buf <
+				data->client.user_virt_sb_base)  ||
+		((uintptr_t)req->resp_buf >=
+		(data->client.user_virt_sb_base + data->client.sb_length))) {
+		pr_err("response buffer address not within shared bufffer\n");
+		return -EINVAL;
+	}
+	if ((req->cmd_req_len == 0) ||
+		(req->cmd_req_len > data->client.sb_length) ||
+		(req->resp_len > data->client.sb_length)) {
+		pr_err("cmd buf length or response buf length not valid\n");
+		return -EINVAL;
+	}
+	if (req->cmd_req_len > UINT_MAX - req->resp_len) {
+		pr_err("Integer overflow detected in req_len & rsp_len\n");
+		return -EINVAL;
+	}
+
+	if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
+		pr_debug("Not enough memory to fit cmd_buf.\n");
+		pr_debug("resp_buf. Required: %u, Available: %zu\n",
+				(req->cmd_req_len + req->resp_len),
+					data->client.sb_length);
+		return -ENOMEM;
+	}
+	if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
+		pr_err("Integer overflow in req_len & cmd_req_buf\n");
+		return -EINVAL;
+	}
+	if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
+		pr_err("Integer overflow in resp_len & resp_buf\n");
+		return -EINVAL;
+	}
+	if (data->client.user_virt_sb_base >
+					(ULONG_MAX - data->client.sb_length)) {
+		pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
+		return -EINVAL;
+	}
+	if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
+		((uintptr_t)data->client.user_virt_sb_base +
+						data->client.sb_length)) ||
+		(((uintptr_t)req->resp_buf + req->resp_len) >
+		((uintptr_t)data->client.user_virt_sb_base +
+						data->client.sb_length))) {
+		pr_err("cmd buf or resp buf is out of shared buffer region\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
 				struct qseecom_send_cmd_req *req)
 {
@@ -1404,46 +1473,7 @@
 	bool found_app = false;
 	int name_len = 0;
 
-	if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
-		pr_err("cmd buffer or response buffer is null\n");
-		return -EINVAL;
-	}
-	if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
-		((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
-					data->client.sb_length))) {
-		pr_err("cmd buffer address not within shared bufffer\n");
-		return -EINVAL;
-	}
-
-
-	if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base)  ||
-		((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
-					data->client.sb_length))){
-		pr_err("response buffer address not within shared bufffer\n");
-		return -EINVAL;
-	}
-
-	if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
-		req->cmd_req_len > data->client.sb_length ||
-		req->resp_len > data->client.sb_length) {
-		pr_err("cmd buffer length or "
-				"response buffer length not valid\n");
-		return -EINVAL;
-	}
-
-	if (req->cmd_req_len > UINT_MAX - req->resp_len) {
-		pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
-		return -EINVAL;
-	}
-
 	reqd_len_sb_in = req->cmd_req_len + req->resp_len;
-	if (reqd_len_sb_in > data->client.sb_length) {
-		pr_debug("Not enough memory to fit cmd_buf and "
-			"resp_buf. Required: %u, Available: %u\n",
-				reqd_len_sb_in, data->client.sb_length);
-		return -ENOMEM;
-	}
-
 	/* find app_id & img_name from list */
 	spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
 	list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
@@ -1517,6 +1547,10 @@
 		pr_err("copy_from_user failed\n");
 		return ret;
 	}
+
+	if (__validate_send_cmd_inputs(data, &req))
+		return -EINVAL;
+
 	ret = __qseecom_send_cmd(data, &req);
 
 	if (ret)
@@ -1525,30 +1559,32 @@
 	return ret;
 }
 
-int boundary_checks_offset(struct qseecom_send_modfd_cmd_req *cmd_req,
+int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *cmd_req,
 			struct qseecom_send_modfd_listener_resp *lstnr_resp,
 			struct qseecom_dev_handle *data, bool listener_svc,
 			int i) {
-	int ret = 0;
 
 	if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
-		if (cmd_req->ifd_data[i].cmd_buf_offset >
-				cmd_req->cmd_req_len - sizeof(uint32_t)) {
+		if ((cmd_req->cmd_req_len < sizeof(uint32_t)) ||
+				(cmd_req->ifd_data[i].cmd_buf_offset >
+				cmd_req->cmd_req_len - sizeof(uint32_t))) {
 			pr_err("Invalid offset 0x%x\n",
 					cmd_req->ifd_data[i].cmd_buf_offset);
-			return ++ret;
+			return -EINVAL;
 		}
 	} else if ((listener_svc) && (lstnr_resp->ifd_data[i].fd > 0)) {
-		if (lstnr_resp->ifd_data[i].cmd_buf_offset >
-				lstnr_resp->resp_len - sizeof(uint32_t)) {
+		if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
+				(lstnr_resp->ifd_data[i].cmd_buf_offset >
+				lstnr_resp->resp_len - sizeof(uint32_t))) {
 			pr_err("Invalid offset 0x%x\n",
 					lstnr_resp->ifd_data[i].cmd_buf_offset);
-			return ++ret;
+			return -EINVAL;
 		}
 	}
-	return ret;
+	return 0;
 }
 
+#define SG_ENTRY_SZ   sizeof(struct qseecom_sg_entry)
 static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
 					struct qseecom_dev_handle *data,
 					bool listener_svc)
@@ -1623,7 +1659,7 @@
 			uint32_t *update;
 			update = (uint32_t *) field;
 
-			if (boundary_checks_offset(cmd_req, lstnr_resp, data,
+			if (__boundary_checks_offset(cmd_req, lstnr_resp, data,
 							listener_svc, i))
 				goto err;
 			if (cleanup)
@@ -1637,9 +1673,11 @@
 			int j = 0;
 
 			if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
-				if (cmd_req->ifd_data[i].cmd_buf_offset >
-					cmd_req->cmd_req_len -
-					sizeof(struct qseecom_sg_entry)) {
+				if ((cmd_req->cmd_req_len <
+					SG_ENTRY_SZ * sg_ptr->nents) ||
+					(cmd_req->ifd_data[i].cmd_buf_offset >
+					(cmd_req->cmd_req_len -
+					SG_ENTRY_SZ * sg_ptr->nents))) {
 					pr_err("Invalid offset = 0x%x\n",
 						cmd_req->ifd_data[i].
 						cmd_buf_offset);
@@ -1647,9 +1685,11 @@
 				}
 			} else if ((listener_svc) &&
 					(lstnr_resp->ifd_data[i].fd > 0)) {
-				if (lstnr_resp->ifd_data[i].cmd_buf_offset >
-							lstnr_resp->resp_len -
-					sizeof(struct qseecom_sg_entry)) {
+				if ((lstnr_resp->resp_len <
+					SG_ENTRY_SZ * sg_ptr->nents) ||
+					(lstnr_resp->ifd_data[i].cmd_buf_offset >
+					(lstnr_resp->resp_len -
+					SG_ENTRY_SZ * sg_ptr->nents))) {
 					pr_err("Invalid offset = 0x%x\n",
 						lstnr_resp->ifd_data[i].
 							cmd_buf_offset);
@@ -1704,35 +1744,14 @@
 		return ret;
 	}
 
-	if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
-		pr_err("cmd buffer or response buffer is null\n");
-		return -EINVAL;
-	}
-	if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
-		((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
-					data->client.sb_length))) {
-		pr_err("cmd buffer address not within shared bufffer\n");
-		return -EINVAL;
-	}
-
-	if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base)  ||
-		((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
-					data->client.sb_length))){
-		pr_err("response buffer address not within shared bufffer\n");
-		return -EINVAL;
-	}
-
-	if (req.cmd_req_len == 0 || req.cmd_req_len > data->client.sb_length ||
-		req.resp_len > data->client.sb_length) {
-		pr_err("cmd or response buffer length not valid\n");
-		return -EINVAL;
-	}
-
 	send_cmd_req.cmd_req_buf = req.cmd_req_buf;
 	send_cmd_req.cmd_req_len = req.cmd_req_len;
 	send_cmd_req.resp_buf = req.resp_buf;
 	send_cmd_req.resp_len = req.resp_len;
 
+	if (__validate_send_cmd_inputs(data, &send_cmd_req))
+		return -EINVAL;
+
 	/* validate offsets */
 	for (i = 0; i < MAX_ION_FD; i++) {
 		if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
@@ -2381,6 +2400,9 @@
 	req.cmd_req_buf = send_buf;
 	req.resp_buf = resp_buf;
 
+	if (__validate_send_cmd_inputs(data, &req))
+		return -EINVAL;
+
 	mutex_lock(&app_access_lock);
 	atomic_inc(&data->ioctl_count);
 	if (qseecom.support_bus_scaling) {
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 4a4a88c..887bb72 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -1948,13 +1948,13 @@
 		return;
 	}
 
-	pr_debug("%s:size=%d: <%d, %d, %d, %d, %d>\n", __func__,
+	pr_debug("%s:size=%d: <%d, %d, %d, %d, %d %d>\n", __func__,
 			prop_len, *payload, *(payload+1), *(payload+2),
-			*(payload+3), *(payload+4));
+			*(payload+3), *(payload+4), *(payload+5));
 
 	hdr = (struct smd_msg_hdr *)msg;
 	hdr->msg_type = WCNSS_PM_CONFIG_REQ;
-	hdr->msg_len = sizeof(struct smd_msg_hdr) + prop_len;
+	hdr->msg_len = sizeof(struct smd_msg_hdr) + (prop_len * sizeof(int));
 
 	rc = wcnss_smd_tx(msg, hdr->msg_len);
 	if (rc < 0)
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index 2f9c086..b1681f1 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -61,7 +61,7 @@
 #define	CORE_RESET_RSP_GID		(0x60)
 #define	CORE_RESET_OID			(0x00)
 #define CORE_RST_NTF_LENGTH		(0x02)
-#define WAKE_TIMEOUT			(10)
+#define WAKE_TIMEOUT			(1000)
 #define WAKE_REG			(0x10)
 #define EFUSE_REG			(0xA0)
 #define WAKEUP_SRC_TIMEOUT		(2000)
@@ -101,6 +101,8 @@
 	struct workqueue_struct *my_wq;
 };
 
+static int nfcc_reboot(struct notifier_block *notifier, unsigned long val,
+			void *v);
 static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len);
 static int nfcc_hw_check(struct i2c_client *client, unsigned short curr_addr);
 static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr,
@@ -124,7 +126,7 @@
 
 
 unsigned int	disable_ctrl;
-bool		region2_sent;
+bool			region2_sent;
 
 static void qca199x_init_stat(struct qca199x_dev *qca199x_dev)
 {
@@ -163,15 +165,16 @@
 	if (device_may_wakeup(&qca199x_dev->client->dev) &&
 		(qca199x_dev->client->dev.power.is_suspended == true)) {
 		dev_dbg(&qca199x_dev->client->dev,
-			"NFC:Processor in suspend state device_may_wakeup\n");
+			"%s: NFC:Processor in suspend state device_may_wakeup\n",
+			__func__);
 		/*
-		* Keep system awake long enough to allow userspace
-		* to process the packet.
-		*/
+		 * Keep system awake long enough to allow userspace
+		 * to process the packet.
+		 */
 		pm_wakeup_event(&qca199x_dev->client->dev, WAKEUP_SRC_TIMEOUT);
 	} else {
 		dev_dbg(&qca199x_dev->client->dev,
-			"NFC:Processor not in suspend state\n");
+			"%s: NFC:Processor not in suspend state\n", __func__);
 	}
 
 	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
@@ -329,7 +332,12 @@
 		/* READ */
 		if ((ftm_raw_write_mode == 0) && (ftm_werr_code == 0)) {
 			ftm_rerr_code = i2c_master_recv(qca199x_dev->client,
-						&rd_byte, 1);
+						&rd_byte, sizeof(rd_byte));
+
+			if (ftm_rerr_code != sizeof(rd_byte)) {
+				total = -EMSGSIZE;
+				goto err;
+			}
 			if (ftm_rerr_code == 0x1)
 				ftm_rerr_code = 0;
 			tmp[0] = (unsigned char)ftm_rerr_code;
@@ -388,8 +396,8 @@
 	if (total > 0) {
 		if ((total > count) || copy_to_user(buf, tmp, total)) {
 			dev_err(&qca199x_dev->client->dev,
-				"failed to copy to user space, total = %d\n",
-					total);
+				"%s: failed to copy to user space, total = %d\n",
+					__func__, total);
 			total = -EFAULT;
 		}
 	}
@@ -438,6 +446,9 @@
 		ret = i2c_master_recv(qca199x_dev->client, tmp, (length +
 			PAYLOAD_HEADER_LENGTH));
 		total = ret;
+		if (ret != (length + PAYLOAD_HEADER_LENGTH))
+			goto leave;
+
 	}
 	dev_dbg(&qca199x_dev->client->dev, "%s : NfcNciRx %x %x %x\n",
 			__func__, tmp[0], tmp[1], tmp[2]);
@@ -456,12 +467,13 @@
 	int nfcc_buffer = 0;
 
 	if (count > MAX_BUFFER_SIZE) {
-		dev_err(&qca199x_dev->client->dev, "out of memory\n");
+		dev_err(&qca199x_dev->client->dev, "%s: out of memory\n",
+			__func__);
 		return -ENOMEM;
 	}
 	if (copy_from_user(tmp, buf, count)) {
 		dev_err(&qca199x_dev->client->dev,
-			"nfc-nci write: failed to copy from user space\n");
+			"%s: failed to copy from user space\n", __func__);
 		return -EFAULT;
 	}
 	/*
@@ -477,7 +489,8 @@
 		/* There has been an error while reading from nfcc */
 		if (nfcc_buffer < 0) {
 			dev_err(&qca199x_dev->client->dev,
-				"nfc-nci write: error while servicing nfcc read buffer\n");
+				"%s: error while servicing nfcc read buffer\n"
+				, __func__);
 		}
 		qca199x_dev->sent_first_nci_write = true;
 		qca199x_enable_irq(qca199x_dev);
@@ -492,7 +505,7 @@
 		if (count == 1) {
 			ftm_raw_write_mode = 0;
 			ret = i2c_master_send(qca199x_dev->client, tmp, count);
-			if (ret == 1)
+			if (ret == count)
 				ftm_werr_code = 0;
 			else
 				ftm_werr_code = ret;
@@ -502,7 +515,7 @@
 		if (count == 2) {
 			ftm_raw_write_mode = 1;
 			ret = i2c_master_send(qca199x_dev->client, tmp, count);
-			if (ret == 2)
+			if (ret == count)
 				ftm_werr_code = 0;
 			else
 				ftm_werr_code = ret;
@@ -515,7 +528,7 @@
 	}
 	if (ret != count) {
 		dev_err(&qca199x_dev->client->dev,
-		"NFC: failed to write %d\n", ret);
+		"%s: failed to write %d\n", __func__, ret);
 		ret = -EIO;
 	}
 	mutex_unlock(&qca199x_dev->read_mutex);
@@ -549,7 +562,7 @@
 		qca199x_enable_irq_clk_req(qca199x_dev);
 	}
 	dev_dbg(&qca199x_dev->client->dev,
-			"%d,%d\n", imajor(inode), iminor(inode));
+			"%s: %d,%d\n", __func__, imajor(inode), iminor(inode));
 	return ret;
 }
 
@@ -561,17 +574,21 @@
 	int r = 0;
 	int time_taken = 0;
 	unsigned char raw_nci_sleep[] = {0x2F, 0x03, 0x00};
-	/* Change slave address to 0xE */
 	unsigned char raw_nci_wake[]  = {0x10, 0x0F};
-	unsigned short	slave_addr	=	0xE;
+	/* Change slave address to 0xE */
+	unsigned short	slave_addr = 0xE;
 	unsigned short	curr_addr;
-	unsigned char wake_status	= WAKE_REG;
+	unsigned char wake_status = WAKE_REG;
 	struct qca199x_dev *qca199x_dev = filp->private_data;
 
-	dev_dbg(&qca199x_dev->client->dev, "nfcc_wake: %s: info: %p\n",
+	dev_dbg(&qca199x_dev->client->dev, "%s: info: %p\n",
 			__func__, qca199x_dev);
 
+	curr_addr = qca199x_dev->client->addr;
 	if (level == NFCC_SLEEP) {
+		/*
+		 * Normal NCI write
+		 */
 		r = i2c_master_send(qca199x_dev->client, &raw_nci_sleep[0],
 						sizeof(raw_nci_sleep));
 
@@ -579,54 +596,79 @@
 			return -EMSGSIZE;
 		qca199x_dev->state = NFCC_STATE_NORMAL_SLEEP;
 	} else {
-		curr_addr = qca199x_dev->client->addr;
 		qca199x_dev->client->addr = slave_addr;
 		r = nfc_i2c_write(qca199x_dev->client, &raw_nci_wake[0],
 						sizeof(raw_nci_wake));
+		if (r != sizeof(raw_nci_wake)) {
+			r = -EMSGSIZE;
+			dev_err(&qca199x_dev->client->dev,
+				"%s: nci wake write failed. Check hardware\n",
+				__func__);
+			goto leave;
+		}
 		do {
 			wake_status = WAKE_REG;
-			r = nfc_i2c_write(qca199x_dev->client, &wake_status, 1);
+			r = nfc_i2c_write(qca199x_dev->client, &wake_status,
+						 sizeof(wake_status));
+			if (r != sizeof(wake_status)) {
+				r = -EMSGSIZE;
+				dev_err(&qca199x_dev->client->dev,
+				"%s: wake status write fail.Check hardware\n",
+				 __func__);
+				goto leave;
+			}
 			/*
-			 * NFCC chip needs to be at least
-			 * 10usec high before make it low
+			 * I2C line is low after ~10 usec
 			 */
 			usleep_range(10, 15);
 			r = i2c_master_recv(qca199x_dev->client, &wake_status,
 						sizeof(wake_status));
+			if (r != sizeof(wake_status)) {
+				r = -EMSGSIZE;
+				dev_err(&qca199x_dev->client->dev,
+				"%s: wake status read fail.Check hardware\n",
+				 __func__);
+				goto leave;
+			}
 
 			time_taken++;
+			/*
+			 * Each NFCC wakeup cycle
+			 * takes about 0.5 ms
+			 */
 			if ((wake_status & NCI_WAKE) != 0)
 				/* NFCC wakeup time is between 0.5 and .52 ms */
-				usleep_range(500, 520);
+				usleep_range(500, 550);
 
 		} while ((wake_status & NCI_WAKE)
 				&& (time_taken < WAKE_TIMEOUT));
-		/* Restore original NFCC slave I2C address */
-		if (time_taken >= WAKE_TIMEOUT)
+		if (time_taken >= WAKE_TIMEOUT) {
 			dev_err(&qca199x_dev->client->dev,
-			"nfc_ioctl_nfcc_version : TIMED OUT to get WAKEUP bit\n");
-
-		qca199x_dev->client->addr = curr_addr;
-		if (r != sizeof(wake_status))
-			return -EMSGSIZE;
+			"%s: timed out to get wakeup bit\n", __func__);
+			r = -EIO;
+			goto leave;
+		}
+		r = 0;
 		qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
 	}
-
+leave:
+	/* Restore original NFCC slave I2C address */
+	qca199x_dev->client->addr = curr_addr;
 	return r;
 }
 
 /*
  * Inside nfc_ioctl_power_states
  *
- * @brief   ioctl functions
+ * @brief	ioctl functions
  *
  *
  * Device control
  * remove control via ioctl
- * (arg = 0): NFC_DISABLE   GPIO = 0
- * (arg = 1): NFC_DISABLE   GPIO = 1
- *  NOT USED   (arg = 2): FW_DL GPIO = 0
- *  NOT USED   (arg = 3): FW_DL GPIO = 1
+ * (arg = 0): NFC_DISABLE	GPIO = 0
+ * (arg = 1): NFC_DISABLE	GPIO = 1
+ *	NOT USED   (arg = 2): FW_DL GPIO = 0
+ *	NOT USED   (arg = 3): FW_DL GPIO = 1
  * (arg = 4): NFCC_WAKE  = 1
  * (arg = 5): NFCC_WAKE  = 0
  *
@@ -645,7 +687,7 @@
 		dev_dbg(&qca199x_dev->client->dev, "gpio_set_value disable: %s: info: %p\n",
 			__func__, qca199x_dev);
 		gpio_set_value(qca199x_dev->dis_gpio, 0);
-		usleep(1000);
+		usleep_range(1000, 1100);
 	} else if (arg == 1) {
 		/*
 		 * We are attempting a hardware reset so let us disable
@@ -667,7 +709,7 @@
 		dev_dbg(&qca199x_dev->client->dev, "gpio_set_value enable: %s: info: %p\n",
 			__func__, qca199x_dev);
 		gpio_set_value(qca199x_dev->dis_gpio, 1);
-		/*nfcc needs atleast 100ms for the chip to power cycle*/
+		/* NFCC needs at least 100 ms to power cycle*/
 		msleep(100);
 	} else if (arg == 2) {
 		mutex_lock(&qca199x_dev->read_mutex);
@@ -688,12 +730,12 @@
 		msleep(20);
 	} else if (arg == 4) {
 		mutex_lock(&qca199x_dev->read_mutex);
-		nfcc_wake(NFCC_WAKE, filp);
+		r = nfcc_wake(NFCC_WAKE, filp);
 		dev_dbg(&qca199x_dev->client->dev, "nfcc wake: %s: info: %p\n",
 			__func__, qca199x_dev);
 		mutex_unlock(&qca199x_dev->read_mutex);
 	} else if (arg == 5) {
-		nfcc_wake(NFCC_SLEEP, filp);
+		r = nfcc_wake(NFCC_SLEEP, filp);
 	} else {
 		r = -ENOIOCTLCMD;
 	}
@@ -705,14 +747,14 @@
 /*
  * Inside nfc_ioctl_nfcc_mode
  *
- * @brief   nfc_ioctl_nfcc_mode
+ * @brief	nfc_ioctl_nfcc_mode
  *
  * (arg = 0) ; NORMAL_MODE - Standard mode, unsolicited read behaviour
  * (arg = 1) ; SOLICITED_MODE - As above but reads are solicited from User Land
  * (arg = 2) ; UNSOLICITED_FTM_RAW MODE - NORMAL_MODE but messages from FTM and
- *             not NCI Host.
+ *			   not NCI Host.
  * (arg = 2) ; SOLICITED_FTM_RAW_MODE - As SOLICITED_MODE but messages from FTM
- *             and not NCI Host.
+ *			   and not NCI Host.
  *
  *
  *
@@ -759,6 +801,61 @@
 }
 
 /*
+ * Inside nfc_ioctl_nfcc_efuse
+ *
+ * @brief   nfc_ioctl_nfcc_efuse
+ *
+ *
+ */
+int nfc_ioctl_nfcc_efuse(struct file *filp, unsigned int cmd,
+				unsigned long arg)
+{
+	int r = 0;
+	unsigned short slave_addr = 0xE;
+	unsigned short curr_addr;
+	unsigned char efuse_addr  = EFUSE_REG;
+	unsigned char efuse_value = 0xFF;
+
+	struct qca199x_dev *qca199x_dev = filp->private_data;
+
+	curr_addr = qca199x_dev->client->addr;
+	qca199x_dev->client->addr = slave_addr;
+
+	r = nfc_i2c_write(qca199x_dev->client,
+				&efuse_addr, 1);
+	if (r < 0) {
+		/* Restore original NFCC slave I2C address */
+		qca199x_dev->client->addr = curr_addr;
+		dev_err(&qca199x_dev->client->dev,
+		"ERROR_WRITE_FAIL : i2c write fail\n");
+		return -EIO;
+	}
+
+	/*
+	 * NFCC chip needs to be at least
+	 * 10usec high before make it low
+	 */
+	usleep_range(10, 15);
+
+	r = i2c_master_recv(qca199x_dev->client, &efuse_value,
+					sizeof(efuse_value));
+	if (r < 0) {
+		/* Restore original NFCC slave I2C address */
+		qca199x_dev->client->addr = curr_addr;
+		dev_err(&qca199x_dev->client->dev,
+		"ERROR_I2C_RCV_FAIL : i2c recv fail\n");
+		return -EIO;
+	}
+
+	dev_dbg(&qca199x_dev->client->dev, "%s : EFUSE_VALUE %02x\n",
+	__func__, efuse_value);
+
+	/* Restore original NFCC slave I2C address */
+	qca199x_dev->client->addr = curr_addr;
+	return efuse_value;
+}
+
+/*
  * Inside nfc_ioctl_nfcc_version
  *
  * @brief   nfc_ioctl_nfcc_version
@@ -769,11 +866,8 @@
 				unsigned long arg)
 {
 	int r = 0;
-	int	time_taken	= 0;
-	unsigned short	slave_addr	=	0xE;
+	unsigned short	slave_addr = 0xE;
 	unsigned short	curr_addr;
-	unsigned char	raw_nci_wake[]			= {0x10, 0x0F};
-	unsigned char	raw_nci_read;
 	unsigned char raw_chip_version_addr		= 0x00;
 	unsigned char raw_chip_rev_id_addr		= 0x9C;
 	unsigned char raw_chip_version			= 0xFF;
@@ -787,88 +881,56 @@
 	 * Always wake up chip when reading 0x9C, otherwise this
 	 * register is not updated
 	 */
+	r = nfcc_wake(NFCC_WAKE, filp);
 	curr_addr = qca199x_dev->client->addr;
 	qca199x_dev->client->addr = slave_addr;
-	r = nfc_i2c_write(qca199x_dev->client, &raw_nci_wake[0],
-						sizeof(raw_nci_wake));
 
-	if (r != sizeof(raw_nci_wake))
+
+	if (r) {
 		dev_err(&qca199x_dev->client->dev,
-		"nfc_ioctl_nfcc_version : failed to send wake command\n");
-
-	/*
-	 * After placing the NFCC to sleep by a PROP
-	 * SLEEP NCI msg (2F 03) and we need to wake
-	 * it back up to obtain some information (by
-	 * setting the wake bit).We need to determine
-	 * when it has in actual fact woken before we
-	 * can read the required data. We do that by
-	 * reading back & testing if that wake bit has
-	 * been cleared.
-	 */
-	do {
-		raw_nci_read = 0x10;
-		r = nfc_i2c_write(qca199x_dev->client, &raw_nci_read, 1);
-		/*
-		 * NFCC chip needs to be at least
-		 * 10usec high before make it low
-		 */
-		usleep_range(10, 15);
-
-		r = i2c_master_recv(qca199x_dev->client, &raw_nci_read,
-						sizeof(raw_nci_read));
-
-		if ((raw_nci_read & NCI_WAKE) != 0)
-			/* NFCC wakeup time is between 0.5 and .52 ms */
-			usleep_range(500, 520);
-
-		time_taken++;
-
-	} while ((raw_nci_read & NCI_WAKE)
-			&& (time_taken < WAKE_TIMEOUT));
-
-	if (time_taken < WAKE_TIMEOUT)
-		qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
-	else
-		dev_err(&qca199x_dev->client->dev,
-		"nfc_ioctl_nfcc_version : TIMED OUT to get WAKEUP bit\n");
-
-
-	if (r != 1) {
-		/*
-		 * r < 0 indicates an error, maybe chip isn't
-		 * up yet.What should we do??? r = 0 indicates
-		 * nothing read, maybe chip isn't up yet. (should
-		 * not happen) r > 1 indicates too many bytes read,
-		 * maybe ?(should not happen)
-		 */
-		dev_err(&qca199x_dev->client->dev,
-		"nfc_ioctl_nfcc_version : i2c error %d\n", r);
+		"%s: nfcc wake failed: %d\n", __func__, r);
+		r = -EIO;
+		goto leave;
 	}
 
 	if (arg == 0) {
 		r = nfc_i2c_write(qca199x_dev->client,
-				&raw_chip_version_addr, 1);
+			&raw_chip_version_addr, sizeof(raw_chip_version_addr));
+		if (r != sizeof(raw_chip_version_addr)) {
+			r = -EMSGSIZE;
+			goto err;
+		}
 	} else if (arg == 1) {
 		r = nfc_i2c_write(qca199x_dev->client,
-				&raw_chip_rev_id_addr, 1);
+			&raw_chip_rev_id_addr, sizeof(raw_chip_rev_id_addr));
+		if (r != sizeof(raw_chip_version_addr)) {
+			r = -EMSGSIZE;
+			goto err;
+		}
 	} else {
-		/* Restore original NFCC slave I2C address */
-		qca199x_dev->client->addr = curr_addr;
-		return -EINVAL;
+		r = -EINVAL;
+		goto err;
 	}
 
 	if (r < 0) {
-		/* Restore original NFCC slave I2C address */
-		qca199x_dev->client->addr = curr_addr;
-		dev_err(&qca199x_dev->client->dev,
-			"NFCC_INVALID_CHIP_VERSION : i2c write fail\n");
-		return -EIO;
+		r = -EIO;
+		goto err;
 	}
-
-	usleep(10);
-	r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
-
+	/*
+	* I2C line is low after ~10 usec
+	*/
+	usleep_range(10, 15);
+	r = i2c_master_recv(qca199x_dev->client, &raw_chip_version,
+		sizeof(raw_chip_version));
+	if (r != sizeof(raw_chip_version)) {
+		r = -EMSGSIZE;
+		goto err;
+	}
+	goto leave;
+err:
+	dev_err(&qca199x_dev->client->dev,
+		"%s: i2c access failed\n", __func__);
+leave:
 	/* Restore original NFCC slave I2C address */
 	qca199x_dev->client->addr = curr_addr;
 	return raw_chip_version;
@@ -877,12 +939,12 @@
 /*
  * Inside nfc_ioctl_kernel_logging
  *
- * @brief   nfc_ioctl_kernel_logging
+ * @brief	nfc_ioctl_kernel_logging
  *
  * (arg = 0) ; NO_LOGGING
  * (arg = 1) ; COMMS_LOGGING - BASIC LOGGING - Mainly just comms over I2C
  * (arg = 2) ; FULL_LOGGING - ENABLE ALL  - DBG messages for handlers etc.
- *           ; ! Be aware as amount of logging could impact behaviour !
+ *		; ! Be aware as amount of logging could impact behaviour !
  *
  *
  */
@@ -890,19 +952,19 @@
 {
 	int retval = 0;
 	struct qca199x_dev *qca199x_dev = container_of(filp->private_data,
-							   struct qca199x_dev,
-							   qca199x_device);
+							struct qca199x_dev,
+							qca199x_device);
 	if (arg == 0) {
 		dev_dbg(&qca199x_dev->client->dev,
-		"nfc_ioctl_kernel_logging : level = NO_LOGGING\n");
+		"%s : level = NO_LOGGING\n", __func__);
 		logging_level = 0;
 	} else if (arg == 1) {
 		dev_dbg(&qca199x_dev->client->dev,
-		"nfc_ioctl_kernel_logging: level = COMMS_LOGGING only\n");
+		"%s: level = COMMS_LOGGING only\n", __func__);
 		logging_level = 1;
 	} else if (arg == 2) {
 		dev_dbg(&qca199x_dev->client->dev,
-		"nfc_ioctl_kernel_logging: level = FULL_LOGGING\n");
+		"%s: level = FULL_LOGGING\n", __func__);
 		logging_level = 2;
 	}
 	return retval;
@@ -911,7 +973,7 @@
 /*
  * Inside nfc_ioctl_core_reset_ntf
  *
- * @brief   nfc_ioctl_core_reset_ntf
+ * @brief	nfc_ioctl_core_reset_ntf
  *
  * Allows callers to determine if a CORE_RESET_NTF has arrived
  *
@@ -923,22 +985,23 @@
 {
 	struct qca199x_dev *qca199x_dev = filp->private_data;
 	dev_dbg(&qca199x_dev->client->dev,
-		"nfc_ioctl_core_reset_ntf: returning = %d\n",
+		"%s: returning = %d\n",
+		__func__,
 		qca199x_dev->core_reset_ntf);
 	return qca199x_dev->core_reset_ntf;
 }
 
-static long nfc_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
+static long nfc_ioctl(struct file *pfile, unsigned int cmd,
+			unsigned long arg)
 {
 	int r = 0;
-
+	struct qca199x_dev *qca199x_dev = pfile->private_data;
 	switch (cmd) {
-
 	case NFC_SET_PWR:
-		nfc_ioctl_power_states(pfile, cmd, arg);
+		r = nfc_ioctl_power_states(pfile, cmd, arg);
 		break;
 	case NFCC_MODE:
-		nfc_ioctl_nfcc_mode(pfile, cmd, arg);
+		r = nfc_ioctl_nfcc_mode(pfile, cmd, arg);
 		break;
 	case NFCC_VERSION:
 		r = nfc_ioctl_nfcc_version(pfile, cmd, arg);
@@ -953,6 +1016,14 @@
 	case NFCC_INITIAL_CORE_RESET_NTF:
 		r = nfc_ioctl_core_reset_ntf(pfile, cmd, arg);
 		break;
+	case NFC_GET_EFUSE:
+		r = nfc_ioctl_nfcc_efuse(pfile, cmd, arg);
+		if (r < 0) {
+			r = 0xFF;
+			dev_err(&qca199x_dev->client->dev,
+			"nfc_ioctl : FAILED TO READ EFUSE TYPE\n");
+		}
+		break;
 	default:
 		r = -ENOIOCTLCMD;
 	}
@@ -985,9 +1056,15 @@
 		((i > 0xF) && (i < 0x12)) || ((i > 0x39) && (i < 0x4d)) ||
 		((i > 0x69) && (i < 0x74)) || (i == 0x18) || (i == 0x30) ||
 		(i == 0x58)) {
-			r = nfc_i2c_write(client, &raw_reg_rd, 1);
+			r = nfc_i2c_write(client, &raw_reg_rd,
+				sizeof(raw_reg_rd));
+			if (r != sizeof(raw_reg_rd))
+				break;
 			msleep(20);
-			r = i2c_master_recv(client, &raw_reg_rd, 1);
+			r = i2c_master_recv(client, &raw_reg_rd,
+				sizeof(raw_reg_rd));
+			if (r != sizeof(raw_reg_rd))
+				break;
 		}
 	}
 	client->addr = temp_addr;
@@ -998,11 +1075,11 @@
 	int r;
 
 	r = i2c_master_send(client, buf, len);
-	dev_dbg(&client->dev, "send: %d\n", r);
+	dev_dbg(&client->dev, "%s: send: %d\n", __func__, r);
 	if (r == -EREMOTEIO) { /* Retry, chip was in standby */
 		usleep_range(6000, 10000);
 		r = i2c_master_send(client, buf, len);
-		dev_dbg(&client->dev, "send2: %d\n", r);
+		dev_dbg(&client->dev, "%s: send attempt 2: %d\n", __func__, r);
 	}
 	if (r != len)
 		return -EREMOTEIO;
@@ -1018,22 +1095,23 @@
 
 	client->addr = curr_addr;
 	/* Set-up Addr 0. No data written */
-	r = i2c_master_send(client, &buf, 1);
+	r = i2c_master_send(client, &buf, sizeof(buf));
 	if (r < 0)
 		goto err_presence_check;
 	buf = 0;
 	/* Read back from Addr 0 */
-	r = i2c_master_recv(client, &buf, 1);
+	r = i2c_master_recv(client, &buf, sizeof(buf));
 	if (r < 0)
 		goto err_presence_check;
 
 	r = 0;
-	return r;
+	goto leave;
 
 err_presence_check:
 	r = -ENXIO;
 	dev_err(&client->dev,
-		"nfc-nci nfcc_presence check - no NFCC available\n");
+		"%s: - no NFCC available\n", __func__);
+leave:
 	return r;
 }
 /* Initialise qca199x_ NFC controller hardware */
@@ -1041,7 +1119,7 @@
 				struct qca199x_dev *qca199x_dev)
 {
 	int r = 0;
-	unsigned char raw_1p8_CONTROL_011[]	= {0x11, XTAL_CLOCK};
+	unsigned char raw_1P8_CONTROL_011[]	= {0x11, XTAL_CLOCK};
 	unsigned char raw_1P8_CONTROL_010[]	= {0x10, PWR_EN};
 	unsigned char raw_1P8_X0_0B0[]		= {0xB0, (FREQ_SEL)};
 	unsigned char raw_slave1[]		= {0x09, NCI_I2C_SLAVE};
@@ -1058,12 +1136,17 @@
 
 	client->addr = curr_addr;
 	qca199x_dev->core_reset_ntf = DEFAULT_INITIAL_CORE_RESET_NTF;
-	r = i2c_master_send(client, &buf, 1);
+	r = i2c_master_send(client, &buf, sizeof(buf));
 	if (r < 0)
 		goto err_init;
 
+	/*
+	 * I2C line is low after ~10 usec
+	 */
+	usleep_range(10, 15);
+
 	buf = 0;
-	r = i2c_master_recv(client, &buf, 1);
+	r = i2c_master_recv(client, &buf, sizeof(buf));
 	if (r < 0)
 		goto err_init;
 
@@ -1073,36 +1156,37 @@
 	if (r < 0)
 		goto err_init;
 
-	usleep(1000);
-	RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
+	usleep_range(1000, 1100);
 
-	r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
-					sizeof(raw_1p8_CONTROL_011));
+	RAW(1P8_CONTROL_011, XTAL_CLOCK | 0x01);
+
+	r = nfc_i2c_write(client, &raw_1P8_CONTROL_011[0],
+					sizeof(raw_1P8_CONTROL_011));
 	if (r < 0)
 		goto err_init;
 
-	usleep(1000);
+	usleep_range(1000, 1100); /* 1 ms wait */
 	RAW(1P8_CONTROL_010, (0x8));
 	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
 					sizeof(raw_1P8_CONTROL_010));
 	if (r < 0)
 		goto err_init;
 
-	usleep(10000);  /* 10ms wait */
+	usleep_range(10000, 11000);  /* 10 ms wait */
 	RAW(1P8_CONTROL_010, (0xC));
 	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
 				sizeof(raw_1P8_CONTROL_010));
 	if (r < 0)
 		goto err_init;
 
-	usleep(100);  /* 100uS wait */
+	usleep_range(100, 110);  /* 100 us wait */
 	RAW(1P8_X0_0B0, (FREQ_SEL_19));
 	r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0],
 					sizeof(raw_1P8_X0_0B0));
 	if (r < 0)
 		goto err_init;
 
-	usleep(1000);
+	usleep_range(1000, 1100); /* 1 ms wait */
 
 	/* PWR_EN = 1 */
 	RAW(1P8_CONTROL_010, (0xd));
@@ -1112,7 +1196,7 @@
 		goto err_init;
 
 
-	usleep(20000);  /* 20ms wait */
+	msleep(20);  /* 20ms wait */
 	/* LS_EN = 1 */
 	RAW(1P8_CONTROL_010, 0xF);
 	r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
@@ -1120,41 +1204,43 @@
 	if (r < 0)
 		goto err_init;
 
-	usleep(20000);  /* 20ms wait */
+	msleep(20);  /* 20ms wait */
 
 	/* Enable the PMIC clock */
 	RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
 	r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
-				  sizeof(raw_1P8_PAD_CFG_CLK_REQ));
+				sizeof(raw_1P8_PAD_CFG_CLK_REQ));
 	if (r < 0)
 		goto err_init;
 
-	usleep(1000);
+	usleep_range(1000, 1100); /* 1 ms wait */
 
 	RAW(1P8_PAD_CFG_PWR_REQ, (0x1));
 	r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0],
-				  sizeof(raw_1P8_PAD_CFG_PWR_REQ));
+				sizeof(raw_1P8_PAD_CFG_PWR_REQ));
 	if (r < 0)
 		goto err_init;
 
-	usleep(1000);
+	usleep_range(1000, 1100); /* 1 ms wait */
 
 	RAW(slave2, 0x10);
 	r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
 	if (r < 0)
 		goto err_init;
 
-	usleep(1000);
+	usleep_range(1000, 1100); /* 1 ms wait */
 
 	RAW(slave1, NCI_I2C_SLAVE);
 	r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
 	if (r < 0)
 		goto err_init;
 
-	usleep(1000);
+	usleep_range(1000, 1100); /* 1 ms wait */
 
 	/* QCA199x NFCC CPU should now boot... */
-	r = i2c_master_recv(client, &raw_slave1_rd, 1);
+	r = i2c_master_recv(client, &raw_slave1_rd, sizeof(raw_slave1_rd));
+	if (r < 0)
+		goto err_init;
 	/* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
 	client->addr = NCI_I2C_SLAVE;
 
@@ -1163,35 +1249,37 @@
 	 * get a core reset notification - This is time for chip
 	 * & NFCC controller to come-up.
 	 */
-	usleep(15000); /* 15 ms */
+	usleep_range(15000, 16500); /* 15 ms */
 
 	do {
-		ret = i2c_master_recv(client, rsp, 5);
+		ret = i2c_master_recv(client, rsp, sizeof(rsp));
+		if (ret < 0)
+			goto err_init;
 		/* Found core reset notification */
-		if (((rsp[0] == CORE_RESET_RSP_GID) &&
+		if ((rsp[0] == CORE_RESET_RSP_GID) &&
 			(rsp[1] == CORE_RESET_OID) &&
-			(rsp[2] == CORE_RST_NTF_LENGTH))
-				|| time_taken == NTF_TIMEOUT) {
+			(rsp[2] == CORE_RST_NTF_LENGTH)) {
 			dev_dbg(&client->dev,
-				"NFC core reset recevd: %s: info: %p\n",
+				"NFC core reset recvd: %s: info: %p\n",
 				__func__, client);
 			core_reset_completed = true;
 		} else {
-		  usleep(2000);  /* 2ms sleep before retry */
+		  usleep_range(2000, 2200);  /* 2 ms wait before retry */
 		}
 		time_taken++;
-	} while (!core_reset_completed);
-	if (time_taken == NTF_TIMEOUT)
+	} while (!core_reset_completed && (time_taken < NTF_TIMEOUT));
+	if (time_taken >= NTF_TIMEOUT) {
 		qca199x_dev->core_reset_ntf = TIMEDOUT_INITIAL_CORE_RESET_NTF;
-	else
-		qca199x_dev->core_reset_ntf = ARRIVED_INITIAL_CORE_RESET_NTF;
+		goto err_init;
+	}
+	qca199x_dev->core_reset_ntf = ARRIVED_INITIAL_CORE_RESET_NTF;
 
 	r = 0;
 	return r;
 err_init:
 	r = 1;
 	dev_err(&client->dev,
-		"nfc-nci nfcc_initialise: failed. Check Hardware\n");
+		"%s: failed. Check Hardware\n", __func__);
 	return r;
 }
 /*
@@ -1202,19 +1290,20 @@
 	int r = 0;
 
 	if (!strcmp(qca199x_dev->clk_src_name, "BBCLK2")) {
-		qca199x_dev->s_clk  =
+		qca199x_dev->s_clk =
 			clk_get(&qca199x_dev->client->dev, "ref_clk");
 		if (qca199x_dev->s_clk == NULL)
 			goto err_invalid_dis_gpio;
 	} else if (!strcmp(qca199x_dev->clk_src_name, "RFCLK3")) {
-		qca199x_dev->s_clk  =
+		qca199x_dev->s_clk =
 			clk_get(&qca199x_dev->client->dev, "ref_clk_rf");
 		if (qca199x_dev->s_clk == NULL)
 			goto err_invalid_dis_gpio;
 	} else if (!strcmp(qca199x_dev->clk_src_name, "GPCLK")) {
 		if (gpio_is_valid(qca199x_dev->clk_src_gpio)) {
-			qca199x_dev->s_clk  =
-				clk_get(&qca199x_dev->client->dev, "core_clk");
+			qca199x_dev->s_clk =
+				clk_get(&qca199x_dev->client->dev,
+				  "core_clk");
 			if (qca199x_dev->s_clk == NULL)
 				goto err_invalid_dis_gpio;
 		} else {
@@ -1222,8 +1311,9 @@
 		}
 	} else if (!strcmp(qca199x_dev->clk_src_name, "GPCLK2")) {
 		if (gpio_is_valid(qca199x_dev->clk_src_gpio)) {
-			qca199x_dev->s_clk  =
-				clk_get(&qca199x_dev->client->dev, "core_clk_pvt");
+			qca199x_dev->s_clk =
+				clk_get(&qca199x_dev->client->dev,
+				  "core_clk_pvt");
 			if (qca199x_dev->s_clk == NULL)
 				goto err_invalid_dis_gpio;
 		} else {
@@ -1299,7 +1389,7 @@
 	}
 
 	if ((!strcmp(pdata->clk_src_name, "GPCLK")) ||
-	    (!strcmp(pdata->clk_src_name, "GPCLK2"))) {
+		(!strcmp(pdata->clk_src_name, "GPCLK2"))) {
 			pdata->clk_src_gpio = of_get_named_gpio(np,
 					"qcom,clk-src-gpio", 0);
 			if ((!gpio_is_valid(pdata->clk_src_gpio)))
@@ -1328,7 +1418,7 @@
 			sizeof(struct qca199x_platform_data), GFP_KERNEL);
 		if (!platform_data) {
 			dev_err(&client->dev,
-			"nfc-nci probe: Failed to allocate memory\n");
+			"%s: Failed to allocate memory\n", __func__);
 			return -ENOMEM;
 		}
 		r = nfc_parse_dt(&client->dev, platform_data);
@@ -1340,20 +1430,20 @@
 	if (!platform_data)
 		return -EINVAL;
 	dev_dbg(&client->dev,
-		"nfc-nci probe: %s, inside nfc-nci flags = %x\n",
+		"%s, inside nfc-nci flags = %x\n",
 		__func__, client->flags);
 	if (platform_data == NULL) {
-		dev_err(&client->dev, "nfc-nci probe: failed\n");
+		dev_err(&client->dev, "%s: failed\n", __func__);
 		return -ENODEV;
 	}
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
-		dev_err(&client->dev, "nfc-nci probe: need I2C_FUNC_I2C\n");
+		dev_err(&client->dev, "%s: need I2C_FUNC_I2C\n", __func__);
 		return -ENODEV;
 	}
 	qca199x_dev = kzalloc(sizeof(*qca199x_dev), GFP_KERNEL);
 	if (qca199x_dev == NULL) {
 		dev_err(&client->dev,
-		"nfc-nci probe: failed to allocate memory for module data\n");
+		"%s: failed to allocate memory for module data\n", __func__);
 		return -ENOMEM;
 	}
 	qca199x_dev->client = client;
@@ -1371,27 +1461,29 @@
 		r = gpio_request(platform_data->dis_gpio, "nfc_reset_gpio");
 		if (r) {
 			dev_err(&client->dev,
-			"NFC: unable to request gpio [%d]\n",
+			"%s: unable to request gpio [%d]\n",
+				__func__,
 				platform_data->dis_gpio);
 			goto err_free_dev;
 		}
 		r = gpio_direction_output(platform_data->dis_gpio, 1);
 		if (r) {
 			dev_err(&client->dev,
-				"NFC: unable to set direction for gpio [%d]\n",
+				"%s: unable to set direction for gpio [%d]\n",
+					__func__,
 					platform_data->dis_gpio);
 			goto err_dis_gpio;
 		}
 	} else {
-		dev_err(&client->dev, "dis gpio not provided\n");
+		dev_err(&client->dev, "%s: dis gpio not provided\n", __func__);
 		goto err_free_dev;
 	}
 
 	/* Guarantee that the NFCC starts in a clean state. */
 	gpio_set_value(platform_data->dis_gpio, 1);/* HPD */
-	usleep(200);
+	usleep_range(200, 220);
 	gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */
-	usleep(200);
+	usleep_range(200, 220);
 
 	r = nfcc_hw_check(client, platform_data->reg);
 	if (r) {
@@ -1403,7 +1495,8 @@
 	if (gpio_is_valid(platform_data->irq_gpio)) {
 		r = gpio_request(platform_data->irq_gpio, "nfc_irq_gpio");
 		if (r) {
-			dev_err(&client->dev, "unable to request gpio [%d]\n",
+			dev_err(&client->dev, "%s: unable to request gpio [%d]\n",
+				__func__,
 				platform_data->irq_gpio);
 			goto err_dis_gpio;
 		}
@@ -1411,7 +1504,8 @@
 		if (r) {
 
 			dev_err(&client->dev,
-			"unable to set direction for gpio [%d]\n",
+			"%s: unable to set direction for gpio [%d]\n",
+				__func__,
 				platform_data->irq_gpio);
 			goto err_irq;
 		}
@@ -1423,7 +1517,7 @@
 		client->irq = irqn;
 
 	} else {
-		dev_err(&client->dev, "irq gpio not provided\n");
+		dev_err(&client->dev, "%s: irq gpio not provided\n", __func__);
 		goto err_dis_gpio;
 	}
 	/* Interrupt from NFCC CLK_REQ to handle REF_CLK
@@ -1434,7 +1528,9 @@
 			r = gpio_request(platform_data->irq_gpio_clk_req,
 				"nfc_irq_gpio_clk_en");
 			if (r) {
-				dev_err(&client->dev, "unable to request CLK_EN gpio [%d]\n",
+				dev_err(&client->dev,
+				"%s: unable to request CLK_EN gpio [%d]\n",
+				__func__,
 					platform_data->irq_gpio_clk_req);
 				goto err_irq;
 			}
@@ -1442,8 +1538,8 @@
 					platform_data->irq_gpio_clk_req);
 			if (r) {
 				dev_err(&client->dev,
-					"unable to set direction for CLK_EN gpio [%d]\n",
-					platform_data->irq_gpio_clk_req);
+				"%s: cannot set direction CLK_EN gpio [%d]\n",
+				__func__, platform_data->irq_gpio_clk_req);
 				goto err_irq_clk;
 			}
 			gpio_to_irq(0);
@@ -1454,7 +1550,8 @@
 			}
 			platform_data->clk_req_irq_num = irqn;
 		} else {
-			dev_err(&client->dev, "irq CLK_EN gpio not provided\n");
+			dev_err(&client->dev,
+			"%s: irq CLK_EN gpio not provided\n", __func__);
 			goto err_irq;
 		}
 	}
@@ -1475,19 +1572,21 @@
 			r = gpio_request(platform_data->clkreq_gpio,
 				"nfc_clkreq_gpio");
 			if (r) {
-				dev_err(&client->dev, "unable to request gpio [%d]\n",
-						platform_data->clkreq_gpio);
+				dev_err(&client->dev,
+					"%s: unable to request gpio [%d]\n",
+					__func__, platform_data->clkreq_gpio);
 				goto err_clkreq_gpio;
 			}
 			r = gpio_direction_input(platform_data->clkreq_gpio);
 			if (r) {
 				dev_err(&client->dev,
-						"unable to set direction for gpio [%d]\n",
-						platform_data->clkreq_gpio);
+				"%s: cannot set direction for gpio [%d]\n",
+				__func__, platform_data->clkreq_gpio);
 				goto err_clkreq_gpio;
 			}
 		} else {
-			dev_err(&client->dev, "clkreq gpio not provided\n");
+			dev_err(&client->dev,
+				"%s: clkreq gpio not provided\n", __func__);
 			goto err_clk;
 		}
 		qca199x_dev->clkreq_gpio = platform_data->clkreq_gpio;
@@ -1514,7 +1613,7 @@
 
 	r = misc_register(&qca199x_dev->qca199x_device);
 	if (r) {
-		dev_err(&client->dev, "misc_register failed\n");
+		dev_err(&client->dev, "%s: misc_register failed\n", __func__);
 		goto err_misc_register;
 	}
 
@@ -1551,7 +1650,7 @@
 	r = request_irq(client->irq, qca199x_dev_irq_handler,
 			  IRQF_TRIGGER_RISING, client->name, qca199x_dev);
 	if (r) {
-		dev_err(&client->dev, "nfc-nci probe: request_irq failed\n");
+		dev_err(&client->dev, "%s: request_irq failed\n", __func__);
 		goto err_request_irq_failed;
 	}
 	qca199x_disable_irq(qca199x_dev);
@@ -1564,7 +1663,8 @@
 						client->name, qca199x_dev);
 		if (r) {
 			dev_err(&client->dev,
-			"nfc-nci probe: request_irq failed. irq no = %d\n, main irq =  %d",
+			"%s: request_irq failed. irq no = %d\n, main irq = %d",
+				__func__,
 				qca199x_dev->clk_req_irq_num, client->irq);
 			goto err_request_irq_failed;
 		}
@@ -1589,13 +1689,13 @@
 	region2_sent = false;
 
 	dev_dbg(&client->dev,
-	"nfc-nci probe: %s, probing qca1990 exited successfully\n",
+	"%s: probing qca1990 exited successfully\n",
 		 __func__);
 	return 0;
 
 err_create_workq:
 	dev_err(&client->dev,
-	"nfc-nci probe: %s, work_queue creation failure\n",
+	"%s: work_queue creation failure\n",
 		 __func__);
 	free_irq(client->irq, qca199x_dev);
 err_nfcc_not_present:
@@ -1613,7 +1713,8 @@
 		(!strcmp(platform_data->clk_src_name, "GPCLK2"))) {
 		r = gpio_direction_input(platform_data->irq_gpio_clk_req);
 		if (r)
-			dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
+			dev_err(&client->dev,
+				"%s: Unable to set direction\n", __func__);
 		gpio_free(platform_data->irq_gpio_clk_req);
 	}
 err_irq:
@@ -1687,7 +1788,7 @@
 
 
 static int nfcc_reboot(struct notifier_block *notifier, unsigned long val,
-		      void *v)
+			  void *v)
 {
 	/*
 	 * Set DISABLE=1 *ONLY* if the NFC service has been disabled.
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index 8186861..398fa3f 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.h
@@ -60,6 +60,7 @@
 #define SET_RX_BLOCK	_IOW(0xE9, 0x04, unsigned int)
 #define SET_EMULATOR_TEST_POINT		_IOW(0xE9, 0x05, unsigned int)
 #define NFCC_VERSION				_IOW(0xE9, 0x08, unsigned int)
+#define NFC_GET_EFUSE				_IOW(0xE9, 0x09, unsigned int)
 #define NFCC_INITIAL_CORE_RESET_NTF		_IOW(0xE9, 0x10, unsigned int)
 
 #define NFC_MAX_I2C_TRANSFER	(0x0400)
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 537dc1d..6752828 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -2209,7 +2209,6 @@
 	rc_new_uah = (params->fcc_uah * pc_new) / 100;
 	soc_new = (rc_new_uah - params->cc_uah - params->uuc_uah)*100
 					/ (params->fcc_uah - params->uuc_uah);
-	soc_new = bound_soc(soc_new);
 
 	/*
 	 * if soc_new is ZERO force it higher so that phone doesnt report soc=0
@@ -2467,6 +2466,8 @@
 	/* always clamp soc due to BMS hw/sw immaturities */
 	new_calculated_soc = clamp_soc_based_on_voltage(chip,
 					new_calculated_soc);
+
+	new_calculated_soc = bound_soc(new_calculated_soc);
 	/*
 	 * If the battery is full, configure the cc threshold so the system
 	 * wakes up after SoC changes
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index a30b5bb..38bd666 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1736,11 +1736,8 @@
 					power_supply_changed(chip->usb_psy);
 				}
 			}
-			if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
-				chip->delta_vddmax_mv = 0;
-				qpnp_chg_set_appropriate_vddmax(chip);
+			if (!qpnp_chg_is_dc_chg_plugged_in(chip))
 				chip->chg_done = false;
-			}
 
 			if (!qpnp_is_dc_higher_prio(chip))
 				qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
@@ -1771,10 +1768,6 @@
 				}
 			}
 
-			if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
-				chip->delta_vddmax_mv = 0;
-				qpnp_chg_set_appropriate_vddmax(chip);
-			}
 			schedule_delayed_work(&chip->eoc_work,
 				msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
 			schedule_work(&chip->soc_check_work);
@@ -1952,14 +1945,8 @@
 			qpnp_chg_force_run_on_batt(chip, !dc_present ? 1 : 0);
 		if (!dc_present && (!qpnp_chg_is_usb_chg_plugged_in(chip) ||
 					qpnp_chg_is_otg_en_set(chip))) {
-			chip->delta_vddmax_mv = 0;
-			qpnp_chg_set_appropriate_vddmax(chip);
 			chip->chg_done = false;
 		} else {
-			if (!qpnp_chg_is_usb_chg_plugged_in(chip)) {
-				chip->delta_vddmax_mv = 0;
-				qpnp_chg_set_appropriate_vddmax(chip);
-			}
 			schedule_delayed_work(&chip->eoc_work,
 				msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
 			schedule_work(&chip->soc_check_work);
@@ -3808,8 +3795,6 @@
 							? "cool" : "warm",
 						qpnp_chg_vddmax_get(chip));
 				}
-				chip->delta_vddmax_mv = 0;
-				qpnp_chg_set_appropriate_vddmax(chip);
 				qpnp_chg_charge_en(chip, 0);
 				/* sleep for a second before enabling */
 				msleep(2000);
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 592f70e..68c991c 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -653,14 +653,25 @@
 	return rc;
 }
 
+/* MIPI_DSI_MRPS, Maximum Return Packet Size */
+static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
+
+static struct dsi_cmd_desc pkt_size_cmd = {
+	{DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, sizeof(max_pktsize)},
+	max_pktsize,
+};
+
 int msm_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
 			struct dsi_buf *rp, int rlen)
 {
-	u32 *lp, data;
-	int i, off, cnt;
+	u32 *lp, data, *temp;
+	int i, j = 0, off, cnt;
 	unsigned char *ctrl_base = dsi_host_private->dsi_base;
+	char reg[16];
+	int repeated_bytes = 0;
 
 	lp = (u32 *)rp->data;
+	temp = (u32 *)reg;
 	cnt = rlen;
 	cnt += 3;
 	cnt >>= 2;
@@ -668,16 +679,52 @@
 	if (cnt > 4)
 		cnt = 4; /* 4 x 32 bits registers only */
 
+	if (rlen == 4)
+		rp->read_cnt = 4;
+	else
+		rp->read_cnt = (max_pktsize[0] + 6);
+
+	if (rp->read_cnt > 16) {
+		int bytes_shifted, data_lost = 0, rem_header_bytes = 0;
+		/* Any data more than 16 bytes will be shifted out */
+		bytes_shifted = rp->read_cnt - rlen;
+		if (bytes_shifted >= 4)
+			data_lost = bytes_shifted - 4; /* remove dcs header */
+		else
+			rem_header_bytes = 4 - bytes_shifted; /* rem header */
+		/*
+		 * (rp->len - 4) -> current rx buffer data length.
+		 * If data_lost > 0, then ((rp->len - 4) - data_lost) will be
+		 * the number of repeating bytes.
+		 * If data_lost == 0, then ((rp->len - 4) + rem_header_bytes)
+		 * will be the number of bytes repeating in between rx buffer
+		 * and the current RDBK_DATA registers. We need to skip the
+		 * repeating bytes.
+		 */
+		repeated_bytes = (rp->len - 4) - data_lost + rem_header_bytes;
+	}
+
 	off = DSI_RDBK_DATA0;
 	off += ((cnt - 1) * 4);
 
 	for (i = 0; i < cnt; i++) {
 		data = (u32)MIPI_INP(ctrl_base + off);
-		*lp++ = ntohl(data); /* to network byte order */
+		/* to network byte order */
+		if (!repeated_bytes)
+			*lp++ = ntohl(data);
+		else
+			*temp++ = ntohl(data);
 		pr_debug("%s: data = 0x%x and ntohl(data) = 0x%x\n",
 					 __func__, data, ntohl(data));
 		off -= 4;
-		rp->len += sizeof(*lp);
+		if (rlen == 4)
+			rp->len += sizeof(*lp);
+	}
+
+	/* Skip duplicates and append other data to the rx buffer */
+	if (repeated_bytes) {
+		for (i = repeated_bytes; i < 16; i++)
+			rp->data[j++] = reg[i];
 	}
 
 	return rlen;
@@ -769,14 +816,6 @@
 	return rc;
 }
 
-/* MIPI_DSI_MRPS, Maximum Return Packet Size */
-static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
-
-static struct dsi_cmd_desc pkt_size_cmd = {
-	{DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, sizeof(max_pktsize)},
-	max_pktsize,
-};
-
 static int msm_dsi_set_max_packet_size(struct mdss_dsi_ctrl_pdata *ctrl,
 						int size)
 {
@@ -814,10 +853,23 @@
 {
 	int rc;
 	struct dsi_buf *tp, *rp;
+	int rx_byte = 0;
+
+	if (rlen <= 2)
+		rx_byte = 4;
+	else
+		rx_byte = DSI_MAX_BYTES_TO_READ;
 
 	tp = &ctrl->tx_buf;
 	rp = &ctrl->rx_buf;
 	mdss_dsi_buf_init(rp);
+	rc = msm_dsi_set_max_packet_size(ctrl, rlen);
+	if (rc) {
+		pr_err("%s: dsi_set_max_pkt failed\n", __func__);
+		rc = -EINVAL;
+		goto dsi_cmds_rx_1_error;
+	}
+
 	mdss_dsi_buf_init(tp);
 
 	rc = mdss_dsi_cmd_dma_add(tp, cmds);
@@ -840,10 +892,12 @@
 	}
 
 	if (rlen <= DSI_SHORT_PKT_DATA_SIZE) {
-		msm_dsi_cmd_dma_rx(ctrl, rp, rlen);
+		msm_dsi_cmd_dma_rx(ctrl, rp, rx_byte);
 	} else {
-		msm_dsi_cmd_dma_rx(ctrl, rp, rlen + DSI_HOST_HDR_SIZE);
-		rp->len = rlen + DSI_HOST_HDR_SIZE;
+		msm_dsi_cmd_dma_rx(ctrl, rp, rx_byte);
+		rp->len = rx_byte - 2;	/*2 bytes for CRC*/
+		rp->len = rp->len - (DSI_MAX_PKT_SIZE - rlen);
+		rp->data = rp->start + (16 - (rlen + 2 + DSI_HOST_HDR_SIZE));
 	}
 	rc = msm_dsi_parse_rx_response(rp);
 
@@ -860,16 +914,15 @@
 {
 	int rc;
 	struct dsi_buf *tp, *rp;
-	int pkt_size, data_bytes, total;
+	int pkt_size, data_bytes, dlen, end = 0, diff;
 
 	tp = &ctrl->tx_buf;
 	rp = &ctrl->rx_buf;
 	mdss_dsi_buf_init(rp);
 	pkt_size = DSI_MAX_PKT_SIZE;
 	data_bytes = MDSS_DSI_LEN;
-	total = 0;
 
-	while (true) {
+	while (!end) {
 		rc = msm_dsi_set_max_packet_size(ctrl, pkt_size);
 		if (rc)
 			break;
@@ -880,7 +933,7 @@
 			pr_err("%s: dsi_cmd_dma_add failed\n", __func__);
 			rc = -EINVAL;
 			break;
-	}
+		}
 		rc = msm_dsi_wait4video_eng_busy(ctrl);
 		if (rc) {
 			pr_err("%s: wait4video_eng failed\n", __func__);
@@ -894,19 +947,32 @@
 		}
 
 		msm_dsi_cmd_dma_rx(ctrl, rp, DSI_MAX_BYTES_TO_READ);
+		if (rlen <= data_bytes) {
+			diff = data_bytes - rlen;
+			end = 1;
+		} else {
+			diff = 0;
+			rlen -= data_bytes;
+		}
+		dlen = DSI_MAX_BYTES_TO_READ - 2;
+		dlen -= diff;
+		rp->data += dlen;
+		rp->len += dlen;
 
-		rp->data += DSI_MAX_BYTES_TO_READ - DSI_HOST_HDR_SIZE;
-		total += data_bytes;
-		if (total >= rlen)
-			break;
-
-		data_bytes = DSI_MAX_BYTES_TO_READ - DSI_HOST_HDR_SIZE;
-		pkt_size += data_bytes;
+		if (!end) {
+			data_bytes = 14;
+			if (rlen < data_bytes)
+				pkt_size += rlen;
+			else
+				pkt_size += data_bytes;
+		}
+		pr_debug("%s: rp data=%x len=%d dlen=%d diff=%d\n",
+			 __func__, (int) (unsigned long) rp->data,
+			 rp->len, dlen, diff);
 	}
 
 	if (!rc) {
 		rp->data = rp->start;
-		rp->len = rlen + DSI_HOST_HDR_SIZE;
 		rc = msm_dsi_parse_rx_response(rp);
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.c b/drivers/video/msm/mdss/mdss_dsi_cmd.c
index 8fc1115c0..6d8f9e9 100644
--- a/drivers/video/msm/mdss/mdss_dsi_cmd.c
+++ b/drivers/video/msm/mdss/mdss_dsi_cmd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -66,6 +66,7 @@
 		off = 8 - off;
 	dp->data += off;
 	dp->len = 0;
+	dp->read_cnt = 0;
 	return dp->data;
 }
 
@@ -86,6 +87,7 @@
 
 	dp->data = dp->start;
 	dp->len = 0;
+	dp->read_cnt = 0;
 	return size;
 }
 
@@ -574,6 +576,7 @@
 	/* strip out dcs type */
 	rp->data++;
 	rp->len = 1;
+	rp->read_cnt -= 3;
 	return rp->len;
 }
 
@@ -585,6 +588,7 @@
 	/* strip out dcs type */
 	rp->data++;
 	rp->len = 2;
+	rp->read_cnt -= 2;
 	return rp->len;
 }
 
@@ -593,6 +597,7 @@
 	/* strip out dcs header */
 	rp->data += 4;
 	rp->len -= 4;
+	rp->read_cnt -= 6;
 	return rp->len;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_dsi_cmd.h b/drivers/video/msm/mdss/mdss_dsi_cmd.h
index f806e78..3abe4fc 100644
--- a/drivers/video/msm/mdss/mdss_dsi_cmd.h
+++ b/drivers/video/msm/mdss/mdss_dsi_cmd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -30,7 +30,7 @@
 
 #define MDSS_DSI_MRPS	0x04  /* Maximum Return Packet Size */
 
-#define MDSS_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align  */
+#define MDSS_DSI_LEN 10 /* 4 x 4 - 4 - 2, bytes dcs header+crc-align  */
 
 struct dsi_buf {
 	u32 *hdr;	/* dsi host header */
@@ -40,6 +40,7 @@
 	char *data;	/* buffer */
 	int len;	/* data length */
 	dma_addr_t dmap; /* mapped dma addr */
+	int read_cnt;
 };
 
 /* dcs read/write */
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
old mode 100644
new mode 100755
index 4c72d28..b6bec08
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -32,11 +32,11 @@
 	struct mdss_mdp_ctl *ctl;
 	u32 pp_num;
 	u8 ref_cnt;
-	struct completion pp_comp;
 	struct completion stop_comp;
+	wait_queue_head_t pp_waitq;
 	struct list_head vsync_handlers;
 	int panel_on;
-	int koff_cnt;
+	atomic_t koff_cnt;
 	int clk_enabled;
 	int vsync_enabled;
 	int rdptr_enabled;
@@ -55,10 +55,14 @@
 	u32 vclk_line;	/* vsync clock per line */
 	struct mdss_panel_recovery recovery;
 	bool ulps;
+	struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
+	u32 pp_timeout_report_cnt;
 };
 
 struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
 
+static int mdss_mdp_cmd_do_notifier(struct mdss_mdp_cmd_ctx *ctx);
+
 static inline u32 mdss_mdp_cmd_line_count(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_mixer *mixer;
@@ -287,7 +291,7 @@
 			ctx->rdptr_enabled--;
 
 		/* keep clk on during kickoff */
-		if (ctx->rdptr_enabled == 0 && ctx->koff_cnt)
+		if (ctx->rdptr_enabled == 0 && atomic_read(&ctx->koff_cnt))
 			ctx->rdptr_enabled++;
 	}
 
@@ -314,14 +318,13 @@
 	if (!ctx->ctl)
 		return;
 	spin_lock_irqsave(&ctx->clk_lock, flags);
-	if (ctx->koff_cnt) {
+	if (atomic_read(&ctx->koff_cnt)) {
 		mdss_mdp_ctl_reset(ctx->ctl);
 		pr_debug("%s: intf_num=%d\n", __func__,
 					ctx->ctl->intf_num);
-		ctx->koff_cnt--;
+		atomic_dec(&ctx->koff_cnt);
 		mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
 						ctx->pp_num);
-		complete_all(&ctx->pp_comp);
 	}
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 }
@@ -348,25 +351,27 @@
 	}
 	mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 
-	complete_all(&ctx->pp_comp);
 	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
 					ctx->rdptr_enabled);
 
-	if (ctx->koff_cnt) {
-		atomic_inc(&ctx->pp_done_cnt);
-		schedule_work(&ctx->pp_done_work);
-		ctx->koff_cnt--;
-		if (ctx->koff_cnt) {
+	if (atomic_add_unless(&ctx->koff_cnt, -1, 0)) {
+		if (atomic_read(&ctx->koff_cnt))
 			pr_err("%s: too many kickoffs=%d!\n", __func__,
-			       ctx->koff_cnt);
-			ctx->koff_cnt = 0;
+			       atomic_read(&ctx->koff_cnt));
+		if (mdss_mdp_cmd_do_notifier(ctx)) {
+			atomic_inc(&ctx->pp_done_cnt);
+			schedule_work(&ctx->pp_done_work);
 		}
-	} else
+		wake_up_all(&ctx->pp_waitq);
+	} else {
 		pr_err("%s: should not have pingpong interrupt!\n", __func__);
+	}
 
-	trace_mdp_cmd_pingpong_done(ctl, ctx->pp_num, ctx->koff_cnt);
+	trace_mdp_cmd_pingpong_done(ctl, ctx->pp_num,
+			atomic_read(&ctx->koff_cnt));
 	pr_debug("%s: ctl_num=%d intf_num=%d ctx=%d kcnt=%d\n", __func__,
-		ctl->num, ctl->intf_num, ctx->pp_num, ctx->koff_cnt);
+		ctl->num, ctl->intf_num, ctx->pp_num,
+			atomic_read(&ctx->koff_cnt));
 
 	spin_unlock(&ctx->clk_lock);
 }
@@ -504,7 +509,6 @@
 	struct mdss_mdp_cmd_ctx *ctx;
 	struct mdss_panel_data *pdata;
 	unsigned long flags;
-	int need_wait = 0;
 	int rc = 0;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
@@ -515,11 +519,6 @@
 
 	pdata = ctl->panel_data;
 
-	spin_lock_irqsave(&ctx->clk_lock, flags);
-	if (ctx->koff_cnt > 0)
-		need_wait = 1;
-	spin_unlock_irqrestore(&ctx->clk_lock, flags);
-
 	ctl->roi_bkup.w = ctl->width;
 	ctl->roi_bkup.h = ctl->height;
 
@@ -527,33 +526,95 @@
 			ctx->rdptr_enabled, ctl->roi_bkup.w,
 			ctl->roi_bkup.h);
 
-	pr_debug("%s: need_wait=%d  intf_num=%d ctx=%p\n",
-			__func__, need_wait, ctl->intf_num, ctx);
+	pr_debug("%s: intf_num=%d ctx=%p koff_cnt=%d\n", __func__,
+			ctl->intf_num, ctx, atomic_read(&ctx->koff_cnt));
 
-	if (need_wait) {
-		rc = wait_for_completion_timeout(
-				&ctx->pp_comp, KOFF_TIMEOUT);
+	rc = wait_event_timeout(ctx->pp_waitq,
+			atomic_read(&ctx->koff_cnt) == 0,
+			KOFF_TIMEOUT);
 
-		trace_mdp_cmd_wait_pingpong(ctl->num, ctx->koff_cnt);
+	if (rc <= 0) {
+		u32 status, mask;
 
-		if (rc <= 0) {
-			WARN(1, "cmd kickoff timed out (%d) ctl=%d\n",
-						rc, ctl->num);
-			mdss_dsi_debug_check_te(pdata);
-			MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1",
-						"edp", "hdmi", "panic");
-			rc = -EPERM;
-			mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_TIMEOUT);
-		} else {
-			rc = 0;
+		mask = BIT(MDSS_MDP_IRQ_PING_PONG_COMP + ctx->pp_num);
+		status = mask & readl_relaxed(ctl->mdata->mdp_base +
+				MDSS_MDP_REG_INTR_STATUS);
+		if (status) {
+			WARN(1, "pp done but irq not triggered\n");
+			mdss_mdp_irq_clear(ctl->mdata,
+					MDSS_MDP_IRQ_PING_PONG_COMP,
+					ctx->pp_num);
+			local_irq_save(flags);
+			mdss_mdp_cmd_pingpong_done(ctl);
+			local_irq_restore(flags);
+			rc = 1;
 		}
+
+		rc = atomic_read(&ctx->koff_cnt) == 0;
 	}
 
-	MDSS_XLOG(ctl->num, ctx->koff_cnt, ctx->clk_enabled,
-					ctx->rdptr_enabled, rc);
+	if (rc <= 0) {
+		if (!ctx->pp_timeout_report_cnt) {
+			WARN(1, "cmd kickoff timed out (%d) ctl=%d\n",
+					rc, ctl->num);
+			mdss_dsi_debug_check_te(pdata);
+			MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1",
+					"edp", "hdmi", "panic");
+		}
+		ctx->pp_timeout_report_cnt++;
+		rc = -EPERM;
+		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_TIMEOUT);
+		atomic_add_unless(&ctx->koff_cnt, -1, 0);
+	} else {
+		rc = 0;
+		ctx->pp_timeout_report_cnt = 0;
+	}
+
+	/* signal any pending ping pong done events */
+	while (atomic_add_unless(&ctx->pp_done_cnt, -1, 0))
+		mdss_mdp_ctl_notify(ctx->ctl, MDP_NOTIFY_FRAME_DONE);
+
+	MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->clk_enabled,
+			ctx->rdptr_enabled, rc);
+
 	return rc;
 }
 
+static int mdss_mdp_cmd_do_notifier(struct mdss_mdp_cmd_ctx *ctx)
+{
+	struct mdss_mdp_cmd_ctx *sctx;
+	sctx = ctx->sync_ctx;
+
+	if (!sctx || atomic_read(&sctx->koff_cnt) == 0)
+		return 1;
+
+	return 0;
+}
+
+static void mdss_mdp_cmd_set_sync_ctx(
+		struct mdss_mdp_ctl *ctl, struct mdss_mdp_ctl *sctl)
+{
+	struct mdss_mdp_cmd_ctx *ctx, *sctx;
+
+	ctx = (struct mdss_mdp_cmd_ctx *)ctl->priv_data;
+	if (!sctl) {
+		ctx->sync_ctx = NULL;
+		return;
+	}
+
+	sctx = (struct mdss_mdp_cmd_ctx *)sctl->priv_data;
+
+	if (!sctl->roi.w && !sctl->roi.h) {
+		/* left only */
+		ctx->sync_ctx = NULL;
+		sctx->sync_ctx = NULL;
+	} else {
+		 /* left + right */
+		ctx->sync_ctx = sctx;
+		sctx->sync_ctx = ctx;
+	}
+}
+
 static int mdss_mdp_cmd_set_partial_roi(struct mdss_mdp_ctl *ctl)
 {
 	int rc = 0;
@@ -572,8 +633,7 @@
 
 int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
 {
-	struct mdss_mdp_cmd_ctx *ctx;
-	unsigned long flags;
+	struct mdss_mdp_cmd_ctx *ctx, *sctx = NULL;
 	int rc;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
@@ -602,10 +662,11 @@
 	MDSS_XLOG(ctl->num, ctl->roi.x, ctl->roi.y, ctl->roi.w,
 						ctl->roi.h);
 
-	spin_lock_irqsave(&ctx->clk_lock, flags);
-	ctx->koff_cnt++;
-	spin_unlock_irqrestore(&ctx->clk_lock, flags);
-	trace_mdp_cmd_kickoff(ctl->num, ctx->koff_cnt);
+	atomic_inc(&ctx->koff_cnt);
+	if (sctx)
+		atomic_inc(&sctx->koff_cnt);
+
+	trace_mdp_cmd_kickoff(ctl->num, atomic_read(&ctx->koff_cnt));
 
 	mdss_mdp_cmd_clk_on(ctx);
 
@@ -615,7 +676,9 @@
 	 * tx dcs command if had any
 	 */
 	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF, NULL);
-	INIT_COMPLETION(ctx->pp_comp);
+
+	mdss_mdp_cmd_set_sync_ctx(ctl, NULL);
+
 	mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
 	mdss_mdp_ctl_perf_set_transaction_status(ctl,
@@ -754,7 +817,8 @@
 
 	ctx->ctl = ctl;
 	ctx->pp_num = mixer->num;
-	init_completion(&ctx->pp_comp);
+	ctx->pp_timeout_report_cnt = 0;
+	init_waitqueue_head(&ctx->pp_waitq);
 	init_completion(&ctx->stop_comp);
 	spin_lock_init(&ctx->clk_lock);
 	mutex_init(&ctx->clk_mtx);
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
index aeccfed..bb8b17b 100644
--- a/include/sound/Kbuild
+++ b/include/sound/Kbuild
@@ -14,3 +14,4 @@
 header-y += lsm_params.h
 header-y += voice_params.h
 header-y += voice_svc.h
+header-y += msmcal-hwdep.h
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 7bf01b6..244bb30 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -95,9 +95,10 @@
 	SNDRV_HWDEP_IFACE_SB_RC,	/* SB Extigy/Audigy2NX remote control */
 	SNDRV_HWDEP_IFACE_HDA,		/* HD-audio */
 	SNDRV_HWDEP_IFACE_USB_STREAM,	/* direct access to usb stream */
+        SNDRV_HWDEP_IFACE_AUDIO_CODEC,  /* codec Audio Control */
 
 	/* Don't forget to change the following: */
-	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM
+	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_AUDIO_CODEC
 };
 
 struct snd_hwdep_info {
diff --git a/include/sound/msmcal-hwdep.h b/include/sound/msmcal-hwdep.h
new file mode 100644
index 0000000..324b497
--- /dev/null
+++ b/include/sound/msmcal-hwdep.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CALIB_HWDEP_H
+#define _CALIB_HWDEP_H
+
+#define WCD9XXX_CODEC_HWDEP_NODE    1000
+enum wcd_cal_type {
+	WCD9XXX_MIN_CAL,
+	WCD9XXX_ANC_CAL = WCD9XXX_MIN_CAL,
+	WCD9XXX_MAD_CAL,
+	WCD9XXX_MBHC_CAL,
+	WCD9XXX_MAX_CAL,
+};
+
+struct wcdcal_ioctl_buffer {
+	__u32 size;
+	__u8 __user *buffer;
+	enum wcd_cal_type cal_type;
+};
+
+#define SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE \
+	_IOW('U', 0x1, struct wcdcal_ioctl_buffer)
+
+#endif /*_CALIB_HWDEP_H*/
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 1e5bfd8..780ac9b 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1606,6 +1606,7 @@
 {
 	unsigned long flags;
 	int cpu, src_cpu, success = 0;
+	int notify = 0;
 
 	smp_wmb();
 	raw_spin_lock_irqsave(&p->pi_lock, flags);
@@ -1663,10 +1664,13 @@
 	ttwu_queue(p, cpu);
 stat:
 	ttwu_stat(p, cpu, wake_flags);
+
+	if (src_cpu != cpu && task_notify_on_migrate(p))
+		notify = 1;
 out:
 	raw_spin_unlock_irqrestore(&p->pi_lock, flags);
 
-	if (src_cpu != cpu && task_notify_on_migrate(p))
+	if (notify)
 		atomic_notifier_call_chain(&migration_notifier_head,
 					   cpu, (void *)src_cpu);
 	return success;
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index e56833a..e591c54 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -71,6 +71,20 @@
 		return -FDT_ERR_BADMAGIC;
 	}
 
+	if (fdt_off_dt_struct(fdt) > (UINT_MAX - fdt_size_dt_struct(fdt)))
+		return FDT_ERR_BADOFFSET;
+
+	if (fdt_off_dt_strings(fdt) > (UINT_MAX -  fdt_size_dt_strings(fdt)))
+		return FDT_ERR_BADOFFSET;
+
+	if ((fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt))
+	    > fdt_totalsize(fdt))
+		return FDT_ERR_BADOFFSET;
+
+	if ((fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))
+	    > fdt_totalsize(fdt))
+		return FDT_ERR_BADOFFSET;
+
 	return 0;
 }
 
diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
index 24437df..d7d09fe 100644
--- a/scripts/dtc/libfdt/fdt_rw.c
+++ b/scripts/dtc/libfdt/fdt_rw.c
@@ -394,7 +394,7 @@
 static void _fdt_packblocks(const char *old, char *new,
 			    int mem_rsv_size, int struct_size)
 {
-	int mem_rsv_off, struct_off, strings_off;
+	uint32_t mem_rsv_off, struct_off, strings_off;
 
 	mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
 	struct_off = mem_rsv_off + mem_rsv_size;
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index a3ed23d..b42599e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -51,8 +51,8 @@
 snd-soc-wcd9304-objs := wcd9304.o wcd9304-tables.o
 snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
 snd-soc-cs8427-objs := cs8427.o
-snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o wcd9xxx-common.o
-snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o wcd9xxx-common.o
+snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o wcd9xxx-common.o wcdcal-hwdep.o
+snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o wcd9xxx-common.o wcdcal-hwdep.o
 snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o wcd9xxx-common.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index b95d441..b29d81c 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -291,6 +291,9 @@
 	u32 anc_slot;
 	bool anc_func;
 
+	/*track adie loopback mode*/
+	bool lb_mode;
+
 	/*track tapan interface type*/
 	u8 intf_type;
 
@@ -306,6 +309,8 @@
 	u8 aux_l_gain;
 	u8 aux_r_gain;
 
+	bool dec_active[NUM_DECIMATORS];
+
 	bool spkr_pa_widget_on;
 
 	struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
@@ -512,6 +517,43 @@
 	return 0;
 }
 
+static int tapan_loopback_mode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = tapan->lb_mode;
+	dev_dbg(codec->dev, "%s: lb_mode = %d\n",
+		__func__, tapan->lb_mode);
+
+	return 0;
+}
+
+static int tapan_loopback_mode_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+		__func__, ucontrol->value.integer.value[0]);
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		tapan->lb_mode = false;
+		break;
+	case 1:
+		tapan->lb_mode = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
 static int tapan_pa_gain_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1036,6 +1078,13 @@
 	return 0;
 }
 
+static const char * const tapan_loopback_mode_ctrl_text[] = {
+		"DISABLE", "ENABLE"};
+static const struct soc_enum tapan_loopback_mode_ctl_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, tapan_loopback_mode_ctrl_text),
+};
+
+
 static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_4P5_DB",
 						      "POS_3_DB", "POS_1P5_DB",
 						      "POS_0_DB", "NEG_2P5_DB",
@@ -1112,6 +1161,9 @@
 	SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
 		tapan_pa_gain_get, tapan_pa_gain_put),
 
+	SOC_ENUM_EXT("LOOPBACK Mode", tapan_loopback_mode_ctl_enum[0],
+		tapan_loopback_mode_get, tapan_loopback_mode_put),
+
 	SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 20, 1,
 		line_gain),
 	SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 20, 1,
@@ -2412,10 +2464,11 @@
 {
 	struct snd_soc_codec *codec = w->codec;
 	unsigned int decimator;
+	struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
 	char *dec_name = NULL;
 	char *widget_name = NULL;
 	char *temp;
-	int ret = 0;
+	int ret = 0, i;
 	u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
 	u8 dec_hpf_cut_of_freq;
 	int offset;
@@ -2467,6 +2520,10 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		for (i = 0; i < NUM_DECIMATORS; i++) {
+			if (decimator == i + 1)
+				tapan_p->dec_active[i] = true;
+		}
 
 		/* Enableable TX digital mute */
 		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
@@ -2497,8 +2554,11 @@
 
 	case SND_SOC_DAPM_POST_PMU:
 
-		/* Disable TX digital mute */
-		snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+		if (tapan_p->lb_mode) {
+			pr_debug("%s: loopback mode unmute the DEC\n",
+							__func__);
+			snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+		}
 
 		if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
 				CF_MIN_3DB_150HZ) {
@@ -2527,7 +2587,10 @@
 		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
 		snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
 			(tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
-
+		for (i = 0; i < NUM_DECIMATORS; i++) {
+			if (decimator == i + 1)
+				tapan_p->dec_active[i] = false;
+		}
 		break;
 	}
 out:
@@ -4028,6 +4091,53 @@
 	return 0;
 }
 
+int tapan_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = NULL;
+	u16 tx_vol_ctl_reg = 0;
+	u8 decimator = 0, i;
+	struct tapan_priv *tapan_p;
+
+	pr_debug("%s: Digital Mute val = %d\n", __func__, mute);
+
+	if (!dai || !dai->codec) {
+		pr_err("%s: Invalid params\n", __func__);
+		return -EINVAL;
+	}
+	codec = dai->codec;
+	tapan_p = snd_soc_codec_get_drvdata(codec);
+
+	if (dai->id != AIF1_CAP) {
+		dev_dbg(codec->dev, "%s: Not capture use case skip\n",
+		__func__);
+		return 0;
+	}
+
+	mute = (mute) ? 1 : 0;
+	if (!mute) {
+		/*
+		 * 5 ms is an emperical value for the mute time
+		 * that was arrived by checking the pop level
+		 * to be inaudible
+		 */
+		usleep_range(5000, 5010);
+	}
+
+	for (i = 0; i < NUM_DECIMATORS; i++) {
+		if (tapan_p->dec_active[i])
+			decimator = i + 1;
+		if (decimator && decimator <= NUM_DECIMATORS) {
+			pr_debug("%s: Mute = %d Decimator = %d", __func__,
+					mute, decimator);
+			tx_vol_ctl_reg = TAPAN_A_CDC_TX1_VOL_CTL_CFG +
+				8 * (decimator - 1);
+			snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, mute);
+		}
+		decimator = 0;
+	}
+	return 0;
+}
+
 static struct snd_soc_dai_ops tapan_dai_ops = {
 	.startup = tapan_startup,
 	.shutdown = tapan_shutdown,
@@ -4036,6 +4146,7 @@
 	.set_fmt = tapan_set_dai_fmt,
 	.set_channel_map = tapan_set_channel_map,
 	.get_channel_map = tapan_get_channel_map,
+	.digital_mute = tapan_digital_mute,
 };
 
 static struct snd_soc_dai_driver tapan9302_dai[] = {
@@ -6225,6 +6336,7 @@
 	tapan->aux_r_gain = 0x1F;
 	tapan->ldo_h_users = 0;
 	tapan->micb_2_users = 0;
+	tapan->lb_mode = false;
 	tapan_update_reg_defaults(codec);
 	tapan_update_reg_mclk_rate(wcd9xxx);
 	tapan_codec_init_reg(codec);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index ce42a94..1dfd72b 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -19,7 +19,6 @@
 #include <linux/ratelimit.h>
 #include <linux/debugfs.h>
 #include <linux/wait.h>
-#include <linux/bitops.h>
 #include <linux/mfd/wcd9xxx/core.h>
 #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
 #include <linux/mfd/wcd9xxx/wcd9320_registers.h>
@@ -41,6 +40,8 @@
 #include "wcd9320.h"
 #include "wcd9xxx-resmgr.h"
 #include "wcd9xxx-common.h"
+#include "wcdcal-hwdep.h"
+
 
 #define TAIKO_MAD_SLIMBUS_TX_PORT 12
 #define TAIKO_MAD_AUDIO_FIRMWARE_PATH "wcd9320/wcd9320_mad_audio.bin"
@@ -453,6 +454,8 @@
 	 */
 	struct list_head reg_save_restore;
 	struct pm_qos_request pm_qos_req;
+	/* cal info for codec */
+	struct fw_info *fw_data;
 };
 
 static const u32 comp_shift[] = {
@@ -2680,8 +2683,11 @@
 	int ret;
 	const struct firmware *fw;
 	struct mad_audio_cal *mad_cal;
+	struct firmware_cal *hwdep_cal = NULL;
+	const void *data;
 	const char *filename = TAIKO_MAD_AUDIO_FIRMWARE_PATH;
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+	size_t cal_size;
 
 	pr_debug("%s: enter\n", __func__);
 	/* wakeup for codec calibration access */
@@ -2690,24 +2696,46 @@
 			   PM_QOS_DEFAULT_VALUE);
 	pm_qos_update_request(&taiko->pm_qos_req,
 			      msm_cpuidle_get_deep_idle_latency());
-	ret = request_firmware(&fw, filename, codec->dev);
-	if (ret != 0) {
-		pr_err("Failed to acquire MAD firwmare data %s: %d\n", filename,
-		       ret);
+	if (!taiko->fw_data) {
+		dev_err(codec->dev, "%s: invalid cal data\n",
+				 __func__);
 		return -ENODEV;
 	}
-
-	if (fw->size < sizeof(struct mad_audio_cal)) {
-		pr_err("%s: incorrect firmware size %u\n", __func__, fw->size);
-		release_firmware(fw);
-		return -ENOMEM;
+	hwdep_cal = wcdcal_get_fw_cal(taiko->fw_data, WCD9XXX_MAD_CAL);
+	if (hwdep_cal) {
+		data = hwdep_cal->data;
+		cal_size = hwdep_cal->size;
+		dev_dbg(codec->dev, "%s: using hwdep calibration\n",
+				__func__);
+	} else {
+		ret = request_firmware(&fw, filename, codec->dev);
+		if (ret != 0) {
+			pr_err("Failed to acquire MAD firwmare data %s: %d\n",
+				filename, ret);
+			return -ENODEV;
+		}
+		if (!fw) {
+			dev_err(codec->dev, "failed to get mad fw");
+			return -ENODEV;
+		}
+		data = fw->data;
+		cal_size = fw->size;
+		dev_dbg(codec->dev, "%s: using request_firmware calibration\n",
+				__func__);
+	}
+	if (cal_size < sizeof(struct mad_audio_cal)) {
+		pr_err("%s: incorrect hwdep cal size %zu\n",
+			__func__, cal_size);
+		ret = -ENOMEM;
+		goto err;
 	}
 
-	mad_cal = (struct mad_audio_cal *)(fw->data);
+	mad_cal = (struct mad_audio_cal *)(data);
 	if (!mad_cal) {
-		pr_err("%s: Invalid calibration data\n", __func__);
-		release_firmware(fw);
-		return -EINVAL;
+		dev_err(codec->dev, "%s: Invalid calibration data\n",
+				__func__);
+		ret =  -EINVAL;
+		goto err;
 	}
 
 	snd_soc_write(codec, TAIKO_A_CDC_MAD_MAIN_CTL_2,
@@ -2757,11 +2785,13 @@
 	snd_soc_write(codec, TAIKO_A_CDC_MAD_ULTR_CTL_6,
 		      mad_cal->ultrasound_info.rms_threshold_msb);
 
-	release_firmware(fw);
 	pr_debug("%s: leave ret %d\n", __func__, ret);
 	pm_qos_update_request(&taiko->pm_qos_req,
 			      PM_QOS_DEFAULT_VALUE);
 	pm_qos_remove_request(&taiko->pm_qos_req);
+err:
+	if (!hwdep_cal)
+		release_firmware(fw);
 	return ret;
 }
 
@@ -3318,15 +3348,18 @@
 	const char *filename;
 	const struct firmware *fw;
 	int i;
-	int ret;
+	int ret =0;
 	int num_anc_slots;
 	struct wcd9xxx_anc_header *anc_head;
 	struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+	struct firmware_cal *hwdep_cal = NULL;
 	u32 anc_writes_size = 0;
 	int anc_size_remaining;
 	u32 *anc_ptr;
 	u16 reg;
 	u8 mask, val, old_val;
+	size_t cal_size;
+	const void *data;
 
 
 	if (taiko->anc_func == 0)
@@ -3335,38 +3368,53 @@
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		filename = "wcd9320/wcd9320_anc.bin";
+		hwdep_cal = wcdcal_get_fw_cal(taiko->fw_data, WCD9XXX_ANC_CAL);
+		if (hwdep_cal) {
+			data = hwdep_cal->data;
+			cal_size = hwdep_cal->size;
+			dev_dbg(codec->dev, "%s: using hwdep calibration\n",
+				__func__);
+		} else {
+			ret = request_firmware(&fw, filename, codec->dev);
+			if (ret != 0) {
+				dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
+					ret);
+				return -ENODEV;
+			}
+			if (!fw) {
+				dev_err(codec->dev, "failed to get anc fw");
+				return -ENODEV;
+			}
+			data = fw->data;
+			cal_size = fw->size;
+			dev_dbg(codec->dev, "%s: using request_firmware calibration\n",
+					 __func__);
 
-		ret = request_firmware(&fw, filename, codec->dev);
-		if (ret != 0) {
-			dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
-				ret);
-			return -ENODEV;
 		}
 
-		if (fw->size < sizeof(struct wcd9xxx_anc_header)) {
+		if (cal_size < sizeof(struct wcd9xxx_anc_header)) {
 			dev_err(codec->dev, "Not enough data\n");
-			release_firmware(fw);
-			return -ENOMEM;
+			goto err;
 		}
 
 		/* First number is the number of register writes */
-		anc_head = (struct wcd9xxx_anc_header *)(fw->data);
-		anc_ptr = (u32 *)((u32)fw->data +
+		anc_head = (struct wcd9xxx_anc_header *)(data);
+		anc_ptr = (u32 *)(data +
 				  sizeof(struct wcd9xxx_anc_header));
-		anc_size_remaining = fw->size -
+		anc_size_remaining = cal_size -
 				     sizeof(struct wcd9xxx_anc_header);
 		num_anc_slots = anc_head->num_anc_slots;
 
 		if (taiko->anc_slot >= num_anc_slots) {
 			dev_err(codec->dev, "Invalid ANC slot selected\n");
-			release_firmware(fw);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto err;
 		}
 		for (i = 0; i < num_anc_slots; i++) {
 			if (anc_size_remaining < TAIKO_PACKED_REG_SIZE) {
 				dev_err(codec->dev, "Invalid register format\n");
-				release_firmware(fw);
-				return -EINVAL;
+				ret = -EINVAL;
+				goto err;
 			}
 			anc_writes_size = (u32)(*anc_ptr);
 			anc_size_remaining -= sizeof(u32);
@@ -3375,8 +3423,8 @@
 			if (anc_writes_size * TAIKO_PACKED_REG_SIZE
 				> anc_size_remaining) {
 				dev_err(codec->dev, "Invalid register format\n");
-				release_firmware(fw);
-				return -ENOMEM;
+				ret = -EINVAL;
+				goto err;
 			}
 
 			if (taiko->anc_slot == i)
@@ -3388,8 +3436,8 @@
 		}
 		if (i == num_anc_slots) {
 			dev_err(codec->dev, "Selected ANC slot not present\n");
-			release_firmware(fw);
-			return -ENOMEM;
+			ret = -EINVAL;
+			goto err;
 		}
 		for (i = 0; i < anc_writes_size; i++) {
 			TAIKO_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
@@ -3399,6 +3447,8 @@
 				(val & mask));
 		}
 		release_firmware(fw);
+		if (!hwdep_cal)
+			release_firmware(fw);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		msleep(40);
@@ -3411,6 +3461,11 @@
 		break;
 	}
 	return 0;
+err:
+	if (!hwdep_cal)
+		release_firmware(fw);
+	return ret;
+
 }
 
 static int taiko_hph_pa_event(struct snd_soc_dapm_widget *w,
@@ -6586,6 +6641,27 @@
 
 	wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, taiko);
 }
+static
+struct firmware_cal *taiko_get_hwdep_fw_cal(struct snd_soc_codec *codec,
+			enum wcd_cal_type type)
+{
+	struct taiko_priv *taiko;
+	struct firmware_cal *hwdep_cal;
+
+	if (!codec) {
+		pr_err("%s: NULL codec pointer\n", __func__);
+		return NULL;
+	}
+	taiko = snd_soc_codec_get_drvdata(codec);
+	hwdep_cal = wcdcal_get_fw_cal(taiko->fw_data, type);
+	if (!hwdep_cal) {
+		dev_err(codec->dev, "%s: cal not sent by %d\n",
+				 __func__, type);
+		return NULL;
+	}
+
+	return hwdep_cal;
+}
 
 int taiko_hs_detect(struct snd_soc_codec *codec,
 		    struct wcd9xxx_mbhc_config *mbhc_cfg)
@@ -6840,6 +6916,7 @@
 	.get_cdc_type = taiko_get_cdc_type,
 	.setup_zdet = taiko_setup_zdet,
 	.compute_impedance = taiko_compute_impedance,
+	.get_hwdep_fw_cal = taiko_get_hwdep_fw_cal,
 };
 
 static const struct wcd9xxx_mbhc_intr cdc_intr_ids = {
@@ -7093,7 +7170,7 @@
 				  WCD9XXX_CDC_TYPE_TAIKO);
 	if (ret) {
 		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
-		goto err_init;
+		goto err_nomem_slimch;
 	}
 
 	taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
@@ -7105,7 +7182,20 @@
 		rco_clk_rate = TAIKO_MCLK_CLK_12P288MHZ;
 	else
 		rco_clk_rate = TAIKO_MCLK_CLK_9P6MHZ;
-
+	taiko->fw_data = kzalloc(sizeof(*(taiko->fw_data)), GFP_KERNEL);
+	if (!taiko->fw_data) {
+		dev_err(codec->dev, "Failed to allocate fw_data\n");
+		goto err_nomem_slimch;
+	}
+	set_bit(WCD9XXX_ANC_CAL, taiko->fw_data->cal_bit);
+	set_bit(WCD9XXX_MAD_CAL, taiko->fw_data->cal_bit);
+	set_bit(WCD9XXX_MBHC_CAL, taiko->fw_data->cal_bit);
+	ret = wcd_cal_create_hwdep(taiko->fw_data,
+					WCD9XXX_CODEC_HWDEP_NODE, codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret);
+		goto err_hwdep;
+	}
 	/* init and start mbhc */
 	ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
 				taiko_enable_mbhc_micbias,
@@ -7113,7 +7203,7 @@
 				rco_clk_rate, true);
 	if (ret) {
 		pr_err("%s: mbhc init failed %d\n", __func__, ret);
-		goto err_init;
+		goto err_hwdep;
 	}
 
 	taiko->codec = codec;
@@ -7137,7 +7227,7 @@
 	ret = taiko_handle_pdata(taiko);
 	if (IS_ERR_VALUE(ret)) {
 		pr_err("%s: bad pdata\n", __func__);
-		goto err_pdata;
+		goto err_hwdep;
 	}
 
 	taiko->spkdrv_reg = taiko_codec_find_regulator(codec,
@@ -7155,7 +7245,7 @@
 	if (!ptr) {
 		pr_err("%s: no mem for slim chan ctl data\n", __func__);
 		ret = -ENOMEM;
-		goto err_nomem_slimch;
+		goto err_hwdep;
 	}
 
 	if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
@@ -7233,11 +7323,11 @@
 
 err_irq:
 	taiko_cleanup_irqs(taiko);
-err_pdata:
-	kfree(ptr);
+        kfree(ptr);
+err_hwdep:
+	kfree(taiko->fw_data);
 err_nomem_slimch:
 	kfree(taiko);
-err_init:
 	return ret;
 }
 static int taiko_codec_remove(struct snd_soc_codec *codec)
@@ -7261,6 +7351,7 @@
 
 	taiko->spkdrv_reg = NULL;
 
+	kfree(taiko->fw_data);
 	kfree(taiko);
 	return 0;
 }
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 09721e1..1475df2 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -35,6 +35,7 @@
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 #include <linux/input.h>
+#include "wcdcal-hwdep.h"
 #include "wcd9320.h"
 #include "wcd9306.h"
 #include "wcd9xxx-mbhc.h"
@@ -74,7 +75,7 @@
 #define OCP_ATTEMPT 1
 
 #define FW_READ_ATTEMPTS 15
-#define FW_READ_TIMEOUT 2000000
+#define FW_READ_TIMEOUT 4000000
 
 #define BUTTON_POLLING_SUPPORTED true
 
@@ -2806,35 +2807,39 @@
 	wcd9xxx_unlock_sleep(core_res);
 }
 
-static bool wcd9xxx_mbhc_fw_validate(const struct firmware *fw)
+static bool wcd9xxx_mbhc_fw_validate(const void *data, size_t size)
 {
 	u32 cfg_offset;
 	struct wcd9xxx_mbhc_imped_detect_cfg *imped_cfg;
 	struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
+	struct firmware_cal fw;
 
-	if (fw->size < WCD9XXX_MBHC_CAL_MIN_SIZE)
+	fw.data = (void *)data;
+	fw.size = size;
+
+	if (fw.size < WCD9XXX_MBHC_CAL_MIN_SIZE)
 		return false;
 
 	/*
 	 * Previous check guarantees that there is enough fw data up
 	 * to num_btn
 	 */
-	btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(fw->data);
-	cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
-	if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_BTN_SZ(btn_cfg)))
+        btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(fw.data);
+        cfg_offset = (u32) ((void *) btn_cfg - (void *) fw.data);
+        if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_BTN_SZ(btn_cfg)))
 		return false;
 
 	/*
 	 * Previous check guarantees that there is enough fw data up
 	 * to start of impedance detection configuration
 	 */
-	imped_cfg = WCD9XXX_MBHC_CAL_IMPED_DET_PTR(fw->data);
-	cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
+        imped_cfg = WCD9XXX_MBHC_CAL_IMPED_DET_PTR(fw.data);
+        cfg_offset = (u32) ((void *) imped_cfg - (void *) fw.data);
 
-	if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_MIN_SZ))
+	if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_MIN_SZ))
 		return false;
 
-	if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_SZ(imped_cfg)))
+	if (fw.size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_SZ(imped_cfg)))
 		return false;
 
 	return true;
@@ -4171,7 +4176,9 @@
 	struct wcd9xxx_mbhc *mbhc;
 	struct snd_soc_codec *codec;
 	const struct firmware *fw;
+        struct firmware_cal *fw_data = NULL;
 	int ret = -1, retry = 0;
+	bool use_default_cal = false;
 
 	dwork = to_delayed_work(work);
 	mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_firmware_dwork);
@@ -4179,29 +4186,62 @@
 
 	while (retry < FW_READ_ATTEMPTS) {
 		retry++;
-		pr_info("%s:Attempt %d to request MBHC firmware\n",
-			__func__, retry);
-		ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin",
-				       codec->dev);
-
-		if (ret != 0) {
+		pr_debug("%s:Attempt %d to request MBHC firmware\n",
+                               __func__, retry);
+		if (mbhc->mbhc_cb->get_hwdep_fw_cal)
+			fw_data = mbhc->mbhc_cb->get_hwdep_fw_cal(codec,
+					WCD9XXX_MBHC_CAL);
+		if (!fw_data)
+			ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin",
+                                       codec->dev);
+		/*
+		* if request_firmware and hwdep cal both fail then
+		* retry for few times before bailing out
+		*/
+		if ((ret != 0) && !fw_data) {
 			usleep_range(FW_READ_TIMEOUT, FW_READ_TIMEOUT);
 		} else {
 			pr_info("%s: MBHC Firmware read succesful\n", __func__);
 			break;
 		}
 	}
-
-	if (ret != 0) {
+	if (!fw_data)
+		pr_debug("%s: using request_firmware\n", __func__);
+	else
+		pr_debug("%s: using hwdep cal\n", __func__);
+	if (ret != 0 && !fw_data) {
 		pr_err("%s: Cannot load MBHC firmware use default cal\n",
-		       __func__);
-	} else if (wcd9xxx_mbhc_fw_validate(fw) == false) {
-		pr_err("%s: Invalid MBHC cal data size use default cal\n",
-		       __func__);
-		release_firmware(fw);
-	} else {
-		mbhc->mbhc_cfg->calibration = (void *)fw->data;
-		mbhc->mbhc_fw = fw;
+			__func__);
+		use_default_cal = true;
+	}
+	if (!use_default_cal) {
+		const void *data;
+		size_t size;
+
+		if (fw_data) {
+			data = fw_data->data;
+			size = fw_data->size;
+		} else {
+			data = fw->data;
+			size = fw->size;
+		}
+		if (wcd9xxx_mbhc_fw_validate(data, size) == false) {
+			pr_err("%s: Invalid MBHC cal data size use default cal\n",
+				__func__);
+			if (!fw_data)
+				release_firmware(fw);
+		} else {
+			if (fw_data) {
+				mbhc->mbhc_cfg->calibration =
+						(void *)fw_data->data;
+				mbhc->mbhc_cal = fw_data;
+			} else {
+				mbhc->mbhc_cfg->calibration =
+						(void *)fw->data;
+				mbhc->mbhc_fw = fw;
+			}
+		}
+
 	}
 
 	(void) wcd9xxx_init_and_calibrate(mbhc);
@@ -4391,15 +4431,16 @@
 		mbhc->mbhc_cb->enable_clock_gate(mbhc->codec, true);
 
 	if (!mbhc->mbhc_cfg->read_fw_bin ||
-	    (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw)) {
+		(mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw) ||
+		(mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_cal)) {
 		rc = wcd9xxx_init_and_calibrate(mbhc);
 	} else {
-		if (!mbhc->mbhc_fw)
+		if (!mbhc->mbhc_fw || !mbhc->mbhc_cal)
 			schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
 					     usecs_to_jiffies(FW_READ_TIMEOUT));
 		else
-			pr_debug("%s: Skipping to read mbhc fw, 0x%p\n",
-				 __func__, mbhc->mbhc_fw);
+			pr_debug("%s: Skipping to read mbhc fw, 0x%p 0x%p\n",
+				 __func__, mbhc->mbhc_fw, mbhc->mbhc_cal);
 	}
 
 	pr_debug("%s: leave %d\n", __func__, rc);
@@ -4409,10 +4450,12 @@
 
 void wcd9xxx_mbhc_stop(struct wcd9xxx_mbhc *mbhc)
 {
-	if (mbhc->mbhc_fw) {
+	if (mbhc->mbhc_fw || mbhc->mbhc_cal) {
 		cancel_delayed_work_sync(&mbhc->mbhc_firmware_dwork);
-		release_firmware(mbhc->mbhc_fw);
+		if (!mbhc->mbhc_cal)
+			release_firmware(mbhc->mbhc_fw);
 		mbhc->mbhc_fw = NULL;
+		mbhc->mbhc_cal = NULL;
 	}
 }
 EXPORT_SYMBOL(wcd9xxx_mbhc_stop);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 91edaca..7eba649 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -13,6 +13,7 @@
 #define __WCD9XXX_MBHC_H__
 
 #include "wcd9xxx-resmgr.h"
+#include "wcdcal-hwdep.h"
 
 #define WCD9XXX_CFILT_FAST_MODE 0x00
 #define WCD9XXX_CFILT_SLOW_MODE 0x40
@@ -285,6 +286,9 @@
 	int (*enable_mb_source) (struct snd_soc_codec *, bool, bool);
 	void (*setup_int_rbias) (struct snd_soc_codec *, bool);
 	void (*pull_mb_to_vddio) (struct snd_soc_codec *, bool);
+	struct firmware_cal * (*get_hwdep_fw_cal) (struct snd_soc_codec *,
+				enum wcd_cal_type);
+
 };
 
 struct wcd9xxx_mbhc {
@@ -312,6 +316,7 @@
 	const struct firmware *mbhc_fw;
 
 	struct delayed_work mbhc_insert_dwork;
+	struct firmware_cal *mbhc_cal;
 
 	u8 current_plug;
 	struct work_struct correct_plug_swch;
diff --git a/sound/soc/codecs/wcdcal-hwdep.c b/sound/soc/codecs/wcdcal-hwdep.c
new file mode 100644
index 0000000..1132a3c
--- /dev/null
+++ b/sound/soc/codecs/wcdcal-hwdep.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/bitops.h>
+#include <sound/hwdep.h>
+#include <sound/msmcal-hwdep.h>
+#include <sound/soc.h>
+#include "wcdcal-hwdep.h"
+
+const int cal_size_info[WCD9XXX_MAX_CAL] = {
+	[WCD9XXX_ANC_CAL] = 4096,
+	[WCD9XXX_MBHC_CAL] = 4096,
+	[WCD9XXX_MAD_CAL] = 4096,
+};
+
+const char *cal_name_info[WCD9XXX_MAX_CAL] = {
+	[WCD9XXX_ANC_CAL] = "anc",
+	[WCD9XXX_MBHC_CAL] = "mbhc",
+	[WCD9XXX_MAD_CAL] = "mad",
+};
+
+struct firmware_cal *wcdcal_get_fw_cal(struct fw_info *fw_data,
+					enum wcd_cal_type type)
+{
+	if (!fw_data) {
+		pr_err("%s: fw_data is NULL\n", __func__);
+		return NULL;
+	}
+	if (type >= WCD9XXX_MAX_CAL ||
+		type < WCD9XXX_MIN_CAL) {
+		pr_err("%s: wrong cal type sent %d\n", __func__, type);
+		return NULL;
+	}
+	mutex_lock(&fw_data->lock);
+	if (!test_bit(WCDCAL_RECIEVED,
+		&fw_data->wcdcal_state[type])) {
+		pr_err("%s: cal not sent by userspace %d\n",
+			__func__, type);
+		mutex_unlock(&fw_data->lock);
+		return NULL;
+	}
+	mutex_unlock(&fw_data->lock);
+	return fw_data->fw[type];
+}
+EXPORT_SYMBOL(wcdcal_get_fw_cal);
+
+static int wcdcal_hwdep_ioctl_shared(struct snd_hwdep *hw,
+			struct wcdcal_ioctl_buffer fw_user)
+{
+	struct fw_info *fw_data = hw->private_data;
+	struct firmware_cal **fw = fw_data->fw;
+	void *data;
+
+	if (!test_bit(fw_user.cal_type, fw_data->cal_bit)) {
+		pr_err("%s: codec didn't set this %d!!\n",
+				__func__, fw_user.cal_type);
+		return -EFAULT;
+	}
+	if (fw_user.cal_type >= WCD9XXX_MAX_CAL ||
+		fw_user.cal_type < WCD9XXX_MIN_CAL) {
+		pr_err("%s: wrong cal type sent %d\n",
+				__func__, fw_user.cal_type);
+		return -EFAULT;
+	}
+	if (fw_user.size > cal_size_info[fw_user.cal_type] ||
+		fw_user.size <= 0) {
+		pr_err("%s: incorrect firmware size %d for %s\n",
+			__func__, fw_user.size,
+			cal_name_info[fw_user.cal_type]);
+		return -EFAULT;
+	}
+	data = fw[fw_user.cal_type]->data;
+	memcpy(data, fw_user.buffer, fw_user.size);
+	fw[fw_user.cal_type]->size = fw_user.size;
+	mutex_lock(&fw_data->lock);
+	set_bit(WCDCAL_RECIEVED, &fw_data->wcdcal_state[fw_user.cal_type]);
+	mutex_unlock(&fw_data->lock);
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+struct wcdcal_ioctl_buffer32 {
+	u32 size;
+	compat_uptr_t buffer;
+	enum wcd_cal_type cal_type;
+};
+
+enum {
+	SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE32 =
+		_IOW('U', 0x1, struct wcdcal_ioctl_buffer32),
+};
+
+static int wcdcal_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	struct wcdcal_ioctl_buffer __user *argp = (void __user *)arg;
+	struct wcdcal_ioctl_buffer32 fw_user32;
+	struct wcdcal_ioctl_buffer fw_user_compat;
+
+	if (cmd != SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE32) {
+		pr_err("%s: wrong ioctl command sent %u!\n", __func__, cmd);
+		return -ENOIOCTLCMD;
+	}
+	if (copy_from_user(&fw_user32, argp, sizeof(fw_user32))) {
+		pr_err("%s: failed to copy\n", __func__);
+		return -EFAULT;
+	}
+	fw_user_compat.size = fw_user32.size;
+	fw_user_compat.buffer = compat_ptr(fw_user32.buffer);
+	fw_user_compat.cal_type = fw_user32.cal_type;
+	return wcdcal_hwdep_ioctl_shared(hw, fw_user_compat);
+}
+#else
+#define wcdcal_hwdep_ioctl_compat NULL
+#endif
+
+static int wcdcal_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	struct wcdcal_ioctl_buffer __user *argp = (void __user *)arg;
+	struct wcdcal_ioctl_buffer fw_user;
+
+	if (cmd != SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE) {
+		pr_err("%s: wrong ioctl command sent %d!\n", __func__, cmd);
+		return -ENOIOCTLCMD;
+	}
+	if (copy_from_user(&fw_user, argp, sizeof(fw_user))) {
+		pr_err("%s: failed to copy\n", __func__);
+		return -EFAULT;
+	}
+	return wcdcal_hwdep_ioctl_shared(hw, fw_user);
+}
+
+static int wcdcal_hwdep_release(struct snd_hwdep *hw, struct file *file)
+{
+	struct fw_info *fw_data = hw->private_data;
+	mutex_lock(&fw_data->lock);
+	/* clear all the calibrations */
+	memset(fw_data->wcdcal_state, 0,
+		sizeof(fw_data->wcdcal_state));
+	mutex_unlock(&fw_data->lock);
+	return 0;
+}
+
+int wcd_cal_create_hwdep(void *data, int node, struct snd_soc_codec *codec)
+{
+	char hwname[40];
+	struct snd_hwdep *hwdep;
+	struct firmware_cal **fw;
+	struct fw_info *fw_data = data;
+	int err, cal_bit;
+
+	if (!fw_data || !codec) {
+		pr_err("%s: wrong arguments passed\n", __func__);
+		return -EINVAL;
+	}
+
+	fw = fw_data->fw;
+	snprintf(hwname, strlen("Codec %s"), "Codec %s", codec->name);
+	err = snd_hwdep_new(codec->card->snd_card, hwname, node, &hwdep);
+	if (err < 0) {
+		dev_err(codec->dev, "%s: new hwdep failed %d\n",
+				__func__, err);
+		return err;
+	}
+	snprintf(hwdep->name, strlen("Codec %s"), "Codec %s", codec->name);
+	hwdep->iface = SNDRV_HWDEP_IFACE_AUDIO_CODEC;
+	hwdep->private_data = fw_data;
+	hwdep->ops.ioctl_compat = wcdcal_hwdep_ioctl_compat;
+	hwdep->ops.ioctl = wcdcal_hwdep_ioctl;
+	hwdep->ops.release = wcdcal_hwdep_release;
+	mutex_init(&fw_data->lock);
+
+	for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
+		set_bit(WCDCAL_UNINITIALISED,
+				&fw_data->wcdcal_state[cal_bit]);
+		fw[cal_bit] = kzalloc(sizeof *(fw[cal_bit]), GFP_KERNEL);
+		if (!fw[cal_bit]) {
+			dev_err(codec->dev, "%s: no memory for %s cal\n",
+				__func__, cal_name_info[cal_bit]);
+			goto end;
+		}
+	}
+	for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
+		fw[cal_bit]->data = kzalloc(cal_size_info[cal_bit],
+						GFP_KERNEL);
+		if (!fw[cal_bit]->data) {
+			dev_err(codec->dev, "%s: no memory for %s cal data\n",
+				__func__, cal_name_info[cal_bit]);
+			goto exit;
+		}
+		set_bit(WCDCAL_INITIALISED,
+			&fw_data->wcdcal_state[cal_bit]);
+	}
+	return 0;
+exit:
+	for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
+		kfree(fw[cal_bit]->data);
+		fw[cal_bit]->data = NULL;
+	}
+end:
+	for_each_set_bit(cal_bit, fw_data->cal_bit, WCD9XXX_MAX_CAL) {
+		kfree(fw[cal_bit]);
+		fw[cal_bit] = NULL;
+	}
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(wcd_cal_create_hwdep);
diff --git a/sound/soc/codecs/wcdcal-hwdep.h b/sound/soc/codecs/wcdcal-hwdep.h
new file mode 100644
index 0000000..632e2f1
--- /dev/null
+++ b/sound/soc/codecs/wcdcal-hwdep.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __WCD9XXX_HWDEP_H__
+#define __WCD9XXX_HWDEP_H__
+#include <sound/msmcal-hwdep.h>
+
+enum wcd_cal_states {
+	WCDCAL_UNINITIALISED,
+	WCDCAL_INITIALISED,
+	WCDCAL_RECIEVED
+};
+
+struct fw_info {
+	struct firmware_cal *fw[WCD9XXX_MAX_CAL];
+	DECLARE_BITMAP(cal_bit, WCD9XXX_MAX_CAL);
+	/* for calibration tracking */
+	unsigned long wcdcal_state[WCD9XXX_MAX_CAL];
+	struct mutex lock;
+};
+
+struct firmware_cal {
+	u8 *data;
+	size_t size;
+};
+
+struct snd_soc_codec;
+int wcd_cal_create_hwdep(void *fw, int node, struct snd_soc_codec *codec);
+struct firmware_cal *wcdcal_get_fw_cal(struct fw_info *fw_data,
+					enum wcd_cal_type type);
+#endif /* __WCD9XXX_HWDEP_H__ */
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 86dd840..fbcd953 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -183,6 +183,7 @@
 	select SND_DYNAMIC_MINORS
 	select AUDIO_OCMEM
 	select DOLBY_DAP
+	select SND_HWDEP
 	help
 	 To add support for SoC audio on MSM8974.
 	 This will enable sound soc drivers which
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 1a4ec7c..ae5c42f 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -304,6 +304,7 @@
 	uint32_t sample_rate = 0;
 	int bytes_available, stream_id;
 	uint32_t stream_index;
+	unsigned long flags;
 
 	pr_debug("%s opcode =%08x\n", __func__, opcode);
 	switch (opcode) {
@@ -476,11 +477,17 @@
 	case RESET_EVENTS:
 		pr_err("%s: Received reset events CB, move to error state",
 			__func__);
-		spin_lock(&prtd->lock);
+		spin_lock_irqsave(&prtd->lock, flags);
 		snd_compr_fragment_elapsed(cstream);
 		prtd->copied_total = prtd->bytes_received;
 		atomic_set(&prtd->error, 1);
-		spin_unlock(&prtd->lock);
+		wake_up(&prtd->drain_wait);
+		if (atomic_read(&prtd->eos)) {
+			pr_debug("%s:unblock eos wait queues", __func__);
+			wake_up(&prtd->eos_wait);
+			atomic_set(&prtd->eos, 0);
+		}
+		spin_unlock_irqrestore(&prtd->lock, flags);
 		break;
 	default:
 		pr_debug("%s: Not Supported Event opcode[0x%x]\n",
@@ -931,14 +938,19 @@
 	rc = wait_event_interruptible(prtd->drain_wait,
 					prtd->drain_ready ||
 					prtd->cmd_interrupt ||
-					atomic_read(&prtd->xrun));
-	pr_debug("%s: out of buffer drain wait\n", __func__);
+					atomic_read(&prtd->xrun) ||
+					atomic_read(&prtd->error));
+	pr_debug("%s: out of buffer drain wait with ret %d\n", __func__, rc);
 	spin_lock_irqsave(&prtd->lock, *flags);
 	if (prtd->cmd_interrupt) {
 		pr_debug("%s: buffer drain interrupted by flush)\n", __func__);
 		rc = -EINTR;
 		prtd->cmd_interrupt = 0;
 	}
+	if (atomic_read(&prtd->error)) {
+		pr_err("%s: Got RESET EVENTS notification, return\n", __func__);
+		rc = -ENETRESET;
+	}
 	return rc;
 }
 
@@ -1243,7 +1255,9 @@
 
 		/* Wait indefinitely for  DRAIN. Flush can also signal this*/
 		rc = wait_event_interruptible(prtd->eos_wait,
-					      (prtd->cmd_ack || prtd->cmd_interrupt));
+						(prtd->cmd_ack ||
+						prtd->cmd_interrupt ||
+						atomic_read(&prtd->error)));
 
 		if (rc < 0)
 			pr_err("%s: EOS wait failed\n", __func__);
@@ -1254,6 +1268,11 @@
 		if (prtd->cmd_interrupt)
 			rc = -EINTR;
 
+		if (atomic_read(&prtd->error)) {
+			pr_err("%s: Got RESET EVENTS notification, return\n", __func__);
+			rc = -ENETRESET;
+		}
+
 		/*FIXME : what if a flush comes while PC is here */
 		if (rc == 0) {
 			/*
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index b165664..27fe7bc 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -29,7 +29,7 @@
 #include "q6voice.h"
 
 
-#define TIMEOUT_MS 300
+#define TIMEOUT_MS 500
 
 
 #define CMD_STATUS_SUCCESS 0