From 366c6fbe659c6e134c3659cebead64be6f8b681c Mon Sep 17 00:00:00 2001 From: Andy Sun Date: Thu, 29 Mar 2018 16:17:05 +0800 Subject: [PATCH] ais: report csid error event to user Enable CSID error interrupts, and sending the error status to user mode components as v4l2 event. Change-Id: I62a08a88ebc39e1192136ba1c9179f709f5439f5 Signed-off-by: Andy Sun --- .../sensor/csid/include/msm_csid_3_5_hwreg.h | 9 +- .../platform/msm/ais/sensor/csid/msm_csid.c | 179 ++++++++++++++++-- .../msm/ais/sensor/msm_sensor_driver.c | 12 +- include/uapi/media/ais/msm_ais_sensor.h | 22 +++ 4 files changed, 198 insertions(+), 24 deletions(-) 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 #include #include +#include +#include +#include +#include +#include +#include #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; - return msm_csid_subdev_ioctl32(sd, cmd, arg); + 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; + + 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<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;