summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/msm/adreno_a5xx.c6
-rw-r--r--drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_hwreg.h9
-rw-r--r--drivers/media/platform/msm/ais/sensor/csid/msm_csid.c179
-rw-r--r--drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c12
-rw-r--r--include/uapi/media/ais/msm_ais_sensor.h22
5 files changed, 201 insertions, 27 deletions
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 119741f7ce47..4daf1fad6ee1 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -1381,13 +1381,13 @@ static int _execute_reg_sequence(struct adreno_device *adreno_dev,
/* todo double check the reg writes */
while ((cur - opcode) < length) {
- if (cur[0] == 1 && ((cur + 4) - opcode) <= length) {
+ if (cur[0] == 1 && (length - (cur - opcode) >= 4)) {
/* Write a 32 bit value to a 64 bit reg */
reg = cur[2];
reg = (reg << 32) | cur[1];
kgsl_regwrite(KGSL_DEVICE(adreno_dev), reg, cur[3]);
cur += 4;
- } else if (cur[0] == 2 && ((cur + 5) - opcode) <= length) {
+ } else if (cur[0] == 2 && (length - (cur - opcode) >= 5)) {
/* Write a 64 bit value to a 64 bit reg */
reg = cur[2];
reg = (reg << 32) | cur[1];
@@ -1395,7 +1395,7 @@ static int _execute_reg_sequence(struct adreno_device *adreno_dev,
val = (val << 32) | cur[3];
kgsl_regwrite(KGSL_DEVICE(adreno_dev), reg, val);
cur += 5;
- } else if (cur[0] == 3 && ((cur + 2) - opcode) <= length) {
+ } else if (cur[0] == 3 && (length - (cur - opcode) >= 2)) {
/* Delay for X usec */
udelay(cur[1]);
cur += 2;
diff --git a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_hwreg.h b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_hwreg.h
index 392d902d3e0c..0486c8aa96d0 100644
--- a/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_hwreg.h
+++ b/drivers/media/platform/msm/ais/sensor/csid/include/msm_csid_3_5_hwreg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -56,7 +56,12 @@ static struct csid_reg_parms_t csid_v3_5 = {
0xC,
0x84,
0xA4,
- 0x7f010800,
+ /*
+ * Default IRQ enabled:
+ * FIFO overflow, Unbounded frame, Stream underflow,
+ * Error ECC, Error CRC, Reset done
+ */
+ 0x73000800,
20,
17,
16,
diff --git a/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c b/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c
index 2b3eefa65606..6d26dff7525d 100644
--- a/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/ais/sensor/csid/msm_csid.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -14,6 +14,12 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/irqreturn.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
#include "msm_csid.h"
#include "msm_sd.h"
#include "msm_camera_io_util.h"
@@ -51,12 +57,13 @@
#define CSID_VERSION_V40 0x40000000
#define MSM_CSID_DRV_NAME "msm_csid"
-#define DBG_CSID 0
+#define DBG_CSID 1
#define SHORT_PKT_CAPTURE 0
#define SHORT_PKT_OFFSET 0x200
#define ENABLE_3P_BIT 1
#define SOF_DEBUG_ENABLE 1
#define SOF_DEBUG_DISABLE 0
+#define MAX_CSID_V4l2_EVENTS 100
#define TRUE 1
#define FALSE 0
@@ -156,6 +163,25 @@ static int msm_csid_stop(struct csid_device *csid_dev, uint32_t cid_mask)
return 0;
}
+static int msm_csid_send_event(struct csid_device *csid_dev,
+ uint32_t event_type, struct msm_csid_event_data *event_data)
+{
+ struct v4l2_event csid_event;
+ struct msm_csid_event_data *d_event_data;
+
+ memset(&csid_event, 0, sizeof(struct v4l2_event));
+ csid_event.id = 0;
+ csid_event.type = event_type;
+
+ d_event_data =
+ (struct msm_csid_event_data *)(&csid_event.u.data[0]);
+ d_event_data->csid_id = event_data->csid_id;
+ d_event_data->error_status = event_data->error_status;
+
+ v4l2_event_queue(csid_dev->msm_sd.sd.devnode, &csid_event);
+ return 0;
+}
+
#if (DBG_CSID)
static void msm_csid_set_debug_reg(struct csid_device *csid_dev,
struct msm_camera_csid_params *csid_params)
@@ -490,8 +516,9 @@ static irqreturn_t msm_csid_irq(int irq_num, void *data)
#else
static irqreturn_t msm_csid_irq(int irq_num, void *data)
{
- uint32_t irq;
+ uint32_t irq, error_irq, rst_done_irq_mask;
struct csid_device *csid_dev = data;
+ struct msm_csid_event_data csid_event;
if (!csid_dev) {
pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__);
@@ -509,11 +536,26 @@ static irqreturn_t msm_csid_irq(int irq_num, void *data)
irq = msm_camera_io_r(csid_dev->base +
csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr);
+ irq &= msm_camera_io_r(csid_dev->base +
+ csid_dev->ctrl_reg->csid_reg.csid_irq_mask_addr);
pr_err_ratelimited("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
__func__, csid_dev->pdev->id, irq);
- if (irq & (0x1 <<
- csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift))
+ error_irq = irq;
+ rst_done_irq_mask =
+ 0x1 << csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift;
+
+ if (irq & rst_done_irq_mask) {
complete(&csid_dev->reset_complete);
+ error_irq &= ~rst_done_irq_mask;
+ }
+
+ if (error_irq) {
+ csid_event.csid_id = csid_dev->pdev->id;
+ csid_event.error_status = error_irq;
+ msm_csid_send_event(csid_dev, CSID_EVENT_SIGNAL_ERROR,
+ &csid_event);
+ }
+
msm_camera_io_w(irq, csid_dev->base +
csid_dev->ctrl_reg->csid_reg.csid_irq_clear_cmd_addr);
return IRQ_HANDLED;
@@ -890,7 +932,6 @@ static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd,
return rc;
}
-
#ifdef CONFIG_COMPAT
static int32_t msm_csid_cmd32(struct csid_device *csid_dev, void *arg)
{
@@ -1061,27 +1102,135 @@ static long msm_csid_subdev_ioctl32(struct v4l2_subdev *sd,
mutex_unlock(&csid_dev->mutex);
return rc;
}
+#endif
-static long msm_csid_subdev_do_ioctl32(
+static long msm_csid_subdev_do_ioctl(
struct file *file, unsigned int cmd, void *arg)
{
+ int rc = -ENOIOCTLCMD;
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_fh *vfh = file->private_data;
+
+ switch (cmd) {
+ case VIDIOC_DQEVENT:
+ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+ return -ENOIOCTLCMD;
+ return v4l2_event_dequeue(vfh, arg,
+ file->f_flags & O_NONBLOCK);
+ case VIDIOC_SUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+
+ case VIDIOC_MSM_CSID_IO_CFG32:
+#ifdef CONFIG_COMPAT
+ rc = msm_csid_subdev_ioctl32(sd, cmd, arg);
+#endif
+ break;
- return msm_csid_subdev_ioctl32(sd, cmd, arg);
+ default:
+ rc = msm_csid_subdev_ioctl(sd, cmd, arg);
+ break;
+ }
+
+ return rc;
}
-static long msm_csid_subdev_fops_ioctl32(struct file *file, unsigned int cmd,
+static long msm_csid_subdev_fops_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- return video_usercopy(file, cmd, arg, msm_csid_subdev_do_ioctl32);
+ return video_usercopy(file, cmd, arg, msm_csid_subdev_do_ioctl);
}
-#endif
+
+static u32 msm_csid_evt_mask_to_csid_event(u32 evt_mask)
+{
+ u32 evt_id = CSID_EVENT_SUBS_MASK_NONE;
+
+ switch (evt_mask) {
+ case CSID_EVENT_MASK_INDEX_SIGNAL_ERROR:
+ evt_id = CSID_EVENT_SIGNAL_ERROR;
+ break;
+ default:
+ evt_id = CSID_EVENT_SUBS_MASK_NONE;
+ break;
+ }
+
+ return evt_id;
+}
+
+static int msm_csid_subscribe_event_mask(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub, int evt_mask_index,
+ u32 evt_id, bool subscribe_flag)
+{
+ int rc = 0;
+
+ sub->type = evt_id;
+
+ if (subscribe_flag)
+ rc = v4l2_event_subscribe(fh, sub,
+ MAX_CSID_V4l2_EVENTS, NULL);
+ else
+ rc = v4l2_event_unsubscribe(fh, sub);
+ if (rc != 0) {
+ pr_err("%s: Subs event_type =0x%x failed\n",
+ __func__, sub->type);
+ return rc;
+ }
+ return rc;
+}
+
+static int msm_csid_process_event_subscription(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub, bool subscribe_flag)
+{
+ int rc = 0, evt_mask_index = 0;
+ u32 evt_mask = sub->type;
+ u32 evt_id = 0;
+
+ if (evt_mask == CSID_EVENT_SUBS_MASK_NONE) {
+ pr_err("%s: Subs event_type is None=0x%x\n",
+ __func__, evt_mask);
+ return 0;
+ }
+
+ evt_mask_index = CSID_EVENT_MASK_INDEX_SIGNAL_ERROR;
+ if (evt_mask & (1<<evt_mask_index)) {
+ evt_id =
+ msm_csid_evt_mask_to_csid_event(
+ evt_mask_index);
+ rc = msm_csid_subscribe_event_mask(fh, sub,
+ evt_mask_index, evt_id, subscribe_flag);
+ if (rc != 0) {
+ pr_err("%s: Subs event index:%d failed\n",
+ __func__, evt_mask_index);
+ return rc;
+ }
+ }
+
+ return rc;
+}
+static int msm_csid_subscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return msm_csid_process_event_subscription(fh, sub, true);
+}
+
+static int msm_csid_unsubscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return msm_csid_process_event_subscription(fh, sub, false);
+}
+
static const struct v4l2_subdev_internal_ops msm_csid_internal_ops;
static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = {
.ioctl = &msm_csid_subdev_ioctl,
.interrupt_service_routine = msm_csid_irq_routine,
+ .subscribe_event = msm_csid_subscribe_event,
+ .unsubscribe_event = msm_csid_unsubscribe_event,
};
static const struct v4l2_subdev_ops msm_csid_subdev_ops = {
@@ -1175,6 +1324,7 @@ static int csid_probe(struct platform_device *pdev)
new_csid_dev->pdev = pdev;
new_csid_dev->msm_sd.sd.internal_ops = &msm_csid_internal_ops;
new_csid_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ new_csid_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
snprintf(new_csid_dev->msm_sd.sd.name,
ARRAY_SIZE(new_csid_dev->msm_sd.sd.name), "msm_csid");
media_entity_init(&new_csid_dev->msm_sd.sd.entity, 0, NULL, 0);
@@ -1183,11 +1333,12 @@ static int csid_probe(struct platform_device *pdev)
new_csid_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x5;
msm_sd_register(&new_csid_dev->msm_sd);
-#ifdef CONFIG_COMPAT
msm_cam_copy_v4l2_subdev_fops(&msm_csid_v4l2_subdev_fops);
- msm_csid_v4l2_subdev_fops.compat_ioctl32 = msm_csid_subdev_fops_ioctl32;
- new_csid_dev->msm_sd.sd.devnode->fops = &msm_csid_v4l2_subdev_fops;
+ msm_csid_v4l2_subdev_fops.unlocked_ioctl = msm_csid_subdev_fops_ioctl;
+#ifdef CONFIG_COMPAT
+ msm_csid_v4l2_subdev_fops.compat_ioctl32 = msm_csid_subdev_fops_ioctl;
#endif
+ new_csid_dev->msm_sd.sd.devnode->fops = &msm_csid_v4l2_subdev_fops;
rc = msm_camera_register_irq(pdev, new_csid_dev->irq,
msm_csid_irq, IRQF_TRIGGER_RISING, "csid", new_csid_dev);
diff --git a/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c
index 5e34016d199c..03ae276d1a6f 100644
--- a/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c
+++ b/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -639,7 +639,7 @@ static irqreturn_t bridge_irq(int irq, void *dev)
{
struct msm_sensor_ctrl_t *s_ctrl = dev;
- pr_err("msm_sensor_driver: received bridge interrupt:0x%x",
+ pr_debug("msm_sensor_driver: received bridge interrupt:0x%x\n",
s_ctrl->sensordata->slave_info->sensor_slave_addr);
schedule_delayed_work(&s_ctrl->irq_delayed_work,
msecs_to_jiffies(0));
@@ -682,7 +682,7 @@ static void bridge_irq_delay_work(struct work_struct *work)
&sensor_event);
mutex_unlock(s_ctrl->msm_sensor_mutex);
exit_queue:
- pr_err("Work IRQ exit");
+ pr_debug("Work IRQ exit\n");
}
/* static function definition */
@@ -947,8 +947,6 @@ CSID_TG:
goto free_camera_info;
}
- pr_err("%s probe succeeded", slave_info->sensor_name);
-
/*
* Update the subdevice id of flash-src based on availability in kernel.
*/
@@ -1009,8 +1007,6 @@ CSID_TG:
pr_err("%s: Failed gpio_direction irq %d",
__func__, rc);
goto cancel_work;
- } else {
- pr_err("sensor probe IRQ direction succeeded");
}
}
@@ -1035,7 +1031,7 @@ CSID_TG:
}
/* Keep irq enabled */
- pr_err("msm_sensor_driver.c irq number = %d", s_ctrl->irq);
+ pr_debug("msm_sensor_driver.c irq number = %d\n", s_ctrl->irq);
}
/*
diff --git a/include/uapi/media/ais/msm_ais_sensor.h b/include/uapi/media/ais/msm_ais_sensor.h
index 59c20c8e84ae..ca9bcf96bcb0 100644
--- a/include/uapi/media/ais/msm_ais_sensor.h
+++ b/include/uapi/media/ais/msm_ais_sensor.h
@@ -199,6 +199,28 @@ enum msm_sensor_event_idx {
#define SENSOR_EVENT_BASE (V4L2_EVENT_PRIVATE_START)
#define SENSOR_EVENT_SIGNAL_STATUS (SENSOR_EVENT_BASE + SENSOR_SIGNAL_STATUS)
+struct msm_csid_event_data {
+ uint8_t csid_id;
+ uint32_t error_status;
+};
+
+enum msm_csid_event_mask_index {
+ CSID_EVENT_MASK_INDEX_SIGNAL_ERROR = 2,
+};
+
+#define CSID_EVENT_SUBS_MASK_NONE 0
+
+#define CSID_EVENT_SUBS_MASK_SIGNAL_ERROR \
+ (1 << CSID_EVENT_MASK_INDEX_SIGNAL_ERROR)
+
+enum msm_csid_event_idx {
+ CSID_SIGNAL_ERROR = 2,
+ CSID_EVENT_MAX = 15
+};
+
+#define CSID_EVENT_BASE (V4L2_EVENT_PRIVATE_START + SENSOR_EVENT_MAX)
+#define CSID_EVENT_SIGNAL_ERROR (CSID_EVENT_BASE + CSID_SIGNAL_ERROR)
+
struct msm_camera_i2c_array_write_config {
struct msm_camera_i2c_reg_setting conf_array;
uint16_t slave_addr;