AGX ORIN Camera Capture Issue

I’ve encountered an issue while developing a driver for a custom camera using the MIPI-CSI protocol for transmission. When I attempt to capture the stream using v4l2-ctl and gst-launch, it gets stuck on the initial few frames. I then utilized the following C program to invoke V4L2 for stream capture. In blocking mode, the program stalls after a certain number of frames (the number of frames that can be obtained depends on the size of the allocated buffers) at ret = ioctl(fd, VIDIOC_DQBUF, &readbuffer);. In non-blocking mode, it consistently returns ‘Resource Temporarily Unavailable’ after a few frames. However, when I add a 100ms delay with usleep(100000) after ret = ioctl(fd, VIDIOC_DQBUF, &readbuffer); in blocking mode, I can capture images continuously. Similarly, in non-blocking mode, by adding a delay and skipping the current ioctl(fd, VIDIOC_QBUF, &readbuffer); when ioctl(fd, VIDIOC_DQBUF, &readbuffer); returns -1, I can continuously acquire images, but after reading several frames, there is a significant occurrence of ‘Resource Temporarily Unavailable’. Is this situation related to the camera’s parameters and the driver? How should I adjust the camera parameters or the device driver?

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/fb.h>
#include <memory.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#define IMG_WIDTH 800
#define IMG_HEIGHT 600
#define BUFSIZE 5

#define NAME_SIZE (1024)

typedef struct write_img_param
{
    unsigned char *ptr;
    char *name;
    // int rbuff_idx;
} write_img_param;

void *write_img(void *args)
{
    write_img_param *param = (write_img_param *)args;
    char *name = param->name;
    unsigned char *mptr = (unsigned char *)param->ptr;
    // int index = param->rbuff_idx;
    FILE *file = fopen(name, "w+");

    // mptr[readbuffer.index]
    printf("img_name:%s\n", name);
    fwrite(mptr, sizeof(unsigned char), 2 * IMG_WIDTH * IMG_HEIGHT, file);

    fclose(file);
}
int main()
{

    int fd = open("/dev/video0", O_RDWR); //| O_NONBLOCK);
    if (fd < 0)
    {
        perror("Open video1:");
        return -1;
    }


    struct v4l2_fmtdesc v4fmt;
    v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    v4fmt.index = 1; // 0 MJPEG 1 YUYV
    int ret = ioctl(fd, VIDIOC_ENUM_FMT, &v4fmt);
    if (ret < 0)
    {
        perror("Get inf failed:");
        return -1;
    }
    printf("index:%d\n", v4fmt.index);
    printf("flags:%d\n", v4fmt.flags);
    printf("description:%s\n", v4fmt.description);
    unsigned char *p = (unsigned char *)(&v4fmt.pixelformat);
    printf("pixelformat:%c%c%c%c\n", p[0], p[1], p[2], p[3]);

   
    struct v4l2_format vfmt;
    vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    vfmt.fmt.pix.width = IMG_WIDTH;
    vfmt.fmt.pix.height = IMG_HEIGHT;
    vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 
    ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);
    if (ret < 0)
    {
        perror("Set format failed:");
        return -1;
    }
    memset(&vfmt, 0, sizeof(vfmt));
    vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(fd, VIDIOC_G_FMT, &vfmt);
    if (ret < 0)
    {
        perror("Get format failed:");
        return -1;
    }

    if (vfmt.fmt.pix.width == IMG_WIDTH && vfmt.fmt.pix.height == IMG_HEIGHT && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
    {
        printf("Set successful!\n");
    }
    else
    {
        printf("Set failed!\n");
        return -1;
    }

   
    struct v4l2_requestbuffers reqbuffer;
    reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuffer.count = BUFSIZE * 5;
    reqbuffer.memory = V4L2_MEMORY_MMAP;
    ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuffer);
    if (ret < 0)
    {
        perror("Request Queue space failed:");
        return -1;
    }


    struct v4l2_buffer mapbuffer;
    int i;
    unsigned char *mptr[BUFSIZE];
    unsigned int size[BUFSIZE];
    mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    for (i = 0; i < BUFSIZE; i++)
    {
        mapbuffer.index = i;
        ret = ioctl(fd, VIDIOC_QUERYBUF, &mapbuffer);
        if (ret < 0)
        {
            perror("Kernel space queue failed:");
            return -1;
        }
        mptr[i] = (unsigned char *)mmap(NULL, mapbuffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mapbuffer.m.offset);
        size[i] = mapbuffer.length;

        ret = ioctl(fd, VIDIOC_QBUF, &mapbuffer);
        if (ret < 0)
        {
            perror("Return failed:");
            return -1;
        }
    }


    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(fd, VIDIOC_STREAMON, &type);
    if (ret < 0)
    {
        perror("Start failed:");
        return -1;
    }

    unsigned char rgbdata[IMG_WIDTH * IMG_HEIGHT * 3];
    int index = 0;

    while (1)
    {
        // V4L2_BUF_FLAG_ERROR
        struct v4l2_buffer readbuffer;
        readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        readbuffer.memory = V4L2_MEMORY_MMAP;
        ret = ioctl(fd, VIDIOC_DQBUF, &readbuffer);
        printf("dqbuf:%d\n", ret);
        if (ret < 0)
        {
            perror("Capture failed :");
            printf("error code:%s\n", strerror(errno));
            // usleep(10000);
            continue;
        }


        char name[NAME_SIZE];
        snprintf(name, NAME_SIZE, "v4l2_ir_%d.yuv", index);

        printf("readbuffer.index:%d\n", readbuffer.index);
        printf("index:%d\n", index);

        write_img_param param; //(write_img_param *)malloc(sizeof(write_img_param));
        param.ptr = mptr[readbuffer.index];
        param.name = name;
        pthread_t thread_0;
        int status_0;
        status_0 = pthread_create(&thread_0, NULL, write_img, &param);
        pthread_join(thread_0, NULL);
        index++;
        usleep(100000);


        ret = ioctl(fd, VIDIOC_QBUF, &readbuffer);
        printf("qbuf:%d\n", ret);
        if (ret < 0)
        {
            perror("return failed:");
        }

        int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        ret = ioctl(fd, VIDIOC_STREAMON, &type);
        if (ret < 0)
        {
            perror("Start failed:");
            return -1;
        }
    }

    ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
    if (ret < 0)
    {
        perror("Stop failed:");
        return -1;
    }

    for (i = 0; i < 4; i++)
    {
        munmap(mptr[i], size[i]);
    }
    close(fd);
    return 0;
}

Below is my driver code, modified from the IMX307 code.

//cs_camera.c
#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 "cs_camera.h"

#define CREATE_TRACE_POINTS

#ifndef DEBUG_PRINTK
#define debug_printk(s , ... )
#define VEYE_TRACE 
#else
#define debug_printk printk
#define VEYE_TRACE printk("%s %s %d \n",__FILE__,__FUNCTION__,__LINE__);
#endif


static const struct of_device_id cs_imx307_of_match[] = {
	{ .compatible = "nvidia,cs_imx307",},
	{ },
};
MODULE_DEVICE_TABLE(of, cs_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_FUSE_ID,
	TEGRA_CAMERA_CID_HDR_EN,*/
	TEGRA_CAMERA_CID_SENSOR_MODE_ID,
};

struct cs_imx307 {
	struct i2c_client	*i2c_client;
	struct v4l2_subdev	*subdev;
	//u8 fuse_id[VEYE327_FUSE_ID_SIZE];
	u32				frame_length;
	s64 last_wdr_et_val;
	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 cs_imx307_get_frame_length_regs(cs307_reg *regs,
				u32 frame_length)
{
	/*regs->addr = VEYE327_FRAME_LENGTH_ADDR_MSB;
	regs->val = (frame_length >> 16) & 0x01;

	(regs + 1)->addr = VEYE327_FRAME_LENGTH_ADDR_MID;
	(regs + 1)->val = (frame_length >> 8) & 0xff;

	(regs + 2)->addr = VEYE327_FRAME_LENGTH_ADDR_LSB;
	(regs + 2)->val = (frame_length) & 0xff;*/
    VEYE_TRACE
    return ;
}

static inline void cs_imx307_get_coarse_time_regs_shs1(cs307_reg *regs,
				u32 coarse_time)
{
	/*regs->addr = VEYE327_COARSE_TIME_SHS1_ADDR_MSB;
	regs->val = (coarse_time >> 16) & 0x01;

	(regs + 1)->addr = VEYE327_COARSE_TIME_SHS1_ADDR_MID;
	(regs + 1)->val = (coarse_time >> 8) & 0xff;

	(regs + 2)->addr = VEYE327_COARSE_TIME_SHS1_ADDR_LSB;
	(regs + 2)->val = (coarse_time) & 0xff;*/
    VEYE_TRACE
    return ;
}

static inline void cs_imx307_get_coarse_time_regs_shs2(cs307_reg *regs,
				u32 coarse_time)
{
	/*regs->addr = VEYE327_COARSE_TIME_SHS2_ADDR_MSB;
	regs->val = (coarse_time >> 16) & 0x01;

	(regs + 1)->addr = VEYE327_COARSE_TIME_SHS2_ADDR_MID;
	(regs + 1)->val = (coarse_time >> 8) & 0xff;

	(regs + 2)->addr = VEYE327_COARSE_TIME_SHS2_ADDR_LSB;
	(regs + 2)->val = (coarse_time) & 0xff;*/
    VEYE_TRACE
    return;

}

static inline void cs_imx307_get_gain_reg(cs307_reg *regs,
				u8 gain)
{
	/*regs->addr = VEYE327_GAIN_ADDR;
	regs->val = (gain) & 0xff;*/
    VEYE_TRACE
    return;
}

//static int test_mode;
//module_param(test_mode, int, 0644);
static inline int cs_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;
    VEYE_TRACE
	return err;
}

static int cs_imx307_write_reg(struct camera_common_data *s_data,
				u16 addr, u8 val)
{
	int err;
	struct device *dev = s_data->dev;
	err = regmap_write(s_data->regmap, addr, val);
	if (err)
		dev_err(dev, "%s: i2c write failed, 0x%x = %x\n",
			__func__, addr, val);
    
    VEYE_TRACE
	return err;
}

static int cs_imx307_write_table(struct cs_imx307 *priv,
				const cs307_reg table[])
{
	struct camera_common_data *s_data = priv->s_data;
	return regmap_util_write_table_8(s_data->regmap,
					 table,
					 NULL, 0,
					 CS307_TABLE_WAIT_MS,
					 CS307_TABLE_END);
}

static int cs_imx307_set_group_hold(struct tegracam_device *tc_dev, bool val)
{
	/*struct camera_common_data *s_data = tc_dev->s_data;
	struct device *dev = tc_dev->dev;
	int err;

	err = veye327_write_reg(s_data,
				VEYE327_GROUP_HOLD_ADDR, val);
	if (err) {
		dev_dbg(dev,
			"%s: Group hold control error\n", __func__);
		return err;
	}*/
    VEYE_TRACE
	return 0;
}
#if 0
static int cs_imx307_set_gain(struct tegracam_device *tc_dev, s64 val)
{
    #if 0
	struct camera_common_data *s_data = tc_dev->s_data;
	struct cs_imx307 *priv = (struct cs_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];
	cs307_reg reg_list[1];
	int err;
	u8 gain;

	/* translate value */
	gain = (u8) (val * 160 / (48 * mode->control_properties.gain_factor));
	dev_dbg(dev, "%s:  gain reg: %d\n",  __func__, gain);

	cs_imx307_get_gain_reg(reg_list, gain);

	err = cs_imx307_write_reg(priv->s_data, reg_list[0].addr,
		 reg_list[0].val);
	if (err)
		goto fail;
    
	return 0;

fail:
	dev_dbg(dev, "%s: GAIN control error\n", __func__);
	return err;
    #endif
    VEYE_TRACE
    return 0;
}

static int cs_imx307_set_coarse_time(struct cs_imx307 *priv, s64 val)
{
    
	struct camera_common_data *s_data = priv->s_data;
	const struct sensor_mode_properties *mode =
		&s_data->sensor_props.sensor_modes[s_data->mode];
	struct device *dev = &priv->i2c_client->dev;
	cs307_reg reg_list[3];
	int err;
	u32 coarse_time_shs1;
	u32 reg_shs1;
	int i = 0;

	coarse_time_shs1 = mode->signal_properties.pixel_clock.val *
		val / mode->image_properties.line_length /
		mode->control_properties.exposure_factor;

	if (priv->frame_length == 0)
		priv->frame_length = CS307_MIN_FRAME_LENGTH;

	reg_shs1 = priv->frame_length - coarse_time_shs1 - 1;

	dev_dbg(dev, "%s: coarse1:%d, shs1:%d, FL:%d\n", __func__,
		 coarse_time_shs1, reg_shs1, priv->frame_length);

	cs_imx307_get_coarse_time_regs_shs1(reg_list, reg_shs1);

	for (i = 0; i < 3; i++) {
		err = cs_imx307_write_reg(priv->s_data, reg_list[i].addr,
			 reg_list[i].val);
		if (err)
			goto fail;
	}

	return 0;

fail:
	dev_dbg(dev, "%s: set coarse time error\n", __func__);
	return err;
    
    VEYE_TRACE
    return 0;
}
#endif
#if 0
static int cs_imx307_set_coarse_time_hdr(struct cs_imx307 *priv, s64 val)
{
	struct device *dev = &priv->i2c_client->dev;
	struct camera_common_data *s_data = priv->s_data;
	const struct sensor_mode_properties *mode =
		&s_data->sensor_props.sensor_modes[s_data->mode];
	cs307_reg reg_list_shs1[3];
	cs307_reg reg_list_shs2[3];
	u32 coarse_time_shs1;
	u32 coarse_time_shs2;
	u32 reg_shs1;
	u32 reg_shs2;
	int err;
	int i = 0;

	if (priv->frame_length == 0)
		priv->frame_length = CS307_MIN_FRAME_LENGTH;

	priv->last_wdr_et_val = val;

	/*WDR, update SHS1 as short ET, and SHS2 is 16x of short*/
	coarse_time_shs1 = mode->signal_properties.pixel_clock.val *
		val / mode->image_properties.line_length /
		mode->control_properties.exposure_factor / 16;
	if (coarse_time_shs1 < CS307_MIN_SHS1_1080P_HDR)
		coarse_time_shs1 = CS307_MIN_SHS1_1080P_HDR;
	if (coarse_time_shs1 > CS307_MAX_SHS1_1080P_HDR)
		coarse_time_shs1 = CS307_MAX_SHS1_1080P_HDR;

	coarse_time_shs2 = (coarse_time_shs1 - CS307_MIN_SHS1_1080P_HDR) * 16 +
				CS307_MIN_SHS2_1080P_HDR;

	reg_shs1 = priv->frame_length - coarse_time_shs1 - 1;
	reg_shs2 = priv->frame_length - coarse_time_shs2 - 1;

	cs_imx307_get_coarse_time_regs_shs1(reg_list_shs1, reg_shs1);
	cs_imx307_get_coarse_time_regs_shs2(reg_list_shs2, reg_shs2);

	dev_dbg(dev, "%s: coarse1:%d, shs1:%d, coarse2:%d, shs2: %d, FL:%d\n",
		__func__,
		 coarse_time_shs1, reg_shs1,
		 coarse_time_shs2, reg_shs2,
		 priv->frame_length);

	for (i = 0; i < 3; i++) {
		err = cs_imx307_write_reg(priv->s_data, reg_list_shs1[i].addr,
			 reg_list_shs1[i].val);
		if (err)
			goto fail;

		err = cs_imx307_write_reg(priv->s_data, reg_list_shs2[i].addr,
			 reg_list_shs2[i].val);
		if (err)
			goto fail;
	}
	return 0;

fail:
	dev_dbg(dev, "%s: set WDR coarse time error\n", __func__);
	return err;
    
    VEYE_TRACE
    return 0;
}


static int cs_imx307_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
    //debug_printk("veye327_set_frame_rate want set rate %d\n",val);
    #if 0
	struct camera_common_data *s_data = tc_dev->s_data;
	struct cs_imx307 *priv = (struct cs_imx307 *)tc_dev->priv;
	struct device *dev = tc_dev->dev;
	cs307_reg reg_list[3];
	int err;
	u32 frame_length;
	const struct sensor_mode_properties *mode =
		&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
	struct v4l2_control control;
	int hdr_en;
	int i = 0;

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

	priv->frame_length = frame_length;
	if (priv->frame_length > CS307_MAX_FRAME_LENGTH)
		priv->frame_length = CS307_MAX_FRAME_LENGTH;

	dev_dbg(dev, "%s: val: %lld, , frame_length: %d\n", __func__,
		val, priv->frame_length);

	cs_imx307_get_frame_length_regs(reg_list, priv->frame_length);

	for (i = 0; i < 3; i++) {
		err = cs_imx307_write_reg(priv->s_data, reg_list[i].addr,
			 reg_list[i].val);
		if (err)
			goto fail;
	}
    
	/* check hdr enable ctrl */
    /*
	control.id = TEGRA_CAMERA_CID_HDR_EN;
	err = camera_common_g_ctrl(s_data, &control);
	if (err < 0) {
		dev_err(dev, "could not find device ctrl.\n");
		return err;
	}

	hdr_en = switch_ctrl_qmenu[control.value];
	if ((hdr_en == SWITCH_ON) && (priv->last_wdr_et_val != 0)) {
		err = cs_imx307_set_coarse_time_hdr(priv, priv->last_wdr_et_val);
		if (err)
			dev_dbg(dev,
			"%s: error coarse time SHS1 SHS2 override\n", __func__);
	}
    */
	return 0;

fail:
	dev_dbg(dev, "%s: FRAME_LENGTH control error\n", __func__);
	return err;
    #endif
    VEYE_TRACE
    return 0;
}

static int cs_imx307_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
    #if 0
	struct camera_common_data *s_data = tc_dev->s_data;
	struct cs_imx307 *priv = (struct cs_imx307 *)tc_dev->priv;
	struct device *dev = tc_dev->dev;
	int err;
	struct v4l2_control control;
	int hdr_en;

	dev_dbg(dev, "%s: val: %lld\n", __func__, val);

	/* check hdr enable ctrl */
	control.id = TEGRA_CAMERA_CID_HDR_EN;
	err = camera_common_g_ctrl(s_data, &control);
	if (err < 0) {
		dev_err(dev, "could not find device ctrl.\n");
		return err;
	}

	hdr_en = switch_ctrl_qmenu[control.value];
	if (hdr_en == SWITCH_ON) {
		err = cs_imx307_set_coarse_time_hdr(priv, val);
		if (err)
			dev_dbg(dev,
			"%s: error coarse time SHS1 SHS2 override\n", __func__);
	} else {
		err = cs_imx307_set_coarse_time(priv, val);
		if (err)
			dev_dbg(dev,
			"%s: error coarse time SHS1 override\n", __func__);
	}

	return err;
    VEYE_TRACE
     #endif
    return 0;
}
#endif
static int cs_imx307_fill_string_ctrl(struct tegracam_device *tc_dev,
				struct v4l2_ctrl *ctrl)
{
    #if 0
	struct cs_imx307 *priv = tc_dev->priv;
	int i;

	switch (ctrl->id) {
	case TEGRA_CAMERA_CID_FUSE_ID:
		for (i = 0; i < CS307_FUSE_ID_SIZE; i++)
			sprintf(&ctrl->p_new.p_char[i*2], "%02x",
				priv->fuse_id[i]);
		break;
	default:
		return -EINVAL;
	}

	ctrl->p_cur.p_char = ctrl->p_new.p_char;
    #endif
    VEYE_TRACE
	return 0;
}

static struct tegracam_ctrl_ops cs_imx307_ctrl_ops = {
	.numctrls = ARRAY_SIZE(ctrl_cid_list),
	.ctrl_cid_list = ctrl_cid_list,
	//.string_ctrl_size = {0, CS307_FUSE_ID_STR_SIZE},
    //delete for jetpack 4.5
	//.set_gain = cs_imx307_set_gain,
	//.set_exposure = cs_imx307_set_exposure,
	//.set_frame_rate = cs_imx307_set_frame_rate,
	.set_group_hold = cs_imx307_set_group_hold,
	.fill_string_ctrl = cs_imx307_fill_string_ctrl,
};

static int cs_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;

    pw->state = SWITCH_ON;
    VEYE_TRACE
	return 0;
    
	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;
	}

	/*exit reset mode: XCLR */
	if (pw->reset_gpio) {
		gpio_set_value(pw->reset_gpio, 0);
		usleep_range(30, 50);
		gpio_set_value(pw->reset_gpio, 1);
		usleep_range(30, 50);
	}

	pw->state = SWITCH_ON;
    VEYE_TRACE
	return 0;

}

static int cs_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;

    pw->state = SWITCH_OFF;
    VEYE_TRACE
	return 0;
    
	dev_dbg(dev, "%s: power off\n", __func__);

	if (pdata && pdata->power_off) {
		err = pdata->power_off(pw);
		if (!err)
			goto power_off_done;
		else
			dev_err(dev, "%s failed.\n", __func__);
		return err;
	}
	/* enter reset mode: XCLR */
	usleep_range(1, 2);
	if (pw->reset_gpio)
		gpio_set_value(pw->reset_gpio, 0);

power_off_done:
	pw->state = SWITCH_OFF;
    VEYE_TRACE
	return 0;
}

static int cs_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;
	const char *mclk_name;
	struct clk *parent;
	int err = 0;
    if(pdata->mclk_name)
    {
        mclk_name = pdata->mclk_name ?
                pdata->mclk_name : "extperiph1";
        pw->mclk = devm_clk_get(dev, mclk_name);
        if (IS_ERR(pw->mclk)) {
            dev_err(dev, "unable to get clock %s\n", mclk_name);
            return PTR_ERR(pw->mclk);
        }
        parent = devm_clk_get(dev, "pllp_grtba");
        if (IS_ERR(parent))
            dev_err(dev, "devm_clk_get failed for pllp_grtba");
        else
            clk_set_parent(pw->mclk, parent);
    }
	pw->reset_gpio = pdata->reset_gpio;

	pw->state = SWITCH_OFF;
    VEYE_TRACE
	return err;
}

static int cs_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;
    VEYE_TRACE
	return 0;
}

static struct camera_common_pdata *cs_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;
	//int gpio;

	if (!np)
		return NULL;

	match = of_match_device(cs_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;*/
    //no reset gpio
    board_priv_pdata->reset_gpio = 0;
    
	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");
    VEYE_TRACE
	return board_priv_pdata;

/*error:
	devm_kfree(dev, board_priv_pdata);
	return ret;*/
}

static int cs_imx307_set_mode(struct tegracam_device *tc_dev)
{
	struct cs_imx307 *priv = (struct cs_imx307 *)tegracam_get_privdata(tc_dev);
	struct camera_common_data *s_data = tc_dev->s_data;
	struct device *dev = tc_dev->dev;
	struct device_node *np = dev->of_node;
	bool limit_analog_gain = false;
	const struct of_device_id *match;
	int err;

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

	limit_analog_gain = of_property_read_bool(np, "limit_analog_gain");
    
	err = cs_imx307_write_table(priv, mode_table[s_data->mode_prop_idx]);
	if (err)
		return err;

	/*if (limit_analog_gain) {
		err = veye327_write_reg(priv->s_data,
			CS307_ANALOG_GAIN_LIMIT_ADDR,
			CS307_ANALOG_GAIN_LIMIT_VALUE);
		if (err)
			return err;
	}*/
    VEYE_TRACE
	return 0;
}

static int cs_imx307_start_streaming(struct tegracam_device *tc_dev)
{
	struct cs_imx307 *priv = (struct cs_imx307 *)tegracam_get_privdata(tc_dev);
	int err;

	/*if (test_mode) {
		err = veye327_write_table(priv,
			mode_table[CS307_MODE_TEST_PATTERN]);
		if (err)
			return err;
	}*/

	err = cs_imx307_write_table(priv,
		mode_table[CS307_MODE_START_STREAM]);
	if (err)
		return err;
    VEYE_TRACE
	return 0;
}

static int cs_imx307_stop_streaming(struct tegracam_device *tc_dev)
{
	//struct camera_common_data *s_data = tc_dev->s_data;
	struct cs_imx307 *priv = (struct cs_imx307 *)tegracam_get_privdata(tc_dev);
	int err;

	err = cs_imx307_write_table(priv, mode_table[CS307_MODE_STOP_STREAM]);
	if (err)
		return err;

	/* SW_RESET will have no ACK */
	//veye327_write_reg(s_data, CS307_SW_RESET_ADDR, 0x01);

	/*
	 * Wait for one frame to make sure sensor is set to
	 * software standby in V-blank
	 *
	 * delay = frame length rows * Tline (10 us)
	 */
	usleep_range(priv->frame_length * 10, priv->frame_length * 10 + 1000);
    VEYE_TRACE
	return 0;
}


static struct camera_common_sensor_ops cs_imx307_common_ops = {
	.numfrmfmts = ARRAY_SIZE(cs_imx307_frmfmt),
	.frmfmt_table = cs_imx307_frmfmt,
	.power_on = cs_imx307_power_on,
	.power_off = cs_imx307_power_off,
	.write_reg = cs_imx307_write_reg,
	.read_reg = cs_imx307_read_reg,
	.parse_dt = cs_imx307_parse_dt,
	.power_get = cs_imx307_power_get,
	.power_put = cs_imx307_power_put,
	.set_mode = cs_imx307_set_mode,
	.start_streaming = cs_imx307_start_streaming,
	.stop_streaming = cs_imx307_stop_streaming,
};

static int cs_imx307_fuse_id_setup(struct cs_imx307 *priv)
{
    //读一下id试试?
    # if 0
	int err;
	int i;
	struct camera_common_data *s_data = priv->s_data;
	struct device *dev = s_data->dev;
	u8 bak = 0;

	for (i = 0; i < CS307_FUSE_ID_SIZE; i++) {
		err |= cs_imx307_read_reg(s_data,
			CS307_FUSE_ID_ADDR + i, &bak);
		if (!err)
			priv->fuse_id[i] = bak;
		else {
			dev_err(dev, "%s: can not read fuse id\n", __func__);
			return -EINVAL;
		}
	}
    #endif
    VEYE_TRACE
	return 0;
}

static int cs_imx307_board_setup(struct cs_imx307 *priv)
{
	struct camera_common_data *s_data = priv->s_data;
	struct device *dev = s_data->dev;
    //struct camera_common_pdata *pdata = s_data->pdata;
	int err = 0;
    u8 reg_val[2];
   // u16 cameraid = 0;
	dev_dbg(dev, "%s++\n", __func__);

	err = camera_common_mclk_enable(s_data);
/*
	if (err) {
		dev_err(dev,
			"Error %d turning on mclk\n", err);
		return err;
	}
*/
	err = cs_imx307_power_on(s_data);
/*
	if (err) {
		dev_err(dev,
			"Error %d during power on sensor\n", err);
		return err;
	}
*/

	err = cs_imx307_fuse_id_setup(priv);
/*	
	if (err) {
		dev_err(dev,
			"Error %d reading fuse id data\n", err);
		goto err_power_on;
	}
*/

	/* Probe sensor model id registers */
	err = cs_imx307_read_reg(s_data, PRODUCTID_L, &reg_val[0]);
/*
	if (err) {
		dev_err(dev, "%s: error during i2c read probe (%d)\n",
			__func__, err);
		goto err_reg_probe;
	}
*/
     err = cs_imx307_read_reg(s_data, PRODUCTID_H, &reg_val[1]);
/*
    if (err) {
		dev_err(dev, "%s: error during i2c read probe (%d)\n",
			__func__, err);
		goto err_reg_probe;
	}

    cameraid = ((u16)reg_val[1]<<8) + reg_val[0];
	dev_err(dev,"read sensor id %04x \n", cameraid);

	if (cameraid == CS_MIPI_IMX307) 
    {
        err = 0;
        dev_err(dev, " camera id is cs-mipi-imx307\n");
    }
    else
    {
        err = -ENODEV;
		dev_err(dev, "%s: invalid sensor model id: %d\n",
			__func__, cameraid);
    }
    VEYE_TRACE


err_reg_probe:
	cs_imx307_power_off(s_data);

err_power_on:
	if (pdata->mclk_name)
        camera_common_mclk_disable(s_data);
*/
	//return err;
	return 0;
}

static int cs_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__);
    VEYE_TRACE
	return 0;
}

static const struct v4l2_subdev_internal_ops cs_imx307_subdev_internal_ops = {
	.open = cs_imx307_open,
};

static int cs_imx307_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct device *dev = &client->dev;
	struct tegracam_device *tc_dev;
	struct cs_imx307 *priv;
	int err;
	dev_info(dev, "probing v4l2 sensor\n");
    VEYE_TRACE
	if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
		return -EINVAL;

	priv = devm_kzalloc(dev,
			sizeof(struct cs_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, "csx307", sizeof(tc_dev->name));
	tc_dev->dev_regmap_config = &sensor_regmap_config;
	tc_dev->sensor_ops = &cs_imx307_common_ops;
	tc_dev->v4l2sd_internal_ops = &cs_imx307_subdev_internal_ops;
	tc_dev->tcctrl_ops = &cs_imx307_ctrl_ops;

	err = tegracam_device_register(tc_dev);
	if (err) {
		dev_err(dev, "tegra camera driver registration failed %d\n",err);
		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 = cs_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 CS307 sensor\n");

	return 0;
}

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

	tegracam_v4l2subdev_unregister(priv->tc_dev);
	tegracam_device_unregister(priv->tc_dev);
    VEYE_TRACE
	return 0;
}

static const struct i2c_device_id cs_imx307_id[] = {
	{ "csx307", 0 },
	{ }
};

MODULE_DEVICE_TABLE(i2c, cs_imx307_id);

static struct i2c_driver cs_imx307_i2c_driver = {
	.driver = {
		.name = "csx307",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(cs_imx307_of_match),
	},
	.probe = cs_imx307_probe,
	.remove = cs_imx307_remove,
	.id_table = cs_imx307_id,
};

module_i2c_driver(cs_imx307_i2c_driver);

MODULE_DESCRIPTION("");
MODULE_AUTHOR("");
MODULE_LICENSE("GPL v2");
/*
 * cs307.h - cs307 sensor mode tables
 *
 * Copyright (c) 2016-2017, 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/>.
 */
#ifndef __CSIMX307_I2C_TABLES__
#define __CSIMX307_I2C_TABLES__

#include <media/camera_common.h>
#include <linux/miscdevice.h>

#define CS307_TABLE_WAIT_MS	0
#define CS307_TABLE_END	1
#define CS307_MAX_RETRIES	3
#define CS307_WAIT_MS_STOP	1
#define CS307_WAIT_MS_START	30

#define CS307_WAIT_MS_CMD	5
#define CS307_WAIT_MS_STREAM	5


#define CS307_GAIN_TABLE_SIZE 255

/* #define INIT_ET_INSETTING 1 */

#define cs307_reg struct reg_8

typedef enum 
{
	CS_MIPI_IMX307 = 0x0037,	
	CS_LVDS_IMX307 = 0x0038,	
	CS_USB_IMX307 = 0x0039,	
	CS_MIPI_SC132 = 0x0132,	
	CS_LVDS_SC132 = 0x0133,	
	CS_USB_SC132 = 0x0134
}ENProductID;

typedef enum
{
    deviceID = 0x00,
    HardWare = 0x01,
    LoadingDone = 0x02,

    Csi2_Enable = 0x03,
    Fpga_CAP_L = 0x04,
    Fpga_CAP_H = 0x05,
    
    TriggerMode = 0x10,
    SlaveMode = 0x11,
    TrigDly_H = 0x12,
    TrigDly_M = 0x13,
    TrigDly_U = 0x14,
    TrigDly_L = 0x15,
    VerTotalTime_H = 0x16,
    VerTotalTime_L = 0x17,
    HorTotalTime_H = 0x18,
    HorTotalTime_L = 0x19,
    
    ARM_VER_L = 0x0100,
    ARM_VER_H = 0x0101,
    PRODUCTID_L = 0x0102,
    PRODUCTID_H = 0x0103,
    SYSTEM_RESET = 0x0104,
    PARAM_SAVE = 0x0105,
    VIDEOFMT_CAP = 0x0106, 
    
    VIDEOFMT_NUM = 0x0107,

    FMTCAP_WIDTH_L = 0x0108,
    FMTCAP_WIDTH_H = 0x0109,
    FMTCAP_HEIGHT_L = 0x010A,
    FMTCAP_HEIGHT_H = 0x010B,
    FMTCAP_FRAMRAT_L = 0x010C,
    FMTCAP_FRAMRAT_H = 0x010D,
    
    FMT_WIDTH_L = 0x0180,
    FMT_WIDTH_H = 0x0181,
    FMT_HEIGHT_L = 0x0182,
    FMT_HEIGHT_H = 0x0183,
    FMT_FRAMRAT_L = 0x0184,
    FMT_FRAMRAT_H = 0x0185,
    IMAGE_DIR = 0x0186,
    SYSTEM_REBOOT = 0x0187,
    NEW_FMT_FRAMRAT_MODE = 0x0188,
    NEW_FMT_FRAMRAT_L = 0x0189,
    NEW_FMT_FRAMRAT_H = 0x018A,
    
    EXP_FRM_MODE = 0x020F,
    AE_MODE = 0x0210,
    EXP_TIME_L = 0x0211,
    EXP_TIME_M = 0x0212,
    EXP_TIME_H = 0x0213,
    EXP_TIME_E = 0x0214,

    AGAIN_NOW_DEC = 0x0215,
    AGAIN_NOW_INTER = 0x0216,
    DGAIN_NOW_DEC = 0x0217,
    DGAIN_NOW_INTER = 0x0218,

    AE_SPEED = 0x0219,
    AE_TARGET = 0x021A,
    AE_MAXTIME_L = 0x021B,
    AE_MAXTIME_M = 0x021C,
    AE_MAXTIME_H = 0x021D,
    AE_MAXTIME_E = 0x021E,
    AE_MAXGAIN_DEC = 0x021F,
    AE_MAXGAIN_INTER = 0x0220,
    //ISP cap
    ISP_CAP_L = 0x0200,
    ISP_CAP_M = 0x0201,
    ISP_CAP_H = 0x0202,
    ISP_CAP_E = 0x0203,
    POWER_HZ = 0x0204,
}ECAMERA_REG;

static cs307_reg cs307_start[] = {
	//{CS307_TABLE_WAIT_MS, CS307_WAIT_MS_START},

};

static cs307_reg cs307_stop[] = {
	//{CS307_TABLE_WAIT_MS, CS307_WAIT_MS_STOP},

};

//video format capbility
//will check the format if supported later
/* Stream and Control Info Struct */
typedef struct _isp_stream_info {
	uint16_t width;
	uint16_t height;
	uint8_t frame_rate;
} ISP_STREAM_INFO;

struct cs_imx307_private {
	u16 module_id;
	int num_streams;
	ISP_STREAM_INFO *stream_info;
};

static cs307_reg cs307_reg_1920x1080_30fps[] = {
/*
    {FMT_WIDTH_L,0x80},
    {FMT_WIDTH_H,0x7},
    {CS307_TABLE_WAIT_MS, CS307_WAIT_MS_CMD},
    {FMT_HEIGHT_L,0x38},
    {FMT_HEIGHT_H,0x4},
    {CS307_TABLE_WAIT_MS, CS307_WAIT_MS_CMD},
    {FMT_FRAMRAT_L,0x1E},
    {FMT_FRAMRAT_H,0x00},
    {CS307_TABLE_WAIT_MS, CS307_WAIT_MS_STREAM},
	{CS307_TABLE_END, 0x00}
*/
};



enum {
	CS307_MODE_1920X1080_30FPS,
	CS307_MODE_START_STREAM,
	CS307_MODE_STOP_STREAM,
	//IMX307_MODE_TEST_PATTERN
};

static cs307_reg *mode_table[] = {
	[CS307_MODE_1920X1080_30FPS] = cs307_reg_1920x1080_30fps,

	[CS307_MODE_START_STREAM] = cs307_start,
	[CS307_MODE_STOP_STREAM] = cs307_stop,
	//[IMX307_MODE_TEST_PATTERN] = tp_colorbars,
};

static const int camera_fps[] = {
        //20,
        50,
};


/*
 * WARNING: frmfmt ordering need to match mode definition in
 * device tree!
 */
 
static const struct camera_common_frmfmt cs_imx307_frmfmt[] = {
    {   { 800, 600}, camera_fps,
        ARRAY_SIZE(camera_fps), 0, 0
    },


};


#endif /* __CSIMX307_I2C_TABLES__ */

/*
 * sensor_common.c - utilities for tegra sensor drivers
 *
 * Copyright (c) 2017-2022, 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 <media/sensor_common.h>
#include <linux/of_graph.h>
#include <linux/string.h>

static int read_property_u32(
	struct device_node *node, const char *name, u32 *value)
{
	const char *str;
	int err = 0;

	err = of_property_read_string(node, name, &str);
	if (err)
		return -ENODATA;

	err = kstrtou32(str, 10, value);
	if (err)
		return -EFAULT;

	return 0;
}

static int read_property_u64(
	struct device_node *node, const char *name, u64 *value)
{
	const char *str;
	int err = 0;

	err = of_property_read_string(node, name, &str);
	if (err)
		return -ENODATA;

	err = kstrtou64(str, 10, value);
	if (err)
		return -EFAULT;

	return 0;
}

static int sensor_common_parse_signal_props(
	struct device *dev, struct device_node *node,
	struct sensor_signal_properties *signal)
{
	const char *temp_str;
	int err = 0;
	u32 value = 0;
	u64 val64 = 0;
	u64 rate;
	int depth;

	err = of_property_read_string(node, "phy_mode", &temp_str);
	if (err) {
		dev_dbg(dev, "%s: use default phy mode DPHY\n", __func__);
		signal->phy_mode = CSI_PHY_MODE_DPHY;
	} else {
		if (strcmp(temp_str, "CPHY") == 0)
			signal->phy_mode = CSI_PHY_MODE_CPHY;
		else if (strcmp(temp_str, "DPHY") == 0)
			signal->phy_mode = CSI_PHY_MODE_DPHY;
		else if (strcmp(temp_str, "SLVS") == 0)
			signal->phy_mode = SLVS_EC;
		else {
			dev_err(dev, "%s: Invalid Phy mode\n", __func__);
			return -EINVAL;
		}
	}

	/* Do not report error for these properties yet */
	err = read_property_u32(node, "readout_orientation", &value);
	if (err)
		signal->readout_orientation = 0;
	else
		signal->readout_orientation = value;

	err = read_property_u32(node, "mclk_khz", &value);
	if (err)
		signal->mclk_freq = 0;
	else
		signal->mclk_freq = value;

	err = read_property_u32(node, "num_lanes", &value);
	if (err) {
		dev_err(dev, "%s:num_lanes property missing\n", __func__);
		return err;
	}
	signal->num_lanes = value;

	err = read_property_u64(node, "pix_clk_hz", &val64);
	if (err) {
		dev_err(dev, "%s:pix_clk_hz property missing\n", __func__);
		return err;
	}
	signal->pixel_clock.val = val64;

	err = read_property_u64(node, "serdes_pix_clk_hz", &val64);
	if (err)
		signal->serdes_pixel_clock.val = 0;
	else
		signal->serdes_pixel_clock.val = val64;

	if (signal->serdes_pixel_clock.val != 0ULL) {
		if (signal->serdes_pixel_clock.val < signal->pixel_clock.val) {
			dev_err(dev,
				"%s: serdes_pix_clk_hz is lower than pix_clk_hz!\n",
				__func__);
			return -EINVAL;
		}
		rate = signal->serdes_pixel_clock.val;
	} else {
		rate = signal->pixel_clock.val;
	}

	err = read_property_u32(node, "csi_pixel_bit_depth", &depth);
	if (err) {
		dev_err(dev,
			"%s:csi_pixel_bit_depth property missing.\n",
			__func__);
		return err;
	}

	/* Convert pixel rate to lane data rate */
	rate = rate * depth / signal->num_lanes;

	if (signal->phy_mode == CSI_PHY_MODE_DPHY) {
		/* MIPI clock rate */
		signal->mipi_clock.val = rate / 2;
	} else if (signal->phy_mode == CSI_PHY_MODE_CPHY) {
		/* Symbol rate */
		signal->mipi_clock.val = rate * 7 / 16;
	} else {
		/* Data rate */
		signal->mipi_clock.val = rate;
	}

	err = read_property_u32(node, "cil_settletime", &value);
	if (err)
		signal->cil_settletime = 0;
	else
		signal->cil_settletime = value;

	err = read_property_u32(node, "lane_polarity", &value);
	/* absence of this value is not an error and default behaviour is
	 * no polarity swap on any CSI lane */
	if (err)
		signal->lane_polarity = 0;
	else
		signal->lane_polarity = value;

	/* initialize default if this prop not available */
	err = of_property_read_string(node, "discontinuous_clk", &temp_str);
	if (!err)
		signal->discontinuous_clk =
			!strncmp(temp_str, "yes", sizeof("yes"));
	else
		signal->discontinuous_clk = 1;

	/* initialize default if this prop not available */
	err = of_property_read_string(node, "dpcm_enable", &temp_str);
	if (!err)
		signal->dpcm_enable =
			!strncmp(temp_str, "true", sizeof("true"));
	else
		signal->dpcm_enable = 0;

	/* initialize default if this prop not available */
	err = of_property_read_string(node,
					"deskew_initial_enable", &temp_str);
	if (!err)
		signal->deskew_initial_enable =
				!strncmp(temp_str, "true", sizeof("true"));
	else
		signal->deskew_initial_enable = 0;
	err = of_property_read_string(node,
					"deskew_periodic_enable", &temp_str);
	if (!err)
		signal->deskew_periodic_enable =
				!strncmp(temp_str, "true", sizeof("true"));
	else
		signal->deskew_periodic_enable = 0;

	err = of_property_read_string(node, "tegra_sinterface", &temp_str);
	if (err) {
		dev_err(dev,
			"%s: tegra_sinterface property missing\n", __func__);
		return err;
	}

	if (strcmp(temp_str, "serial_a") == 0)
		signal->tegra_sinterface = 0;
	else if (strcmp(temp_str, "serial_b") == 0)
		signal->tegra_sinterface = 1;
	else if (strcmp(temp_str, "serial_c") == 0)
		signal->tegra_sinterface = 2;
	else if (strcmp(temp_str, "serial_d") == 0)
		signal->tegra_sinterface = 3;
	else if (strcmp(temp_str, "serial_e") == 0)
		signal->tegra_sinterface = 4;
	else if (strcmp(temp_str, "serial_f") == 0)
		signal->tegra_sinterface = 5;
	else if (strcmp(temp_str, "serial_g") == 0)
		signal->tegra_sinterface = 6;
	else if (strcmp(temp_str, "serial_h") == 0)
		signal->tegra_sinterface = 7;
	else if (strcmp(temp_str, "host") == 0)
		signal->tegra_sinterface = 0; /* for vivid driver */
	else {
		dev_err(dev,
			"%s: tegra_sinterface property out of range\n",
			__func__);
		return -EINVAL;
	}

	return 0;
}

static int extract_pixel_format(
	const char *pixel_t, u32 *format)
{
	size_t size = strnlen(pixel_t, OF_MAX_STR_LEN);

	if (strncmp(pixel_t, "bayer_bggr10", size) == 0)
		*format = V4L2_PIX_FMT_SBGGR10;
	else if (strncmp(pixel_t, "bayer_rggb10", size) == 0)
		*format = V4L2_PIX_FMT_SRGGB10;
	else if (strncmp(pixel_t, "bayer_grbg10", size) == 0)
		*format = V4L2_PIX_FMT_SGRBG10;
	else if (strncmp(pixel_t, "bayer_gbrg10", size) == 0)
		*format = V4L2_PIX_FMT_SGBRG10;
	else if (strncmp(pixel_t, "bayer_bggr12", size) == 0)
		*format = V4L2_PIX_FMT_SBGGR12;
	else if (strncmp(pixel_t, "bayer_rggb12", size) == 0)
		*format = V4L2_PIX_FMT_SRGGB12;
	else if (strncmp(pixel_t, "bayer_gbrg12", size) == 0)
		*format = V4L2_PIX_FMT_SGBRG12;
	else if (strncmp(pixel_t, "bayer_grbg12", size) == 0)
		*format = V4L2_PIX_FMT_SGRBG12;
	else if (strncmp(pixel_t, "rgb_rgb88824", size) == 0)
		*format = V4L2_PIX_FMT_RGB24;
	else if (strncmp(pixel_t, "bayer_wdr_pwl_rggb12", size) == 0)
		*format = V4L2_PIX_FMT_SRGGB12;
	else if (strncmp(pixel_t, "bayer_wdr_pwl_gbrg12", size) == 0)
		*format = V4L2_PIX_FMT_SGBRG12;
	else if (strncmp(pixel_t, "bayer_wdr_pwl_grbg12", size) == 0)
		*format = V4L2_PIX_FMT_SGRBG12;
	else if (strncmp(pixel_t, "bayer_wdr_dol_rggb10", size) == 0)
		*format = V4L2_PIX_FMT_SRGGB10;
	else if (strncmp(pixel_t, "bayer_xbggr10p", size) == 0)
		*format = V4L2_PIX_FMT_XBGGR10P;
	else if (strncmp(pixel_t, "bayer_xrggb10p", size) == 0)
		*format = V4L2_PIX_FMT_XRGGB10P;
	else if (strncmp(pixel_t, "yuv_yuyv16", size) == 0)
		*format = V4L2_PIX_FMT_YUYV;
	else if (strncmp(pixel_t, "yuv_yvyu16", size) == 0)
		*format = V4L2_PIX_FMT_YVYU;
	else if (strncmp(pixel_t, "yuv_uyvy16", size) == 0)
		*format = V4L2_PIX_FMT_UYVY;
	else if (strncmp(pixel_t, "yuv_uyvy8", size) == 0)
		*format = V4L2_PIX_FMT_UYVY;
	else if (strncmp(pixel_t, "yuv_vyuy16", size) == 0)
		*format = V4L2_PIX_FMT_VYUY;
	else {
		pr_err("%s: Need to extend format%s\n", __func__, pixel_t);
		return -EINVAL;
	}

	return 0;
}

static int sensor_common_parse_image_props(
	struct device *dev, struct device_node *node,
	struct sensor_image_properties *image)
{
	const char *temp_str;
	int err = 0, ret = 0;
	const char *phase_str, *mode_str;
	int depth;
	char pix_format[24];
	u32 value = 0;

	err = read_property_u32(node, "active_w",
		&image->width);
	if (err) {
		dev_err(dev, "%s:active_w property missing\n", __func__);
		goto fail;
	}

	err = read_property_u32(node, "active_h",
		&image->height);
	if (err) {
		dev_err(dev, "%s:active_h property missing\n", __func__);
		goto fail;
	}

	err = read_property_u32(node, "line_length",
		&image->line_length);
	if (err) {
		dev_err(dev, "%s:Line length property missing\n", __func__);
		goto fail;
	}

	/* embedded_metadata_height is optional */
	err = read_property_u32(node, "embedded_metadata_height", &value);
	if (err)
		image->embedded_metadata_height = 0;
	else
		image->embedded_metadata_height = value;

	err = of_property_read_string(node, "pixel_t", &temp_str);
	if (err) {
		/* pixel_t missing is only an error if alternate not provided */

		/* check for alternative format string */
		err = of_property_read_string(node, "pixel_phase", &phase_str);
		if (err) {
			dev_err(dev,
				"%s:pixel_phase property missing.\n",
				__func__);
			dev_err(dev,
				"%s:Either pixel_t or alternate must be present.\n",
				__func__);
			goto fail;
		}
		err = of_property_read_string(node, "mode_type", &mode_str);
		if (err) {
			dev_err(dev,
				"%s:mode_type property missing.\n",
				__func__);
			dev_err(dev,
				"%s:Either pixel_t or alternate must be present.\n",
				__func__);
			goto fail;
		}
		err = read_property_u32(node, "csi_pixel_bit_depth", &depth);
		if (err) {
			dev_err(dev,
				"%s:csi_pixel_bit_depth property missing.\n",
				__func__);
			dev_err(dev,
				"%s:Either pixel_t or alternate must be present.\n",
				__func__);
			goto fail;
		}
		ret = sprintf(pix_format, "%s_%s%d", mode_str, phase_str, depth);
		if (ret < 0)
			return -EINVAL;
		temp_str = pix_format;
	}

	err = extract_pixel_format(temp_str, &image->pixel_format);
	if (err) {
		dev_err(dev, "Unsupported pixel format\n");
		goto fail;
	}

fail:
	return err;
}

static int sensor_common_parse_dv_timings(
	struct device *dev, struct device_node *node,
	struct sensor_dv_timings *timings)
{
	int err = 0;
	u32 value = 0;

	/* Do not report error for these properties yet */
	err = read_property_u32(node, "horz_front_porch", &value);
	if (err)
		timings->hfrontporch = 0;
	else
		timings->hfrontporch = value;

	err = read_property_u32(node, "horz_sync", &value);
	if (err)
		timings->hsync = 0;
	else
		timings->hsync = value;

	err = read_property_u32(node, "horz_back_porch", &value);
	if (err)
		timings->hbackporch = 0;
	else
		timings->hbackporch = value;

	err = read_property_u32(node, "vert_front_porch", &value);
	if (err)
		timings->vfrontporch = 0;
	else
		timings->vfrontporch = value;

	err = read_property_u32(node, "vert_sync", &value);
	if (err)
		timings->vsync = 0;
	else
		timings->vsync = value;

	err = read_property_u32(node, "vert_back_porch", &value);
	if (err)
		timings->vbackporch = 0;
	else
		timings->vbackporch = value;

	return 0;
}

static int sensor_common_parse_control_props(
	struct device *dev, struct device_node *node,
	struct sensor_control_properties *control)
{
	int err = 0;
	u32 value = 0;
	u64 val64 = 0;

	err = read_property_u32(node, "gain_factor", &value);
	if (err) {
		dev_dbg(dev, "%s:%s:property missing\n",
			__func__, "gain_factor");
		control->gain_factor = 1;
		return 0;
	} else
		control->gain_factor = value;

	err = read_property_u32(node, "framerate_factor", &value);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "framerate_factor");
		control->framerate_factor = 1;
	} else
		control->framerate_factor = value;

	err = read_property_u32(node, "exposure_factor", &value);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "exposure_factor");
		control->exposure_factor = 1;
	} else
		control->exposure_factor = value;

	/* ignore err for this prop */
	err = read_property_u32(node, "inherent_gain", &value);
	if (err)
		control->inherent_gain = 0;
	else
		control->inherent_gain = value;

	err = read_property_u32(node, "min_gain_val", &value);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "min_gain_val");
		control->min_gain_val = 0;
	} else
		control->min_gain_val = value;

	err = read_property_u32(node, "max_gain_val", &value);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "max_gain_val");
		control->max_gain_val = 0;
	} else
		control->max_gain_val = value;

	err = read_property_u32(node, "step_gain_val", &value);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "step_gain_val");
		control->step_gain_val = 0;
	} else
		control->step_gain_val = value;

	/* ignore err for this prop */
	err = read_property_u32(node, "min_hdr_ratio", &value);
	if (err)
		control->min_hdr_ratio = 1;
	else
		control->min_hdr_ratio = value;

	err = read_property_u32(node, "max_hdr_ratio", &value);
	if (err)
		control->max_hdr_ratio = 1;
	else
		control->max_hdr_ratio = value;

	err = read_property_u32(node, "min_framerate", &value);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "min_framerate");
		control->min_framerate = 0;
	} else
		control->min_framerate = value;

	err = read_property_u32(node, "max_framerate", &value);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "max_framerate");
		control->max_framerate = 0;
	} else
		control->max_framerate = value;

	err = read_property_u32(node, "step_framerate", &value);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "step_framerate");
		control->step_framerate = 0;
	} else
		control->step_framerate = value;

	err = read_property_u64(node, "min_exp_time", &val64);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "min_exp_time");
		control->min_exp_time.val = 0;
	}
		control->min_exp_time.val = val64;

	err = read_property_u64(node, "max_exp_time", &val64);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "max_exp_time");
		control->max_exp_time.val = 0;
	} else
		control->max_exp_time.val = val64;

	err = read_property_u64(node, "step_exp_time", &val64);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "step_exp_time");
		control->step_exp_time.val = 0;
	} else
		control->step_exp_time.val = val64;

	err = read_property_u32(node, "default_gain", &value);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "default_gain");
		control->default_gain = 0;
	} else
		control->default_gain = value;

	err = read_property_u32(node, "default_framerate", &value);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "default_framerate");
		control->default_framerate = 0;
	} else
		control->default_framerate = value;

	err = read_property_u64(node, "default_exp_time", &val64);
	if (err) {
		dev_err(dev, "%s:%s:property missing\n",
			__func__, "default_exp_time");
		control->default_exp_time.val = 0;
	} else
		control->default_exp_time.val = val64;

	err = read_property_u32(node, "is_interlaced", &value);
	if (err)
		control->is_interlaced = 0;
	else
		control->is_interlaced = value;

	err = read_property_u32(node, "interlaced_type", &value);
	if (err)
		control->interlace_type = 0;
	else
		control->interlace_type = value;

	return 0;
}

int sensor_common_parse_num_modes(const struct device *dev)
{
	struct device_node *np;
	struct device_node *node = NULL;
	char temp_str[OF_MAX_STR_LEN];
	int num_modes = 0;
	int i, ret;

	if (!dev || !dev->of_node)
		return 0;

	np = dev->of_node;

	for (i = 0; num_modes < MAX_NUM_SENSOR_MODES; i++) {
		ret = snprintf(temp_str, sizeof(temp_str), "%s%d",
			OF_SENSORMODE_PREFIX, i);
		if (ret < 0)
			return 0;
		node = of_get_child_by_name(np, temp_str);
		of_node_put(node);
		if (node == NULL)
			break;
		num_modes++;
	}

	return num_modes;
}
EXPORT_SYMBOL(sensor_common_parse_num_modes);

static int sensor_common_init_i2c_device_config(
	struct device *dev, struct device_node *np,
	struct sensor_cfg *cfg)
{
	struct i2c_sensor_cfg *i2c_sensor = &cfg->u.i2c_sensor;
	struct device_node *node = NULL;
	struct device_node *parent = NULL;
	int err = 0;
	u32 value = 0;
	bool is_mux_valid = 0;

	cfg->type = CAMERA_DEVICE_I2C_SENSOR;
	err = of_property_read_u32(np, "reg", &value);
	if (err) {
		dev_err(dev, "sensor address unavailable\n");
		return err;
	}

	/* Reading more devices has to be supported */
	i2c_sensor->num_devs = 1;
	i2c_sensor->sd[0].addr = value;

	parent = of_get_parent(np);
	/* verify the parent is mux or i2c bus */
	is_mux_valid =
		of_property_read_bool(parent, "i2c-mux,deselect-on-exit");
	i2c_sensor->mux.is_mux_valid = is_mux_valid;

	if (is_mux_valid) {

		/* at mux port read the mux channel */
		err = of_property_read_u32(parent, "reg", &value);
		if (err) {
			dev_err(dev, "mux channel unavailable\n");
			return err;
		}
		i2c_sensor->mux.mux_channel = value;

		/* move to mux node */
		node = of_get_parent(parent);
		of_node_put(parent);
		err = of_property_read_u32(node, "reg", &value);
		if (err) {
			dev_err(dev, "mux address unavailable\n");
			return err;
		}
		i2c_sensor->mux.mux_addr = value;

		/* move to i2c bus node */
		parent = of_get_parent(node);
		of_node_put(node);
	} else {
		/* move to next parent to check
		 * if it is a gpio based i2c mux
		 */
		node = of_get_parent(parent);

		if (of_device_is_compatible(node, "i2c-mux-gpio")) {
			of_node_put(parent);

			/* move to i2c bus node */
			parent = of_parse_phandle(node, "i2c-parent", 0);
		}
	}

	/* read parent which is i2c bus */
	err = of_property_read_u32_index(parent, "reg", 1, &value);
	if (err) {
		dev_err(dev, "i2c bus regbase unavailable\n");
		return err;
	}
	i2c_sensor->bus.reg_base = value;

	err = of_property_read_u32(parent, "clock-frequency", &value);
	if (err) {
		dev_err(dev, "bus clock frequency unavailable\n");
		return err;
	}
	i2c_sensor->bus.clk_rate = value;

	of_node_put(parent);
	/*
	 * Read any additional flags to configure I2C for any
	 * special properties of the device like-high-speed mode,
	 * 10bit addressing etc.,
	 */

	return 0;
}

static int sensor_common_init_spi_device_config(
	struct device *dev, struct device_node *np,
	struct sensor_cfg *cfg)
{
	struct spi_sensor_cfg *spi_sensor = &cfg->u.spi_sensor;
	struct device_node *parent = NULL;
	int err = 0;
	u32 value = 0;

	cfg->type = CAMERA_DEVICE_SPI_SENSOR;
	err = of_property_read_u32(np, "reg", &value);
	if (err) {
		dev_err(dev, "sensor address unavailable\n");
		return err;
	}

	/* Reading more devices has to be supported */
	spi_sensor->num_devs = 1;
	spi_sensor->sd[0].addr = value;

	parent = of_get_parent(np);

	/* TODO: Add logic for spi mux if available */

	/* read parent which is spi bus */
	err = of_property_read_u32_index(parent, "reg", 1, &value);
	if (err) {
		dev_err(dev, "spi bus regbase unavailable\n");
		return err;
	}
	spi_sensor->bus.reg_base = value;

	err = of_property_read_u32(parent, "spi-max-frequency", &value);
	if (err) {
		dev_err(dev, "bus clock frequency unavailable\n");
		return err;
	}
	spi_sensor->bus.clk_rate = value;

	of_node_put(parent);
	/* Read any additional flags to configure SPI */

	return 0;
}

static int sensor_common_init_device_config(
	struct device *dev, struct device_node *np,
	struct sensor_cfg *cfg)
{
	struct device_node *parent = NULL;
	char *tmp;
	int err = 0;

	if (!np)
		return -EINVAL;

	parent = of_get_parent(np);
	if (!parent)
		return -EINVAL;

	tmp = strnstr(parent->name, "i2c", 4);
	if (tmp != NULL) {
		err = sensor_common_init_i2c_device_config(dev, np, cfg);
		if (err)
			goto exit;
	}

	tmp = strnstr(parent->name, "spi", 4);
	if (tmp != NULL) {
		err = sensor_common_init_spi_device_config(dev, np, cfg);
		if (err)
			goto exit;
	}

exit:
	of_node_put(parent);
	return err;
}

int sensor_common_init_sensor_properties(
	struct device *dev, struct device_node *np,
	struct sensor_properties *sensor)
{
	char temp_str[OF_MAX_STR_LEN];
	struct device_node *node = NULL;
	int num_modes = 0;
	int err, i;

	if (sensor == NULL)
		return -EINVAL;

	err = sensor_common_init_device_config(dev, np, &sensor->cfg);
	if (err)
		return err;

	/* get number of modes */
	for (i = 0; num_modes < MAX_NUM_SENSOR_MODES; i++) {
		err = snprintf(temp_str, sizeof(temp_str), "%s%d",
			OF_SENSORMODE_PREFIX, i);
		if (err < 0)
			return -EINVAL;

		node = of_get_child_by_name(np, temp_str);
		of_node_put(node);
		if (node == NULL)
			break;
		num_modes++;
	}
	sensor->num_modes = num_modes;

	sensor->sensor_modes = devm_kzalloc(dev,
		num_modes * sizeof(struct sensor_mode_properties),
		GFP_KERNEL);
	if (!sensor->sensor_modes) {
		dev_err(dev, "Failed to allocate memory for sensor modes\n");
		err = -ENOMEM;
		goto alloc_fail;
	}

	for (i = 0; i < num_modes; i++) {
		err = snprintf(temp_str, sizeof(temp_str), "%s%d",
			OF_SENSORMODE_PREFIX, i);
		if (err < 0)
			return -EINVAL;

		node = of_get_child_by_name(np, temp_str);
		if (node == NULL) {
			dev_err(dev, "Failed to find %s\n", temp_str);
			err = -ENODATA;
			goto fail;
		};

		dev_dbg(dev, "parsing for %s props\n", temp_str);

		err = sensor_common_parse_signal_props(dev, node,
			&sensor->sensor_modes[i].signal_properties);
		if (err) {
			dev_err(dev, "Failed to read %s signal props\n",
				temp_str);
			goto fail;
		}

		err = sensor_common_parse_image_props(dev, node,
			&sensor->sensor_modes[i].image_properties);
		if (err) {
			dev_err(dev, "Failed to read %s image props\n",
				temp_str);
			goto fail;
		}

		err = sensor_common_parse_dv_timings(dev, node,
			&sensor->sensor_modes[i].dv_timings);
		if (err) {
			dev_err(dev, "Failed to read %s DV timings\n",
				temp_str);
			goto fail;
		}

		err = sensor_common_parse_control_props(dev, node,
			&sensor->sensor_modes[i].control_properties);
		if (err) {
			dev_err(dev, "Failed to read %s control props\n",
				temp_str);
			goto fail;
		}
		of_node_put(node);
	}

	return 0;

fail:
	devm_kfree(dev, sensor->sensor_modes);
alloc_fail:
	of_node_put(node);
	return err;
}
EXPORT_SYMBOL(sensor_common_init_sensor_properties);

Here is my dts code.

/ {
	tegra-capture-vi {
		num-channels = <6>;
		ports {
			#address-cells = <1>;
			#size-cells = <0>;
			port@0 {
				reg = <0>;
				csimx307_vi_in0: endpoint {
					port-index = <0>;
					bus-width = <2>;
					remote-endpoint = <&csimx307_csi_out0>;
				};
			};
			port@1 {
				reg = <1>;
				csimx307_vi_in1: endpoint {
					port-index = <1>;
					bus-width = <2>;
					remote-endpoint = <&csimx307_csi_out1>;
				};
			};
			port@2 {
				reg = <2>;
				csimx307_vi_in2: endpoint {
					port-index = <2>;
					bus-width = <2>;
					remote-endpoint = <&csimx307_csi_out2>;
				};
			};
			port@3 {
				reg = <3>;
				csimx307_vi_in3: endpoint {
					port-index = <3>;
					bus-width = <2>;
					remote-endpoint = <&csimx307_csi_out3>;
				};
			};
			port@4 {
				reg = <4>;
				csimx307_vi_in4: endpoint {
					port-index = <4>;
					bus-width = <2>;
					remote-endpoint = <&csimx307_csi_out4>;
				};
			};
			port@5 {
				reg = <5>;
				csimx307_vi_in5: endpoint {
					port-index = <5>;
					bus-width = <2>;
					remote-endpoint = <&csimx307_csi_out5>;
				};
			};
		};
	};

	host1x@13e00000 {
		nvcsi@15a00000 {
			num-channels = <6>;
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";
			channel@0 {
				reg = <0>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						csimx307_csi_in0: endpoint@0 {
							port-index = <0>;
							bus-width = <2>;
							remote-endpoint = <&csimx307_out0>;
						};
					};
					port@1 {
						reg = <1>;
						csimx307_csi_out0: endpoint@1 {
							remote-endpoint = <&csimx307_vi_in0>;
						};
					};
				};
			};
			channel@1 {
				reg = <1>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						csimx307_csi_in1: endpoint@2 {
							port-index = <1>;
							bus-width = <2>;
							remote-endpoint = <&csimx307_out1>;
						};
					};
					port@1 {
						reg = <1>;
						csimx307_csi_out1: endpoint@3 {
							remote-endpoint = <&csimx307_vi_in1>;
						};
					};
				};
			};
			channel@2 {
				reg = <2>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						csimx307_csi_in2: endpoint@4 {
							port-index = <2>;
							bus-width = <2>;
							remote-endpoint = <&csimx307_out2>;
						};
					};
					port@1 {
						reg = <1>;
						csimx307_csi_out2: endpoint@5 {
							remote-endpoint = <&csimx307_vi_in2>;
						};
					};
				};
			};
			channel@3 {
				reg = <3>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						csimx307_csi_in3: endpoint@6 {
							port-index = <3>;
							bus-width = <2>;
							remote-endpoint = <&csimx307_out3>;
						};
					};
					port@1 {
						reg = <1>;
						csimx307_csi_out3: endpoint@7 {
							remote-endpoint = <&csimx307_vi_in3>;
						};
					};
				};
			};
			channel@4 {
				reg = <4>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						csimx307_csi_in4: endpoint@8 {
							port-index = <4>;
							bus-width = <2>;
							remote-endpoint = <&csimx307_out4>;
						};
					};
					port@1 {
						reg = <1>;
						csimx307_csi_out4: endpoint@9 {
							remote-endpoint = <&csimx307_vi_in4>;
						};
					};
				};
			};
			channel@5 {
				reg = <5>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						csimx307_csi_in5: endpoint@10 {
							port-index = <6>;
							bus-width = <2>;
							remote-endpoint = <&csimx307_out5>;
						};
					};
					port@1 {
						reg = <1>;
						csimx307_csi_out5: endpoint@11 {
							remote-endpoint = <&csimx307_vi_in5>;
						};
					};
				};
			};
		};
	};

	i2c@3180000 {
		tca9548@70 {
			i2c@0 {
				csimx307_a@3b {
					compatible = "nvidia,cs_imx307";
					reg = <0x3b>;
					devnode = "video0";

					/* Physical dimensions of sensor */
                    physical_w = "5.6";
                    physical_h = "3.1";

					/* Define any required hw resources needed by driver */
					/* ie. clocks, io pins, power sources */
					avdd-reg = "vana";
					iovdd-reg = "vif";

					/* Enable EEPROM support */
					has-eeprom = "0";
                mode0 { /* CS307_MODE_1920X1080_30FPS */
					mclk_khz = "24000";
					num_lanes = "2";
					tegra_sinterface = "serial_a";
					phy_mode = "DPHY";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					active_w = "800";
					active_h = "600";
					mode_type = "yuv";
                    pixel_phase = "uyvy";
                    csi_pixel_bit_depth = "8";
					readout_orientation = "0";
					line_length = "800";
					inherent_gain = "1";
					//mclk_multiplier = "2";
					mclk_multiplier = "4.63";
					//pix_clk_hz = "48000000";
					pix_clk_hz = "125000000";

					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 = "1000000"; /* 1.0 fps */
					max_framerate = "30000000"; /* 30 fps */
					step_framerate = "1000000";
					default_framerate = "30000000"; /* 30 fps */
					min_exp_time = "13"; /* us */
					max_exp_time = "333333"; /* us */
					step_exp_time = "1";
					default_exp_time = "2495"; /* us */

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

						port@0 {
							reg = <0>;
							csimx307_out0: endpoint {
								port-index = <0>;
								bus-width = <2>;
								remote-endpoint = <&csimx307_csi_in0>;
							};
						};
					};
				};
			};

			i2c@1 {
				csimx307_b@3b {
					compatible = "nvidia,cs_imx307";
					reg = <0x3b>;
					devnode = "video1";

					/* Physical dimensions of sensor */
                    physical_w = "5.6";
                    physical_h = "3.1";

					/* Define any required hw resources needed by driver */
					/* ie. clocks, io pins, power sources */
					avdd-reg = "vana";
					iovdd-reg = "vif";

					/* Enable EEPROM support */
					has-eeprom = "0";

				mode0 { /* CS307_MODE_1920X1080_30FPS */
					//mclk_khz = "24000";
					mclk_khz = "27000";
					num_lanes = "2";
					tegra_sinterface = "serial_b";
					phy_mode = "DPHY";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					active_w = "800";
					active_h = "600";
					mode_type = "yuv";
                    pixel_phase = "uyvy";
                    csi_pixel_bit_depth = "8";
					readout_orientation = "0";
					//line_length = "800";
					line_length = "864";
					inherent_gain = "1";
					//mclk_multiplier = "2";
					//mclk_multiplier = "1.92";
					mclk_multiplier = "4.63";
					//pix_clk_hz = "48000000";
					//pix_clk_hz = "51840000";
					pix_clk_hz = "125000000";

					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 = "1000000"; /* 1.0 fps */
					max_framerate = "30000000"; /* 30 fps */
					step_framerate = "1000000";
					default_framerate = "30000000"; /* 30 fps */
					min_exp_time = "13"; /* us */
					max_exp_time = "333333"; /* us */
					step_exp_time = "1";
					default_exp_time = "2495"; /* us */

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

						port@0 {
							reg = <0>;
							csimx307_out1: endpoint {
								port-index = <1>;
								bus-width = <2>;
								remote-endpoint = <&csimx307_csi_in1>;
							};
						};
					};
				};
			};

			i2c@2 {
				csimx307_c@3b {
					compatible = "nvidia,cs_imx307";
					reg = <0x3b>;
					devnode = "video2";

					/* Physical dimensions of sensor */
                    physical_w = "5.6";
                    physical_h = "3.1";

					/* Define any required hw resources needed by driver */
					/* ie. clocks, io pins, power sources */
					avdd-reg = "vana";
					iovdd-reg = "vif";

					/* Enable EEPROM support */
					has-eeprom = "0";

				mode0 { /* CS307_MODE_1920X1080_30FPS */
					mclk_khz = "24000";
					num_lanes = "2";
					tegra_sinterface = "serial_c";
					phy_mode = "DPHY";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					active_w = "800";
					active_h = "600";
					mode_type = "yuv";
                    pixel_phase = "uyvy";
                    //csi_pixel_bit_depth = "8";
                    csi_pixel_bit_depth = "16";
					readout_orientation = "0";
					line_length = "864";
					inherent_gain = "1";
					//mclk_multiplier = "2";
					mclk_multiplier = "4.63";
					//pix_clk_hz = "48000000";
					pix_clk_hz = "125000000";

					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 = "1000000"; /* 1.0 fps */
					max_framerate = "30000000"; /* 30 fps */
					step_framerate = "1000000";
					default_framerate = "30000000"; /* 30 fps */
					min_exp_time = "13"; /* us */
					max_exp_time = "333333"; /* us */
					step_exp_time = "1";
					default_exp_time = "2495"; /* us */

					embedded_metadata_height = "0";
				};
 

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

						port@0 {
							reg = <0>;
							csimx307_out2: endpoint {
								port-index = <2>;
								bus-width = <2>;
								remote-endpoint = <&csimx307_csi_in2>;
							};
						};
					};
				};
			};

			i2c@3 {
				csimx307_d@3b {
					compatible = "nvidia,cs_imx307";
					reg = <0x3b>;
					devnode = "video3";

					/* Physical dimensions of sensor */
                    physical_w = "5.6";
                    physical_h = "3.1";

					/* Define any required hw resources needed by driver */
					/* ie. clocks, io pins, power sources */
					avdd-reg = "vana";
					iovdd-reg = "vif";

					/* Enable EEPROM support */
					has-eeprom = "0";

				mode0 { /* CS307_MODE_1920X1080_30FPS */
					mclk_khz = "24000";
					num_lanes = "2";
					tegra_sinterface = "serial_d";
					phy_mode = "DPHY";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					active_w = "800";
					active_h = "600";
					mode_type = "yuv";
                    pixel_phase = "uyvy";
                    csi_pixel_bit_depth = "8";
					readout_orientation = "0";
					line_length = "800";
					inherent_gain = "1";
					mclk_multiplier = "2";
					pix_clk_hz = "48000000";

					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 = "1000000"; /* 1.0 fps */
					max_framerate = "30000000"; /* 30 fps */
					step_framerate = "1000000";
					default_framerate = "30000000"; /* 30 fps */
					min_exp_time = "13"; /* us */
					max_exp_time = "333333"; /* us */
					step_exp_time = "1";
					default_exp_time = "2495"; /* us */

					embedded_metadata_height = "0";
				};


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

						port@0 {
							reg = <0>;
							csimx307_out3: endpoint {
								port-index = <3>;
								bus-width = <2>;
								remote-endpoint = <&csimx307_csi_in3>;
							};
						};
					};
				};
			};

			i2c@4 {
				csimx307_e@3b {
					compatible = "nvidia,cs_imx307";
					reg = <0x3b>;
					devnode = "video4";

					/* Physical dimensions of sensor */
                    physical_w = "5.6";
                    physical_h = "3.1";

					/* Define any required hw resources needed by driver */
					/* ie. clocks, io pins, power sources */
					avdd-reg = "vana";
					iovdd-reg = "vif";

					/* Enable EEPROM support */
					has-eeprom = "0";

				mode0 { /* CS307_MODE_1920X1080_30FPS */
					mclk_khz = "24000";
					num_lanes = "2";
					tegra_sinterface = "serial_e";
					phy_mode = "DPHY";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					active_w = "800";
					active_h = "600";
					mode_type = "yuv";
                    pixel_phase = "uyvy";
                    csi_pixel_bit_depth = "8";
					readout_orientation = "0";
					line_length = "800";
					inherent_gain = "1";
					mclk_multiplier = "2";
					pix_clk_hz = "48000000";

					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 = "1000000"; /* 1.0 fps */
					max_framerate = "30000000"; /* 30 fps */
					step_framerate = "1000000";
					default_framerate = "30000000"; /* 30 fps */
					min_exp_time = "13"; /* us */
					max_exp_time = "333333"; /* us */
					step_exp_time = "1";
					default_exp_time = "2495"; /* us */

					embedded_metadata_height = "0";
				};
 


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

						port@0 {
							reg = <0>;
							csimx307_out4: endpoint {
								port-index = <4>;
								bus-width = <2>;
								remote-endpoint = <&csimx307_csi_in4>;
							};
						};
					};
				};
			};

			i2c@5 {
				csimx307_g@3b  {
					compatible = "nvidia,cs_imx307";
					reg = <0x3b>;
					devnode = "video5";

					/* Physical dimensions of sensor */
                    physical_w = "5.6";
                    physical_h = "3.1";

					/* Define any required hw resources needed by driver */
					/* ie. clocks, io pins, power sources */
					avdd-reg = "vana";
					iovdd-reg = "vif";

					/* Enable EEPROM support */
					has-eeprom = "0";

				mode0{ /* CS307_MODE_1920X1080_30FPS */
					mclk_khz = "24000";
					num_lanes = "2";
					tegra_sinterface = "serial_g";
					phy_mode = "DPHY";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					active_w = "800";
					active_h = "600";
					mode_type = "yuv";
                    pixel_phase = "uyvy";
                    csi_pixel_bit_depth = "8";
					readout_orientation = "0";
					line_length = "800";
					inherent_gain = "1";
					mclk_multiplier = "2";
					pix_clk_hz = "48000000";

					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 = "1000000"; /* 1.0 fps */
					max_framerate = "30000000"; /* 30 fps */
					step_framerate = "1000000";
					default_framerate = "30000000"; /* 30 fps */
					min_exp_time = "13"; /* us */
					max_exp_time = "333333"; /* us */
					step_exp_time = "1";
					default_exp_time = "2495"; /* us */

					embedded_metadata_height = "0";
				};
 

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

						port@0 {
							reg = <0>;
							csimx307_out5: endpoint {
								port-index = <5>;
								bus-width = <2>;
								remote-endpoint = <&csimx307_csi_in5>;
							};
						};
					};
				};
			};
		};
	};

	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
		* Set this to the highest pix_clk_hz out of all available modes.
		*
		* 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 = <12>;
		max_lane_speed = <1500000>;
		min_bits_per_pixel = <8>;
		vi_peak_byte_per_pixel = <2>;
		vi_bw_margin_pct = <25>;
		max_pixel_rate = <160000>;
		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 vender.
		*/
		modules {
			module0 {
				badge = "csimx307_bottomleft_P5V27C";
				position = "bottomleft";
				orientation = "1";
				drivernode0 {
					pcl_id = "v4l2_sensor";
					devname = "csimx307 30-003b";
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9548@70/i2c@0/csimx307_a@3b";
				};

			};
			module1 {
				badge = "csimx307_centerleft_P5V27C";
				position = "centerleft";
				orientation = "1";
				drivernode0 {
					pcl_id = "v4l2_sensor";
					devname = "csimx307 31-003b";
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9548@70/i2c@1/csimx307_b@3b";
				};

			};
			module2 {
				badge = "csimx307_centerright_P5V27C";
				position = "centerright";
				orientation = "1";
				drivernode0 {
					pcl_id = "v4l2_sensor";
					devname = "csimx307 32-003b";
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9548@70/i2c@2/csimx307_c@3b";
				};

			};
			module3 {
				badge = "csimx307_topleft_P5V27C";
				position = "topleft";
				orientation = "1";
				drivernode0 {
					pcl_id = "v4l2_sensor";
					devname = "csimx307 33-003b";
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9548@70/i2c@3/csimx307_d@3b";
				};

			};
			module4 {
				badge = "csimx307_bottomright_P5V27C";
				position = "bottomright";
				orientation = "1";
				drivernode0 {
					pcl_id = "v4l2_sensor";
					devname = "csimx307 34-003b";
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9548@70/i2c@4/csimx307_e@3b";
				};

			};
			module5 {
				badge = "csimx307_topright_P5V27C";
				position = "topright";
				orientation = "1";
				drivernode0 {
					pcl_id = "v4l2_sensor";
					devname = "csimx307 35-003b";
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9548@70/i2c@5/csimx307_g@3b";
				};

			};
		};
	};
};

hello sultanofsleep,

here’s an erroneous,
this should be using CSI-G, please revise port index as… port-index = <6>; for this node.

[EDIT] may bad, please ignore this part. it looks you’ve correct CSI/VI port definition in the device tree.

besides,
is it only CSI-C for 16-bit configuration, other 5 camera nodes for 8-bit configuration?
please double check you’ve correct camera config, and please also check the VI driver side to ensure you’ve extend the format supports.
for example,
$public_sources/kernel_src/kernel/nvidia/drivers/media/platform/tegra/camera/sensor_common.c

static int extract_pixel_format( 
        const char *pixel_t, u32 *format)
{
...
        else if (strncmp(pixel_t, "yuv_uyvy16", size) == 0)
                *format = V4L2_PIX_FMT_UYVY;

Our custom camera has three output channels, only using camera nodes 0-2. For testing, different camera parameters were set for each channel, but the same stalling issue occurred across all. Our output format is UYVY, there is no I2C, the pixel clock is 27MHz, and the frame rate is 50Hz. The MIPI operates in a 500M continuous mode.

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

hello sultanofsleep,

could you please also check it’s outputting MIPI signaling as soon as you call s_stream?
is this related to multi-cam use-case? are you able to repo the same failure with single camera?