Support LT6911UXE

In order to adapt the LT6911UXE HDMI to MIPI chip, we made the following changes to the device tree:

/ {
	tegra-capture-vi {
		num-channels = <1>;
		ports {
			#address-cells = <1>;
			#size-cells = <0>;
			port@0 {
				reg = <0>;
				e2832_vi_in0: endpoint {
					port-index = <0>;
					bus-width = <2>;
					remote-endpoint = <&e2832_csi_out0>;
				};
			};
		};
	};

	host1x@13e00000 {
        /* Delete existing VI node to avoid conflicts */
        // /delete-node/ vi;
        
		nvcsi@15a00000 {
			num-channels = <1>;
			#address-cells = <1>;
			#size-cells = <0>;
			channel@0 {
				reg = <0>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						e2832_csi_in0: endpoint@0 {
							port-index = <0>;
							bus-width = <2>;
							remote-endpoint = <&e2832_out0>;
						};
					};
					port@1 {
						reg = <1>;
						e2832_csi_out0: endpoint@1 {
							remote-endpoint = <&e2832_vi_in0>;
						};
					};
				};
			};
		};
	};

	i2c@3180000 {
        clock-frequency = <400000>;
        status = "okay";
        
		e2832@2b {
			compatible = "uih,lt6911uxe";
            reset-gpios = <&tegra_main_gpio TEGRA194_MAIN_GPIO(T, 5) GPIO_ACTIVE_LOW>;
            
			/* I2C device address */
			reg = <0x2b>;

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

			/* Physical dimensions of sensor */
			physical_w = "3.674";
			physical_h = "2.738";

			sensor_model = "e2832";

			mode0 { // E2832_1280x720_60Fps
				mclk_khz = "24000";
				num_lanes = "2";
				tegra_sinterface = "serial_a";
				phy_mode = "DPHY";
				discontinuous_clk = "yes";
				dpcm_enable = "false";
				cil_settletime = "0";
                            
				active_w = "1280";
				active_h = "720";
				mode_type = "yuv";
				pixel_phase = "uyvy";
				csi_pixel_bit_depth = "16";
				readout_orientation = "0";
				// line_length = "1650";
				line_length = "1650";
				inherent_gain = "1";
				// /*mclk_multiplier = "24";*/
				pix_clk_hz = "74082000";

				horz_front_porch="110";
                horz_sync="40";
                horz_back_porch="220";
                vert_front_porch="5";
                vert_sync="5";
                vert_back_porch="20";

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

			ports {
				#address-cells = <1>;
				#size-cells = <0>;
				port@0 {
					reg = <0>;
					e2832_out0: endpoint {
						port-index = <0>;
						bus-width = <2>;
						remote-endpoint = <&e2832_csi_in0>;
					};
				};
			};
		};
	};
};

/ {

	tegra-camera-platform {
		compatible = "nvidia, tegra-camera-platform";
		
        num_csi_lanes = <2>;
		max_lane_speed = <1500000>;
		min_bits_per_pixel = <16>;
		vi_peak_byte_per_pixel = <2>;
		vi_bw_margin_pct = <25>;
		max_pixel_rate = <750000>;
		isp_peak_byte_per_pixel = <5>;
		isp_bw_margin_pct = <25>;
		status = "ok";

		modules {
			module0 {
				badge = "e2832_ltx6911";
				position = "bottom";
				orientation = "1";
				drivernode0 {
					/* Declare PCL support driver (classically known as guid)  */
					pcl_id = "v4l2_sensor";
					/* Driver v4l2 device name */
					devname = "e2832 2-002b";
					/* Declare the device-tree hierarchy to driver instance */
					proc-device-tree = "/proc/device-tree/i2c@3180000/e2832@2b";
				};
			};
		};
	};
};

After loading the driver everything looks fine and you can even generate the /dev/video0 node. But when we use nvarguscamerasrc to get the data, we get the following error:

gst-launch-1.0 nvarguscamerasrc ! "video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, framerate=(fraction)60/1"  ! nvvidconv ! nv3dsink sync=0 -vvv
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Error generated. /dvs/git/dirty/git-master_linux/multimedia/nvgstreamer/gst-nvarguscamera/gstnvarguscamerasrc.cpp, execute:751 No cameras available
/GstPipeline:pipeline0/GstNvArgusCameraSrc:nvarguscamerasrc0.GstPad:src: caps = video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)NV12, framerate=(fraction)60/1
/GstPipeline:pipeline0/GstCapsFilter:capsfilter0.GstPad:src: caps = video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)NV12, framerate=(fraction)60/1
/GstPipeline:pipeline0/Gstnvvconv:nvvconv0.GstPad:src: caps = video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, framerate=(fraction)60/1, format=(string)RGBA
/GstPipeline:pipeline0/GstNv3dSink:nv3dsink0.GstPad:sink: caps = video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, framerate=(fraction)60/1, format=(string)RGBA
/GstPipeline:pipeline0/Gstnvvconv:nvvconv0.GstPad:sink: caps = video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)NV12, framerate=(fraction)60/1
/GstPipeline:pipeline0/GstCapsFilter:capsfilter0.GstPad:sink: caps = video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)NV12, framerate=(fraction)60/1
Got EOS from element "pipeline0".
Execution ended after 0:00:00.028872832
Setting pipeline to NULL ...
Freeing pipeline ...

lt6911uxe.ko just like this:

static const struct of_device_id lt6911uxe_of_match[] = {
	{ .compatible = "uih,lt6911uxe", },
	{ },
};
MODULE_DEVICE_TABLE(of, lt6911uxe_of_match);

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

static const int lt6911uxe_60fps[] = {
	60,
};

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

struct lt6911uxe {
	struct i2c_client		*i2c_client;
	struct v4l2_subdev		*sd;
	u16	fine_integ_time;
	u32	frame_length;
	struct camera_common_data	*s_data;
	struct tegracam_device		*tc_dev;
};

static const struct camera_common_frmfmt lt6911uxe_frmfmt[] = {
	// {{1920, 1080}, lt6911uxe_60fps, 1, 0, 0},
	// {{3840, 2160}, lt6911uxe_60fps, 1, 0, 1},
	{{1280,  720}, lt6911uxe_60fps, 1, 0, 0},
};

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

static int lt6911uxe_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
    printk("%s: %d \n", __func__, __LINE__);
    
	return 0;
}

static int lt6911uxe_set_group_hold(struct tegracam_device *tc_dev, bool val)
{
	/* lt6911uxe does not support group hold */
    printk("%s: %d \n", __func__, __LINE__);
	return 0;
}

/* As soon as the reset pin is released, the bridge starts streaming */
static int lt6911uxe_start_streaming(struct tegracam_device *tc_dev)
{
	struct camera_common_data *s_data = tc_dev->s_data;
	struct camera_common_power_rail *pw = s_data->power;
    struct lt6911uxe *priv = (struct lt6911uxe *)s_data->priv;
	struct v4l2_subdev *sd = priv->sd;
printk("%s: %d \n", __func__, __LINE__);
	if (pw->reset_gpio) {
		if (gpio_cansleep(pw->reset_gpio))
			gpio_set_value_cansleep(pw->reset_gpio, 1);
		else
			gpio_set_value(pw->reset_gpio, 1);
	}

	/* Add By Ali*/
	stream_switch(sd, true);   // Write register to stream on

	return 0;
}

static int lt6911uxe_stop_streaming(struct tegracam_device *tc_dev)
{
	struct camera_common_data *s_data = tc_dev->s_data;
	struct camera_common_power_rail *pw = s_data->power;
	struct lt6911uxe *priv = (struct lt6911uxe *)s_data->priv;
	struct v4l2_subdev *sd = priv->sd;
printk("%s: %d \n", __func__, __LINE__);
	if (pw->reset_gpio) {
		if (gpio_cansleep(pw->reset_gpio))
			gpio_set_value_cansleep(pw->reset_gpio, 0);
		else
			gpio_set_value(pw->reset_gpio, 0);
	}

	/* Add By Ali*/
	// stream_switch(sd, false);

	return 0;
}

static int lt6911uxe_set_mode(struct tegracam_device *tc_dev)
{
	/* Width and Height taken care of by the firmware */
    printk("%s: %d \n", __func__, __LINE__);
	return 0;
}

static inline int lt6911uxe_read_reg(struct camera_common_data *s_data,
	u16 addr, u8 *val)
{
	int err = 0;
	u32 reg_val = 0;
printk("%s: %d \n", __func__, __LINE__);
	err = regmap_read(s_data->regmap, addr, &reg_val);
	*val = reg_val & 0xff;

	return err;
}

static inline int lt6911uxe_write_reg(struct camera_common_data *s_data,
	u16 addr, u8 val)
{
    printk("%s: %d \n", __func__, __LINE__);
	return 0;
}

static int lt6911uxe_power_get(struct tegracam_device *tc_dev)
{
	struct device *dev = tc_dev->dev;
	struct camera_common_data *s_data = tc_dev->s_data;
	struct camera_common_power_rail *pw = s_data->power;
	struct camera_common_pdata *pdata = s_data->pdata;
	struct clk *parent;
	int err = 0;
printk("%s: %d \n", __func__, __LINE__);
	if (!pdata) {
		dev_err(dev, "pdata missing\n");
		return -EFAULT;
	}

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

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

	/* analog 3.3v */
	if (pdata->regulators.avdd)
		err |= camera_common_regulator_get(dev, &pw->avdd, pdata->regulators.avdd);

	if (err) {
		dev_err(dev, "%s: unable to get regulator(s)\n", __func__);
		goto done;
	}

	/* dig 1.2v */
	if (pdata->regulators.dvdd)
		err |= camera_common_regulator_get(dev, &pw->dvdd, pdata->regulators.dvdd);

	if (err) {
		dev_err(dev, "%s: unable to get regulator(s)\n", __func__);
		goto done;
	}

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

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

done:
	pw->state = SWITCH_OFF;

	return err;
}

static int lt6911uxe_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;
printk("%s: %d \n", __func__, __LINE__);
	if (unlikely(!pw))
		return -EFAULT;

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

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

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

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

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

	return 0;
}

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

	if (!np)
		return NULL;

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

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

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

	err = of_property_read_string(np, "mclk", &board_priv_pdata->mclk_name);
	if (err)
		dev_err(dev, "mclk absent,assuming sensor driven externally\n");

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

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

	return board_priv_pdata;

error:
	devm_kfree(dev, board_priv_pdata);

	return ret;
}

static int lt6911uxe_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;
    
    
printk("%s: %d \n", __func__, __LINE__);
	if (pdata && pdata->power_on) {
		err = pdata->power_on(pw);
		if (err)
			dev_err(dev, "%s failed.\n", __func__);
		else
			pw->state = SWITCH_ON;
		return err;
	}

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

	usleep_range(10, 20);

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

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

	/* Need to wait for atleat 1 ms before turning up 1.2v */
	usleep_range(1000, 1200);
	if (pw->dvdd) {
		err = regulator_enable(pw->dvdd);
		if (err)
			goto lt6911uxe_dvdd_fail;
	}

	usleep_range(10, 20);

	pw->state = SWITCH_ON;

	return 0;

lt6911uxe_dvdd_fail:
	regulator_disable(pw->iovdd);

lt6911uxe_iovdd_fail:
	regulator_disable(pw->avdd);

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

	return -ENODEV;
}

static int lt6911uxe_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;
    printk("%s: %d \n", __func__, __LINE__);
	if (pdata && pdata->power_off) {
		err = pdata->power_off(pw);
		if (err) {
			dev_err(dev, "%s failed.\n", __func__);
			return err;
		}
	} else {
		if (pw->reset_gpio) {
			if (gpio_cansleep(pw->reset_gpio))
				gpio_set_value_cansleep(pw->reset_gpio, 0);
			else
				gpio_set_value(pw->reset_gpio, 0);
		}
	}

	usleep_range(10, 20);

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

	pw->state = SWITCH_OFF;

	return 0;
}

static int lt6911uxe_board_setup(struct lt6911uxe *priv)
{
	struct camera_common_data *s_data = priv->s_data;
	struct camera_common_pdata *pdata = s_data->pdata;
	struct device *dev = s_data->dev;
	int err = 0;
    
    printk("%s: %d \n", __func__, __LINE__);
    
	if (pdata->mclk_name) {
		err = camera_common_mclk_enable(s_data);
		if (err) {
			dev_err(dev, "error turning on mclk (%d)\n", err);
			goto done;
		}
	}

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

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

done:
	return err;
}

static struct tegracam_ctrl_ops lt6911uxe_ctrl_ops = {
	.set_group_hold = lt6911uxe_set_group_hold,
};

static const struct v4l2_subdev_internal_ops lt6911uxe_subdev_internal_ops = {
	.open = lt6911uxe_open,
};

static struct camera_common_sensor_ops lt6911uxe_common_ops = {
	.numfrmfmts = ARRAY_SIZE(lt6911uxe_frmfmt),
	.frmfmt_table = lt6911uxe_frmfmt,
	.power_on = lt6911uxe_power_on,
	.power_off = lt6911uxe_power_off,
	.write_reg = lt6911uxe_write_reg,
	.read_reg = lt6911uxe_read_reg,
	.parse_dt = lt6911uxe_parse_dt,
	.power_get = lt6911uxe_power_get,
	.power_put = lt6911uxe_power_put,
	.set_mode = lt6911uxe_set_mode,
	.start_streaming = lt6911uxe_start_streaming,
	.stop_streaming = lt6911uxe_stop_streaming,
};


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

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

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

	priv = devm_kzalloc(dev, sizeof(struct lt6911uxe), 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, "lt6911uxe", sizeof(tc_dev->name));
	tc_dev->dev_regmap_config = &sensor_regmap_config;
	tc_dev->sensor_ops = &lt6911uxe_common_ops;
	tc_dev->v4l2sd_internal_ops = &lt6911uxe_subdev_internal_ops;
	tc_dev->tcctrl_ops = &lt6911uxe_ctrl_ops;

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

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

	err = tegracam_v4l2subdev_register(tc_dev, true);
	if (err) {
		dev_err(dev, "tegra camera subdev registration failed\n");
		return err;
	}
    
    stream_switch(priv->sd, true);
	dev_err(dev, "detected lt6911uxe sensor\n");

	return 0;
}

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

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

	return 0;
}

static const struct i2c_device_id lt6911uxe_id[] = {
	{ "uih,lt6911uxe", 0 },
	{ }
};

MODULE_DEVICE_TABLE(i2c, lt6911uxe_id);

static struct i2c_driver lt6911uxe_i2c_driver = {
	.driver = {
		.name = "uih,lt6911uxe",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(lt6911uxe_of_match),
	},
	.probe = lt6911uxe_probe,
	.remove = lt6911uxe_remove,
	.id_table = lt6911uxe_id,
};
module_i2c_driver(lt6911uxe_i2c_driver);

What are the possible reasons for the above phenomenon?

Sorry to tell nvarguscamerasrc don’t support YUV sensor.
Suppose you need use v4l2src or v4l2 APP for it.

Which sensor formats are supported by nvarguscamerasrc?

Only support Bayer format.

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