Remove HW board E3326, and add YUV sensor IMX224 in TX1, but preview is not ok

The YUV sensor with ISP camera will work after power on. The MCLK is controlled by ISP not TX1.
The code is modified from ov5693.c.

The camera module need 4 lane. then I remove the HW board E3326 and connect (pin to pin) my camera module with camera connecter J22.
I add my custom camera dts and remove the default dts(tegra210-platforms/tegra210-jetson-cv-camera-modules.dtsi)

gst-launch-1.0 -v v4l2src device=“/dev/video0” ! “video/x-raw,width=1280,height=720, format=(string)I420” ! nvvidconv ! “video/x-raw(memory:NVMM)” ! nvoverlaysink sync=false -e

Now the preview is not ok.

the error log is as followed:
[ 1072.718925] tegra_mipi_cal 700e3000.mipical: Mipi cal timeout,val:110000, lanes:300000
[ 1072.918684] video4linux video0: frame start syncpt timeout!0
[ 1072.938685] tegra_mipi_cal 700e3000.mipical: Mipi cal timeout,val:110000, lanes:300000
[ 1072.942074] nvmap_alloc_handle: PID 2330: gst-launch-1.0: WARNING: All NvMap Allocations must have a tag to identify the subsystem allocating memory.Plase pass the tag to the API call NvRmMemHanldeAllocAttr() or relevant.
[ 1073.159305] video4linux video0: frame start syncpt timeout!0
[ 1073.359280] video4linux video0: frame start syncpt timeout!0

Please help check the source code. Can you give some suggestions.

arch/arm64/boot/dts/tegra210-platforms/tegra210-imx224.dtsi
drivers/media/i2c/imx224.c

drivers/media/platform/tegra/camera/camera_common.c
{
V4L2_MBUS_FMT_UYVY8_2X8,
V4L2_COLORSPACE_SRGB,
V4L2_PIX_FMT_UYVY,
},

#include <dt-bindings/media/camera.h>
#include <dt-bindings/platform/t210/t210.h>

#define CAM0_RST_L TEGRA_GPIO(S, 4)
#define CAM0_PWDN TEGRA_GPIO(S, 7)
/ {

host1x {
	vi {
		num-channels = <1>;
		ports {
			#address-cells = <1>;
			#size-cells = <0>;
			port@0 {
				reg = <0>;
				vi_in0: endpoint {
				    csi-port = <0>;
					bus-width = <4>;
					remote-endpoint = <&ov5693_out0>;
				};
			};
		};
	};

	i2c@546c0000 {
		status = "okay";
		#address-cells = <1>;
		#size-cells = <0>;
		ov5693_c@36 {
			compatible = "nvidia,imx224";
			/* I2C device address */
			reg = <0x36>;

			physical_w = "3.674";
			physical_h = "2.738";

			sensor_model ="imx224";

			avdd-reg = "vana";
			iovdd-reg = "vif";
			clocks = <&tegra_car TEGRA210_CLK_ID_CLK_OUT_3>;
			clock-names = "mclk";
			clock-frequency = <24000000>;

			mclk = "cam_mclk1";
			reset-gpios = <&gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
			pwdn-gpios = <&gpio CAM0_PWDN GPIO_ACTIVE_HIGH>;
			vana-supply = <&en_vdd_cam_hv_2v8>;
			vif-supply = <&en_vdd_cam>;

			mode0 { // OV5693_MODE_2592X1944
				mclk_khz = "24000";
				num_lanes = "4";
				tegra_sinterface = "serial_a";
				discontinuous_clk = "no";
				dpcm_enable = "false";
				cil_settletime = "0";

				active_w = "1280";
				active_h = "720";
				pixel_t = "uyvy";
				readout_orientation = "180";
				line_length = "2688";
				inherent_gain = "1";
				mclk_multiplier = "17.0";
				pix_clk_hz = "160000000";

				min_gain_val = "1.0";
				max_gain_val = "16";
				min_hdr_ratio = "1";
				max_hdr_ratio = "64";
				min_framerate = "1.816577";
				max_framerate = "30";
				min_exp_time = "34";
				max_exp_time = "550385";
				embedded_metadata_height = "0";
			};
			ports {
				#address-cells = <1>;
				#size-cells = <0>;
				port@0 {
					reg = <0>;
					ov5693_out0: endpoint {
						csi-port = <0>;
						bus-width = <4>;
						remote-endpoint = <&vi_in0>;
					};
				};
			};
		};
    };
};


tegra-camera-platform {
	compatible = "nvidia, tegra-camera-platform";
	modules {
		module0 {
			badge = "e3326_front_P5V27C";
			position = "rear";
			orientation = "1";
			drivernode0 {
				pcl_id = "v4l2_sensor";
				proc-device-tree = "/proc/device-tree/host1x/i2c@546c0000/ov5693_c@36";
			};
			drivernode1 {
				pcl_id = "v4l2_focuser_stub";
			};
		};
	};
};

};

#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/camera_common.h>
#include <media//imx224.h>

#include “cam_dev/camera_gpio.h”

#include “imx224_mode_tbls.h”

#define IMX224_MAX_COARSE_DIFF 6

#define IMX224_GAIN_SHIFT 8
#define IMX224_REAL_GAIN_SHIFT 4
#define IMX224_MIN_GAIN (1 << IMX224_GAIN_SHIFT)
#define IMX224_MAX_GAIN (16 << IMX224_GAIN_SHIFT)
#define IMX224_MAX_UNREAL_GAIN (0x0F80)
#define IMX224_MIN_FRAME_LENGTH (0x0)
#define IMX224_MAX_FRAME_LENGTH (0x7fff)
#define IMX224_MIN_EXPOSURE_COARSE (0x0002)
#define IMX224_MAX_EXPOSURE_COARSE
(IMX224_MAX_FRAME_LENGTH-IMX224_MAX_COARSE_DIFF)

#define IMX224_DEFAULT_GAIN IMX224_MIN_GAIN
#define IMX224_DEFAULT_FRAME_LENGTH (0x07C0)
#define IMX224_DEFAULT_EXPOSURE_COARSE
(IMX224_DEFAULT_FRAME_LENGTH-IMX224_MAX_COARSE_DIFF)

#define IMX224_DEFAULT_MODE IMX224_MODE_2592X1944
#define IMX224_DEFAULT_HDR_MODE IMX224_MODE_2592X1944_HDR
#define IMX224_DEFAULT_WIDTH 1280
#define IMX224_DEFAULT_HEIGHT 720
//#define IMX224_DEFAULT_DATAFMT V4L2_MBUS_FMT_SRGGB10_1X10 //V4L2_MBUS_FMT_UYVY8_2X8
#define IMX224_DEFAULT_DATAFMT V4L2_MBUS_FMT_UYVY8_2X8
#define IMX224_DEFAULT_CLK_FREQ 24000000
#define DEBUG 1
struct imx224 {
struct camera_common_power_rail power;
int numctrls;
struct v4l2_ctrl_handler ctrl_handler;
struct i2c_client *i2c_client;
struct v4l2_subdev *subdev;
struct media_pad pad;

int				reg_offset;

s32				group_hold_prev;
bool				group_hold_en;
struct regmap			*regmap;
struct camera_common_data	*s_data;
struct camera_common_pdata	*pdata;
struct v4l2_ctrl		*ctrls[];

};

static struct regmap_config imx224_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
};

static int imx224_s_ctrl(struct v4l2_ctrl *ctrl);
static void imx224_update_ctrl_range(struct imx224 *priv, s32 frame_length);

static const struct v4l2_ctrl_ops imx224_ctrl_ops = {
.s_ctrl = imx224_s_ctrl,
};

static struct v4l2_ctrl_config ctrl_config_list = {
/* Do not change the name field for the controls! */
{
.ops = &imx224_ctrl_ops,
.id = V4L2_CID_GAIN,
.name = “Gain”,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = IMX224_MIN_GAIN,
.max = IMX224_MAX_GAIN,
.def = IMX224_DEFAULT_GAIN,
.step = 1,
},
{
.ops = &imx224_ctrl_ops,
.id = V4L2_CID_FRAME_LENGTH,
.name = “Frame Length”,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = IMX224_MIN_FRAME_LENGTH,
.max = IMX224_MAX_FRAME_LENGTH,
.def = IMX224_DEFAULT_FRAME_LENGTH,
.step = 1,
},
{
.ops = &imx224_ctrl_ops,
.id = V4L2_CID_COARSE_TIME,
.name = “Coarse Time”,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = IMX224_MIN_EXPOSURE_COARSE,
.max = IMX224_MAX_EXPOSURE_COARSE,
.def = IMX224_DEFAULT_EXPOSURE_COARSE,
.step = 1,
},
{
.ops = &imx224_ctrl_ops,
.id = V4L2_CID_COARSE_TIME_SHORT,
.name = “Coarse Time Short”,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = IMX224_MIN_EXPOSURE_COARSE,
.max = IMX224_MAX_EXPOSURE_COARSE,
.def = IMX224_DEFAULT_EXPOSURE_COARSE,
.step = 1,
},
{
.ops = &imx224_ctrl_ops,
.id = V4L2_CID_GROUP_HOLD,
.name = “Group Hold”,
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
.min = 0,
.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
.menu_skip_mask = 0,
.def = 0,
.qmenu_int = switch_ctrl_qmenu,
},
{
.ops = &imx224_ctrl_ops,
.id = V4L2_CID_HDR_EN,
.name = “HDR enable”,
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
.min = 0,
.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
.menu_skip_mask = 0,
.def = 0,
.qmenu_int = switch_ctrl_qmenu,
},
{
.ops = &imx224_ctrl_ops,
.id = V4L2_CID_FUSE_ID,
.name = “Fuse ID”,
.type = V4L2_CTRL_TYPE_STRING,
.flags = V4L2_CTRL_FLAG_READ_ONLY,
.min = 0,
.max = IMX224_FUSE_ID_STR_SIZE,
.step = 2,
},
};

static inline void imx224_get_frame_length_regs(imx224_reg *regs,
u32 frame_length)
{
printk(“imx224_get_frame_length_regs\n”);
}

static inline void imx224_get_coarse_time_regs(imx224_reg *regs,
u32 coarse_time)
{
printk(“imx224_get_coarse_time_regs\n”);
}

static inline void imx224_get_coarse_time_short_regs(imx224_reg *regs,
u32 coarse_time)
{
printk(“imx224_get_coarse_time_short_regs\n”);
}

static inline void imx224_get_gain_regs(imx224_reg *regs,
u16 gain)
{
printk(“imx224_get_gain_regs\n”);
}

static int test_mode;
module_param(test_mode, int, 0644);

static inline int imx224_read_reg(struct camera_common_data *s_data,
u16 addr, u8 *val)
{
struct imx224 *priv = (struct imx224 *)s_data->priv;
printk(“%s\n”,func);
return 0;

return regmap_read(priv->regmap, addr, (unsigned int *) val);

}

static int imx224_write_reg(struct camera_common_data *s_data, u16 addr, u8 val)
{
int err;
struct imx224 *priv = (struct imx224 *)s_data->priv;
printk(“%s\n”,func);
return 0;

err = regmap_write(priv->regmap, addr, val);
if (err)
	pr_err("%s:i2c write failed, %x = %x\n",
		__func__, addr, val);

return err;

}

static int imx224_write_table(struct imx224 *priv,
const imx224_reg table)
{
printk(“%s\n”,func);
return 0;
return regmap_util_write_table_8(priv->regmap,
table,
NULL, 0,
IMX224_TABLE_WAIT_MS,
IMX224_TABLE_END);
}

static void imx224_gpio_set(struct imx224 *priv,
unsigned int gpio, int val)
{
printk(“%s\n”,func);
if (priv->pdata->use_cam_gpio)
cam_gpio_ctrl(priv->i2c_client, gpio, val, 1);
else {
if (gpio_cansleep(gpio))
gpio_set_value_cansleep(gpio, val);
else
gpio_set_value(gpio, val);
}
}

static int imx224_power_on(struct camera_common_data *s_data)
{
int err = 0;
struct imx224 *priv = (struct imx224 *)s_data->priv;
struct camera_common_power_rail *pw = &priv->power;
printk(“%s\n”,func);
dev_dbg(&priv->i2c_client->dev, “%s: power on\n”, func);

if (priv->pdata && priv->pdata->power_on) {
	err = priv->pdata->power_on(pw);
	if (err)
		pr_err("%s failed.\n", __func__);
	else
		pw->state = SWITCH_ON;
	return err;
}

/* sleeps calls in the sequence below are for internal device
 * signal propagation as specified by sensor vendor */

if (pw->avdd)
	err = regulator_enable(pw->avdd);
if (err)
	goto imx224_avdd_fail;

if (pw->iovdd)
	err = regulator_enable(pw->iovdd);
if (err)
	goto imx224_iovdd_fail;

usleep_range(1, 2);
if (pw->pwdn_gpio)
	imx224_gpio_set(priv, pw->pwdn_gpio, 1);

/* datasheet 2.9: reset requires ~2ms settling time
 * a power on reset is generated after core power becomes stable */
usleep_range(2000, 2010);

if (pw->reset_gpio)
	imx224_gpio_set(priv, pw->reset_gpio, 1);

/* datasheet fig 2-9: t3 */
usleep_range(1350, 1360);

pw->state = SWITCH_ON;
return 0;

imx224_iovdd_fail:
regulator_disable(pw->avdd);

imx224_avdd_fail:
pr_err(“%s failed.\n”, func);
return -ENODEV;
}

static int imx224_power_off(struct camera_common_data *s_data)
{
int err = 0;
struct imx224 *priv = (struct imx224 *)s_data->priv;
struct camera_common_power_rail *pw = &priv->power;

dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__);
printk("%s\n",__func__);

if (priv->pdata && priv->pdata->power_on) {
	err = priv->pdata->power_off(pw);
	if (!err)
		pw->state = SWITCH_OFF;
	else
		pr_err("%s failed.\n", __func__);
	return err;
}

/* sleeps calls in the sequence below are for internal device
 * signal propagation as specified by sensor vendor */

usleep_range(21, 25);
if (pw->pwdn_gpio)
	imx224_gpio_set(priv, pw->pwdn_gpio, 0);
usleep_range(1, 2);
if (pw->reset_gpio)
	imx224_gpio_set(priv, pw->reset_gpio, 0);

/* datasheet 2.9: reset requires ~2ms settling time*/
usleep_range(2000, 2010);

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

return 0;

}

static int imx224_power_put(struct imx224 *priv)
{
struct camera_common_power_rail *pw = &priv->power;

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

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

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

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

if (priv->pdata->use_cam_gpio)
	cam_gpio_deregister(priv->i2c_client, pw->pwdn_gpio);
else {
	gpio_free(pw->pwdn_gpio);
	gpio_free(pw->reset_gpio);
}

return 0;

}

static int imx224_power_get(struct imx224 *priv)
{
struct camera_common_power_rail *pw = &priv->power;
struct camera_common_pdata *pdata = priv->pdata;
const char *mclk_name;
const char *parentclk_name;
struct clk *parent;
int err = 0;

mclk_name = priv->pdata->mclk_name ?
	    priv->pdata->mclk_name : "cam_mclk1";
pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name);
if (IS_ERR(pw->mclk)) {
	dev_err(&priv->i2c_client->dev,
		"unable to get clock %s\n", mclk_name);
	return PTR_ERR(pw->mclk);
}

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


/* analog 2.8v */
err |= camera_common_regulator_get(priv->i2c_client,
		&pw->avdd, pdata->regulators.avdd);
/* IO 1.8v */
err |= camera_common_regulator_get(priv->i2c_client,
		&pw->iovdd, pdata->regulators.iovdd);

if (!err) {
	pw->reset_gpio = pdata->reset_gpio;
	pw->pwdn_gpio = pdata->pwdn_gpio;
}

if (priv->pdata->use_cam_gpio) {
	err = cam_gpio_register(priv->i2c_client, pw->pwdn_gpio);
	if (err)
		dev_err(&priv->i2c_client->dev,
			"%s ERR can't register cam gpio %u!\n",
			 __func__, pw->pwdn_gpio);
} else {
	gpio_request(pw->pwdn_gpio, "cam_pwdn_gpio");
	gpio_request(pw->reset_gpio, "cam_reset_gpio");
}


pw->state = SWITCH_OFF;
return err;

}

static int imx224_set_gain(struct imx224 *priv, s32 val);
static int imx224_set_frame_length(struct imx224 *priv, s32 val);
static int imx224_set_coarse_time(struct imx224 *priv, s32 val);
static int imx224_set_coarse_time_short(struct imx224 *priv, s32 val);

static int imx224_s_stream(struct v4l2_subdev *sd, int enable)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct camera_common_data *s_data = to_camera_common_data(client);
struct imx224 *priv = (struct imx224 *)s_data->priv;
struct v4l2_control control;
int err;

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

if (!enable) {
	imx224_update_ctrl_range(priv, IMX224_MAX_FRAME_LENGTH);

	return imx224_write_table(priv,
		mode_table[IMX224_MODE_STOP_STREAM]);
}

err = imx224_write_table(priv, mode_table[s_data->mode]);
if (err)
	goto exit;

/* write list of override regs for the asking frame length,
 * coarse integration time, and gain. Failures to write
 * overrides are non-fatal */
control.id = V4L2_CID_GAIN;
err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
err |= imx224_set_gain(priv, control.value);
if (err)
	dev_dbg(&client->dev, "%s: warning gain override failed\n",
		__func__);

control.id = V4L2_CID_FRAME_LENGTH;
err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
err |= imx224_set_frame_length(priv, control.value);
if (err)
	dev_dbg(&client->dev,
		"%s: warning frame length override failed\n",
		__func__);

control.id = V4L2_CID_COARSE_TIME;
err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
err |= imx224_set_coarse_time(priv, control.value);
if (err)
	dev_dbg(&client->dev,
		"%s: warning coarse time override failed\n",
		__func__);

control.id = V4L2_CID_COARSE_TIME_SHORT;
err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
err |= imx224_set_coarse_time_short(priv, control.value);
if (err)
	dev_dbg(&client->dev,
		"%s: warning coarse time short override failed\n",
		__func__);

err = imx224_write_table(priv, mode_table[IMX224_MODE_START_STREAM]);
if (err)
	goto exit;

if (test_mode)
	err = imx224_write_table(priv,
		mode_table[IMX224_MODE_TEST_PATTERN]);

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

exit:
dev_dbg(&client->dev, “%s: error setting stream\n”, func);
return err;
}

static int imx224_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct camera_common_data *s_data = to_camera_common_data(client);
struct imx224 *priv = (struct imx224 *)s_data->priv;
struct camera_common_power_rail *pw = &priv->power;

*status = pw->state == SWITCH_ON;
return 0;

}

static struct v4l2_subdev_video_ops imx224_subdev_video_ops = {
.s_stream = imx224_s_stream,
.s_mbus_fmt = camera_common_s_fmt,
.g_mbus_fmt = camera_common_g_fmt,
.try_mbus_fmt = camera_common_try_fmt,
.enum_mbus_fmt = camera_common_enum_fmt,
.g_mbus_config = camera_common_g_mbus_config,
.g_input_status = imx224_g_input_status,
.enum_framesizes = camera_common_enum_framesizes,
.enum_frameintervals = camera_common_enum_frameintervals,
};

static struct v4l2_subdev_core_ops imx224_subdev_core_ops = {
.s_power = camera_common_s_power,
};

static int imx224_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *format)
{
printk(“%s\n”,func);
return camera_common_g_fmt(sd, &format->format);
}

static int imx224_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *format)
{
int ret;

printk("%s\n",__func__);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
	ret = camera_common_try_fmt(sd, &format->format);
else
	ret = camera_common_s_fmt(sd, &format->format);

return ret;

}

static struct v4l2_subdev_pad_ops imx224_subdev_pad_ops = {
.enum_mbus_code = camera_common_enum_mbus_code,
.set_fmt = imx224_set_fmt,
.get_fmt = imx224_get_fmt,
};

static struct v4l2_subdev_ops imx224_subdev_ops = {
.core = &imx224_subdev_core_ops,
.video = &imx224_subdev_video_ops,
.pad = &imx224_subdev_pad_ops,
};

static struct of_device_id imx224_of_match = {
{ .compatible = “nvidia,imx224”, },
{ },
};

static struct camera_common_sensor_ops imx224_common_ops = {
.power_on = imx224_power_on,
.power_off = imx224_power_off,
.write_reg = imx224_write_reg,
.read_reg = imx224_read_reg,
};

static int imx224_set_group_hold(struct imx224 *priv)
{
int err;
int gh_prev = switch_ctrl_qmenu[priv->group_hold_prev];

printk("%s\n",__func__);
if (priv->group_hold_en == true && gh_prev == SWITCH_OFF) {
	/* enter group hold */
	err = imx224_write_reg(priv->s_data,
			       IMX224_GROUP_HOLD_ADDR, 0x01);
	if (err)
		goto fail;

	priv->group_hold_prev = 1;

	dev_dbg(&priv->i2c_client->dev,
		 "%s: enter group hold\n", __func__);
} else if (priv->group_hold_en == false && gh_prev == SWITCH_ON) {
	/* leave group hold */
	err = imx224_write_reg(priv->s_data,
			       IMX224_GROUP_HOLD_ADDR, 0x11);
	if (err)
		goto fail;

	err = imx224_write_reg(priv->s_data,
			       IMX224_GROUP_HOLD_ADDR, 0x61);
	if (err)
		goto fail;

	priv->group_hold_prev = 0;

	dev_dbg(&priv->i2c_client->dev,
		 "%s: leave group hold\n", __func__);
}

return 0;

fail:
dev_dbg(&priv->i2c_client->dev,
“%s: Group hold control error\n”, func);
return err;
}

static u16 imx224_to_real_gain(u32 rep, int shift)
{
u16 gain;
int gain_int;
int gain_dec;
int min_int = (1 << shift);

printk("%s\n",__func__);
if (rep < IMX224_MIN_GAIN)
	rep = IMX224_MIN_GAIN;
else if (rep > IMX224_MAX_GAIN)
	rep = IMX224_MAX_GAIN;

gain_int = (int)(rep >> shift);
gain_dec = (int)(rep & ~(0xffff << shift));

/* derived from formulat gain = (x * 16 + 0.5) */
gain = ((gain_int * min_int + gain_dec) * 32 + min_int) / (2 * min_int);

return gain;

}

static int imx224_set_gain(struct imx224 *priv, s32 val)
{
imx224_reg reg_list[2];
int err;
u16 gain;
int i;

if (!priv->group_hold_prev)
	imx224_set_group_hold(priv);

/* translate value */
gain = imx224_to_real_gain((u32)val, IMX224_GAIN_SHIFT);

imx224_get_gain_regs(reg_list, gain);
dev_dbg(&priv->i2c_client->dev,
	 "%s: gain %04x val: %04x\n", __func__, val, gain);

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

return 0;

fail:
dev_dbg(&priv->i2c_client->dev,
“%s: GAIN control error\n”, func);
return err;
}

static void imx224_update_ctrl_range(struct imx224 *priv, s32 frame_length)
{
struct v4l2_ctrl *ctrl = NULL;
int ctrl_ids[2] = {V4L2_CID_COARSE_TIME,
V4L2_CID_COARSE_TIME_SHORT};
s32 max, min, def;
int i, j;

printk("%s\n",__func__);
for (i = 0; i < ARRAY_SIZE(ctrl_ids); i++) {
	for (j = 0; j < priv->numctrls; j++) {
		if (priv->ctrls[j]->id == ctrl_ids[i]) {
			ctrl = priv->ctrls[j];
			break;
		}
	}

	if (j == priv->numctrls) {
		dev_err(&priv->i2c_client->dev,
			"could not find ctrl %x\n",
			ctrl_ids[i]);
		continue;
	}

	max = frame_length - IMX224_MAX_COARSE_DIFF;
	/* clamp the value in case above is negative */
	max = clamp_val(max, IMX224_MIN_EXPOSURE_COARSE,
		IMX224_MAX_EXPOSURE_COARSE);
	min = IMX224_MIN_EXPOSURE_COARSE;
	def = clamp_val(IMX224_DEFAULT_EXPOSURE_COARSE, min, max);
	if (__v4l2_ctrl_modify_range(ctrl, min, max, 1, def))
		dev_err(&priv->i2c_client->dev,
			"ctrl %x: range update failed\n",
			ctrl_ids[i]);
}

}

static int imx224_set_frame_length(struct imx224 *priv, s32 val)
{
imx224_reg reg_list[2];
int err;
u32 frame_length;
int i;

printk("%s\n",__func__);
if (!priv->group_hold_prev)
	imx224_set_group_hold(priv);

frame_length = (u32)val;

imx224_get_frame_length_regs(reg_list, frame_length);
dev_dbg(&priv->i2c_client->dev,
	 "%s: val: %d\n", __func__, frame_length);

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

imx224_update_ctrl_range(priv, val);
return 0;

fail:
dev_dbg(&priv->i2c_client->dev,
“%s: FRAME_LENGTH control error\n”, func);
return err;
}

static int imx224_set_coarse_time(struct imx224 *priv, s32 val)
{
imx224_reg reg_list[3];
int err;
u32 coarse_time;
int i;

printk("%s\n",__func__);
if (!priv->group_hold_prev)
	imx224_set_group_hold(priv);

coarse_time = (u32)val;

imx224_get_coarse_time_regs(reg_list, coarse_time);
dev_dbg(&priv->i2c_client->dev,
	 "%s: val: %d\n", __func__, coarse_time);

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

return 0;

fail:
dev_dbg(&priv->i2c_client->dev,
“%s: COARSE_TIME control error\n”, func);
return err;
}

static int imx224_set_coarse_time_short(struct imx224 *priv, s32 val)
{
imx224_reg reg_list[3];
int err;
struct v4l2_control hdr_control;
int hdr_en;
u32 coarse_time_short;
int i;

printk("%s\n",__func__);
if (!priv->group_hold_prev)
	imx224_set_group_hold(priv);

/* check hdr enable ctrl */
hdr_control.id = V4L2_CID_HDR_EN;

err = camera_common_g_ctrl(priv->s_data, &hdr_control);
if (err < 0) {
	dev_err(&priv->i2c_client->dev,
		"could not find device ctrl.\n");
	return err;
}

hdr_en = switch_ctrl_qmenu[hdr_control.value];
if (hdr_en == SWITCH_OFF)
	return 0;

coarse_time_short = (u32)val;

imx224_get_coarse_time_short_regs(reg_list, coarse_time_short);
dev_dbg(&priv->i2c_client->dev,
	 "%s: val: %d\n", __func__, coarse_time_short);

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

return 0;

fail:
dev_dbg(&priv->i2c_client->dev,
“%s: COARSE_TIME_SHORT control error\n”, func);
return err;
}

static int imx224_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct imx224 *priv =
container_of(ctrl->handler, struct imx224, ctrl_handler);
int err = 0;

printk("%s\n",__func__);
if (priv->power.state == SWITCH_OFF)
	return 0;

switch (ctrl->id) {
case V4L2_CID_GAIN:
	err = imx224_set_gain(priv, ctrl->val);
	break;
case V4L2_CID_FRAME_LENGTH:
	err = imx224_set_frame_length(priv, ctrl->val);
	break;
case V4L2_CID_COARSE_TIME:
	err = imx224_set_coarse_time(priv, ctrl->val);
	break;
case V4L2_CID_COARSE_TIME_SHORT:
	err = imx224_set_coarse_time_short(priv, ctrl->val);
	break;
case V4L2_CID_GROUP_HOLD:
	if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) {
		priv->group_hold_en = true;
	} else {
		priv->group_hold_en = false;
		err = imx224_set_group_hold(priv);
	}
	break;
case V4L2_CID_HDR_EN:
	break;
default:
	pr_err("%s: unknown ctrl id.\n", __func__);
	return -EINVAL;
}

return err;

}

static int imx224_ctrls_init(struct imx224 *priv, bool eeprom_ctrl)
{
struct i2c_client *client = priv->i2c_client;
struct camera_common_data *common_data = priv->s_data;
struct v4l2_ctrl *ctrl;
int numctrls;
int err;
int i;

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

numctrls = ARRAY_SIZE(ctrl_config_list);
v4l2_ctrl_handler_init(&priv->ctrl_handler, numctrls);

for (i = 0; i < numctrls; i++) {
	ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler,
		&ctrl_config_list[i], NULL);
	if (ctrl == NULL) {
		dev_err(&client->dev, "Failed to init %s ctrl\n",
			ctrl_config_list[i].name);
		continue;
	}

	if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING &&
		ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) {
		ctrl->string = devm_kzalloc(&client->dev,
			ctrl_config_list[i].max + 1, GFP_KERNEL);
		if (!ctrl->string)
			return -ENOMEM;
	}
	priv->ctrls[i] = ctrl;
}

priv->numctrls = numctrls;
priv->subdev->ctrl_handler = &priv->ctrl_handler;
if (priv->ctrl_handler.error) {
	dev_err(&client->dev, "Error %d adding controls\n",
		priv->ctrl_handler.error);
	err = priv->ctrl_handler.error;
	goto error;
}

err = v4l2_ctrl_handler_setup(&priv->ctrl_handler);
if (err) {
	dev_err(&client->dev,
		"Error %d setting default controls\n", err);
	goto error;
}


return 0;

error:
v4l2_ctrl_handler_free(&priv->ctrl_handler);
return err;
}

MODULE_DEVICE_TABLE(of, imx224_of_match);

static struct camera_common_pdata *imx224_parse_dt(struct i2c_client *client)
{
struct device_node *node = client->dev.of_node;
struct camera_common_pdata *board_priv_pdata;
const struct of_device_id *match;
int gpio;
int err;

printk("%s\n",__func__);
if (!node)
	return NULL;

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

board_priv_pdata = devm_kzalloc(&client->dev,
		   sizeof(*board_priv_pdata), GFP_KERNEL);
if (!board_priv_pdata)
	return NULL;

err = camera_common_parse_clocks(client, board_priv_pdata);
if (err) {
	dev_err(&client->dev, "Failed to find clocks\n");
	goto error;
}

gpio = of_get_named_gpio(node, "pwdn-gpios", 0);
if (gpio < 0) {
	dev_err(&client->dev, "pwdn gpios not in DT\n");
	goto error;
}
board_priv_pdata->pwdn_gpio = (unsigned int)gpio;

gpio = of_get_named_gpio(node, "reset-gpios", 0);
if (gpio < 0) {
	/* reset-gpio is not absoluctly needed */
	dev_dbg(&client->dev, "reset gpios not in DT\n");
	gpio = 0;
}
board_priv_pdata->reset_gpio = (unsigned int)gpio;

board_priv_pdata->use_cam_gpio =
	of_property_read_bool(node, "cam,use-cam-gpio");

err = of_property_read_string(node, "avdd-reg",
		&board_priv_pdata->regulators.avdd);
if (err) {
	dev_err(&client->dev, "avdd-reg not in DT\n");
	goto error;
}
err = of_property_read_string(node, "iovdd-reg",
		&board_priv_pdata->regulators.iovdd);
if (err) {
	dev_err(&client->dev, "iovdd-reg not in DT\n");
	goto error;
}

return board_priv_pdata;

error:
devm_kfree(&client->dev, board_priv_pdata);
return NULL;
}

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

printk("%s\n",__func__);
pr_info("[andy IMX224]: open v4l2 sensor.\n");
dev_dbg(&client->dev, "%s:\n", __func__);
return 0;

}

static const struct v4l2_subdev_internal_ops imx224_subdev_internal_ops = {
.open = imx224_open,
};

static const struct media_entity_operations imx224_media_ops = {
.link_validate = v4l2_subdev_link_validate,
};

static int imx224_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct camera_common_data *common_data;
struct device_node *node = client->dev.of_node;
struct imx224 *priv;
char debugfs_name[10];
int err;

pr_info("[andy IMX224]: probing v4l2 sensor.\n");

if (!IS_ENABLED(CONFIG_OF) || !node)
	return -EINVAL;

common_data = devm_kzalloc(&client->dev,
		    sizeof(struct camera_common_data), GFP_KERNEL);
if (!common_data)
	return -ENOMEM;

priv = devm_kzalloc(&client->dev,
		    sizeof(struct imx224) + sizeof(struct v4l2_ctrl *) *
		    ARRAY_SIZE(ctrl_config_list),
		    GFP_KERNEL);
if (!priv)
	return -ENOMEM;

priv->regmap = devm_regmap_init_i2c(client, &imx224_regmap_config);
if (IS_ERR(priv->regmap)) {
	dev_err(&client->dev,
		"regmap init failed: %ld\n", PTR_ERR(priv->regmap));
	return -ENODEV;
}

priv->pdata = imx224_parse_dt(client);
if (!priv->pdata) {
	dev_err(&client->dev, "unable to get platform data\n");
	return -EFAULT;
}

common_data->ops		= &imx224_common_ops;
common_data->ctrl_handler	= &priv->ctrl_handler;
common_data->i2c_client		= client;
common_data->frmfmt		= imx224_frmfmt;
common_data->colorfmt		= camera_common_find_datafmt(
				  IMX224_DEFAULT_DATAFMT);
common_data->power		= &priv->power;
common_data->ctrls		= priv->ctrls;
common_data->priv		= (void *)priv;
common_data->numctrls		= ARRAY_SIZE(ctrl_config_list);
common_data->numfmts		= ARRAY_SIZE(imx224_frmfmt);
common_data->def_mode		= IMX224_DEFAULT_MODE;
common_data->def_width		= IMX224_DEFAULT_WIDTH;
common_data->def_height		= IMX224_DEFAULT_HEIGHT;
common_data->fmt_width		= common_data->def_width;
common_data->fmt_height		= common_data->def_height;
common_data->def_clk_freq	= IMX224_DEFAULT_CLK_FREQ;

priv->i2c_client = client;
priv->s_data			= common_data;
priv->subdev			= &common_data->subdev;
priv->subdev->dev		= &client->dev;
priv->s_data->dev		= &client->dev;

err = imx224_power_get(priv);
if (err)
	return err;

pr_info("[andy IMX224]: probing v4l2 sensor 1.\n");
err = camera_common_parse_ports(client, common_data);
if (err) {
	dev_err(&client->dev, "Failed to find port info\n");
	return err;
}
sprintf(debugfs_name, "imx224_%c", common_data->csi_port + 'a');
dev_err(&client->dev, "%s: name %s\n", __func__, debugfs_name);
camera_common_create_debugfs(common_data, debugfs_name);

v4l2_i2c_subdev_init(priv->subdev, client, &imx224_subdev_ops);

err = imx224_ctrls_init(priv, !err);
if (err)
	return err;

pr_info("[andy IMX224]: probing v4l2 sensor 2.\n");
priv->subdev->internal_ops = &imx224_subdev_internal_ops;
priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
		       V4L2_SUBDEV_FL_HAS_EVENTS;

#if defined(CONFIG_MEDIA_CONTROLLER)
priv->pad.flags = MEDIA_PAD_FL_SOURCE;
priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
priv->subdev->entity.ops = &imx224_media_ops;
err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0);
if (err < 0) {
dev_err(&client->dev, “unable to init media entity\n”);
return err;
}
#endif

err = v4l2_async_register_subdev(priv->subdev);
if (err)
	return err;

printk("Detected IMX224 sensor\n");
dev_dbg(&client->dev, "Detected IMX224 sensor\n");


return 0;

}

static int
imx224_remove(struct i2c_client *client)
{
struct camera_common_data *s_data = to_camera_common_data(client);
struct imx224 *priv = (struct imx224 *)s_data->priv;

v4l2_async_unregister_subdev(priv->subdev);

#if defined(CONFIG_MEDIA_CONTROLLER)
media_entity_cleanup(&priv->subdev->entity);
#endif

v4l2_ctrl_handler_free(&priv->ctrl_handler);
imx224_power_put(priv);
camera_common_remove_debugfs(s_data);

return 0;

}

static const struct i2c_device_id imx224_id = {
{ “imx224”, 0 },
{ }
};

MODULE_DEVICE_TABLE(i2c, imx224_id);

static struct i2c_driver imx224_i2c_driver = {
.driver = {
.name = “imx224”,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(imx224_of_match),
},
.probe = imx224_probe,
.remove = imx224_remove,
.id_table = imx224_id,
};

module_i2c_driver(imx224_i2c_driver);

MODULE_DESCRIPTION(“SoC Camera driver for Sony IMX224”);
MODULE_AUTHOR(“David Wang davidw@nvidia.com”);
MODULE_LICENSE(“GPL v2”);

Hi PanAndy
Looks like the CSI got time out to receive SOF. Please make you you power sequence is correct, and probe the MIPI signal to make sure the signal match the MIPI spec.

Hello ShaneCCC,

Using Main Platform Device Tree not Plugin Manager is ok?

Yes, you can check the “Sensor Driver Programming Guide” chapter to know it.

Hi ShaneCCC,

Thanks for your information. Now I have enabled the YUV sensor. But the preview is not ok.
3 frames are green + 1 frame is ok.

Can you share me some suggestions, thanks

I dump the YUV data from the following cmd.

v4l2-ctl -d /dev/video0 -w --verbose --set-fmt-video=width=1280,height=720,pixelformat=UYVY --set-ctrl bypass_mode=0 --stream-mmap --stream-count=20 --stream-to=test.yuv


I think sensor setting is wrong!

green is video data zero.

UYVY data all zero displayed green

test under command…
/usr/bin/gst-launch-1.0 v4l2src device=/dev/video0 !
‘video/x-raw,format=UYVY,width=1280,height=720,framerate=30/1’ !
nvvidconv ! ‘video/x-raw(memory:NVMM),width=1280,height=720,format=I420’ !
nvoverlaysink sync=false

so if your sensor output UYVY. then not use NVIDIA ISP block.
device tree file wrong.

Hi PanAndy
I think you almost successful.
Does the v4l2-ctl can dump good frame?
You may need to modify the discontinuous_clk in the device tree to try.

Hi ShaneCCC,

I have modify the discontinuous_clk =“yes”, but it’s no effect.

The sensor FAE told me the sensor output one additional line. 1280x721.

Can I modify the kernel driver to skip this line.

I try to modify embedded_metadata_height = “1”, it’s also no useful.

Does it emdedded metadata ? Do you capture it with v4l2-ctrl? How you try the gst-launch? Any kernel error show up.

Hi ShaneCCC,

I dump yuv data with v4l2-ctrl.

and I have tried the gst-launch, the preview is not ok, Auto exposure is instability,green.

the kernel log is as followed. In my opinion, just the first or the sencond frame is wrong
[ 76.755132] ov5693 6-0036: ov5693_s_stream++
[ 76.759972] ov5693 6-0036: ov5693_s_stream++
[ 76.766361] ov5693 6-0036: ov5693_set_gain: gain 0100 val: 0010
[ 76.772359] ov5693 6-0036: ov5693_set_frame_length: val: 1984
[ 76.779345] ov5693 6-0036: ov5693_set_coarse_time: val: 1978
[ 76.785533] ov5693 6-0036: ov5693_s_stream–
[ 76.793340] tegra_mipi_cal 700e3000.mipical: Mipi cal timeout,val:1168b0, lanes:300000
[ 77.054016] video4linux video0: MW_ACK_DONE syncpoint time out!0
[ 77.061137] ov5693 6-0036: ov5693_s_stream++
[ 77.076502] ov5693 6-0036: ov5693_power_off: power off

Hi ShaneCCC,

Now I have fixed this issue. The resolution 1280x720 is not right. 1280x800 is right.
But the preview fps is very low, maybe 10fps.
I doubt the ability to handle the frame is low.
How to change the code to enlarge the MIPI frequency.

PanAndy
Did you probe the MIPI clock?
The mipi clock is control by the sensor setting. It’s better to consult with the sensor vendor.