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

Commit 226e0804 authored by rohithr's avatar rohithr Committed by Andy Sun
Browse files

msm: camera: Register and listen to bridge-chip interrupts



Changes that help facilitate sending the FPD-III to CSI
bridge chip's input signal status to the user-mode
components.

Change-Id: I5e39c75b61f05edc8a1dc77677b9cad85fc563eb
Signed-off-by: default avatarAndy Sun <bins@codeaurora.org>
parent 67c751e0
Loading
Loading
Loading
Loading
+122 −2
Original line number Diff line number Diff line
@@ -10,6 +10,12 @@
 * GNU General Public License for more details.
 */

#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_sensor.h"
#include "msm_sd.h"
#include "msm_cci.h"
@@ -21,6 +27,7 @@
#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)

#define MAX_SENSOR_V4l2_EVENTS 100
static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl;
static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl;

@@ -404,12 +411,26 @@ static long msm_sensor_subdev_do_ioctl(
{
	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_MSM_SENSOR_CFG32:
		cmd = VIDIOC_MSM_SENSOR_CFG;
	case VIDIOC_DQEVENT: {
		if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
			return -ENOIOCTLCMD;
		return v4l2_event_dequeue(vfh, arg,
			file->f_flags & O_NONBLOCK);
	}
	break;
	case VIDIOC_SUBSCRIBE_EVENT:
		pr_debug("msm_sensor_subdev_do_ioctl: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);
	default:
		return msm_sensor_subdev_ioctl(sd, cmd, arg);
			pr_debug("msm_sensor.c msm_sensor_subdev_do_ioctl");
		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
	}
}

@@ -1467,8 +1488,107 @@ static int msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd,
	return 0;
}

static u32 msm_sensor_evt_mask_to_sensor_event(u32 evt_mask)
{
	u32 evt_id = SENSOR_EVENT_SUBS_MASK_NONE;

	switch (evt_mask) {
	case SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS:
		evt_id = SENSOR_EVENT_SIGNAL_STATUS;
		break;
	default:
		evt_id = SENSOR_EVENT_SUBS_MASK_NONE;
		break;
	}

	return evt_id;
}

static int msm_sensor_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_SENSOR_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_sensor_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 (SENSOR_EVENT_SUBS_MASK_NONE == evt_mask) {
		pr_err("%s: Subs event_type is None=0x%x\n",
			__func__, evt_mask);
		return 0;
	}

	evt_mask_index = SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS;
	if (evt_mask & (1<<evt_mask_index)) {
		evt_id =
			msm_sensor_evt_mask_to_sensor_event(
				evt_mask_index);
		rc = msm_sensor_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;
}

int msm_sensor_send_event(struct msm_sensor_ctrl_t *s_ctrl,
	uint32_t event_type,
	struct msm_sensor_event_data *event_data)
{
	struct v4l2_event sensor_event;

	memset(&sensor_event, 0, sizeof(struct v4l2_event));
	sensor_event.id = 0;
	sensor_event.type = event_type;

	memcpy(&sensor_event.u.data[0], event_data,
		sizeof(struct msm_sensor_event_data));
	v4l2_event_queue(s_ctrl->msm_sd.sd.devnode, &sensor_event);
	return 0;
}

static int msm_sensor_subscribe_event(struct v4l2_subdev *sd,
	struct v4l2_fh *fh,
	struct v4l2_event_subscription *sub)
{
	return msm_sensor_process_event_subscription(fh, sub, true);
}

static int msm_sensor_unsubscribe_event(struct v4l2_subdev *sd,
	struct v4l2_fh *fh,
	struct v4l2_event_subscription *sub)
{
	return msm_sensor_process_event_subscription(fh, sub, false);
}

static struct v4l2_subdev_core_ops msm_sensor_subdev_core_ops = {
	.ioctl = msm_sensor_subdev_ioctl,
	.subscribe_event = msm_sensor_subscribe_event,
	.unsubscribe_event = msm_sensor_unsubscribe_event,
	.s_power = msm_sensor_power,
};

+9 −1
Original line number Diff line number Diff line
@@ -90,10 +90,18 @@ struct msm_sensor_ctrl_t {
	uint32_t set_mclk_23880000;
	uint8_t is_csid_tg_mode;
	uint32_t is_secure;

	/* Interrupt GPIOs */
	struct gpio gpio_array[1];
	/* device status and Flags */
	int irq;
	struct msm_sensor_init_t s_init;
	/* worker to handle interrupts */
	struct delayed_work irq_delayed_work;
};

int msm_sensor_send_event(struct msm_sensor_ctrl_t *s_ctrl,
	uint32_t event_type, struct msm_sensor_event_data *event_data);

int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp);

int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl);
+106 −2
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ static int32_t msm_sensor_driver_create_v4l_subdev
		s_ctrl->sensordata->sensor_name);
	v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, s_ctrl->pdev);
	s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
	s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
	media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0);
	s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
	s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR;
@@ -143,6 +144,8 @@ static int32_t msm_sensor_driver_create_v4l_subdev
		return rc;
	}
	msm_cam_copy_v4l2_subdev_fops(&msm_sensor_v4l2_subdev_fops);
	msm_sensor_v4l2_subdev_fops.unlocked_ioctl =
		msm_sensor_subdev_fops_ioctl;
#ifdef CONFIG_COMPAT
	msm_sensor_v4l2_subdev_fops.compat_ioctl32 =
		msm_sensor_subdev_fops_ioctl;
@@ -627,6 +630,56 @@ static void msm_sensor_fill_sensor_info(struct msm_sensor_ctrl_t *s_ctrl,
	strlcpy(entity_name, s_ctrl->msm_sd.sd.entity.name, MAX_SENSOR_NAME);
}

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",
		s_ctrl->sensordata->slave_info->sensor_slave_addr);
	schedule_delayed_work(&s_ctrl->irq_delayed_work,
						msecs_to_jiffies(0));
	return IRQ_HANDLED;
}

static void bridge_irq_delay_work(struct work_struct *work)
{
	struct msm_sensor_ctrl_t *s_ctrl;
	struct msm_camera_i2c_client *sensor_i2c_client;
	struct msm_camera_slave_info *slave_info;
	const char *sensor_name;

	struct msm_sensor_event_data sensor_event;

	s_ctrl = container_of(work, struct msm_sensor_ctrl_t,
				irq_delayed_work.work);
	if (!s_ctrl) {
		pr_err("%s:%d failed: %pK\n",
			__func__, __LINE__, s_ctrl);
		goto exit_queue;
	}
	sensor_i2c_client = s_ctrl->sensor_i2c_client;
	slave_info = s_ctrl->sensordata->slave_info;
	sensor_name = s_ctrl->sensordata->sensor_name;

	if (!sensor_i2c_client || !slave_info || !sensor_name) {
		pr_err("%s:%d failed: %pK %pK %pK\n",
			__func__, __LINE__, sensor_i2c_client, slave_info,
			sensor_name);
		goto exit_queue;
	}

	mutex_lock(s_ctrl->msm_sensor_mutex);
	/* Fill the sensor event */
	sensor_event.sensor_slave_addr =
		slave_info->sensor_slave_addr;
	/* Queue the event */
	msm_sensor_send_event(s_ctrl, SENSOR_EVENT_SIGNAL_STATUS,
		&sensor_event);
	mutex_unlock(s_ctrl->msm_sensor_mutex);
exit_queue:
	pr_err("Work IRQ exit");
}

/* static function definition */
int32_t msm_sensor_driver_probe(void *setting,
	struct msm_sensor_info_t *probed_info, char *entity_name)
@@ -928,6 +981,57 @@ CSID_TG:

	msm_sensor_fill_sensor_info(s_ctrl, probed_info, entity_name);

	if (slave_info->gpio_intr_config.gpio_num != -1) {
		/* Configure INTB interrupt */
		s_ctrl->gpio_array[0].gpio =
			slave_info->gpio_intr_config.gpio_num;
		s_ctrl->gpio_array[0].flags = 0;
		/* Only setup IRQ1 for now... */
		INIT_DELAYED_WORK(&s_ctrl->irq_delayed_work,
			bridge_irq_delay_work);
		rc = gpio_request_array(&s_ctrl->gpio_array[0], 1);
		if (rc < 0) {
			pr_err("%s: Failed to request irq_gpio %d",
				__func__, rc);
			goto cancel_work;
		}

		if (gpio_is_valid(s_ctrl->gpio_array[0].gpio)) {
			rc |= gpio_direction_input(
				s_ctrl->gpio_array[0].gpio);
			if (rc) {
				pr_err("%s: Failed gpio_direction irq %d",
						__func__, rc);
				goto cancel_work;
			} else {
				pr_err("sensor probe IRQ direction succeeded");
			}
		}

		s_ctrl->irq = gpio_to_irq(s_ctrl->gpio_array[0].gpio);
		if (s_ctrl->irq) {
			rc = request_irq(s_ctrl->irq, bridge_irq,
					IRQF_ONESHOT |
					(slave_info->
					gpio_intr_config.gpio_trigger),
					"qcom,camera", s_ctrl);
			if (rc) {
				pr_err("%s: Failed request_irq %d",
						__func__, rc);
				goto cancel_work;
			}

		} else {
			pr_err("%s: Failed gpio_to_irq %d",
				__func__, rc);
			rc = -EINVAL;
			goto cancel_work;
		}

		/* Keep irq enabled */
		pr_err("msm_sensor_driver.c irq number = %d", s_ctrl->irq);
	}

	/*
	Set probe succeeded flag to 1 so that no other camera shall
	* probed on this slot
@@ -935,6 +1039,8 @@ CSID_TG:
	s_ctrl->is_probe_succeed = 1;
	return rc;

cancel_work:
	cancel_delayed_work(&s_ctrl->irq_delayed_work);
free_camera_info:
	kfree(camera_info);
free_slave_info:
@@ -1120,7 +1226,6 @@ static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl)
	/* Store sensor control structure in static database */
	g_sctrl[s_ctrl->id] = s_ctrl;
	CDBG("g_sctrl[%d] %pK", s_ctrl->id, g_sctrl[s_ctrl->id]);

	return rc;

FREE_DT_DATA:
@@ -1173,7 +1278,6 @@ static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev)

	/* Fill platform device id*/
	pdev->id = s_ctrl->id;

	/* Fill device in power info */
	s_ctrl->sensordata->power_info.dev = &pdev->dev;

+21 −0
Original line number Diff line number Diff line
@@ -178,6 +178,27 @@ enum cci_i2c_master_t {
	MASTER_MAX,
};

struct msm_sensor_event_data {
	uint16_t sensor_slave_addr;
};

enum msm_sensor_event_mask_index {
	SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS	= 2,
};

#define SENSOR_EVENT_SUBS_MASK_NONE			0

#define SENSOR_EVENT_SUBS_MASK_SIGNAL_STATUS \
			(1 << SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS)

enum msm_sensor_event_idx {
	SENSOR_SIGNAL_STATUS      = 2,
	SENSOR_EVENT_MAX          = 15
};

#define SENSOR_EVENT_BASE            (V4L2_EVENT_PRIVATE_START)
#define SENSOR_EVENT_SIGNAL_STATUS   (SENSOR_EVENT_BASE + SENSOR_SIGNAL_STATUS)

struct msm_camera_i2c_array_write_config {
	struct msm_camera_i2c_reg_setting conf_array;
	uint16_t slave_addr;
+8 −0
Original line number Diff line number Diff line
@@ -285,6 +285,11 @@ struct msm_sensor_id_info_t {
	unsigned short sensor_id_mask;
};

struct msm_camera_sensor_gpio_intr_config {
	int gpio_num;
	uint32_t gpio_trigger;
};

struct msm_camera_sensor_slave_info {
	char sensor_name[32];
	char eeprom_name[32];
@@ -300,6 +305,9 @@ struct msm_camera_sensor_slave_info {
	unsigned char  is_init_params_valid;
	struct msm_sensor_init_params sensor_init_params;
	enum msm_sensor_output_format_t output_format;
	struct msm_camera_sensor_gpio_intr_config
				gpio_intr_config;
	unsigned int camera_sensor_device_id;
};

struct msm_camera_i2c_reg_array {