Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 366c6fbe authored by Andy Sun's avatar Andy Sun
Browse files

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: default avatarAndy Sun <bins@codeaurora.org>
parent 9896df09
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
/* 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,
+165 −14
Original line number Diff line number Diff line
/* 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);
+4 −8
Original line number Diff line number Diff line
/* 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);
	}

	/*
+22 −0
Original line number Diff line number Diff line
@@ -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;