Merge "msm: mpq8064: Dummy read to prevent false interrupt from triggering" into msm-3.4
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 98e2fd9..01e1201 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -1113,7 +1113,6 @@
 {
 	struct vcap_client_data *c_data = to_client_data(file->private_data);
 	struct vcap_dev *dev = c_data->dev;
-	unsigned long flags;
 	int rc;
 	unsigned long rate;
 	long rate_rc;
@@ -1126,14 +1125,14 @@
 
 	switch (c_data->op_mode) {
 	case VC_VCAP_OP:
-		spin_lock_irqsave(&dev->dev_slock, flags);
+		mutex_lock(&dev->dev_mutex);
 		if (dev->vc_resource) {
 			pr_err("VCAP Err: %s: VC resource taken", __func__);
-			spin_unlock_irqrestore(&dev->dev_slock, flags);
+			mutex_unlock(&dev->dev_mutex);
 			return -EBUSY;
 		}
 		dev->vc_resource = 1;
-		spin_unlock_irqrestore(&dev->dev_slock, flags);
+		mutex_unlock(&dev->dev_mutex);
 
 		c_data->dev->vc_client = c_data;
 
@@ -1179,14 +1178,14 @@
 			goto free_res;
 		break;
 	case VP_VCAP_OP:
-		spin_lock_irqsave(&dev->dev_slock, flags);
+		mutex_lock(&dev->dev_mutex);
 		if (dev->vp_resource) {
 			pr_err("VCAP Err: %s: VP resource taken", __func__);
-			spin_unlock_irqrestore(&dev->dev_slock, flags);
+			mutex_unlock(&dev->dev_mutex);
 			return -EBUSY;
 		}
 		dev->vp_resource = 1;
-		spin_unlock_irqrestore(&dev->dev_slock, flags);
+		mutex_unlock(&dev->dev_mutex);
 		c_data->dev->vp_client = c_data;
 
 		rate = 160000000;
@@ -1240,16 +1239,16 @@
 			goto s_on_deinit_nr_buf;
 		break;
 	case VC_AND_VP_VCAP_OP:
-		spin_lock_irqsave(&dev->dev_slock, flags);
+		mutex_lock(&dev->dev_mutex);
 		if (dev->vc_resource || dev->vp_resource) {
 			pr_err("VCAP Err: %s: VC/VP resource taken",
 				__func__);
-			spin_unlock_irqrestore(&dev->dev_slock, flags);
+			mutex_unlock(&dev->dev_mutex);
 			return -EBUSY;
 		}
 		dev->vc_resource = 1;
 		dev->vp_resource = 1;
-		spin_unlock_irqrestore(&dev->dev_slock, flags);
+		mutex_unlock(&dev->dev_mutex);
 		c_data->dev->vc_client = c_data;
 		c_data->dev->vp_client = c_data;
 
@@ -1347,7 +1346,7 @@
 s_on_deinit_m_buf:
 	deinit_motion_buf(c_data);
 free_res:
-	spin_lock_irqsave(&dev->dev_slock, flags);
+	mutex_lock(&dev->dev_mutex);
 	if (c_data->op_mode == VC_VCAP_OP) {
 		dev->vc_resource = 0;
 		c_data->dev->vc_client = NULL;
@@ -1360,7 +1359,7 @@
 		dev->vc_resource = 0;
 		dev->vp_resource = 0;
 	}
-	spin_unlock_irqrestore(&dev->dev_slock, flags);
+	mutex_unlock(&dev->dev_mutex);
 	return rc;
 }
 
@@ -1381,7 +1380,6 @@
 int streamoff_work(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev = c_data->dev;
-	unsigned long flags;
 	int rc;
 	switch (c_data->op_mode) {
 	case VC_VCAP_OP:
@@ -1390,14 +1388,14 @@
 				__func__);
 			return -EBUSY;
 		}
-		spin_lock_irqsave(&dev->dev_slock, flags);
+		mutex_lock(&dev->dev_mutex);
 		if (!dev->vc_resource) {
 			pr_err("VCAP Err: %s: VC res not acquired", __func__);
-			spin_unlock_irqrestore(&dev->dev_slock, flags);
+			mutex_unlock(&dev->dev_mutex);
 			return -EBUSY;
 		}
 		dev->vc_resource = 0;
-		spin_unlock_irqrestore(&dev->dev_slock, flags);
+		mutex_unlock(&dev->dev_mutex);
 		rc = vb2_streamoff(&c_data->vc_vidq,
 				V4L2_BUF_TYPE_VIDEO_CAPTURE);
 		if (rc >= 0) {
@@ -1406,19 +1404,24 @@
 		}
 		return rc;
 	case VP_VCAP_OP:
+		if (!dev->vp_dummy_complete) {
+			pr_err("VCAP Err: %s: VP dummy read not complete",
+				__func__);
+			return -EINVAL;
+		}
 		if (c_data != dev->vp_client) {
 			pr_err("VCAP Err: %s: VP held by other client",
 				__func__);
 			return -EBUSY;
 		}
-		spin_lock_irqsave(&dev->dev_slock, flags);
+		mutex_lock(&dev->dev_mutex);
 		if (!dev->vp_resource) {
 			pr_err("VCAP Err: %s: VP res not acquired", __func__);
-			spin_unlock_irqrestore(&dev->dev_slock, flags);
+			mutex_unlock(&dev->dev_mutex);
 			return -EBUSY;
 		}
 		dev->vp_resource = 0;
-		spin_unlock_irqrestore(&dev->dev_slock, flags);
+		mutex_unlock(&dev->dev_mutex);
 		rc = streamoff_validate_q(&c_data->vp_in_vidq);
 		if (rc < 0)
 			return rc;
@@ -1444,21 +1447,26 @@
 		atomic_set(&c_data->dev->vp_enabled, 0);
 		return rc;
 	case VC_AND_VP_VCAP_OP:
+		if (!dev->vp_dummy_complete) {
+			pr_err("VCAP Err: %s: VP dummy read not complete",
+				__func__);
+			return -EINVAL;
+		}
 		if (c_data != dev->vp_client || c_data != dev->vc_client) {
 			pr_err("VCAP Err: %s: VC/VP held by other client",
 				__func__);
 			return -EBUSY;
 		}
-		spin_lock_irqsave(&dev->dev_slock, flags);
+		mutex_lock(&dev->dev_mutex);
 		if (!(dev->vc_resource || dev->vp_resource)) {
 			pr_err("VCAP Err: %s: VC or VP res not acquired",
 				__func__);
-			spin_unlock_irqrestore(&dev->dev_slock, flags);
+			mutex_unlock(&dev->dev_mutex);
 			return -EBUSY;
 		}
 		dev->vc_resource = 0;
 		dev->vp_resource = 0;
-		spin_unlock_irqrestore(&dev->dev_slock, flags);
+		mutex_unlock(&dev->dev_mutex);
 		rc = streamoff_validate_q(&c_data->vc_vidq);
 		if (rc < 0)
 			return rc;
@@ -1562,10 +1570,11 @@
 	struct vcap_dev *dev = video_drvdata(file);
 	struct vcap_client_data *c_data;
 	struct vb2_queue *q;
-	unsigned long flags;
 	int ret;
-	c_data = kzalloc(sizeof(*c_data), GFP_KERNEL);
 	if (!dev)
+		return -EINVAL;
+	c_data = kzalloc(sizeof(*c_data), GFP_KERNEL);
+	if (!c_data)
 		return -ENOMEM;
 
 	c_data->dev = dev;
@@ -1619,22 +1628,33 @@
 	v4l2_fh_init(&c_data->vfh, dev->vfd);
 	v4l2_fh_add(&c_data->vfh);
 
-	spin_lock_irqsave(&dev->dev_slock, flags);
+	mutex_lock(&dev->dev_mutex);
 	atomic_inc(&dev->open_clients);
 	ret = atomic_read(&dev->open_clients);
-	spin_unlock_irqrestore(&dev->dev_slock, flags);
 	if (ret == 1) {
 		ret = vcap_enable(dev, dev->ddev, 54860000);
 		if (ret < 0) {
 			pr_err("Err: %s: Power on vcap failed", __func__);
+			mutex_unlock(&dev->dev_mutex);
+			goto vcap_power_failed;
+		}
+
+		ret = vp_dummy_event(c_data);
+		if (ret < 0) {
+			pr_err("Err: %s: Dummy Event failed", __func__);
+			mutex_unlock(&dev->dev_mutex);
+			vcap_disable(dev);
 			goto vcap_power_failed;
 		}
 	}
+	mutex_unlock(&dev->dev_mutex);
 
 	file->private_data = &c_data->vfh;
 	return 0;
 
 vcap_power_failed:
+	atomic_dec(&dev->open_clients);
+
 	v4l2_fh_del(&c_data->vfh);
 	v4l2_fh_exit(&c_data->vfh);
 	vb2_queue_release(&c_data->vp_out_vidq);
@@ -1651,7 +1671,6 @@
 {
 	struct vcap_dev *dev = video_drvdata(file);
 	struct vcap_client_data *c_data = to_client_data(file->private_data);
-	unsigned long flags;
 	int ret;
 
 	if (c_data == NULL)
@@ -1660,12 +1679,14 @@
 	if (c_data->streaming)
 		streamoff_work(c_data);
 
-	spin_lock_irqsave(&dev->dev_slock, flags);
+	mutex_lock(&dev->dev_mutex);
 	atomic_dec(&dev->open_clients);
 	ret = atomic_read(&dev->open_clients);
-	spin_unlock_irqrestore(&dev->dev_slock, flags);
-	if (ret == 0)
+	mutex_unlock(&dev->dev_mutex);
+	if (ret == 0) {
 		vcap_disable(dev);
+		dev->vp_dummy_complete = false;
+	}
 	v4l2_fh_del(&c_data->vfh);
 	v4l2_fh_exit(&c_data->vfh);
 	vb2_queue_release(&c_data->vp_out_vidq);
@@ -1908,7 +1929,8 @@
 	atomic_set(&dev->vp_enabled, 0);
 	atomic_set(&dev->open_clients, 0);
 	dev->ddev = &pdev->dev;
-	spin_lock_init(&dev->dev_slock);
+	mutex_init(&dev->dev_mutex);
+	init_waitqueue_head(&dev->vp_dummy_waitq);
 	vcap_disable(dev);
 
 	dprintk(1, "Exit probe succesfully");
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index be1b4ff..b73185d 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -261,6 +261,12 @@
 	int rc;
 
 	irq = readl_relaxed(VCAP_VP_INT_STATUS);
+	if (dev->vp_dummy_event == true) {
+		writel_relaxed(irq, VCAP_VP_INT_CLEAR);
+		dev->vp_dummy_complete = true;
+		wake_up(&dev->vp_dummy_waitq);
+		return IRQ_HANDLED;
+	}
 
 	if (irq & 0x02000000) {
 		v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
@@ -434,6 +440,8 @@
 		return -ENOEXEC;
 	}
 	buf = &c_data->vid_vp_action.bufNR;
+	if (!buf)
+		return -ENOMEM;
 
 	frame_size = c_data->vp_in_fmt.width * c_data->vp_in_fmt.height;
 	if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
@@ -442,7 +450,7 @@
 		tot_size = frame_size / 2 * 3;
 
 	buf->vaddr = kzalloc(tot_size, GFP_KERNEL);
-	if (!buf)
+	if (!buf->vaddr)
 		return -ENOMEM;
 
 	buf->paddr = virt_to_phys(buf->vaddr);
@@ -478,6 +486,74 @@
 	return;
 }
 
+int vp_dummy_event(struct vcap_client_data *c_data)
+{
+	struct vcap_dev *dev = c_data->dev;
+	unsigned int width, height;
+	unsigned long paddr;
+	void *temp;
+	uint32_t reg;
+	int rc = 0;
+
+	dprintk(2, "%s: Start VP dummy event\n", __func__);
+	temp = kzalloc(0x1200, GFP_KERNEL);
+	if (!temp) {
+		pr_err("%s: Failed to alloc mem", __func__);
+		return -ENOMEM;
+	}
+	paddr = virt_to_phys(temp);
+
+	width = c_data->vp_out_fmt.width;
+	height = c_data->vp_out_fmt.height;
+
+	c_data->vp_out_fmt.width = 0x3F;
+	c_data->vp_out_fmt.height = 0x16;
+
+	config_vp_format(c_data);
+	writel_relaxed(paddr, VCAP_VP_T1_Y_BASE_ADDR);
+	writel_relaxed(paddr + 0x2C0, VCAP_VP_T1_C_BASE_ADDR);
+	writel_relaxed(paddr + 0x440, VCAP_VP_T2_Y_BASE_ADDR);
+	writel_relaxed(paddr + 0x700, VCAP_VP_T2_C_BASE_ADDR);
+	writel_relaxed(paddr + 0x880, VCAP_VP_OUT_Y_BASE_ADDR);
+	writel_relaxed(paddr + 0xB40, VCAP_VP_OUT_C_BASE_ADDR);
+	writel_iowmb(paddr + 0x1100, VCAP_VP_MOTION_EST_ADDR);
+	writel_relaxed(4 << 20 | 0x2 << 4, VCAP_VP_IN_CONFIG);
+	writel_relaxed(4 << 20 | 0x1 << 4, VCAP_VP_OUT_CONFIG);
+
+	dev->vp_dummy_event = true;
+
+	writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
+	writel_iowmb(0x00000000, VCAP_VP_CTRL);
+	writel_iowmb(0x00030000, VCAP_VP_CTRL);
+
+	enable_irq(dev->vpirq->start);
+	rc = wait_event_interruptible_timeout(dev->vp_dummy_waitq,
+		dev->vp_dummy_complete, msecs_to_jiffies(50));
+	if (!rc && !dev->vp_dummy_complete) {
+		pr_err("%s: VP dummy event timeout", __func__);
+		rc = -ETIME;
+		writel_iowmb(0x00000000, VCAP_VP_CTRL);
+
+		writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
+		writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+		dev->vp_dummy_complete = false;
+	}
+
+	writel_relaxed(0x00000000, VCAP_VP_INTERRUPT_ENABLE);
+	disable_irq(dev->vpirq->start);
+	dev->vp_dummy_event = false;
+
+	reg = readl_relaxed(VCAP_OFFSET(0x0D94));
+	writel_relaxed(reg, VCAP_OFFSET(0x0D9C));
+
+	c_data->vp_out_fmt.width = width;
+	c_data->vp_out_fmt.height = height;
+	kfree(temp);
+
+	dprintk(2, "%s: Exit VP dummy event\n", __func__);
+	return rc;
+}
+
 int kickoff_vp(struct vcap_client_data *c_data)
 {
 	struct vcap_dev *dev;
diff --git a/drivers/media/video/vcap_vp.h b/drivers/media/video/vcap_vp.h
index 5415e54..5c32903 100644
--- a/drivers/media/video/vcap_vp.h
+++ b/drivers/media/video/vcap_vp.h
@@ -100,5 +100,6 @@
 void deinit_nr_buf(struct vcap_client_data *c_data);
 int kickoff_vp(struct vcap_client_data *c_data);
 int continue_vp(struct vcap_client_data *c_data);
+int vp_dummy_event(struct vcap_client_data *c_data);
 
 #endif
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index f7d1e6b..9719aa6 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -158,10 +158,13 @@
 	atomic_t			    vc_enabled;
 	atomic_t			    vp_enabled;
 
-	spinlock_t				dev_slock;
+	struct mutex			dev_mutex;
 	atomic_t			    open_clients;
 	bool					vc_resource;
 	bool					vp_resource;
+	bool					vp_dummy_event;
+	bool					vp_dummy_complete;
+	wait_queue_head_t		vp_dummy_waitq;
 
 	struct workqueue_struct	*vcap_wq;
 	struct vp_work_t		vp_work;