msm: camera: Fix for camera crash

1. update get_sensor_info function to send sensor type
   to the upper layers
2. update table ack pending flag in case of table ack
   received
3. add ov5647 sensor power down function

Change-Id: I92c8e25d377d2fee09276b72119eb95adfcc79f8
Signed-off-by: Raju P.L.S.S.S.N <rplsssn@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 157c939..9080e60 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -461,6 +461,7 @@
 	.sensor_platform_info = &sensor_board_info_imx074,
 	.csi_if	= 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &imx074_actuator_info
 };
 static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
@@ -495,6 +496,7 @@
 	.sensor_platform_info = &sensor_board_info_imx091,
 	.csi_if	= 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 
 static struct camera_vreg_t apq_8064_mt9m114_vreg[] = {
@@ -529,6 +531,7 @@
 	.sensor_platform_info = &sensor_board_info_mt9m114,
 	.csi_if = 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
 };
 
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
@@ -556,6 +559,7 @@
 	.sensor_platform_info = &sensor_board_info_ov2720,
 	.csi_if	= 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 
 void __init apq8064_init_cam(void)
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 315e8fc..92e88aa72 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -446,6 +446,7 @@
 	.sensor_platform_info = &sensor_board_info_imx074,
 	.csi_if	= 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &imx074_actuator_info
 };
 
@@ -480,6 +481,7 @@
 	.sensor_platform_info = &sensor_board_info_mt9m114,
 	.csi_if = 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
 };
 
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
@@ -506,6 +508,7 @@
 	.sensor_platform_info = &sensor_board_info_ov2720,
 	.csi_if	= 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 
 static struct camera_vreg_t msm_8930_s5k3l1yx_vreg[] = {
@@ -539,6 +542,7 @@
 	.sensor_platform_info = &sensor_board_info_s5k3l1yx,
 	.csi_if               = 1,
 	.camera_type          = BACK_CAMERA_2D,
+	.sensor_type          = BAYER_SENSOR,
 };
 
 void __init msm8930_init_cam(void)
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index d51a6d3..c2a378f 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -517,6 +517,7 @@
 	.sensor_platform_info = &sensor_board_info_imx074,
 	.csi_if	= 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 	.actuator_info = &imx074_actuator_info
 };
 
@@ -551,6 +552,7 @@
 	.sensor_platform_info = &sensor_board_info_mt9m114,
 	.csi_if = 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
 };
 
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
@@ -577,6 +579,7 @@
 	.sensor_platform_info = &sensor_board_info_ov2720,
 	.csi_if	= 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 
 static struct camera_vreg_t msm_8960_s5k3l1yx_vreg[] = {
@@ -610,6 +613,7 @@
 	.sensor_platform_info = &sensor_board_info_s5k3l1yx,
 	.csi_if               = 1,
 	.camera_type          = BACK_CAMERA_2D,
+	.sensor_type          = BAYER_SENSOR,
 };
 
 static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
@@ -643,6 +647,7 @@
 	.sensor_platform_info = &sensor_board_info_imx091,
 	.csi_if	= 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 
 static struct pm8xxx_mpp_config_data privacy_light_on_config = {
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 608eb1e..2269073 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -149,6 +149,7 @@
 	.sensor_platform_info   = &sensor_board_info_s5k4e1,
 	.csi_if                 = 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 #ifdef CONFIG_DW9712_ACT
 	.actuator_info = &s5k4e1_actuator_info
 #endif
@@ -178,6 +179,7 @@
 	.sensor_platform_info   = &sensor_board_info_ov7692,
 	.csi_if		 = 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = YUV_SENSOR,
 };
 #endif
 
@@ -225,6 +227,7 @@
 	.sensor_platform_info   = &sensor_board_info_ov5647,
 	.csi_if                 = 1,
 	.camera_type	= BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 
 #ifdef CONFIG_AD5046_ACT
 	.actuator_info = &ad5046_actuator_info
@@ -254,6 +257,7 @@
 	.sensor_platform_info   = &sensor_board_info_mt9e013,
 	.csi_if                 = 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 #endif
 
@@ -279,6 +283,7 @@
 	.sensor_platform_info   = &sensor_board_info_ov9726,
 	.csi_if                 = 1,
 	.camera_type = FRONT_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
 };
 #endif
 
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index ae4d632..7b74f1e 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -172,6 +172,11 @@
 	BACK_CAMERA_INT_3D,
 };
 
+enum msm_sensor_type {
+	BAYER_SENSOR,
+	YUV_SENSOR,
+};
+
 enum camera_vreg_type {
 	REG_LDO,
 	REG_VS,
@@ -261,6 +266,7 @@
 	struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
 	char *eeprom_data;
 	enum msm_camera_type camera_type;
+	enum msm_sensor_type sensor_type;
 	struct msm_actuator_info *actuator_info;
 	int pmic_gpio_enable;
 };
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 628fa62..001e02a 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -194,7 +194,8 @@
 	info.pxlcode = pcam->usr_fmts[0].pxlcode;
 	info.flashtype = sdata->flash_type; /* two flash_types here? */
 	info.camera_type = sdata->camera_type;
-	info.sensor_type = 0; /* need to add YUV/SOC in probing */
+	/* sensor_type needed to add YUV/SOC in probing */
+	info.sensor_type = sdata->sensor_type;
 	info.mount_angle = sdata->sensor_platform_info->mount_angle;
 	/* copy back to user space */
 	if (copy_to_user((void *)arg,
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index a332fba..af27a56 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -292,7 +292,8 @@
 		"VFE_DEMOSAICv3_BPC_UPDATE"},
 	{VFE_CMD_XBAR_CFG, VFE_MAX, VFE_MAX},
 	{VFE_CMD_MODULE_CFG, VFE_MAX, VFE_MAX},
-	{VFE_CMD_ZSL, VFE_MAX, VFE_MAX},
+	{VFE_CMD_ZSL, VFE_START, QDSP_CMDQUEUE,
+			"VFE_CMD_ZSL", "VFE_START"},
 	{VFE_CMD_LINEARIZATION_UPDATE, VFE_MAX, VFE_MAX},
 	{VFE_CMD_DEMOSAICV3_ABF_UPDATE, VFE_DEMOSAICv3_ABF_CFG,
 		QDSP_TABLEQUEUE, "VFE_CMD_DEMOSAICV3_ABF_UPDATE",
@@ -452,6 +453,75 @@
 							y_phy, cbcr_phy);
 			break;
 		case MSG_OUTPUT1:
+			if (op_mode & SNAPSHOT_MASK_MODE) {
+				kfree(data);
+				return;
+			} else {
+				free_buf = vfe2x_check_free_buffer(
+							VFE_MSG_OUTPUT_IRQ,
+							VFE_MSG_OUTPUT_SECONDARY
+							);
+				CDBG("free_buf = %x\n",
+						(unsigned int) free_buf);
+				if (free_buf) {
+					fack.header = VFE_OUTPUT1_ACK;
+
+					fack.output2newybufferaddress =
+						(void *)(free_buf->ch_paddr[0]);
+
+					fack.output2newcbcrbufferaddress =
+						(void *)(free_buf->ch_paddr[1]);
+
+					cmd_data = &fack;
+					len = sizeof(fack);
+					msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+							cmd_data, len);
+			      } else {
+					fack.header = VFE_OUTPUT1_ACK;
+					fack.output2newybufferaddress =
+					(void *)
+				((struct vfe_endframe *)data)->y_address;
+					fack.output2newcbcrbufferaddress =
+					(void *)
+				((struct vfe_endframe *)data)->cbcr_address;
+					cmd_data = &fack;
+					len = sizeof(fack);
+					msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+						cmd_data, len);
+				}
+			}
+			y_phy = ((struct vfe_endframe *)data)->y_address;
+			cbcr_phy = ((struct vfe_endframe *)data)->cbcr_address;
+
+
+			CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
+				 y_phy, cbcr_phy);
+			if (free_buf) {
+				for (i = 0; i < 3; i++) {
+					if (vfe2x_ctrl->free_buf.buf[i].
+							ch_paddr[0] == y_phy) {
+						vfe2x_ctrl->free_buf.
+							buf[i].ch_paddr[0] =
+							free_buf->ch_paddr[0];
+						vfe2x_ctrl->free_buf.
+							buf[i].ch_paddr[1] =
+							free_buf->ch_paddr[1];
+						break;
+					}
+				}
+				if (i == 3)
+					CDBG("Address doesnt match\n");
+			}
+			memcpy(((struct vfe_frame_extra *)extdata),
+				&((struct vfe_endframe *)data)->extra,
+				sizeof(struct vfe_frame_extra));
+
+			vfe2x_ctrl->vfeFrameId =
+				((struct vfe_frame_extra *)extdata)->frame_id;
+			vfe_send_outmsg(&vfe2x_ctrl->subdev,
+						MSG_ID_OUTPUT_SECONDARY,
+						y_phy, cbcr_phy);
+			break;
 		case MSG_OUTPUT2:
 			if (op_mode & SNAPSHOT_MASK_MODE) {
 				kfree(data);
@@ -601,6 +671,7 @@
 	}
 	if (MSG_TABLE_CMD_ACK == id) {
 		spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+		vfe2x_ctrl->tableack_pending = 0;
 		if (list_empty(&vfe2x_ctrl->table_q)) {
 			if (vfe2x_ctrl->start_pending) {
 				CDBG("Send START\n");
@@ -633,14 +704,12 @@
 						cmd_data, len);
 				vfe2x_ctrl->update_pending = 0;
 			}
-			vfe2x_ctrl->tableack_pending = 0;
 			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 			return;
 		}
 		table_pending = list_first_entry(&vfe2x_ctrl->table_q,
 					struct table_cmd, list);
 		if (!table_pending) {
-			vfe2x_ctrl->tableack_pending = 0;
 			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 			return;
 		}
@@ -673,16 +742,32 @@
 
 	if (mode == OUTPUT_SEC) {
 		/* Thumbnail */
-		ao->output1buffer1_y_phy = ad->ping.ch_paddr[0];
-		ao->output1buffer1_cbcr_phy = ad->ping.ch_paddr[1];
-		ao->output1buffer2_y_phy = ad->pong.ch_paddr[0];
-		ao->output1buffer2_cbcr_phy = ad->pong.ch_paddr[1];
-		bptr = &ao->output1buffer3_y_phy;
-		for (cnt = 0; cnt < 6; cnt++) {
-			*bptr = ad->pong.ch_paddr[0];
-			bptr++;
-			*bptr = ad->pong.ch_paddr[1];
-			bptr++;
+		if (vfe2x_ctrl->zsl_mode) {
+			ao->output2buffer1_y_phy = ad->ping.ch_paddr[0];
+			ao->output2buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+			ao->output2buffer2_y_phy = ad->pong.ch_paddr[0];
+			ao->output2buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+			ao->output2buffer3_y_phy = ad->free_buf.ch_paddr[0];
+			ao->output2buffer3_cbcr_phy = ad->free_buf.ch_paddr[1];
+			bptr = &ao->output2buffer4_y_phy;
+			for (cnt = 0; cnt < 5; cnt++) {
+				*bptr = ad->pong.ch_paddr[0];
+				bptr++;
+				*bptr = ad->pong.ch_paddr[1];
+				bptr++;
+			}
+		} else {
+			ao->output1buffer1_y_phy = ad->ping.ch_paddr[0];
+			ao->output1buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+			ao->output1buffer2_y_phy = ad->pong.ch_paddr[0];
+			ao->output1buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+			bptr = &ao->output1buffer3_y_phy;
+			for (cnt = 0; cnt < 6; cnt++) {
+				*bptr = ad->pong.ch_paddr[0];
+				bptr++;
+				*bptr = ad->pong.ch_paddr[1];
+				bptr++;
+			}
 		}
 	} else if (mode == OUTPUT_PRIM && o_mode != SNAPSHOT_MASK_MODE) {
 		/* Preview */
@@ -775,8 +860,13 @@
 		else if (path == VFE_MSG_OUTPUT_SECONDARY)
 			outch = &vfe2x_ctrl->thumb;
 	} else {
-		if (path == VFE_MSG_OUTPUT_PRIMARY)
-			outch = &vfe2x_ctrl->prev;
+		if (path == VFE_MSG_OUTPUT_PRIMARY) {
+			if (vfe2x_ctrl->zsl_mode)
+				outch = &vfe2x_ctrl->zsl_prim;
+			else
+				outch = &vfe2x_ctrl->prev;
+		} else if (path == VFE_MSG_OUTPUT_SECONDARY)
+				outch = &vfe2x_ctrl->zsl_sec;
 	}
 	if (outch->free_buf.ch_paddr[0])
 		return &outch->free_buf;
@@ -797,8 +887,13 @@
 		else if (path == VFE_MSG_OUTPUT_SECONDARY)
 			outch = &vfe2x_ctrl->thumb;
 	} else {
-		if (path == VFE_MSG_OUTPUT_PRIMARY)
-			outch = &vfe2x_ctrl->prev;
+		if (path == VFE_MSG_OUTPUT_PRIMARY) {
+			if (vfe2x_ctrl->zsl_mode)
+				outch = &vfe2x_ctrl->zsl_prim;
+			else
+				outch = &vfe2x_ctrl->prev;
+		} else if (path == VFE_MSG_OUTPUT_SECONDARY)
+			outch = &vfe2x_ctrl->zsl_sec;
 	}
 	if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
 		/* Configure Preview Ping Pong */
@@ -823,8 +918,13 @@
 		else if (path == VFE_MSG_OUTPUT_PRIMARY)
 			ch = &vfe2x_ctrl->snap;
 	} else {
-		if (path == VFE_MSG_OUTPUT_PRIMARY)
-			ch = &vfe2x_ctrl->prev;
+		if (path == VFE_MSG_OUTPUT_PRIMARY) {
+			if (vfe2x_ctrl->zsl_mode)
+				ch = &vfe2x_ctrl->zsl_prim;
+			else
+				ch = &vfe2x_ctrl->prev;
+		} else if (path == VFE_MSG_OUTPUT_SECONDARY)
+			ch = &vfe2x_ctrl->zsl_sec;
 	}
 
 	BUG_ON(ch == NULL);
@@ -1121,6 +1221,7 @@
 			case VFE_CMD_START:
 			case VFE_CMD_CAPTURE:
 			case VFE_CMD_CAPTURE_RAW:
+			case VFE_CMD_ZSL:
 				spin_lock_irqsave(&vfe2x_ctrl->table_lock,
 									flags);
 				if ((!list_empty(&vfe2x_ctrl->table_q)) ||
@@ -1185,6 +1286,7 @@
 	case CMD_AXI_CFG_SEC: {
 		CDBG("CMD_AXI_CFG_SEC\n");
 		raw_mode = 0;
+		vfe2x_ctrl->zsl_mode = 0;
 		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 		if (!axio) {
 			pr_err("NULL axio\n");
@@ -1237,6 +1339,7 @@
 	case CMD_AXI_CFG_PRIM: {
 		CDBG("CMD_AXI_CFG_PRIM : %d\n", op_mode);
 		raw_mode = 0;
+		vfe2x_ctrl->zsl_mode = 0;
 		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 		if (!axio) {
 			pr_err("NULL axio\n");
@@ -1299,9 +1402,74 @@
 		cmd_data = axio;
 	}
 		break;
+	case CMD_AXI_CFG_ZSL: {
+		CDBG("CMD_AXI_CFG_ZSL: %d\n", op_mode);
+		raw_mode = 0;
+		vfe2x_ctrl->zsl_mode = 1;
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			pr_err("NULL axio\n");
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user((char *)axio + 4,
+					(void __user *)(vfecmd.value),
+					sizeof(struct axiout))) {
+			pr_err("copy_from_user failed\n");
+			rc = -EFAULT;
+			goto config_done;
+		}
+		if (!vfe2x_ctrl->reconfig_vfe) {
+				rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_PREVIEW,
+						VFE_MSG_OUTPUT_PRIMARY);
+				rc = vfe2x_configure_pingpong_buffers(
+						VFE_MSG_V2X_PREVIEW,
+						VFE_MSG_OUTPUT_SECONDARY);
+			if (rc < 0) {
+				pr_err("%s error configuring pingpong buffers"
+					" for preview", __func__);
+				rc = -EINVAL;
+				goto config_done;
+			}
+				free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_PRIMARY);
+				free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_SECONDARY);
+		} else {
+			vfe2x_ctrl->prev.ping.ch_paddr[0] =
+				vfe2x_ctrl->free_buf.buf[0].ch_paddr[0];
+			vfe2x_ctrl->prev.ping.ch_paddr[1] =
+				vfe2x_ctrl->free_buf.buf[0].ch_paddr[1];
+			vfe2x_ctrl->prev.pong.ch_paddr[0] =
+				vfe2x_ctrl->free_buf.buf[1].ch_paddr[0];
+			vfe2x_ctrl->prev.pong.ch_paddr[1] =
+				vfe2x_ctrl->free_buf.buf[1].ch_paddr[1];
+			vfe2x_ctrl->prev.free_buf.ch_paddr[0] =
+				vfe2x_ctrl->free_buf.buf[2].ch_paddr[0];
+			vfe2x_ctrl->prev.free_buf.ch_paddr[1] =
+				vfe2x_ctrl->free_buf.buf[2].ch_paddr[1];
+			vfe2x_ctrl->reconfig_vfe = 0;
+		}
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+		*(uint32_t *)axio = header;
+		vfe_7x_config_axi(OUTPUT_PRIM, &vfe2x_ctrl->zsl_prim, axio);
+		vfe_7x_config_axi(OUTPUT_SEC, &vfe2x_ctrl->zsl_sec, axio);
+		cmd_data = axio;
+	}
+		break;
 	case CMD_AXI_CFG_SEC|CMD_AXI_CFG_PRIM: {
 		CDBG("CMD_AXI_CFG_SEC|PRIM\n");
 		raw_mode = 0;
+		vfe2x_ctrl->zsl_mode = 0;
 		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
 		if (!axio) {
 			pr_err("NULL axio\n");
@@ -1440,20 +1608,22 @@
 		spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 	} else {
 		if (queue == QDSP_TABLEQUEUE) {
-			CDBG("sending table cmd\n");
 			spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+			CDBG("sending table cmd\n");
+			vfe2x_ctrl->tableack_pending = 1;
 			rc = msm_adsp_write(vfe_mod, queue,
 				cmd_data, vfecmd.length + 4);
-			vfe2x_ctrl->tableack_pending = 1;
 			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 		} else {
-			CDBG("send n-table cmd\n");
 			if (*(uint32_t *)cmd_data == VFE_OUTPUT2_ACK) {
 				uint32_t *ptr = cmd_data;
 				CDBG("%x %x %x\n", ptr[0], ptr[1], ptr[2]);
 			}
+			spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+			CDBG("send n-table cmd\n");
 			rc = msm_adsp_write(vfe_mod, queue,
 				cmd_data, vfecmd.length + 4);
+			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
 			CDBG("%x\n", vfecmd.length + 4);
 		}
 	}
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
index 2b77159..2f2d3c6 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
@@ -85,6 +85,10 @@
 	struct buf_info raw;
 	struct buf_info thumb;
 	struct prev_free_buf_info free_buf;
+	struct buf_info zsl_prim;
+	struct buf_info zsl_sec;
+	struct prev_free_buf_info zsl_free_buf[2];
+
 
 	spinlock_t  table_lock;
 	struct list_head table_q;
@@ -106,6 +110,7 @@
 	struct clk *vfe_clk[3];
 	spinlock_t  sd_notify_lock;
 	uint32_t    reconfig_vfe;
+	uint32_t    zsl_mode;
 } __packed;
 
 struct vfe_frame_extra {
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 1112be7..d882e52 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -214,59 +214,6 @@
 	return rc;
 }
 
-int32_t msm_sensor_setting2(struct msm_sensor_ctrl_t *s_ctrl,
-			int update_type, int res)
-{
-	int32_t rc = 0;
-	static int csi_config;
-
-	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
-	if (csi_config == 0 || res == 0)
-		msleep(66);
-	else
-		msleep(266);
-	if (update_type == MSM_SENSOR_REG_INIT) {
-		CDBG("Register INIT\n");
-		s_ctrl->curr_csi_params = NULL;
-		msm_camera_i2c_write(
-				s_ctrl->sensor_i2c_client,
-				0x103, 0x1,
-				MSM_CAMERA_I2C_BYTE_DATA);
-		msm_sensor_enable_debugfs(s_ctrl);
-		msm_sensor_write_init_settings(s_ctrl);
-		csi_config = 0;
-	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
-		CDBG("PERIODIC : %d\n", res);
-		msm_sensor_write_conf_array(
-			s_ctrl->sensor_i2c_client,
-			s_ctrl->msm_sensor_reg->mode_settings, res);
-		msleep(30);
-		if (!csi_config) {
-			s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
-			CDBG("CSI config in progress\n");
-			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
-				NOTIFY_CSIC_CFG,
-				s_ctrl->curr_csic_params);
-			CDBG("CSI config is done\n");
-			mb();
-			msleep(30);
-			csi_config = 1;
-		msm_camera_i2c_write(
-			s_ctrl->sensor_i2c_client,
-			0x100, 0x1,
-			MSM_CAMERA_I2C_BYTE_DATA);
-		}
-		msm_camera_i2c_write(
-			s_ctrl->sensor_i2c_client,
-			0x4800, 0x4,
-			MSM_CAMERA_I2C_BYTE_DATA);
-		msleep(266);
-		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
-		msleep(50);
-	}
-	return rc;
-}
-
 int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res)
 {
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index fed514c..9a85836 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -12,6 +12,7 @@
  */
 
 #include "msm_sensor.h"
+#include "msm.h"
 #define SENSOR_NAME "ov5647"
 #define PLATFORM_DRIVER_NAME "msm_camera_ov5647"
 #define ov5647_obj ov5647_##obj
@@ -333,27 +334,31 @@
 		, gain, line, line);
 
 	if (line > 1964) {
+		s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-			s_ctrl->sensor_exp_gain_info->vert_offset,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines,
 			(uint8_t)((line+4) >> 8),
 			MSM_CAMERA_I2C_BYTE_DATA);
 
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-			s_ctrl->sensor_exp_gain_info->vert_offset + 1,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
 			(uint8_t)((line+4) & 0x00FF),
 			MSM_CAMERA_I2C_BYTE_DATA);
+		s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
 
 		max_line = line + 4;
 	} else if (line > 1968) {
+		s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-			s_ctrl->sensor_exp_gain_info->vert_offset,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines,
 			(uint8_t)((line+4) >> 8),
 			MSM_CAMERA_I2C_BYTE_DATA);
 
 		 msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-			s_ctrl->sensor_exp_gain_info->vert_offset + 1,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
 			(uint8_t)((line+4) & 0x00FF),
 			MSM_CAMERA_I2C_BYTE_DATA);
+		s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
 			max_line = 1968;
 	}
 
@@ -447,24 +452,24 @@
 	if (line > 980) {
 
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-		s_ctrl->sensor_exp_gain_info->vert_offset,
+		s_ctrl->sensor_output_reg_addr->frame_length_lines,
 		(uint8_t)((line+4) >> 8),
 		MSM_CAMERA_I2C_BYTE_DATA);
 
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-		s_ctrl->sensor_exp_gain_info->vert_offset + 1,
+		s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
 		(uint8_t)((line+4) & 0x00FF),
 		MSM_CAMERA_I2C_BYTE_DATA);
 		max_line = line + 4;
 	} else if (line > 984) {
 
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-		s_ctrl->sensor_exp_gain_info->vert_offset,
+		s_ctrl->sensor_output_reg_addr->frame_length_lines,
 		(uint8_t)(984 >> 8),
 		MSM_CAMERA_I2C_BYTE_DATA);
 
 		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
-		s_ctrl->sensor_exp_gain_info->vert_offset + 1 ,
+		s_ctrl->sensor_output_reg_addr->frame_length_lines + 1 ,
 		(uint8_t)(984 & 0x00FF),
 		MSM_CAMERA_I2C_BYTE_DATA);
 		max_line = 984;
@@ -568,33 +573,118 @@
 	.video  = &ov5647_subdev_video_ops,
 };
 
+int32_t ov5647_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	struct msm_camera_sensor_info *info = NULL;
+	unsigned short rdata;
+	int rc;
+
+	info = s_ctrl->sensordata;
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x4202, 0xf,
+		MSM_CAMERA_I2C_BYTE_DATA);
+	msleep(20);
+	rc = msm_camera_i2c_read(s_ctrl->sensor_i2c_client, 0x3018,
+			&rdata, MSM_CAMERA_I2C_WORD_DATA);
+	CDBG("ov5647_sensor_power_down: %d\n", rc);
+	rdata |= 0x18;
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x3018, rdata,
+		MSM_CAMERA_I2C_WORD_DATA);
+	msleep(20);
+	gpio_direction_output(info->sensor_pwd, 1);
+	usleep_range(5000, 5100);
+	msm_sensor_power_down(s_ctrl);
+	return 0;
+}
+
 int32_t ov5647_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
 {
 	int32_t rc = 0;
 	struct msm_camera_sensor_info *info = NULL;
 
+	info = s_ctrl->sensordata;
+	gpio_direction_output(info->sensor_pwd, 1);
+	gpio_direction_output(info->sensor_reset, 0);
+	usleep_range(10000, 11000);
+	if (info->pmic_gpio_enable) {
+		info->pmic_gpio_enable = 0;
+		lcd_camera_power_onoff(1);
+	}
+	usleep_range(10000, 11000);
 	rc = msm_sensor_power_up(s_ctrl);
 	if (rc < 0) {
 		CDBG("%s: msm_sensor_power_up failed\n", __func__);
 		return rc;
 	}
-	info = s_ctrl->sensordata;
 
-	gpio_direction_output(info->sensor_pwd, 1);
-	gpio_direction_output(info->sensor_reset, 0);
-	usleep_range(1000, 1100);
 	/* turn on ldo and vreg */
-	if (info->pmic_gpio_enable)
-		lcd_camera_power_onoff(1);
 
 	gpio_direction_output(info->sensor_pwd, 0);
-	usleep_range(4000, 4100);
+	msleep(20);
 	gpio_direction_output(info->sensor_reset, 1);
-	usleep_range(2000, 2100);
+	msleep(25);
 
 	return rc;
 
 }
+
+int32_t ov5647_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res)
+{
+	int32_t rc = 0;
+	static int csi_config;
+
+	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+	if (csi_config == 0 || res == 0)
+		msleep(66);
+	else
+		msleep(266);
+	msm_camera_i2c_write(
+			s_ctrl->sensor_i2c_client,
+			0x4800, 0x25,
+			MSM_CAMERA_I2C_BYTE_DATA);
+	if (update_type == MSM_SENSOR_REG_INIT) {
+		CDBG("Register INIT\n");
+		s_ctrl->curr_csi_params = NULL;
+		msm_camera_i2c_write(
+				s_ctrl->sensor_i2c_client,
+				0x103, 0x1,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		msm_sensor_enable_debugfs(s_ctrl);
+		msm_sensor_write_init_settings(s_ctrl);
+		csi_config = 0;
+	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
+		CDBG("PERIODIC : %d\n", res);
+		msm_sensor_write_conf_array(
+			s_ctrl->sensor_i2c_client,
+			s_ctrl->msm_sensor_reg->mode_settings, res);
+		msleep(30);
+		if (!csi_config) {
+			s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
+			CDBG("CSI config in progress\n");
+			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+				NOTIFY_CSIC_CFG,
+				s_ctrl->curr_csic_params);
+			CDBG("CSI config is done\n");
+			mb();
+			msleep(30);
+			csi_config = 1;
+		msm_camera_i2c_write(
+			s_ctrl->sensor_i2c_client,
+			0x100, 0x1,
+			MSM_CAMERA_I2C_BYTE_DATA);
+		}
+		msm_camera_i2c_write(
+			s_ctrl->sensor_i2c_client,
+			0x4800, 0x4,
+			MSM_CAMERA_I2C_BYTE_DATA);
+		msleep(266);
+		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
+		msleep(50);
+	}
+	return rc;
+}
 static struct msm_sensor_fn_t ov5647_func_tbl = {
 	.sensor_start_stream = msm_sensor_start_stream,
 	.sensor_stop_stream = msm_sensor_stop_stream,
@@ -603,13 +693,13 @@
 	.sensor_set_fps = msm_sensor_set_fps,
 	.sensor_write_exp_gain = ov5647_write_prev_exp_gain,
 	.sensor_write_snapshot_exp_gain = ov5647_write_pict_exp_gain,
-	.sensor_setting = msm_sensor_setting2,
+	.sensor_setting = ov5647_sensor_setting,
 	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
 	.sensor_mode_init = msm_sensor_mode_init,
 	.sensor_get_output_info = msm_sensor_get_output_info,
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = ov5647_sensor_power_up,
-	.sensor_power_down = msm_sensor_power_down,
+	.sensor_power_down = ov5647_sensor_power_down,
 };
 
 static struct msm_sensor_reg_t ov5647_regs = {