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 <bins@codeaurora.org>
This commit is contained in:
Andy Sun 2018-03-29 16:17:05 +08:00
parent 9896df099c
commit 366c6fbe65
4 changed files with 198 additions and 24 deletions

View file

@ -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,

View file

@ -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;
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;
}
static long msm_csid_subdev_fops_ioctl32(struct file *file, unsigned int cmd,
return rc;
}
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);

View file

@ -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);
}
/*

View file

@ -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;