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

Commit 01fdc3e9 authored by Terence Ho's avatar Terence Ho
Browse files

msm: ais: add cci debugger interface



Expose CCI nodes and add CCI interface for debugging.

Change-Id: I890a2cf03360e524b9ce401dbd599ab2afa79c5b
Signed-off-by: default avatarTerence Ho <terenceh@codeaurora.org>
parent 74d166b4
Loading
Loading
Loading
Loading
+165 −0
Original line number Diff line number Diff line
@@ -1732,3 +1732,168 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd,

	return rc;
}


int32_t cam_cci_core_cam_ctrl(struct v4l2_subdev *sd,
	void *arg)
{
	int32_t rc = 0;
	struct cci_device *cci_dev = v4l2_get_subdevdata(sd);
	struct cam_control *cmd = (struct cam_control *)arg;
	struct cam_cci_ctrl cci_ctrl;

	if (!cci_dev || !arg) {
		CAM_ERR(CAM_SENSOR, "s_ctrl is NULL");
		return -EINVAL;
	}

	CAM_DBG(CAM_CCI, "cmd %d", cmd->op_code);

	if (cmd->op_code != AIS_SENSOR_I2C_POWER_DOWN) {
		if (cmd->handle_type != CAM_HANDLE_USER_POINTER) {
			CAM_ERR(CAM_SENSOR, "Invalid handle type: %d",
				cmd->handle_type);
			return -EINVAL;
		}
	}

	switch (cmd->op_code) {
	case AIS_SENSOR_I2C_POWER_UP: {
		struct ais_sensor_cmd_i2c_pwrup cci_pwrup;

		rc = copy_from_user(&cci_pwrup,
			(void __user *) cmd->handle, sizeof(cci_pwrup));
		if (rc < 0) {
			CAM_ERR(CAM_SENSOR, "Failed Copying from user");
			goto error;
		}

		cci_dev->cci_debug.cci_i2c_master = cci_pwrup.master;
		cci_dev->cci_debug.retries = cci_pwrup.retries;

		cci_ctrl.cci_info = &cci_dev->cci_debug;
		cci_ctrl.cmd = MSM_CCI_INIT;

		rc = cam_cci_core_cfg(sd, &cci_ctrl);
	}
		break;
	case AIS_SENSOR_I2C_POWER_DOWN: {
		cci_ctrl.cci_info = &cci_dev->cci_debug;
		cci_ctrl.cmd = MSM_CCI_RELEASE;

		rc = cam_cci_core_cfg(sd, &cci_ctrl);
	}
		break;
	case AIS_SENSOR_I2C_READ: {
		struct ais_sensor_cmd_i2c_read i2c_read;
		unsigned char buf[CAMERA_SENSOR_I2C_TYPE_MAX];
		struct cam_cci_ctrl cci_ctrl;

		rc = copy_from_user(&i2c_read,
			(void __user *) cmd->handle, sizeof(i2c_read));
		if (rc < 0) {
			CAM_ERR(CAM_SENSOR, "Failed Copying from user");
			goto error;
		}

		if (i2c_read.addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
			|| i2c_read.addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
			|| i2c_read.data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
			|| i2c_read.data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)
			return rc;

		cci_dev->cci_debug.sid = i2c_read.i2c_config.slave_addr >> 1;
		cci_dev->cci_debug.i2c_freq_mode =
					i2c_read.i2c_config.i2c_freq_mode;

		cci_ctrl.cci_info = &cci_dev->cci_debug;
		cci_ctrl.cmd = MSM_CCI_I2C_READ;

		cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = i2c_read.addr_type;
		cci_ctrl.cfg.cci_i2c_read_cfg.data_type = i2c_read.data_type;
		cci_ctrl.cfg.cci_i2c_read_cfg.addr = i2c_read.reg_addr;
		cci_ctrl.cfg.cci_i2c_read_cfg.data = buf;
		cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = i2c_read.data_type;

		rc = cam_cci_core_cfg(sd, &cci_ctrl);

		if (i2c_read.data_type == CAMERA_SENSOR_I2C_TYPE_BYTE)
			i2c_read.reg_data = buf[0];
		else if (i2c_read.data_type == CAMERA_SENSOR_I2C_TYPE_WORD)
			i2c_read.reg_data = buf[0] << 8 | buf[1];
		else if (i2c_read.data_type == CAMERA_SENSOR_I2C_TYPE_3B)
			i2c_read.reg_data = buf[0] << 16 | buf[1] << 8 | buf[2];
		else
			i2c_read.reg_data = buf[0] << 24 | buf[1] << 16 |
				buf[2] << 8 | buf[3];

		CAM_DBG(CAM_SENSOR, "Read 0x%x : 0x%x <- 0x%x",
			i2c_read.i2c_config.slave_addr,
			i2c_read.reg_addr, i2c_read.reg_data);

		if (copy_to_user((void __user *) cmd->handle, &i2c_read,
				sizeof(i2c_read))) {
			CAM_ERR(CAM_SENSOR, "Failed Copy to User");
			rc = -EFAULT;
		}
	}
		break;
	case AIS_SENSOR_I2C_WRITE: {
		struct ais_sensor_cmd_i2c_wr i2c_write;
		struct cam_sensor_i2c_reg_array reg_setting;

		rc = copy_from_user(&i2c_write,
			(void __user *) cmd->handle, sizeof(i2c_write));
		if (rc < 0) {
			CAM_ERR(CAM_SENSOR, "Failed Copying from user");
			goto error;
		}

		if (i2c_write.addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
			|| i2c_write.addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
			|| i2c_write.data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
			|| i2c_write.data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)
			return rc;

		cci_dev->cci_debug.sid =
				i2c_write.i2c_config.slave_addr >> 1;
		cci_dev->cci_debug.i2c_freq_mode =
				i2c_write.i2c_config.i2c_freq_mode;

		cci_ctrl.cci_info = &cci_dev->cci_debug;
		cci_ctrl.cmd = MSM_CCI_I2C_WRITE;

		reg_setting.reg_addr = i2c_write.wr_payload.reg_addr;
		reg_setting.reg_data = i2c_write.wr_payload.reg_data;
		reg_setting.delay = i2c_write.wr_payload.delay;
		reg_setting.data_mask = 0;

		cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = i2c_write.addr_type;
		cci_ctrl.cfg.cci_i2c_write_cfg.data_type = i2c_write.data_type;
		cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = &reg_setting;
		cci_ctrl.cfg.cci_i2c_write_cfg.size = 1;
		cci_ctrl.cfg.cci_i2c_write_cfg.delay = 0;

		CAM_DBG(CAM_SENSOR,
			"Write 0x%x, 0x%x <- 0x%x [%d, %d]",
			i2c_write.i2c_config.slave_addr,
			i2c_write.wr_payload.reg_addr,
			i2c_write.wr_payload.reg_data,
			i2c_write.addr_type, i2c_write.data_type);

		rc = cam_cci_core_cfg(sd, &cci_ctrl);

		if (reg_setting.delay > 20)
			msleep(reg_setting.delay);
		else if (reg_setting.delay)
			usleep_range(reg_setting.delay * 1000,
				(reg_setting.delay * 1000)
				+ 1000);

	}
		break;
	}

error:
	return rc;
}
+11 −1
Original line number Diff line number Diff line
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2019, 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,7 @@

#include <linux/irqreturn.h>
#include <media/cam_sensor.h>
#include <media/ais_sensor.h>
#include "cam_cci_dev.h"
#include "cam_cci_soc.h"

@@ -35,6 +36,15 @@ void cam_cci_get_clk_rates(struct cci_device *cci_dev,
int32_t cam_cci_core_cfg(struct v4l2_subdev *sd,
	struct cam_cci_ctrl *cci_ctrl);

/**
 * @sd: V4L2 sub device
 * @arg: user argument
 *
 * This API handles user I2C operations for CCI
 */
int32_t cam_cci_core_cam_ctrl(struct v4l2_subdev *sd,
	void *arg);

/**
 * @irq_num: IRQ number
 * @data: CCI private structure
+6 −1
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ static long cam_cci_subdev_ioctl(struct v4l2_subdev *sd,
		rc = cam_cci_core_cfg(sd, arg);
		break;
	case VIDIOC_CAM_CONTROL:
		rc = cam_cci_core_cam_ctrl(sd, arg);
		break;
	default:
		CAM_ERR(CAM_CCI, "Invalid ioctl cmd: %d", cmd);
@@ -351,7 +352,7 @@ static long cam_cci_subdev_do_ioctl(
	struct video_device *vdev = video_devdata(file);
	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);

	return cam_cci_subdev_ioctl(sd, cmd, NULL);
	return cam_cci_subdev_ioctl(sd, cmd, arg);
}

static long cam_cci_subdev_fops_ioctl(struct file *file, unsigned int cmd,
@@ -428,6 +429,10 @@ static int cam_cci_platform_probe(struct platform_device *pdev)

	g_cci_subdev[soc_info->index] = &new_cci_dev->v4l2_dev_str.sd;
	mutex_init(&(new_cci_dev->init_mutex));

	new_cci_dev->cci_debug.cci_device = soc_info->index;
	new_cci_dev->cci_debug.cci_subdev = g_cci_subdev[soc_info->index];

	CAM_INFO(CAM_CCI, "Device Type :%d", soc_info->index);

	cam_register_subdev_fops(&cci_v4l2_subdev_fops);
+47 −46
Original line number Diff line number Diff line
@@ -171,6 +171,52 @@ enum cam_cci_state_t {
	CCI_STATE_DISABLED,
};

enum cam_cci_i2c_cmd_type {
	CCI_I2C_SET_PARAM_CMD = 1,
	CCI_I2C_WAIT_CMD,
	CCI_I2C_WAIT_SYNC_CMD,
	CCI_I2C_WAIT_GPIO_EVENT_CMD,
	CCI_I2C_TRIG_I2C_EVENT_CMD,
	CCI_I2C_LOCK_CMD,
	CCI_I2C_UNLOCK_CMD,
	CCI_I2C_REPORT_CMD,
	CCI_I2C_WRITE_CMD,
	CCI_I2C_READ_CMD,
	CCI_I2C_WRITE_DISABLE_P_CMD,
	CCI_I2C_READ_DISABLE_P_CMD,
	CCI_I2C_WRITE_CMD2,
	CCI_I2C_WRITE_CMD3,
	CCI_I2C_REPEAT_CMD,
	CCI_I2C_INVALID_CMD,
};

enum cam_cci_gpio_cmd_type {
	CCI_GPIO_SET_PARAM_CMD = 1,
	CCI_GPIO_WAIT_CMD,
	CCI_GPIO_WAIT_SYNC_CMD,
	CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD,
	CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD,
	CCI_GPIO_OUT_CMD,
	CCI_GPIO_TRIG_EVENT_CMD,
	CCI_GPIO_REPORT_CMD,
	CCI_GPIO_REPEAT_CMD,
	CCI_GPIO_CONTINUE_CMD,
	CCI_GPIO_INVALID_CMD,
};

struct cam_sensor_cci_client {
	struct v4l2_subdev *cci_subdev;
	uint32_t freq;
	enum i2c_freq_mode i2c_freq_mode;
	enum cci_i2c_master_t cci_i2c_master;
	uint16_t sid;
	uint16_t cid;
	uint32_t timeout;
	uint16_t retries;
	uint16_t id_map;
	uint16_t cci_device;
};

/**
 * struct cci_device
 * @pdev:                       Platform device
@@ -237,52 +283,7 @@ struct cci_device {
	bool is_burst_read;
	uint32_t irqs_disabled;
	struct mutex init_mutex;
};

enum cam_cci_i2c_cmd_type {
	CCI_I2C_SET_PARAM_CMD = 1,
	CCI_I2C_WAIT_CMD,
	CCI_I2C_WAIT_SYNC_CMD,
	CCI_I2C_WAIT_GPIO_EVENT_CMD,
	CCI_I2C_TRIG_I2C_EVENT_CMD,
	CCI_I2C_LOCK_CMD,
	CCI_I2C_UNLOCK_CMD,
	CCI_I2C_REPORT_CMD,
	CCI_I2C_WRITE_CMD,
	CCI_I2C_READ_CMD,
	CCI_I2C_WRITE_DISABLE_P_CMD,
	CCI_I2C_READ_DISABLE_P_CMD,
	CCI_I2C_WRITE_CMD2,
	CCI_I2C_WRITE_CMD3,
	CCI_I2C_REPEAT_CMD,
	CCI_I2C_INVALID_CMD,
};

enum cam_cci_gpio_cmd_type {
	CCI_GPIO_SET_PARAM_CMD = 1,
	CCI_GPIO_WAIT_CMD,
	CCI_GPIO_WAIT_SYNC_CMD,
	CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD,
	CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD,
	CCI_GPIO_OUT_CMD,
	CCI_GPIO_TRIG_EVENT_CMD,
	CCI_GPIO_REPORT_CMD,
	CCI_GPIO_REPEAT_CMD,
	CCI_GPIO_CONTINUE_CMD,
	CCI_GPIO_INVALID_CMD,
};

struct cam_sensor_cci_client {
	struct v4l2_subdev *cci_subdev;
	uint32_t freq;
	enum i2c_freq_mode i2c_freq_mode;
	enum cci_i2c_master_t cci_i2c_master;
	uint16_t sid;
	uint16_t cid;
	uint32_t timeout;
	uint16_t retries;
	uint16_t id_map;
	uint16_t cci_device;
	struct cam_sensor_cci_client cci_debug;
};

struct cam_cci_ctrl {
+12 −0
Original line number Diff line number Diff line
@@ -148,4 +148,16 @@ struct ais_sensor_cmd_i2c_wr_array {
	struct ais_sensor_i2c_wr_payload *wr_array;
} __attribute__((packed));

/**
 * struct ais_sensor_cmd_i2c_pwrup - i2c power up
 * @master          :    logical master
 * @retries         :    number of retries
 * @reserved        :    reserved
 */
struct ais_sensor_cmd_i2c_pwrup {
	uint8_t     master;
	uint8_t     retries;
	uint16_t     reserved;
} __attribute__((packed));

#endif