IMX307 sensor driver for Jetson Nano 32.4.3

Hi all,
We are porting IMX307 sensor driver to Jetson Nano L4T 32.4.3
IMX307 is 1920x1080, 30 FPS, 4 lanes, 12bit
IMX307 works as master mode, it means the the master clock INCK of IMX307 is from an external oscillator(74.25MHZ)

The driver probes OK, We use following command to capture frame:
v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=RG12 --stream-mmap --stream-count=1 -d /dev/video0 --stream-to=1.raw
But the streaming fails.Attempt to get one frame enters into probably infinite loop with the following error messages:

[10194.466296] imx307 6-001a: imx307_start_streaming: start stream
[10194.478825] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 0
[10194.512285] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 1
[10194.580067] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 2
[10194.612573] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 4
[10194.679537] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 5
[10194.712510] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 7
[10194.746640] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 8
[10194.813202] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 9
[10194.879899] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 11
[10194.913219] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 13
[10194.979387] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 14
[10195.012316] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 16
[10195.079283] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 17
[10195.145877] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 19
[10195.179180] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 21
[10195.212870] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 22
[10195.279267] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 23
[10195.312868] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 25
[10195.379277] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 26
[10195.412583] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 28
[10195.480060] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 29
[10195.512735] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 31
[10195.545874] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 32
[10195.579541] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 33
[10195.612435] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 34
[10195.679975] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 35
[10195.712441] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 37
[10195.813183] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 38
[10195.845499] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 41
[10196.082801] video4linux video0: tegra_channel_capture_done: MW_ACK_DONE syncpoint time out!0
[10196.101994] vi 54080000.vi: TEGRA_CSI_PIXEL_PARSER_STATUS 0x00004015
[10196.102016] vi 54080000.vi: TEGRA_CSI_CIL_STATUS 0x00000000
[10196.102140] vi 54080000.vi: TEGRA_CSI_CILX_STATUS 0x00000000
[10196.102263] vi 54080000.vi: cil_settingtime was autocalculated
[10196.102291] vi 54080000.vi: csi clock settle time: 13, cil settle time: 10
[10196.102448] imx307 6-001a: imx307_stop_streaming: stop stream
[10196.178303] imx307 6-001a: imx307_power_off: power off

Here is our device tree for imx307

/*
 * Copyright (c) 2018-2019, NVIDIA CORPORATION.  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 as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that 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 <dt-bindings/media/camera.h>
#include <dt-bindings/platform/t210/t210.h>

/ {
	host1x {
		vi_base: vi {
			num-channels = <1>;
			ports {
				#address-cells = <1>;
				#size-cells = <0>;
				vi_port0: port@0 {
					reg = <0>;
					rbpcv2_imx307_vi_in0: endpoint {
						port-index = <0>;
						bus-width = <4>;
						remote-endpoint = <&rbpcv2_imx307_csi_out0>;
					};
				};
			};
		};

		csi_base: nvcsi {
			num-channels = <1>;
			#address-cells = <1>;
			#size-cells = <0>;
			csi_chan0: channel@0 {
				reg = <0>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					csi_chan0_port0: port@0 {
						reg = <0>;
						rbpcv2_imx307_csi_in0: endpoint@0 {
							port-index = <0>;
							bus-width = <4>;
							remote-endpoint = <&rbpcv2_imx307_out0>;
						};
					};
					csi_chan0_port1: port@1 {
						reg = <1>;
						rbpcv2_imx307_csi_out0: endpoint@1 {
							remote-endpoint = <&rbpcv2_imx307_vi_in0>;
						};
					};
				};
			};
		};

		i2c@546c0000 {
			imx307_single_cam0: rbpcv2_imx307_a@34 {
				compatible = "nvidia,imx307";
				/* I2C device address */
				reg = <0x1a>;

				/* V4L2 device node location */
				devnode = "video0";

				/* Physical dimensions of sensor */
				physical_w = "3.680";
				physical_h = "2.760";

				sensor_model = "imx307";

				use_sensor_mode_id = "true";
#if 0
				clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_3>;
				clock-names = "clk_out_3";
				clock-frequency = <24000000>;
				mclk = "clk_out_3";
#endif
				/**
				* ==== Modes ====
				* A modeX node is required to support v4l2 driver
				* implementation with NVIDIA camera software stack
				*
				* == Signal properties ==
				*
				* phy_mode = "";
				* PHY mode used by the MIPI lanes for this device
				*
				* tegra_sinterface = "";
				* CSI Serial interface connected to tegra
				* Incase of virtual HW devices, use virtual
				* For SW emulated devices, use host
				*
				* pix_clk_hz = "";
				* Sensor pixel clock used for calculations like exposure and framerate
				*
				* readout_orientation = "0";
				* Based on camera module orientation.
				* Only change readout_orientation if you specifically
				* Program a different readout order for this mode
				*
				* == Image format Properties ==
				*
				* active_w = "";
				* Pixel active region width
				*
				* active_h = "";
				* Pixel active region height
				*
				* pixel_t = "";
				* The sensor readout pixel pattern
				*
				* line_length = "";
				* Pixel line length (width) for sensor mode.
				*
				* == Source Control Settings ==
				*
				* Gain factor used to convert fixed point integer to float
				* Gain range [min_gain/gain_factor, max_gain/gain_factor]
				* Gain step [step_gain/gain_factor is the smallest step that can be configured]
				* Default gain [Default gain to be initialized for the control.
				*     use min_gain_val as default for optimal results]
				* Framerate factor used to convert fixed point integer to float
				* Framerate range [min_framerate/framerate_factor, max_framerate/framerate_factor]
				* Framerate step [step_framerate/framerate_factor is the smallest step that can be configured]
				* Default Framerate [Default framerate to be initialized for the control.
				*     use max_framerate to get required performance]
				* Exposure factor used to convert fixed point integer to float
				* For convenience use 1 sec = 1000000us as conversion factor
				* Exposure range [min_exp_time/exposure_factor, max_exp_time/exposure_factor]
				* Exposure step [step_exp_time/exposure_factor is the smallest step that can be configured]
				* Default Exposure Time [Default exposure to be initialized for the control.
				*     Set default exposure based on the default_framerate for optimal exposure settings]
				*
				* gain_factor = ""; (integer factor used for floating to fixed point conversion)
				* min_gain_val = ""; (ceil to integer)
				* max_gain_val = ""; (ceil to integer)
				* step_gain_val = ""; (ceil to integer)
				* default_gain = ""; (ceil to integer)
				* Gain limits for mode
				*
				* exposure_factor = ""; (integer factor used for floating to fixed point conversion)
				* min_exp_time = ""; (ceil to integer)
				* max_exp_time = ""; (ceil to integer)
				* step_exp_time = ""; (ceil to integer)
				* default_exp_time = ""; (ceil to integer)
				* Exposure Time limits for mode (sec)
				*
				* framerate_factor = ""; (integer factor used for floating to fixed point conversion)
				* min_framerate = ""; (ceil to integer)
				* max_framerate = ""; (ceil to integer)
				* step_framerate = ""; (ceil to integer)
				* default_framerate = ""; (ceil to integer)
				* Framerate limits for mode (fps)
				*
				* embedded_metadata_height = "";
				* Sensor embedded metadata height in units of rows.
				* If sensor does not support embedded metadata value should be 0.
				*/
				mode0 { /* IMX307_MODE_1920x1080_30FPS */
				#if 1
					//mclk_khz = "24000";
					mclk_khz = "74250";
					num_lanes = "4";
					tegra_sinterface = "serial_a";
					phy_mode = "DPHY";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";
					dynamic_pixel_bit_depth = "12";
					csi_pixel_bit_depth = "12";
					mode_type = "bayer";
					pixel_phase = "rggb";
					//pixel_t = "bayer_rggb";
					active_w = "1920";
					active_h = "1080";
					readout_orientation = "0";
					line_length = "1945";
					inherent_gain = "1";
					mclk_multiplier = "9.33";
					//pix_clk_hz = "110000000";
					pix_clk_hz = "74250000";

					gain_factor = "10";
					exposure_factor = "1000000";
					min_gain_val = "0";         /* 0dB */
					max_gain_val = "480";       /* 48dB */
					step_gain_val = "3";        /* 0.3 */
					default_gain = "0";
					min_hdr_ratio = "1";
					max_hdr_ratio = "1";
					framerate_factor = "1000000";
					min_framerate = "1500000";
					max_framerate = "30000000"; /* 30 */
					step_framerate = "1";
					default_framerate = "30000000"; /* 30.0 fps */
					min_exp_time = "30";        /* us */
					max_exp_time = "660000";    /* us */
					step_exp_time = "1";
					default_exp_time = "33334"; /* us */
					embedded_metadata_height = "0";
				#endif
				
				};


				ports {
					#address-cells = <1>;
					#size-cells = <0>;

					port@0 {
						reg = <0>;
						rbpcv2_imx307_out0: endpoint {
							port-index = <0>;
							bus-width = <4>;
							remote-endpoint = <&rbpcv2_imx307_csi_in0>;
						};
					};
				};
			};
		};
    };

	lens_imx307@RBPCV2 {
		min_focus_distance = "0.0";
		hyper_focal = "0.0";
		focal_length = "3.04";
		f_number = "2.0";
		aperture = "0.0";
	};
};

/ {
	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 = <12>;
		vi_peak_byte_per_pixel = <2>;
		vi_bw_margin_pct = <25>;
		max_pixel_rate = <34000>;
		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 = "porg_front_RBPCV2";
				position = "front";
				orientation = "1";
				cam_module0_drivernode0: drivernode0 {
					pcl_id = "v4l2_sensor";
					devname = "imx307 6-0010";
					proc-device-tree = "/proc/device-tree/host1x/i2c@546c0000/rbpcv2_imx307_a@34";
				};
				cam_module0_drivernode1: drivernode1 {
					pcl_id = "v4l2_lens";
					proc-device-tree = "/proc/device-tree/lens_imx307@RBPCV2/";
				};
			};
		};
	};
};

imx307.c

/*
 * imx307.c - imx307 sensor driver
 *
 * Copyright (c) 2015-2019, 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/imx307.h>

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

/* imx307 - sensor parameter limits */
#define IMX307_MIN_GAIN				0x00
#define IMX307_MAX_GAIN				0xff
#define IMX307_MIN_FRAME_LENGTH			0x0100
#define IMX307_MAX_FRAME_LENGTH			0xffff
#define IMX307_MIN_COARSE_EXPOSURE		0x0001
#define IMX307_MAX_COARSE_DIFF			0x0004

/* imx307 sensor register address */
#define IMX307_MODEL_ID_ADDR_MSB		0x0000
#define IMX307_MODEL_ID_ADDR_LSB		0x0001
#define IMX307_GAIN_ADDR			0x3014
#define IMX307_FRAME_LENGTH_ADDR_MSB		0x0160
#define IMX307_FRAME_LENGTH_ADDR_LSB		0x0161
#define IMX307_COARSE_INTEG_TIME_ADDR_MSB	0x015a
#define IMX307_COARSE_INTEG_TIME_ADDR_LSB	0x015b
#define IMX307_FINE_INTEG_TIME_ADDR_MSB		0x0388
#define IMX307_FINE_INTEG_TIME_ADDR_LSB		0x0389

static const struct of_device_id imx307_of_match[] = {
	{ .compatible = "nvidia,imx307", },
	{ },
};
MODULE_DEVICE_TABLE(of, imx307_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 imx307 {
	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 imx307_get_frame_length_regs(imx307_reg *regs,
	u32 frame_length)
{
	regs->addr = IMX307_FRAME_LENGTH_ADDR_MSB;
	regs->val = (frame_length >> 8) & 0xff;
	(regs + 1)->addr = IMX307_FRAME_LENGTH_ADDR_LSB;
	(regs + 1)->val = (frame_length) & 0xff;
}

static inline void imx307_get_coarse_integ_time_regs(imx307_reg *regs,
	u32 coarse_time)
{
	regs->addr = IMX307_COARSE_INTEG_TIME_ADDR_MSB;
	regs->val = (coarse_time >> 8) & 0xff;
	(regs + 1)->addr = IMX307_COARSE_INTEG_TIME_ADDR_LSB;
	(regs + 1)->val = (coarse_time) & 0xff;
}

static inline void imx307_get_gain_reg(imx307_reg *reg, u8 gain)
{
	reg->addr = IMX307_GAIN_ADDR;
	reg->val = gain & 0xff;
}

static inline int imx307_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 imx307_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 imx307_read_table(struct imx307 *priv, const imx307_reg table[])
{
	u8 reg_val[2];
	while(table->addr != IMX307_TABLE_END)
	{
		if(table->addr == IMX307_TABLE_WAIT_MS)
		{
			table++;
			continue;
		}
		imx307_read_reg(priv->s_data,table->addr,&reg_val[0]);
		printk("imx307 reg 0x%x  val 0x%02x\n",table->addr,reg_val[0]);
		table++;
	}
	return 0;
}
static int imx307_write_table(struct imx307 *priv, const imx307_reg table[])
{
	return regmap_util_write_table_8(priv->s_data->regmap, table, NULL, 0,
		IMX307_TABLE_WAIT_MS, IMX307_TABLE_END);
	
}

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


static int imx307_set_gain(struct tegracam_device *tc_dev, s64 val)
{
#if 0
	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;
	imx307_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 < IMX307_MIN_GAIN)
		gain = IMX307_MAX_GAIN;
	else if (gain > IMX307_MAX_GAIN)
		gain = IMX307_MAX_GAIN;

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

	imx307_get_gain_reg(&gain_reg, (u8)gain);
	err = imx307_write_reg(s_data, gain_reg.addr, gain_reg.val);
	if (err)
		dev_dbg(dev, "%s: gain control error\n", __func__);
#endif
	return 0;
}

static int imx307_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
#if 0
	struct camera_common_data *s_data = tc_dev->s_data;
	struct imx307 *priv = (struct imx307 *)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;
	imx307_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 < IMX307_MIN_FRAME_LENGTH)
		frame_length = IMX307_MIN_FRAME_LENGTH;
	else if (frame_length > IMX307_MAX_FRAME_LENGTH)
		frame_length = IMX307_MAX_FRAME_LENGTH;

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

	imx307_get_frame_length_regs(fl_regs, frame_length);
	for (i = 0; i < 2; i++) {
		err = imx307_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;
#endif
	return 0;
}

static int imx307_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
#if 0
	struct camera_common_data *s_data = tc_dev->s_data;
	struct imx307 *priv = (struct imx307 *)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;
	imx307_reg ct_regs[2];
	const s32 max_coarse_time = priv->frame_length - IMX307_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 < IMX307_MIN_COARSE_EXPOSURE)
		coarse_time = IMX307_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);

	imx307_get_coarse_integ_time_regs(ct_regs, coarse_time);

	for (i = 0; i < 2; i++) {
		err = imx307_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;
		}
	}
#endif
	return 0;
}

static struct tegracam_ctrl_ops imx307_ctrl_ops = {
	.numctrls = ARRAY_SIZE(ctrl_cid_list),
	.ctrl_cid_list = ctrl_cid_list,
	.set_gain = imx307_set_gain,
	.set_exposure = imx307_set_exposure,
	.set_frame_rate = imx307_set_frame_rate,
	.set_group_hold = imx307_set_group_hold,
};

static int imx307_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_info(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 imx307_avdd_fail;
	}

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

	if (pw->dvdd) {
		err = regulator_enable(pw->dvdd);
		if (err)
			goto imx307_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;

imx307_dvdd_fail:
	regulator_disable(pw->iovdd);

imx307_iovdd_fail:
	regulator_disable(pw->avdd);

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

	return -ENODEV;
}

static int imx307_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_info(dev, "%s: power off\n", __func__);
	return 0;

	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 imx307_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 imx307_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 *imx307_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(imx307_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 imx307_set_mode(struct tegracam_device *tc_dev)
{
	struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);
	struct camera_common_data *s_data = tc_dev->s_data;

	struct device *dev = tc_dev->dev;
	int err = 0;

	dev_info(dev, "%s: setmod  %d \n", __func__,s_data->mode);
	err = imx307_write_table(priv, mode_table[IMX307_MODE_COMMON]);
	if (err)
		return err;

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

	return 0;
}

static int imx307_start_streaming(struct tegracam_device *tc_dev)
{
	struct device *dev = tc_dev->dev;
	struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);

	dev_info(dev, "%s: start stream\n", __func__);
	return imx307_write_table(priv, mode_table[IMX307_START_STREAM]);
}

static int imx307_stop_streaming(struct tegracam_device *tc_dev)
{
	struct device *dev = tc_dev->dev;
	int err;
	struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);

	dev_info(dev, "%s: stop stream\n", __func__);
	err = imx307_write_table(priv, mode_table[IMX307_STOP_STREAM]);

	usleep_range(50000, 51000);

	return err;
}

static struct camera_common_sensor_ops imx307_common_ops = {
	.numfrmfmts = ARRAY_SIZE(imx307_frmfmt),
	.frmfmt_table = imx307_frmfmt,
	.power_on = imx307_power_on,
	.power_off = imx307_power_off,
	.write_reg = imx307_write_reg,
	.read_reg = imx307_read_reg,
	.parse_dt = imx307_parse_dt,
	.power_get = imx307_power_get,
	.power_put = imx307_power_put,
	.set_mode = imx307_set_mode,
	.start_streaming = imx307_start_streaming,
	.stop_streaming = imx307_stop_streaming,
};

static int imx307_board_setup(struct imx307 *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 = imx307_power_on(s_data);
	if (err) {
		dev_err(dev, "error during power on sensor (%d)\n", err);
		goto err_power_on;
	}


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

done:
	return err;
}

static int imx307_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 imx307_subdev_internal_ops = {
	.open = imx307_open,
};

static int imx307_probe(struct i2c_client *client,
	const struct i2c_device_id *id)
{
	struct device *dev = &client->dev;
	struct tegracam_device *tc_dev;
	struct imx307 *priv;
	int err;
#if 1 
	struct device_node *np= dev->of_node;
	do
	{
		printk("name %s     \n",np->name);
		printk("fame %s     \n",np->full_name);
		of_node_put(np);
	}while((np = of_get_next_parent(np)));
#endif
	dev_dbg(dev, "probing v4l2 sensor at addr 0x%0x\n", client->addr);
	dev_info(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 imx307), 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, "imx307", sizeof(tc_dev->name));
	tc_dev->dev_regmap_config = &sensor_regmap_config;
	tc_dev->sensor_ops = &imx307_common_ops;
	tc_dev->v4l2sd_internal_ops = &imx307_subdev_internal_ops;
	tc_dev->tcctrl_ops = &imx307_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 = imx307_board_setup(priv);
	if (err) {
		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_info(dev, "detected imx307 sensor\n");

	return 0;
}

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

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

	return 0;
}

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

static struct i2c_driver imx307_i2c_driver = {
	.driver = {
		.name = "imx307",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(imx307_of_match),
	},
	.probe = imx307_probe,
	.remove = imx307_remove,
	.id_table = imx307_id,
};
module_i2c_driver(imx307_i2c_driver);

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

imx307_mode_tbls.h

/*
 * imx307.c - imx307 sensor driver
 *
 * Copyright (c) 2015-2019, 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/imx307.h>

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

/* imx307 - sensor parameter limits */
#define IMX307_MIN_GAIN				0x00
#define IMX307_MAX_GAIN				0xff
#define IMX307_MIN_FRAME_LENGTH			0x0100
#define IMX307_MAX_FRAME_LENGTH			0xffff
#define IMX307_MIN_COARSE_EXPOSURE		0x0001
#define IMX307_MAX_COARSE_DIFF			0x0004

/* imx307 sensor register address */
#define IMX307_MODEL_ID_ADDR_MSB		0x0000
#define IMX307_MODEL_ID_ADDR_LSB		0x0001
#define IMX307_GAIN_ADDR			0x3014
#define IMX307_FRAME_LENGTH_ADDR_MSB		0x0160
#define IMX307_FRAME_LENGTH_ADDR_LSB		0x0161
#define IMX307_COARSE_INTEG_TIME_ADDR_MSB	0x015a
#define IMX307_COARSE_INTEG_TIME_ADDR_LSB	0x015b
#define IMX307_FINE_INTEG_TIME_ADDR_MSB		0x0388
#define IMX307_FINE_INTEG_TIME_ADDR_LSB		0x0389

static const struct of_device_id imx307_of_match[] = {
	{ .compatible = "nvidia,imx307", },
	{ },
};
MODULE_DEVICE_TABLE(of, imx307_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 imx307 {
	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 imx307_get_frame_length_regs(imx307_reg *regs,
	u32 frame_length)
{
	regs->addr = IMX307_FRAME_LENGTH_ADDR_MSB;
	regs->val = (frame_length >> 8) & 0xff;
	(regs + 1)->addr = IMX307_FRAME_LENGTH_ADDR_LSB;
	(regs + 1)->val = (frame_length) & 0xff;
}

static inline void imx307_get_coarse_integ_time_regs(imx307_reg *regs,
	u32 coarse_time)
{
	regs->addr = IMX307_COARSE_INTEG_TIME_ADDR_MSB;
	regs->val = (coarse_time >> 8) & 0xff;
	(regs + 1)->addr = IMX307_COARSE_INTEG_TIME_ADDR_LSB;
	(regs + 1)->val = (coarse_time) & 0xff;
}

static inline void imx307_get_gain_reg(imx307_reg *reg, u8 gain)
{
	reg->addr = IMX307_GAIN_ADDR;
	reg->val = gain & 0xff;
}

static inline int imx307_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 imx307_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 imx307_read_table(struct imx307 *priv, const imx307_reg table[])
{
	u8 reg_val[2];
	while(table->addr != IMX307_TABLE_END)
	{
		if(table->addr == IMX307_TABLE_WAIT_MS)
		{
			table++;
			continue;
		}
		imx307_read_reg(priv->s_data,table->addr,&reg_val[0]);
		printk("imx307 reg 0x%x  val 0x%02x\n",table->addr,reg_val[0]);
		table++;
	}
	return 0;
}
static int imx307_write_table(struct imx307 *priv, const imx307_reg table[])
{
	return regmap_util_write_table_8(priv->s_data->regmap, table, NULL, 0,
		IMX307_TABLE_WAIT_MS, IMX307_TABLE_END);
	
}

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


static int imx307_set_gain(struct tegracam_device *tc_dev, s64 val)
{
#if 0
	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;
	imx307_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 < IMX307_MIN_GAIN)
		gain = IMX307_MAX_GAIN;
	else if (gain > IMX307_MAX_GAIN)
		gain = IMX307_MAX_GAIN;

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

	imx307_get_gain_reg(&gain_reg, (u8)gain);
	err = imx307_write_reg(s_data, gain_reg.addr, gain_reg.val);
	if (err)
		dev_dbg(dev, "%s: gain control error\n", __func__);
#endif
	return 0;
}

static int imx307_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
#if 0
	struct camera_common_data *s_data = tc_dev->s_data;
	struct imx307 *priv = (struct imx307 *)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;
	imx307_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 < IMX307_MIN_FRAME_LENGTH)
		frame_length = IMX307_MIN_FRAME_LENGTH;
	else if (frame_length > IMX307_MAX_FRAME_LENGTH)
		frame_length = IMX307_MAX_FRAME_LENGTH;

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

	imx307_get_frame_length_regs(fl_regs, frame_length);
	for (i = 0; i < 2; i++) {
		err = imx307_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;
#endif
	return 0;
}

static int imx307_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
#if 0
	struct camera_common_data *s_data = tc_dev->s_data;
	struct imx307 *priv = (struct imx307 *)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;
	imx307_reg ct_regs[2];
	const s32 max_coarse_time = priv->frame_length - IMX307_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 < IMX307_MIN_COARSE_EXPOSURE)
		coarse_time = IMX307_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);

	imx307_get_coarse_integ_time_regs(ct_regs, coarse_time);

	for (i = 0; i < 2; i++) {
		err = imx307_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;
		}
	}
#endif
	return 0;
}

static struct tegracam_ctrl_ops imx307_ctrl_ops = {
	.numctrls = ARRAY_SIZE(ctrl_cid_list),
	.ctrl_cid_list = ctrl_cid_list,
	.set_gain = imx307_set_gain,
	.set_exposure = imx307_set_exposure,
	.set_frame_rate = imx307_set_frame_rate,
	.set_group_hold = imx307_set_group_hold,
};

static int imx307_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_info(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 imx307_avdd_fail;
	}

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

	if (pw->dvdd) {
		err = regulator_enable(pw->dvdd);
		if (err)
			goto imx307_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;

imx307_dvdd_fail:
	regulator_disable(pw->iovdd);

imx307_iovdd_fail:
	regulator_disable(pw->avdd);

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

	return -ENODEV;
}

static int imx307_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_info(dev, "%s: power off\n", __func__);
	return 0;

	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 imx307_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 imx307_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 *imx307_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(imx307_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 imx307_set_mode(struct tegracam_device *tc_dev)
{
	struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);
	struct camera_common_data *s_data = tc_dev->s_data;

	struct device *dev = tc_dev->dev;
	int err = 0;

	dev_info(dev, "%s: setmod  %d \n", __func__,s_data->mode);
	err = imx307_write_table(priv, mode_table[IMX307_MODE_COMMON]);
	if (err)
		return err;

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

	return 0;
}

static int imx307_start_streaming(struct tegracam_device *tc_dev)
{
	struct device *dev = tc_dev->dev;
	struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);

	dev_info(dev, "%s: start stream\n", __func__);
	return imx307_write_table(priv, mode_table[IMX307_START_STREAM]);
}

static int imx307_stop_streaming(struct tegracam_device *tc_dev)
{
	struct device *dev = tc_dev->dev;
	int err;
	struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);

	dev_info(dev, "%s: stop stream\n", __func__);
	err = imx307_write_table(priv, mode_table[IMX307_STOP_STREAM]);

	usleep_range(50000, 51000);

	return err;
}

static struct camera_common_sensor_ops imx307_common_ops = {
	.numfrmfmts = ARRAY_SIZE(imx307_frmfmt),
	.frmfmt_table = imx307_frmfmt,
	.power_on = imx307_power_on,
	.power_off = imx307_power_off,
	.write_reg = imx307_write_reg,
	.read_reg = imx307_read_reg,
	.parse_dt = imx307_parse_dt,
	.power_get = imx307_power_get,
	.power_put = imx307_power_put,
	.set_mode = imx307_set_mode,
	.start_streaming = imx307_start_streaming,
	.stop_streaming = imx307_stop_streaming,
};

static int imx307_board_setup(struct imx307 *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 = imx307_power_on(s_data);
	if (err) {
		dev_err(dev, "error during power on sensor (%d)\n", err);
		goto err_power_on;
	}


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

done:
	return err;
}

static int imx307_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 imx307_subdev_internal_ops = {
	.open = imx307_open,
};

static int imx307_probe(struct i2c_client *client,
	const struct i2c_device_id *id)
{
	struct device *dev = &client->dev;
	struct tegracam_device *tc_dev;
	struct imx307 *priv;
	int err;
#if 1 
	struct device_node *np= dev->of_node;
	do
	{
		printk("name %s     \n",np->name);
		printk("fame %s     \n",np->full_name);
		of_node_put(np);
	}while((np = of_get_next_parent(np)));
#endif
	dev_dbg(dev, "probing v4l2 sensor at addr 0x%0x\n", client->addr);
	dev_info(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 imx307), 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, "imx307", sizeof(tc_dev->name));
	tc_dev->dev_regmap_config = &sensor_regmap_config;
	tc_dev->sensor_ops = &imx307_common_ops;
	tc_dev->v4l2sd_internal_ops = &imx307_subdev_internal_ops;
	tc_dev->tcctrl_ops = &imx307_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 = imx307_board_setup(priv);
	if (err) {
		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_info(dev, "detected imx307 sensor\n");

	return 0;
}

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

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

	return 0;
}

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

static struct i2c_driver imx307_i2c_driver = {
	.driver = {
		.name = "imx307",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(imx307_of_match),
	},
	.probe = imx307_probe,
	.remove = imx307_remove,
	.id_table = imx307_id,
};
module_i2c_driver(imx307_i2c_driver);

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

Have check the REG CSI_CSI_PIXEL_PARSER_A_STATUS_0 in TRM for below error.

[10196.101994] vi 54080000.vi: TEGRA_CSI_PIXEL_PARSER_STATUS 0x00004015

Yes, we check the reg CSI_PIXE_PARSER_A_STATUS,
0x4015 means PPA_PL_CRC_ERR, PPA_SL_PROCESSED, PPA_HDR_ERR
we think there is no problem with the configs of IMX307, because we use imx307 in other platform with same configs, it can capture succeed.
So the problem is maybe hardware, the mipi signal is not good?

PPA_SL_PROCESSED tell short line that could be the output pixel doesn’t as expect.

PPA_SL_PROCESSED tell short line that could be the output pixel doesn’t as expect.

How can we fix the problems, we try to modify line_length, but it’s no useful
We can confirm the total output pixel perline of imx307 is 1948

Short line tell the output width less than 1920 you can modify the driver to report less to try.

Thanks your reply.
But I’m confused, How can we modify the driver to report less?
Should we modify output size register of imx307, if we decrease it,the real output width maybe less than now.
Or we decrease the line_length in dts, did the vi driver use this parameter? We check the kernel source, it seems only sensor driver use it .

Modify kernel driver to report less pixel like below structure.
And confirm the modification by v4l2-ctl --list-formats-ext

static const struct camera_common_frmfmt ov5693_frmfmt[] = {
        {{2592, 1944},  ov5693_30fps,   1, 0,   OV5693_MODE_2592X1944},
        {{2592, 1458},  ov5693_30fps,   1, 0,   OV5693_MODE_2592X1458},
        {{1280, 720},   ov5693_120fps,  1, 0,   OV5693_MODE_1280X720_120FPS},
};

I modify it, but it’s no useful
What else can we do?

Does the error value change when reduce the width? Did you try modify more like 1920 → 1280 to check the error?

I did this, the error no change

Does the error value change when reduce the width? Did you try modify more like 1920 → 1280 to check the error?

I think modify this is no useful, because this parameter is configure to vi controller, but now the problem is in csi module.

There is no update from you for a period, assuming this is not an issue any more.
Hence we are closing this topic. If need further support, please open a new one.
Thanks

Did you confirm by v4l2-ctl --list-formats-ext to confirm the modification.

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