camera: ispif: Improve start/stop/reset sequence.

Halt ispif immediately before stopping sensor streaming,
and start ispif before start sensor streaming.
Handle ispif reset properly using wait_for_completion*
instead of msleep().

Signed-off-by: Shuzhen Wang <shuzhenw@codeaurora.org>
diff --git a/drivers/media/video/msm/msm_ispif.c b/drivers/media/video/msm/msm_ispif.c
index 8683d3b..c5e38ef 100644
--- a/drivers/media/video/msm/msm_ispif.c
+++ b/drivers/media/video/msm/msm_ispif.c
@@ -70,8 +70,8 @@
 #define RAW_INTF_1_OVERFLOW_IRQ      25
 #define RESET_DONE_IRQ               27
 
-#define ISPIF_IRQ_STATUS_MASK        0x2493000
-#define ISPIF_IRQ_1_STATUS_MASK      0x2493000
+#define ISPIF_IRQ_STATUS_MASK        0xA493000
+#define ISPIF_IRQ_1_STATUS_MASK      0xA493000
 #define ISPIF_IRQ_STATUS_RDI_SOF_MASK	0x492000
 
 #define MAX_CID 15
@@ -80,61 +80,57 @@
 
 static uint32_t global_intf_cmd_mask = 0xFFFFFFFF;
 
-static void msm_ispif_swreg_misc_reset(void)
+static int msm_ispif_intf_reset(uint8_t intftype)
 {
-	uint32_t data = 0x01, data1 = 0x01;
+	int rc = 0;
+	uint32_t data;
 
-	data |= 0x1 << SW_REG_RST_STB;
-	msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
-	usleep_range(11000, 12000);
-	data1 |= 0x1 << MISC_LOGIC_RST_STB;
-	msm_io_w(data1, ispif->base + ISPIF_RST_CMD_ADDR);
-	usleep_range(11000, 12000);
-}
-
-static void msm_ispif_intf_reset(uint8_t intftype)
-{
-	uint32_t data = 0x01 , data1 = 0x01;
-
-	msm_io_w(0x1<<STROBED_RST_EN, ispif->base + ISPIF_RST_CMD_ADDR);
 	switch (intftype) {
 	case PIX0:
-		data |= 0x1 << PIX_VFE_RST_STB;
+		data = (0x1 << STROBED_RST_EN) +
+			(0x1 << PIX_VFE_RST_STB) +
+			(0x1 << PIX_CSID_RST_STB);
 		msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
-		usleep_range(11000, 12000);
-		data1 |= 0x1 << PIX_CSID_RST_STB;
-		msm_io_w(data1, ispif->base + ISPIF_RST_CMD_ADDR);
-		usleep_range(11000, 12000);
 		break;
 
 	case RDI0:
-		data |= 0x1 << RDI_VFE_RST_STB;
+		data = (0x1 << STROBED_RST_EN) +
+			(0x1 << RDI_VFE_RST_STB)  +
+			(0x1 << RDI_CSID_RST_STB);
 		msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
-		usleep_range(11000, 12000);
-		data1 |= 0x1 << RDI_CSID_RST_STB;
-		msm_io_w(data1, ispif->base + ISPIF_RST_CMD_ADDR);
-		usleep_range(11000, 12000);
 		break;
 
 	case RDI1:
-		data |= 0x1 << RDI_1_VFE_RST_STB;
+		data = (0x1 << STROBED_RST_EN) +
+			(0x1 << RDI_1_VFE_RST_STB) +
+			(0x1 << RDI_1_CSID_RST_STB);
 		msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
-		usleep_range(11000, 12000);
-		data1 |= 0x1 << RDI_1_CSID_RST_STB;
-		msm_io_w(data1, ispif->base + ISPIF_RST_CMD_ADDR);
-		usleep_range(11000, 12000);
 		break;
 
 	default:
+		rc = -EINVAL;
 		break;
 	}
+	if (rc >= 0)
+		rc = wait_for_completion_interruptible(
+				&ispif->reset_complete);
+
+	return rc;
 }
 
-static void msm_ispif_reset(void)
+static int msm_ispif_reset(void)
 {
-	msm_ispif_swreg_misc_reset();
-	msm_ispif_intf_reset(PIX0);
-	msm_ispif_intf_reset(RDI0);
+	uint32_t data = (0x1 << STROBED_RST_EN) +
+		(0x1 << SW_REG_RST_STB) +
+		(0x1 << MISC_LOGIC_RST_STB) +
+		(0x1 << PIX_VFE_RST_STB) +
+		(0x1 << PIX_CSID_RST_STB) +
+		(0x1 << RDI_VFE_RST_STB) +
+		(0x1 << RDI_CSID_RST_STB) +
+		(0x1 << RDI_1_VFE_RST_STB) +
+		(0x1 << RDI_1_CSID_RST_STB);
+	msm_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
+	return wait_for_completion_interruptible(&ispif->reset_complete);
 }
 
 static int msm_ispif_subdev_g_chip_ident(struct v4l2_subdev *sd,
@@ -279,7 +275,7 @@
 	CDBG("abort stream request\n");
 	mutex_lock(&ispif->mutex);
 	msm_ispif_intf_cmd(intf, intf_cmd_mask);
-	msm_ispif_intf_reset(intf);
+	rc = msm_ispif_intf_reset(intf);
 	global_intf_cmd_mask |= 0xFF<<(intf * 8);
 	mutex_unlock(&ispif->mutex);
 	return rc;
@@ -393,6 +389,8 @@
 	CDBG("ispif->irq: Irq_status0 = 0x%x\n",
 		out->ispifIrqStatus0);
 	if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
+		if (out->ispifIrqStatus0 & (0x1 << RESET_DONE_IRQ))
+			complete(&ispif->reset_complete);
 		if (out->ispifIrqStatus0 & (0x1 << PIX_INTF_0_OVERFLOW_IRQ))
 			pr_err("%s: pix intf 0 overflow.\n", __func__);
 		if (out->ispifIrqStatus0 & (0x1 << RAW_INTF_0_OVERFLOW_IRQ))
@@ -471,10 +469,11 @@
 		goto ispif_irq_fail;
 
 	global_intf_cmd_mask = 0xFFFFFFFF;
+	init_completion(&ispif->reset_complete);
 
-	msm_ispif_reset();
+	rc = msm_ispif_reset();
 	*sd = &(ispif->subdev);
-	return 0;
+	return rc;
 
 ispif_irq_fail:
 	iounmap(ispif->base);
diff --git a/drivers/media/video/msm/msm_ispif.h b/drivers/media/video/msm/msm_ispif.h
index 601e9ea..3b923ea 100644
--- a/drivers/media/video/msm/msm_ispif.h
+++ b/drivers/media/video/msm/msm_ispif.h
@@ -41,6 +41,7 @@
 	void __iomem *base;
 	struct mutex mutex;
 	uint8_t start_ack_pending;
+	struct completion reset_complete;
 };
 
 #define VIDIOC_MSM_ISPSF_CFG \
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index f684b4f..acd5214 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -183,17 +183,15 @@
 				VIDIOC_MSM_ISPSF_CFG, &ispif_params);
 			if (rc < 0)
 				return rc;
-
-			rc = v4l2_subdev_call(p_mctl->ispif_sdev, video,
-				s_stream, ISPIF_STREAM(PIX0,
-					ISPIF_ON_FRAME_BOUNDARY));
-			if (rc < 0)
-				return rc;
 		}
 		break;
 	case NOTIFY_ISPIF_STREAM:
 		/* call ISPIF stream on/off */
-		rc = 0;
+		rc = v4l2_subdev_call(p_mctl->ispif_sdev, video,
+				s_stream, (int)arg);
+		if (rc < 0)
+			return rc;
+
 		break;
 	case NOTIFY_ISP_MSG_EVT:
 	case NOTIFY_VFE_MSG_OUT:
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 9e558d2..9122d1a 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -373,12 +373,9 @@
 		vfe32_ctrl->vfebase + VFE_IRQ_CMD);
 
 	/* in either continuous or snapshot mode, stop command can be issued
-	 * at any time. stop ispif & camif immediately. */
-	v4l2_subdev_notify(vfe32_ctrl->subdev, NOTIFY_ISPIF_STREAM,
-			(void *)ISPIF_STREAM(PIX0, ISPIF_OFF_IMMEDIATELY));
+	 * at any time. stop camif immediately. */
 	msm_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY,
 		vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
-	wmb();
 
 	/* axi halt command. */
 	msm_io_w(AXI_HALT,
@@ -690,8 +687,6 @@
 	msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
 
-	v4l2_subdev_notify(vfe32_ctrl->subdev, NOTIFY_ISPIF_STREAM,
-			(void *)ISPIF_STREAM(PIX0, ISPIF_ON_FRAME_BOUNDARY));
 
 	atomic_set(&vfe32_ctrl->vstate, 1);
 }
@@ -2094,10 +2089,6 @@
 					vfe32_AXI_WM_CFG[vfe32_ctrl->
 							outpath.out1.ch1]);
 			}
-
-			v4l2_subdev_notify(vfe32_ctrl->subdev,
-				NOTIFY_ISPIF_STREAM, (void *)
-				ISPIF_STREAM(PIX0, ISPIF_OFF_FRAME_BOUNDARY));
 			msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
 				vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
 
@@ -2180,9 +2171,6 @@
 		if (vfe32_ctrl->vfe_capture_count == 0) {
 			/* Ensure the write order while writing
 			 to the command register using the barrier */
-			v4l2_subdev_notify(vfe32_ctrl->subdev,
-				NOTIFY_ISPIF_STREAM, (void *)
-				ISPIF_STREAM(PIX0, ISPIF_OFF_FRAME_BOUNDARY));
 			msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
 				vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
 		}
@@ -2833,10 +2821,6 @@
 				if ((vfe32_ctrl->outpath.out0.capture_cnt == 0)
 						&& (vfe32_ctrl->outpath.out1.
 						capture_cnt == 0)) {
-					v4l2_subdev_notify(vfe32_ctrl->subdev,
-						NOTIFY_ISPIF_STREAM, (void *)
-						ISPIF_STREAM(PIX0,
-						ISPIF_OFF_IMMEDIATELY));
 					msm_io_w_mb(
 						CAMIF_COMMAND_STOP_IMMEDIATELY,
 						vfe32_ctrl->vfebase +
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 0797982..2e0df74 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -11,6 +11,8 @@
  */
 
 #include "msm_sensor.h"
+#include "msm.h"
+#include "msm_ispif.h"
 
 /*=============================================================*/
 
@@ -220,6 +222,10 @@
 			int update_type, int res)
 {
 	int32_t rc = 0;
+
+	v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+		NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM(
+		PIX0, ISPIF_OFF_IMMEDIATELY));
 	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
 	msleep(30);
 	if (update_type == MSM_SENSOR_REG_INIT) {
@@ -240,6 +246,10 @@
 			mb();
 			msleep(20);
 		}
+
+		v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+			NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM(
+			PIX0, ISPIF_ON_FRAME_BOUNDARY));
 		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
 		msleep(30);
 	}