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;