移植传感器驱动遇到的问题求解

硬件平台:jetson-xavier-nx-devkit-emmc
准备移植一个新的传感器支持,传感器使用fpga模拟mipi信号,目前使用开发板默认支持的imx219传感器驱动进行修改,由于fpga模拟传感器未模拟i2c控制,所以修改imx219驱动将所有的i2c通信屏蔽并修改为通信成功,此时mipi接口若未接入任何设备,也能检测到vide0设备,通过v4l2进行采集时,内核将打印错误日志:

[   92.957342] tegra194-vi5 15c10000.vi: no reply from camera processor
[   92.957501] tegra194-vi5 15c10000.vi: uncorr_err: request timed out after 2500 ms
[   92.957681] tegra194-vi5 15c10000.vi: err_rec: attempting to reset the capture channel
[   92.969184] tegra-capture-ivc ivc-bc00000.rtcpu:ivccontrol@3: No callback found for msg id: 0x39
[   92.969418] tegra-capture-ivc ivc-bc00000.rtcpu:ivccontrol@3: No callback found for msg id: 0x41
[   92.969568] tegra-capture-ivc ivc-bc00000.rtcpu:ivccontrol@3: No callback found for msg id: 0x37

我认为这是正常的,但是接入fpga模拟的mipi设备后,内核依然会打印上面的日志,并且采集不到图像,通过trace跟踪得到调试信息:

kworker/0:0-9668  [000] ....  3084.471542: rtos_queue_send_from_isr_failed: tstamp:96915908625 queue:0x0bcb2b38
     kworker/0:0-9668  [000] ....  3084.471543: rtos_queue_send_from_isr_failed: tstamp:96915908774 queue:0x0bcb73a0
     kworker/0:0-9668  [000] ....  3084.471544: rtos_queue_send_from_isr_failed: tstamp:96915908927 queue:0x0bcb8f20
     kworker/0:0-9668  [000] ....  3084.471544: rtos_queue_send_from_isr_failed: tstamp:96915909074 queue:0x0bcb9ce0
     kworker/0:0-9668  [000] ....  3084.471580: rtos_queue_send_from_isr_failed: tstamp:96915909220 queue:0x0bcbaaa0
     kworker/0:0-9668  [000] ....  3084.471582: rtcpu_vinotify_event: tstamp:96916279652 tag:RESERVED_18 channel:0x23 frame:0 vi_tstamp:94828105632 data:0x10000000
     kworker/0:0-9668  [000] ....  3084.471583: rtcpu_vinotify_event: tstamp:96916279796 tag:RESERVED_18 channel:0x23 frame:0 vi_tstamp:94828113824 data:0x31000001
     kworker/0:0-9668  [000] ....  3084.471584: rtcpu_vinotify_event: tstamp:96916279967 tag:RESERVED_19 channel:0x23 frame:0 vi_tstamp:94828115968 data:0x07020001
     kworker/0:0-9668  [000] ....  3084.471585: rtcpu_vinotify_event: tstamp:96916280103 tag:RESERVED_18 channel:0x23 frame:0 vi_tstamp:94828149344 data:0x10000000
     kworker/0:0-9668  [000] ....  3084.471586: rtcpu_vinotify_event: tstamp:96916280260 tag:RESERVED_18 channel:0x23 frame:0 vi_tstamp:94828157600 data:0x31000002
     kworker/0:0-9668  [000] ....  3084.531389: rtcpu_nvcsi_intr: tstamp:96916500657 class:GLOBAL type:PHY_INTR0 phy:0 cil:0 st:0 vc:0 status:0x0e000000
     kworker/0:0-9668  [000] ....  3084.531395: rtcpu_nvcsi_intr: tstamp:96916500657 class:CORRECTABLE_ERR type:PHY_INTR phy:0 cil:0 st:0 vc:0 status:0x00000e

为了分析内核报错问题,我阅读了《Xavier_TRM_DP09253002_v1.4p.pdf》和https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%20Linux%20Driver%20Package%20Development%20Guide/jetson_xavier_camera_soft_archi.html#wwconnect_header并在互联网上查阅了相关资料,也阅读了相关的驱动程序代码,但是依然不能解决这个问题。
请问,谁能帮我解答我的问题呢:
1、《Xavier_TRM_DP09253002_v1.4p.pdf》中的哪一章有对驱动程序中的rtcpu进行说明
2、《Xavier_TRM_DP09253002_v1.4p.pdf》中的VIC与驱动程序中的IVC是同一个东西吗
3 、有没有什么文档或者资料能说明
4、对于基本的传感器驱动编写,我应该注意哪些,遇到问题后,如何才能快速的定位问题

hello 913775933,

there’s error indicate VI engine did not receive the camera frames, please check the developer guide, To verify the port binding result to ensure you’ve correct port bindings.
BTW,
here’s training video, V4L2 Sensor Driver Development Tutorial to show the steps of writing a V4L2 compliant driver for an image sensor to connect to the NVIDIA Jetson platform. thanks

非常感谢您的回复!
在错误日志中

这个错误日志中的status:0x00000e和status:0x0e000000,我查看了论坛的一些说明,说可以通过查看《Xavier_TRM_DP09253002_v1.4p》中NVCSI_PHY_0_CILA_INTR_0_STATUS_CILA_0寄存器得到错误信息。
我通过查看Xavier_TRM_DP09253002_v1.4p分别得到错误
intr_cil_data_lane_sot_2lsb_err1_a
intr_cil_data_lane_sot_2lsb_err0_a

intr_dphy_cil_deskew_calib_err_lane1_a
intr_dphy_cil_deskew_calib_err_lane0_a
但是该文档没有对这些错误进行详细的说明,我如何通过trace得到的错误状态码得到详细的错误信息,并知道对应的解决办法呢?

hello 913775933,

this is sensor bring-up issue, please review your device tree property, device Tree is used to store all the needed information, you should check all the clock configurations, those timing settings should also match your sensor hardware specific settings.

BTW,
suggest you describe the issue in English, since there’re lots of developers from worldwide.

Hello JerryChang:

Thank you very much for your suggestion. Now I will describe my problem in English.
After debugging, I found this post “Bypass check using FPGA (HDMI to CSI-2)” with very similar problems to mine, but It didn’t solve the problem. I also got the intr_cil_data_lane_rxfifo_full_err0_a error.
When encountering this error, what is a good solution?

hello 913775933,

had you review the port binding to review the hardware connection definition for CSI, VI, and camera sensor?

Yes, these hardware connections have been ensured without problems. I just replaced the imx219 with our own mipi sensor and modified the device tree and imx219 driver.
I have modified the device tree:

mclk_khz = "25000";
num_lanes = "1";
tegra_sinterface = "serial_a";
phy_mode = "DPHY";
//discontinuous_clk = "yes";
discontinuous_clk = "yes";
dpcm_enable = "false";
cil_settletime = "0";

active_w = "1024";
active_h = "1024";
pixel_t = "bayer_rggb12";
readout_orientation = "90";
line_length = "2500";//"3448";
inherent_gain = "1";
mclk_multiplier = "2";
pix_clk_hz = "50000000";

gain_factor = "16";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "16"; /* 1.00x */
max_gain_val = "170"; /* 10.66x */
step_gain_val = "1";
default_gain = "16"; /* 1.00x */
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "2000000"; /* 2.0 fps */
max_framerate = "10000000"; /* 60.0 fps */
step_framerate = "1";
default_framerate = "10000000"; /* 60.0 fps */
min_exp_time = "13"; /* us */
max_exp_time = "683709"; /* us */
step_exp_time = "1";
default_exp_time = "2495"; /* us */

embedded_metadata_height = "2";

could you please also share tegra-camera-platform{} for reference, thanks

tcp: tegra-camera-platform {
		compatible = "nvidia, tegra-camera-platform";
		/**
		* Physical settings to calculate max ISO BW
		*
		* num_csi_lanes = <>;
		* Total number of CSI lanes when all cameras are active
		*
		* max_lane_speed = <>;
		* Max lane speed in Kbit/s
		*
		* min_bits_per_pixel = <>;
		* Min bits per pixel
		*
		* vi_peak_byte_per_pixel = <>;
		* Max byte per pixel for the VI ISO case
		*
		* vi_bw_margin_pct = <>;
		* Vi bandwidth margin in percentage
		*
		* max_pixel_rate = <>;
		* Max pixel rate in Kpixel/s for the ISP ISO case
		*
		* isp_peak_byte_per_pixel = <>;
		* Max byte per pixel for the ISP ISO case
		*
		* isp_bw_margin_pct = <>;
		* Isp bandwidth margin in percentage
		*/
		num_csi_lanes = <4>;
		max_lane_speed = <1500000>;
		min_bits_per_pixel = <10>;
		vi_peak_byte_per_pixel = <2>;
		vi_bw_margin_pct = <25>;
		max_pixel_rate = <240000>;
		isp_peak_byte_per_pixel = <5>;
		isp_bw_margin_pct = <25>;

		/**
		 * The general guideline for naming badge_info contains 3 parts, and is as follows,
		 * The first part is the camera_board_id for the module; if the module is in a FFD
		 * platform, then use the platform name for this part.
		 * The second part contains the position of the module, ex. "rear" or "front".
		 * The third part contains the last 6 characters of a part number which is found
		 * in the module's specsheet from the vendor.
		 */
		modules {
			cam_module0: module0 {
				badge = "jakku_front_RBP194";
				position = "front";
				orientation = "1";
				cam_module0_drivernode0: drivernode0 {
					pcl_id = "v4l2_sensor";
					devname = "imx219 9-0010";
					proc-device-tree = "/proc/device-tree/cam_i2cmux/i2c@0/rbpcv2_imx219_a@10";
				};
				cam_module0_drivernode1: drivernode1 {
					pcl_id = "v4l2_lens";
					proc-device-tree = "/proc/device-tree/lens_imx219@RBPCV2/";
				};
			};
			cam_module1: module1 {
				badge = "jakku_rear_RBP194";
				position = "rear";
				orientation = "1";
				cam_module1_drivernode0: drivernode0 {
					pcl_id = "v4l2_sensor";
					devname = "imx219 10-0010";
					proc-device-tree = "/proc/device-tree/cam_i2cmux/i2c@1/rbpcv2_imx219_c@10";
				};
				cam_module1_drivernode1: drivernode1 {
					pcl_id = "v4l2_lens";
					proc-device-tree = "/proc/device-tree/lens_imx219@RBPCV2/";
				};
			};
		};
	};

hello 913775933,

you have incorrect camera module definition.
such as… devname = "imx219 9-0010"; this is actually looking for IMX219’s camera driver to register the camera node.
the proc-device-tree indicate the path of your camera node in linux file system, please also revise that accordingly.

please see this training video, V4L2 Sensor Driver Development Tutorial to show the steps of writing a V4L2 compliant driver for an image sensor to connect to the NVIDIA Jetson platform.
thanks

I have modified the imx219 driver and compiled it into the kernel. I blocked the I2C configuration of the imx219 to the sensor, so that the imx219 was always initialized successfully.

/*
 * imx219.c - imx219 sensor driver
 *
 * Copyright (c) 2015-2020, NVIDIA CORPORATION.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>

#include <media/tegra_v4l2_camera.h>
#include <media/tegracam_core.h>
#include <media/imx219.h>

#include "../platform/tegra/camera/camera_gpio.h"
#include "imx219_mode_tbls.h"

/* imx219 - sensor parameter limits */
#define IMX219_MIN_GAIN				0x0000
#define IMX219_MAX_GAIN				0x00e8
#define IMX219_MIN_FRAME_LENGTH			0x0100
#define IMX219_MAX_FRAME_LENGTH			0xffff
#define IMX219_MIN_COARSE_EXPOSURE		0x0001
#define IMX219_MAX_COARSE_DIFF			0x0004

/* imx219 sensor register address */
#define IMX219_MODEL_ID_ADDR_MSB		0x0000
#define IMX219_MODEL_ID_ADDR_LSB		0x0001
#define IMX219_GAIN_ADDR			0x0157
#define IMX219_FRAME_LENGTH_ADDR_MSB		0x0160
#define IMX219_FRAME_LENGTH_ADDR_LSB		0x0161
#define IMX219_COARSE_INTEG_TIME_ADDR_MSB	0x015a
#define IMX219_COARSE_INTEG_TIME_ADDR_LSB	0x015b
#define IMX219_FINE_INTEG_TIME_ADDR_MSB		0x0388
#define IMX219_FINE_INTEG_TIME_ADDR_LSB		0x0389

static const struct of_device_id imx219_of_match[] = {
	{ .compatible = "nvidia,imx219", },
	{ },
};
MODULE_DEVICE_TABLE(of, imx219_of_match);

static const u32 ctrl_cid_list[] = {
	TEGRA_CAMERA_CID_GAIN,
	TEGRA_CAMERA_CID_EXPOSURE,
	TEGRA_CAMERA_CID_FRAME_RATE,
	TEGRA_CAMERA_CID_SENSOR_MODE_ID,
};

struct imx219 {
	struct i2c_client		*i2c_client;
	struct v4l2_subdev		*subdev;
	u16				fine_integ_time;
	u32				frame_length;
	struct camera_common_data	*s_data;
	struct tegracam_device		*tc_dev;
};

static const struct regmap_config sensor_regmap_config = {
	.reg_bits = 16,
	.val_bits = 8,
	.cache_type = REGCACHE_RBTREE,
	.use_single_rw = true,
};

static inline void imx219_get_frame_length_regs(imx219_reg *regs,
	u32 frame_length)
{
	regs->addr = IMX219_FRAME_LENGTH_ADDR_MSB;
	regs->val = (frame_length >> 8) & 0xff;
	(regs + 1)->addr = IMX219_FRAME_LENGTH_ADDR_LSB;
	(regs + 1)->val = (frame_length) & 0xff;
}

static inline void imx219_get_coarse_integ_time_regs(imx219_reg *regs,
	u32 coarse_time)
{
	regs->addr = IMX219_COARSE_INTEG_TIME_ADDR_MSB;
	regs->val = (coarse_time >> 8) & 0xff;
	(regs + 1)->addr = IMX219_COARSE_INTEG_TIME_ADDR_LSB;
	(regs + 1)->val = (coarse_time) & 0xff;
}

static inline void imx219_get_gain_reg(imx219_reg *reg, u8 gain)
{
	reg->addr = IMX219_GAIN_ADDR;
	reg->val = gain & 0xff;
}

static inline int imx219_read_reg(struct camera_common_data *s_data,
	u16 addr, u8 *val)
{
	int err = 0;
	u32 reg_val = 0;

/*	err = regmap_read(s_data->regmap, addr, &reg_val);*/
	*val = reg_val & 0xff;

	return err;
}

static inline int imx219_write_reg(struct camera_common_data *s_data,
	u16 addr, u8 val)
{
	int err = 0;

// 	err = regmap_write(s_data->regmap, addr, val);
// 	if (err)
// 		dev_err(s_data->dev, "%s: i2c write failed, 0x%x = %x",
// 			__func__, addr, val);

	return err;
}

static int imx219_write_table(struct imx219 *priv, const imx219_reg table[])
{
// 	return regmap_util_write_table_8(priv->s_data->regmap, table, NULL, 0,
// 		IMX219_TABLE_WAIT_MS, IMX219_TABLE_END);
	return 0;
}

static int imx219_set_group_hold(struct tegracam_device *tc_dev, bool val)
{
	/* imx219 does not support group hold */
	return 0;
}

// static int imx219_get_fine_integ_time(struct imx219 *priv, u16 *fine_time)
// {
// 	struct camera_common_data *s_data = priv->s_data;
// 	int err = 0;
// 	u8 reg_val[2];
// 
// 	err = imx219_read_reg(s_data, IMX219_FINE_INTEG_TIME_ADDR_MSB,
// 		&reg_val[0]);
// 	if (err)
// 		goto done;
// 
// 	err = imx219_read_reg(s_data, IMX219_FINE_INTEG_TIME_ADDR_LSB,
// 		&reg_val[1]);
// 	if (err)
// 		goto done;
// 
// 	*fine_time = (reg_val[0] << 8) | reg_val[1];
// 
// done:
// 	return err;
// }

static int imx219_set_gain(struct tegracam_device *tc_dev, s64 val)
{
	struct camera_common_data *s_data = tc_dev->s_data;
	struct device *dev = s_data->dev;
	const struct sensor_mode_properties *mode =
		&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];

	int err = 0;
	imx219_reg gain_reg;
	s16 gain;

	if (val < mode->control_properties.min_gain_val)
		val = mode->control_properties.min_gain_val;
	else if (val > mode->control_properties.max_gain_val)
		val = mode->control_properties.max_gain_val;

	/* translate value (from normalized analog gain) */
	gain = (s16)((256 * mode->control_properties.gain_factor) / val);
	gain = 256 - gain;

	if (gain < IMX219_MIN_GAIN)
		gain = IMX219_MAX_GAIN;
	else if (gain > IMX219_MAX_GAIN)
		gain = IMX219_MAX_GAIN;

	dev_dbg(dev, "%s: val: %lld (/%d) [times], gain: %u\n",
		__func__, val, mode->control_properties.gain_factor, gain);

	imx219_get_gain_reg(&gain_reg, (u8)gain);
	err = imx219_write_reg(s_data, gain_reg.addr, gain_reg.val);
	if (err)
		dev_dbg(dev, "%s: gain control error\n", __func__);

	return 0;
}

static int imx219_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
	struct camera_common_data *s_data = tc_dev->s_data;
	struct imx219 *priv = (struct imx219 *)tc_dev->priv;
	struct device *dev = tc_dev->dev;
	const struct sensor_mode_properties *mode =
		&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];

	int err = 0;
	imx219_reg fl_regs[2];
	u32 frame_length;
	int i;

	frame_length = (u32)(mode->signal_properties.pixel_clock.val *
		(u64)mode->control_properties.framerate_factor /
		mode->image_properties.line_length / val);

	if (frame_length < IMX219_MIN_FRAME_LENGTH)
		frame_length = IMX219_MIN_FRAME_LENGTH;
	else if (frame_length > IMX219_MAX_FRAME_LENGTH)
		frame_length = IMX219_MAX_FRAME_LENGTH;

	dev_dbg(dev,
		"%s: val: %llde-6 [fps], frame_length: %u [lines]\n",
		__func__, val, frame_length);

	imx219_get_frame_length_regs(fl_regs, frame_length);
	for (i = 0; i < 2; i++) {
		err = imx219_write_reg(s_data, fl_regs[i].addr, fl_regs[i].val);
		if (err) {
			dev_dbg(dev,
				"%s: frame_length control error\n", __func__);
			return err;
		}
	}

	priv->frame_length = frame_length;

	return 0;
}

static int imx219_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
	struct camera_common_data *s_data = tc_dev->s_data;
	struct imx219 *priv = (struct imx219 *)tc_dev->priv;
	struct device *dev = tc_dev->dev;
	const struct sensor_mode_properties *mode =
		&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];

	int err = 0;
	imx219_reg ct_regs[2];
	const s32 max_coarse_time = priv->frame_length - IMX219_MAX_COARSE_DIFF;
	const s32 fine_integ_time_factor = priv->fine_integ_time *
		mode->control_properties.exposure_factor /
		mode->signal_properties.pixel_clock.val;
	u32 coarse_time;
	int i;

	coarse_time = (val - fine_integ_time_factor)
		* mode->signal_properties.pixel_clock.val
		/ mode->control_properties.exposure_factor
		/ mode->image_properties.line_length;

	if (coarse_time < IMX219_MIN_COARSE_EXPOSURE)
		coarse_time = IMX219_MIN_COARSE_EXPOSURE;
	else if (coarse_time > max_coarse_time) {
		coarse_time = max_coarse_time;
		dev_dbg(dev,
			"%s: exposure limited by frame_length: %d [lines]\n",
			__func__, max_coarse_time);
	}

	dev_dbg(dev, "%s: val: %lld [us], coarse_time: %d [lines]\n",
		__func__, val, coarse_time);

	imx219_get_coarse_integ_time_regs(ct_regs, coarse_time);

	for (i = 0; i < 2; i++) {
		err = imx219_write_reg(s_data, ct_regs[i].addr, ct_regs[i].val);
		if (err) {
			dev_dbg(dev,
				"%s: coarse_time control error\n", __func__);
			return err;
		}
	}

	return 0;
}

static struct tegracam_ctrl_ops imx219_ctrl_ops = {
	.numctrls = ARRAY_SIZE(ctrl_cid_list),
	.ctrl_cid_list = ctrl_cid_list,
	.set_gain = imx219_set_gain,
	.set_exposure = imx219_set_exposure,
	.set_frame_rate = imx219_set_frame_rate,
	.set_group_hold = imx219_set_group_hold,
};

static int imx219_power_on(struct camera_common_data *s_data)
{
	int err = 0;
	struct camera_common_power_rail *pw = s_data->power;
	struct camera_common_pdata *pdata = s_data->pdata;
	struct device *dev = s_data->dev;

	dev_dbg(dev, "%s: power on\n", __func__);
	if (pdata && pdata->power_on) {
		err = pdata->power_on(pw);
		if (err)
			dev_err(dev, "%s failed.\n", __func__);
		else
			pw->state = SWITCH_ON;
		return err;
	}

	if (pw->reset_gpio) {
		if (gpio_cansleep(pw->reset_gpio))
			gpio_set_value_cansleep(pw->reset_gpio, 0);
		else
			gpio_set_value(pw->reset_gpio, 0);
	}

	if (unlikely(!(pw->avdd || pw->iovdd || pw->dvdd)))
		goto skip_power_seqn;

	usleep_range(10, 20);

	if (pw->avdd) {
		err = regulator_enable(pw->avdd);
		if (err)
			goto imx219_avdd_fail;
	}

	if (pw->iovdd) {
		err = regulator_enable(pw->iovdd);
		if (err)
			goto imx219_iovdd_fail;
	}

	if (pw->dvdd) {
		err = regulator_enable(pw->dvdd);
		if (err)
			goto imx219_dvdd_fail;
	}

	usleep_range(10, 20);

skip_power_seqn:
	if (pw->reset_gpio) {
		if (gpio_cansleep(pw->reset_gpio))
			gpio_set_value_cansleep(pw->reset_gpio, 1);
		else
			gpio_set_value(pw->reset_gpio, 1);
	}

	/* Need to wait for t4 + t5 + t9 time as per the data sheet */
	/* t4 - 200us, t5 - 21.2ms, t9 - 1.2ms */
	usleep_range(23000, 23100);

	pw->state = SWITCH_ON;

	return 0;

imx219_dvdd_fail:
	regulator_disable(pw->iovdd);

imx219_iovdd_fail:
	regulator_disable(pw->avdd);

imx219_avdd_fail:
	dev_err(dev, "%s failed.\n", __func__);

	return -ENODEV;
}

static int imx219_power_off(struct camera_common_data *s_data)
{
	int err = 0;
	struct camera_common_power_rail *pw = s_data->power;
	struct camera_common_pdata *pdata = s_data->pdata;
	struct device *dev = s_data->dev;

	dev_dbg(dev, "%s: power off\n", __func__);

	if (pdata && pdata->power_off) {
		err = pdata->power_off(pw);
		if (err) {
			dev_err(dev, "%s failed.\n", __func__);
			return err;
		}
	} else {
		if (pw->reset_gpio) {
			if (gpio_cansleep(pw->reset_gpio))
				gpio_set_value_cansleep(pw->reset_gpio, 0);
			else
				gpio_set_value(pw->reset_gpio, 0);
		}

		usleep_range(10, 10);

		if (pw->dvdd)
			regulator_disable(pw->dvdd);
		if (pw->iovdd)
			regulator_disable(pw->iovdd);
		if (pw->avdd)
			regulator_disable(pw->avdd);
	}

	pw->state = SWITCH_OFF;

	return 0;
}

static int imx219_power_put(struct tegracam_device *tc_dev)
{
	struct camera_common_data *s_data = tc_dev->s_data;
	struct camera_common_power_rail *pw = s_data->power;

	if (unlikely(!pw))
		return -EFAULT;

	if (likely(pw->dvdd))
		devm_regulator_put(pw->dvdd);

	if (likely(pw->avdd))
		devm_regulator_put(pw->avdd);

	if (likely(pw->iovdd))
		devm_regulator_put(pw->iovdd);

	pw->dvdd = NULL;
	pw->avdd = NULL;
	pw->iovdd = NULL;

	if (likely(pw->reset_gpio))
		gpio_free(pw->reset_gpio);

	return 0;
}

static int imx219_power_get(struct tegracam_device *tc_dev)
{
	struct device *dev = tc_dev->dev;
	struct camera_common_data *s_data = tc_dev->s_data;
	struct camera_common_power_rail *pw = s_data->power;
	struct camera_common_pdata *pdata = s_data->pdata;
	struct clk *parent;
	int err = 0;

	if (!pdata) {
		dev_err(dev, "pdata missing\n");
		return -EFAULT;
	}

	/* Sensor MCLK (aka. INCK) */
	if (pdata->mclk_name) {
		pw->mclk = devm_clk_get(dev, pdata->mclk_name);
		if (IS_ERR(pw->mclk)) {
			dev_err(dev, "unable to get clock %s\n",
				pdata->mclk_name);
			return PTR_ERR(pw->mclk);
		}

		if (pdata->parentclk_name) {
			parent = devm_clk_get(dev, pdata->parentclk_name);
			if (IS_ERR(parent)) {
				dev_err(dev, "unable to get parent clock %s",
					pdata->parentclk_name);
			} else
				clk_set_parent(pw->mclk, parent);
		}
	}

	/* analog 2.8v */
	if (pdata->regulators.avdd)
		err |= camera_common_regulator_get(dev,
				&pw->avdd, pdata->regulators.avdd);
	/* IO 1.8v */
	if (pdata->regulators.iovdd)
		err |= camera_common_regulator_get(dev,
				&pw->iovdd, pdata->regulators.iovdd);
	/* dig 1.2v */
	if (pdata->regulators.dvdd)
		err |= camera_common_regulator_get(dev,
				&pw->dvdd, pdata->regulators.dvdd);
	if (err) {
		dev_err(dev, "%s: unable to get regulator(s)\n", __func__);
		goto done;
	}

	/* Reset or ENABLE GPIO */
	pw->reset_gpio = pdata->reset_gpio;
	err = gpio_request(pw->reset_gpio, "cam_reset_gpio");
	if (err < 0) {
		dev_err(dev, "%s: unable to request reset_gpio (%d)\n",
			__func__, err);
		goto done;
	}

done:
	pw->state = SWITCH_OFF;

	return err;
}

static struct camera_common_pdata *imx219_parse_dt(
	struct tegracam_device *tc_dev)
{
	struct device *dev = tc_dev->dev;
	struct device_node *np = dev->of_node;
	struct camera_common_pdata *board_priv_pdata;
	const struct of_device_id *match;
	struct camera_common_pdata *ret = NULL;
	int err = 0;
	int gpio;

	if (!np)
		return NULL;

	match = of_match_device(imx219_of_match, dev);
	if (!match) {
		dev_err(dev, "Failed to find matching dt id\n");
		return NULL;
	}

	board_priv_pdata = devm_kzalloc(dev,
		sizeof(*board_priv_pdata), GFP_KERNEL);
	if (!board_priv_pdata)
		return NULL;

	gpio = of_get_named_gpio(np, "reset-gpios", 0);
	if (gpio < 0) {
		if (gpio == -EPROBE_DEFER)
			ret = ERR_PTR(-EPROBE_DEFER);
		dev_err(dev, "reset-gpios not found\n");
		goto error;
	}
	board_priv_pdata->reset_gpio = (unsigned int)gpio;

	err = of_property_read_string(np, "mclk", &board_priv_pdata->mclk_name);
	if (err)
		dev_dbg(dev, "mclk name not present, "
			"assume sensor driven externally\n");

	err = of_property_read_string(np, "avdd-reg",
		&board_priv_pdata->regulators.avdd);
	err |= of_property_read_string(np, "iovdd-reg",
		&board_priv_pdata->regulators.iovdd);
	err |= of_property_read_string(np, "dvdd-reg",
		&board_priv_pdata->regulators.dvdd);
	if (err)
		dev_dbg(dev, "avdd, iovdd and/or dvdd reglrs. not present, "
			"assume sensor powered independently\n");

	board_priv_pdata->has_eeprom =
		of_property_read_bool(np, "has-eeprom");

	return board_priv_pdata;

error:
	devm_kfree(dev, board_priv_pdata);

	return ret;
}

static int imx219_set_mode(struct tegracam_device *tc_dev)
{
	struct imx219 *priv = (struct imx219 *)tegracam_get_privdata(tc_dev);
	struct camera_common_data *s_data = tc_dev->s_data;

	int err = 0;

	err = imx219_write_table(priv, mode_table[IMX219_MODE_COMMON]);
	if (err)
		return err;

	err = imx219_write_table(priv, mode_table[s_data->mode]);
	if (err)
		return err;

	return 0;
}

static int imx219_start_streaming(struct tegracam_device *tc_dev)
{
	struct imx219 *priv = (struct imx219 *)tegracam_get_privdata(tc_dev);

	u32 reg_val = 0;
	//regmap_read(priv->s_data->regmap,0xFFFF, &reg_val);

	//regmap_write(priv->s_data->regmap, 0xFFFFF, 0xFF);
	return 0;// imx219_write_table(priv, mode_table[IMX219_START_STREAM]);
}

static int imx219_stop_streaming(struct tegracam_device *tc_dev)
{
	int err = 0;
	struct imx219 *priv = (struct imx219 *)tegracam_get_privdata(tc_dev);

	//err = imx219_write_table(priv, mode_table[IMX219_STOP_STREAM]);
    u32 reg_val = 0;
    //regmap_read(priv->s_data->regmap, 0x0000, &reg_val);
	//regmap_write(priv->s_data->regmap, 0x0000, 0x00);
	usleep_range(50000, 51000);

	return err;
}

static struct camera_common_sensor_ops imx219_common_ops = {
	.numfrmfmts = ARRAY_SIZE(imx219_frmfmt),
	.frmfmt_table = imx219_frmfmt,
	.power_on = imx219_power_on,
	.power_off = imx219_power_off,
	.write_reg = imx219_write_reg,
	.read_reg = imx219_read_reg,
	.parse_dt = imx219_parse_dt,
	.power_get = imx219_power_get,
	.power_put = imx219_power_put,
	.set_mode = imx219_set_mode,
	.start_streaming = imx219_start_streaming,
	.stop_streaming = imx219_stop_streaming,
};

static int imx219_board_setup(struct imx219 *priv)
{
	struct camera_common_data *s_data = priv->s_data;
	struct camera_common_pdata *pdata = s_data->pdata;
	struct device *dev = s_data->dev;
	//u8 reg_val[2];
	int err = 0;

	if (pdata->mclk_name) {
		err = camera_common_mclk_enable(s_data);
		if (err) {
			dev_err(dev, "error turning on mclk (%d)\n", err);
			goto done;
		}
	}

	err = imx219_power_on(s_data);
	if (err) {
		dev_err(dev, "error during power on sensor (%d)\n", err);
		goto err_power_on;
	}

// 	/* Probe sensor model id registers */
// 	err = imx219_read_reg(s_data, IMX219_MODEL_ID_ADDR_MSB, &reg_val[0]);
// 	if (err) {
// 		dev_err(dev, "%s: error during i2c read probe (%d)\n",
// 			__func__, err);
// 		goto err_reg_probe;
// 	}
// 	err = imx219_read_reg(s_data, IMX219_MODEL_ID_ADDR_LSB, &reg_val[1]);
// 	if (err) {
// 		dev_err(dev, "%s: error during i2c read probe (%d)\n",
// 			__func__, err);
// 		goto err_reg_probe;
// 	}
// 	if (!((reg_val[0] == 0x02) && reg_val[1] == 0x19))
// 		dev_err(dev, "%s: invalid sensor model id: %x%x\n",
// 			__func__, reg_val[0], reg_val[1]);
// 
// 	/* Sensor fine integration time */
// 	err = imx219_get_fine_integ_time(priv, &priv->fine_integ_time);
// 	if (err)
// 		dev_err(dev, "%s: error querying sensor fine integ. time\n",
// 			__func__);

//err_reg_probe:
	imx219_power_off(s_data);

err_power_on:
	if (pdata->mclk_name)
		camera_common_mclk_disable(s_data);

done:
	return err;
}

static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);

	dev_dbg(&client->dev, "%s:\n", __func__);

	return 0;
}

static const struct v4l2_subdev_internal_ops imx219_subdev_internal_ops = {
	.open = imx219_open,
};

static int imx219_probe(struct i2c_client *client,
	const struct i2c_device_id *id)
{
	struct device *dev = &client->dev;
	struct tegracam_device *tc_dev;
	struct imx219 *priv;
	int err;

	dev_dbg(dev, "probing v4l2 sensor at addr 0x%0x\n", client->addr);

	if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
		return -EINVAL;

	priv = devm_kzalloc(dev,
			sizeof(struct imx219), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	tc_dev = devm_kzalloc(dev,
			sizeof(struct tegracam_device), GFP_KERNEL);
	if (!tc_dev)
		return -ENOMEM;

	priv->i2c_client = tc_dev->client = client;
	tc_dev->dev = dev;
	strncpy(tc_dev->name, "imx219", sizeof(tc_dev->name));
	tc_dev->dev_regmap_config = &sensor_regmap_config;
	tc_dev->sensor_ops = &imx219_common_ops;
	tc_dev->v4l2sd_internal_ops = &imx219_subdev_internal_ops;
	tc_dev->tcctrl_ops = &imx219_ctrl_ops;

	err = tegracam_device_register(tc_dev);
	if (err) {
		dev_err(dev, "tegra camera driver registration failed\n");
		return err;
	}
	priv->tc_dev = tc_dev;
	priv->s_data = tc_dev->s_data;
	priv->subdev = &tc_dev->s_data->subdev;
	tegracam_set_privdata(tc_dev, (void *)priv);

	err = imx219_board_setup(priv);
	if (err) {
		tegracam_device_unregister(tc_dev);
		dev_err(dev, "board setup failed\n");
		return err;
	}

	err = tegracam_v4l2subdev_register(tc_dev, true);
	if (err) {
		dev_err(dev, "tegra camera subdev registration failed\n");
		return err;
	}

	dev_dbg(dev, "detected imx219 sensor\n");

	return 0;
}

static int imx219_remove(struct i2c_client *client)
{
	struct camera_common_data *s_data = to_camera_common_data(&client->dev);
	struct imx219 *priv = (struct imx219 *)s_data->priv;

	tegracam_v4l2subdev_unregister(priv->tc_dev);
	tegracam_device_unregister(priv->tc_dev);

	return 0;
}

static const struct i2c_device_id imx219_id[] = {
	{ "imx219", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, imx219_id);

static struct i2c_driver imx219_i2c_driver = {
	.driver = {
		.name = "imx219",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(imx219_of_match),
	},
	.probe = imx219_probe,
	.remove = imx219_remove,
	.id_table = imx219_id,
};
module_i2c_driver(imx219_i2c_driver);

MODULE_DESCRIPTION("Media Controller driver for Sony IMX219");
MODULE_AUTHOR("NVIDIA Corporation");
MODULE_LICENSE("GPL v2");

/*
 * imx219_tables.h - sensor mode tables for imx219 HDR sensor.
 *
 * Copyright (c) 2015-2022, NVIDIA CORPORATION & AFFILIATES.All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __IMX219_I2C_TABLES__
#define __IMX219_I2C_TABLES__

#define IMX219_TABLE_WAIT_MS	0
#define IMX219_TABLE_END	1

#define imx219_reg struct reg_8

static imx219_reg imx219_start_stream[] = {
	{0x0100, 0x01},
	{IMX219_TABLE_WAIT_MS, 3},
	{IMX219_TABLE_END, 0x00}
};

static imx219_reg imx219_stop_stream[] = {
	{0x0100, 0x00},
	{IMX219_TABLE_END, 0x00}
};

static imx219_reg imx219_mode_common[] = {
	/* software reset */
	{0x0103, 0x01},
	{IMX219_TABLE_WAIT_MS, 10},
	/* sensor config */
	{0x0114, 0x01}, /* D-Phy, 2-lane */
	{0x0128, 0x00},
	{0x012A, 0x18}, /* 24 MHz INCK */
	{0x012B, 0x00},
	/* access code - vendor addr. ranges */
	{0x30EB, 0x05},
	{0x30EB, 0x0C},
	{0x300A, 0xFF},
	{0x300B, 0xFF},
	{0x30EB, 0x05},
	{0x30EB, 0x09},
	/* cis tuning */
	{0x455E, 0x00},
	{0x471E, 0x4B},
	{0x4767, 0x0F},
	{0x4750, 0x14},
	{0x4540, 0x00},
	{0x47B4, 0x14},
	{0x4713, 0x30},
	{0x478B, 0x10},
	{0x478F, 0x10},
	{0x4793, 0x10},
	{0x4797, 0x0E},
	{0x479B, 0x0E},
	{IMX219_TABLE_END, 0x00}
};

//static imx219_reg imx219_mode_3264x2464_21fps[] = {
//	/* capture settings */
//	{0x0157, 0x00}, /* ANALOG_GAIN_GLOBAL[7:0] */
//	{0x015A, 0x09}, /* COARSE_INTEG_TIME[15:8] */
//	{0x015B, 0xbd}, /* COARSE_INTEG_TIME[7:0] */
//	/* format settings */
//	{0x0160, 0x09}, /* FRM_LENGTH[15:8] */
//	{0x0161, 0xC1}, /* FRM_LENGTH[7:0] */
//	{0x0162, 0x0D}, /* LINE_LENGTH[15:8] */
//	{0x0163, 0x78}, /* LINE_LENGTH[7:0] */
//	{0x0164, 0x00},
//	{0x0165, 0x08},
//	{0x0166, 0x0C},
//	{0x0167, 0xC7},
//	{0x0168, 0x00},
//	{0x0169, 0x00},
//	{0x016A, 0x09},
//	{0x016B, 0x9F},
//	{0x016C, 0x0C},
//	{0x016D, 0xC0},
//	{0x016E, 0x09},
//	{0x016F, 0xA0},
//	{0x0170, 0x01},
//	{0x0171, 0x01},
//	{0x0174, 0x00},
//	{0x0175, 0x00},
//	{0x018C, 0x0A},
//	{0x018D, 0x0A},
//	{0x0264, 0x00},
//	{0x0265, 0x08},
//	{0x0266, 0x0C},
//	{0x0267, 0xC7},
//	{0x026C, 0x0C},
//	{0x026D, 0xC0},
//	/* clock dividers */
//	{0x0301, 0x05},
//	{0x0303, 0x01},
//	{0x0304, 0x03},
//	{0x0305, 0x03},
//	{0x0306, 0x00},
//	{0x0307, 0x39},
//	{0x0309, 0x0A},
//	{0x030B, 0x01},
//	{0x030C, 0x00},
//	{0x030D, 0x72},
//	{IMX219_TABLE_END, 0x00}
//};
//
//static imx219_reg imx219_mode_3264x1848_28fps[] = {
//	/* capture settings */
//	{0x0157, 0x00}, /* ANALOG_GAIN_GLOBAL[7:0] */
//	{0x015A, 0x07}, /* COARSE_INTEG_TIME[15:8] */
//	{0x015B, 0x55}, /* COARSE_INTEG_TIME[7:0] */
//	/* format settings */
//	{0x0160, 0x07}, /* FRM_LENGTH[15:8] */
//	{0x0161, 0x59}, /* FRM_LENGTH[7:0] */
//	{0x0162, 0x0D}, /* LINE_LENGTH[15:8] */
//	{0x0163, 0x78}, /* LINE_LENGTH[7:0] */
//	{0x0164, 0x00},
//	{0x0165, 0x08},
//	{0x0166, 0x0C},
//	{0x0167, 0xC7},
//	{0x0168, 0x01},
//	{0x0169, 0x34},
//	{0x016A, 0x08},
//	{0x016B, 0x6B},
//	{0x016C, 0x0C},
//	{0x016D, 0xC0},
//	{0x016E, 0x07},
//	{0x016F, 0x38},
//	{0x0170, 0x01},
//	{0x0171, 0x01},
//	{0x0174, 0x00},
//	{0x0175, 0x00},
//	{0x018C, 0x0A},
//	{0x018D, 0x0A},
//	{0x0264, 0x00},
//	{0x0265, 0x08},
//	{0x0266, 0x0C},
//	{0x0267, 0xC7},
//	{0x026C, 0x0C},
//	{0x026D, 0xC0},
//	/* clocks dividers */
//	{0x0301, 0x05},
//	{0x0303, 0x01},
//	{0x0304, 0x03},
//	{0x0305, 0x03},
//	{0x0306, 0x00},
//	{0x0307, 0x39},
//	{0x0309, 0x0A},
//	{0x030B, 0x01},
//	{0x030C, 0x00},
//	{0x030D, 0x72},
//	{IMX219_TABLE_END, 0x00}
//};
//
//static imx219_reg imx219_mode_1920x1080_30fps[] = {
//	/* capture settings */
//	{0x0157, 0x00}, /* ANALOG_GAIN_GLOBAL[7:0] */
//	{0x015A, 0x06}, /* COARSE_INTEG_TIME[15:8] */
//	{0x015B, 0xde}, /* COARSE_INTEG_TIME[7:0] */
//	/* format settings */
//	{0x0160, 0x06}, /* FRM_LENGTH[15:8] */
//	{0x0161, 0xE2}, /* FRM_LENGTH[7:0] */
//	{0x0162, 0x0D}, /* LINE_LENGTH[15:8] */
//	{0x0163, 0x78}, /* LINE_LENGTH[7:0] */
//	{0x0164, 0x02},
//	{0x0165, 0xA8},
//	{0x0166, 0x0A},
//	{0x0167, 0x27},
//	{0x0168, 0x02},
//	{0x0169, 0xB4},
//	{0x016A, 0x06},
//	{0x016B, 0xEB},
//	{0x016C, 0x07},
//	{0x016D, 0x80},
//	{0x016E, 0x04},
//	{0x016F, 0x38},
//	{0x0170, 0x01},
//	{0x0171, 0x01},
//	{0x0174, 0x00},
//	{0x0175, 0x00},
//	{0x018C, 0x0A},
//	{0x018D, 0x0A},
//	/* clocks dividers */
//	{0x0301, 0x05},
//	{0x0303, 0x01},
//	{0x0304, 0x03},
//	{0x0305, 0x03},
//	{0x0306, 0x00},
//	{0x0307, 0x39},
//	{0x0309, 0x0A},
//	{0x030B, 0x01},
//	{0x030C, 0x00},
//	{0x030D, 0x72},
//	{IMX219_TABLE_END, 0x00}
//};
//
//static imx219_reg imx219_mode_1640x1232_30fps[] = {
//	/* capture settings */
//	{0x0157, 0x00}, /* ANALOG_GAIN_GLOBAL[7:0] */
//	{0x015A, 0x06}, /* COARSE_INTEG_TIME[15:8] */
//	{0x015B, 0xA8}, /* COARSE_INTEG_TIME[7:0] */
//	/* format settings */
//	{0x0160, 0x06}, /* FRM_LENGTH[15:8] */
//	{0x0161, 0xE2}, /* FRM_LENGTH[7:0] */
//	{0x0162, 0x0D}, /* LINE_LENGTH[15:8] */
//	{0x0163, 0x78}, /* LINE_LENGTH[7:0] */
//	{0x0164, 0x00},
//	{0x0165, 0x00},
//	{0x0166, 0x0C},
//	{0x0167, 0xCF},
//	{0x0168, 0x00},
//	{0x0169, 0x00},
//	{0x016A, 0x09},
//	{0x016B, 0x9F},
//	{0x016C, 0x06},
//	{0x016D, 0x68},
//	{0x016E, 0x04},
//	{0x016F, 0xD0},
//	{0x0170, 0x01},
//	{0x0171, 0x01},
//	{0x0174, 0x01},
//	{0x0175, 0x01},
//	{0x018C, 0x0A},
//	{0x018D, 0x0A},
//	/* clocks dividers */
//	{0x0301, 0x05},
//	{0x0303, 0x01},
//	{0x0304, 0x03},
//	{0x0305, 0x03},
//	{0x0306, 0x00},
//	{0x0307, 0x39},
//	{0x0309, 0x0A},
//	{0x030B, 0x01},
//	{0x030C, 0x00},
//	{0x030D, 0x72},
//	{IMX219_TABLE_END, 0x00}
//};

static imx219_reg imx219_mode_1280x720_60fps[] = {
	/* capture settings */
	{0x0157, 0x00}, /* ANALOG_GAIN_GLOBAL[7:0] */
	{0x015A, 0x03}, /* COARSE_INTEG_TIME[15:8] */
	{0x015B, 0x6c}, /* COARSE_INTEG_TIME[7:0] */
	/* format settings */
	{0x0160, 0x03}, /* FRM_LENGTH[15:8] */
	{0x0161, 0x70}, /* FRM_LENGTH[7:0] */
	{0x0162, 0x0D}, /* LINE_LENGTH[15:8] */
	{0x0163, 0x78}, /* LINE_LENGTH[7:0] */
	{0x0164, 0x01},
	{0x0165, 0x68},
	{0x0166, 0x0B},
	{0x0167, 0x67},
	{0x0168, 0x02},
	{0x0169, 0x00},
	{0x016A, 0x07},
	{0x016B, 0x9F},
	{0x016C, 0x05},
	{0x016D, 0x00},
	{0x016E, 0x02},
	{0x016F, 0xD0},
	{0x0170, 0x01},
	{0x0171, 0x01},
	{0x0174, 0x01},
	{0x0175, 0x01},
	{0x018C, 0x0A},
	{0x018D, 0x0A},
	/* clocks dividers */
	{0x0301, 0x05},
	{0x0303, 0x01},
	{0x0304, 0x03},
	{0x0305, 0x03},
	{0x0306, 0x00},
	{0x0307, 0x39},
	{0x0309, 0x0A},
	{0x030B, 0x01},
	{0x030C, 0x00},
	{0x030D, 0x72},
	{IMX219_TABLE_END, 0x00}
};

/*
static imx219_reg imx219_mode_1280x720_120fps[] = {
	// capture settings
	{0x0157, 0x00}, // ANALOG_GAIN_GLOBAL[7:0]
	{0x015A, 0x01}, // COARSE_INTEG_TIME[15:8]
	{0x015B, 0x85}, // COARSE_INTEG_TIME[7:0]
	// format settings
	{0x0160, 0x01}, // FRM_LENGTH[15:8]
	{0x0161, 0x89}, // FRM_LENGTH[7:0]
	{0x0162, 0x0D}, // LINE_LENGTH[15:8]
	{0x0163, 0xE8}, // LINE_LENGTH[7:0]
	{0x0164, 0x01},
	{0x0165, 0x68},
	{0x0166, 0x0B},
	{0x0167, 0x67},
	{0x0168, 0x02},
	{0x0169, 0x00},
	{0x016A, 0x07},
	{0x016B, 0x9F},
	{0x016C, 0x05},
	{0x016D, 0x00},
	{0x016E, 0x02},
	{0x016F, 0xD0},
	{0x0170, 0x01},
	{0x0171, 0x01},
	{0x0174, 0x03},
	{0x0175, 0x03},
	{0x018C, 0x0A},
	{0x018D, 0x0A},
	// clocks dividers
	{0x0301, 0x05},
	{0x0303, 0x01},
	{0x0304, 0x03},
	{0x0305, 0x03},
	{0x0306, 0x00},
	{0x0307, 0x35},
	{0x0309, 0x0A},
	{0x030B, 0x01},
	{0x030C, 0x00},
	{0x030D, 0x66},
	{IMX219_TABLE_END, 0x00}
};
*/
enum {
// 	IMX219_MODE_3264x2464_21FPS,
// 	IMX219_MODE_3264x1848_28FPS,
// 	IMX219_MODE_1920x1080_30FPS,
// 	IMX219_MODE_1640x1232_30FPS,
	IMX219_MODE_1280x720_60FPS,

	IMX219_MODE_COMMON,
	IMX219_START_STREAM,
	IMX219_STOP_STREAM,
};

static imx219_reg *mode_table[] = {
// 	[IMX219_MODE_3264x2464_21FPS] = imx219_mode_3264x2464_21fps,
// 	[IMX219_MODE_3264x1848_28FPS] = imx219_mode_3264x1848_28fps,
// 	[IMX219_MODE_1920x1080_30FPS] = imx219_mode_1920x1080_30fps,
/*	[IMX219_MODE_1640x1232_30FPS] = imx219_mode_1640x1232_30fps,*/
	[IMX219_MODE_1280x720_60FPS] = imx219_mode_1280x720_60fps,

	[IMX219_MODE_COMMON]  = imx219_mode_common,
	[IMX219_START_STREAM]  = imx219_start_stream,
	[IMX219_STOP_STREAM]  = imx219_stop_stream,
};

static const int imx219_21fps[] = {
	21,
};

static const int imx219_28fps[] = {
	28,
};

static const int imx219_30fps[] = {
	30,
};

static const int imx219_60fps[] = {
	10,
};

/*
 * WARNING: frmfmt ordering need to match mode definition in
 * device tree!
 */
static const struct camera_common_frmfmt imx219_frmfmt[] = {
// 	{{3264, 2464},	imx219_21fps, 1, 0, IMX219_MODE_3264x2464_21FPS},
// 	/* Add modes with no device tree support after below */
// 	{{3264, 1848},	imx219_28fps, 1, 0, IMX219_MODE_3264x1848_28FPS},
// 	{{1920, 1080},	imx219_30fps, 1, 0, IMX219_MODE_1920x1080_30FPS},
// 	{{1640, 1232},	imx219_30fps, 1, 0, IMX219_MODE_1640x1232_30FPS},
	{{1024, 1024},	imx219_60fps, 1, 0, IMX219_MODE_1280x720_60FPS},
};

#endif /* __IMX219_I2C_TABLES__ */

hello 913775933,

according to developer guide, Verifying the V4L2 Sensor Driver.
are you able to execute v4l2 utility for testing the camera driver?

This seems to go back to the problem at the beginning, I have executed v4l2-ctl -d /dev/video1 --set-ctrl bypass_mode=0,sensor_mode=0 --stream-mmap --stream-count=10000000 --set-fmt-video=width=1024,height=1024,pixelformat=RG12 --verbose for image acquisition test, the test obviously failed, v4l2-ctl did not acquire any images, so I am asking for your help.

By executing command:

echo 1 > /sys/kernel/debug/tracing/tracing_on
echo 30720 > /sys/kernel/debug/tracing/buffer_size_kb
echo 1 > /sys/kernel/debug/tracing/events/tegra_rtcpu/enable
echo 1 > /sys/kernel/debug/tracing/events/freertos/enable
echo 2 > /sys/kernel/debug/camrtc/log-level
echo > /sys/kernel/debug/tracing/trace

and
cat /sys/kernel/debug/tracing/trace

I got the error message:

     kworker/1:1-733   [001] ....    72.579537: rtcpu_nvcsi_intr: tstamp:2598679819 class:GLOBAL type:PHY_INTR0 phy:0 cil:0 st:0 vc:0 status:0x00000010
     kworker/1:1-733   [001] ....    72.579537: rtcpu_nvcsi_intr: tstamp:2598679819 class:CORRECTABLE_ERR type:PHY_INTR phy:0 cil:0 st:0 vc:0 status:0x00000010

hello 913775933,

PHY_INTR = 0x10 means there’s Rx FIFO overflow failure.
since you’re having FPGA device to output the signaling, this might due to your FPGA configuration errors.

you may also dig into TRM for checking MIPI-CSI registers, PF_CRC and PH_WC.
those two registers can be used to check the errors for each packet. i.e. PH is the packet header and PF is packet footer.
you may also refer to TRM for the address offset,
for example, here’s commands to check stream-0, PH_WC, $ sudo ./busybox devmem 0x15a101dc
thanks

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.