需要做哪些工作
要实现一个新的MIPI Sensor的驱动,我们需要实现如下图中红框的两个部分:
1 - DTS
2 - V4L2 device driver
如何做
我们依旧以官方文档中的imx185为例, 主要是如下2个文件的实现:
source/nvidia-oot/drivers/media/i2c/nv_imx185.c
source/nvidia-oot/drivers/media/i2c/imx185_mode_tbls.h
|- function list
|| imx185_get_frame_length_regs
|| imx185_get_coarse_time_regs_shs1
|| imx185_get_coarse_time_regs_shs2
|| imx185_get_gain_reg
|| imx185_read_reg
|| imx185_write_reg
|| imx185_write_table
|| imx185_set_group_hold
|| imx185_set_gain
|| imx185_set_coarse_time
|| imx185_set_coarse_time_hdr
|| imx185_set_frame_rate
|| imx185_set_exposure
|| imx185_fill_string_ctrl
|| imx185_power_on
|| imx185_power_off
|| imx185_power_get
|| imx185_power_put
|| imx185_parse_dt
|| imx185_set_mode
|| imx185_start_streaming
|| imx185_stop_streaming
|| imx185_fuse_id_setup
|| imx185_board_setup
|| imx185_open
|| imx185_probe
|| imx185_remove
实现通用操作函数集
这些函数是对sensor的最基本控制,必须要实现
700 static struct camera_common_sensor_ops imx185_common_ops = {
701 .numfrmfmts = ARRAY_SIZE(imx185_frmfmt),
702 .frmfmt_table = imx185_frmfmt,
703 .power_on = imx185_power_on,
704 .power_off = imx185_power_off,
705 .write_reg = imx185_write_reg,
706 .read_reg = imx185_read_reg,
707 .parse_dt = imx185_parse_dt,
708 .power_get = imx185_power_get,
709 .power_put = imx185_power_put,
710 .set_mode = imx185_set_mode,
711 .start_streaming = imx185_start_streaming,
712 .stop_streaming = imx185_stop_streaming,
713 };
实现曝光控制函数集
Jetson V4L2 相机框架目前支持的自定义 V4L2 ctrl
财产 | 价值 |
---|---|
TEGRA_CAMERA_CID_GAIN | 传感器增益,64 位 Q 格式值。该值为n ,比例为 1: n。 例如,值 3 表示比例为 1:3,即产生 3 倍放大。 属性值对(仅限版本 2.0) 有关详细信息,请参阅增益控制。 |
TEGRA_CAMERA_CID_FRAME_RATE | 帧速率,以帧/秒为单位。 |
TEGRA_CAMERA_CID_EXPOSURE | 曝光时间,以秒为单位。更多信息,请参阅曝光控制。 |
TEGRA_CAMERA_CID_EXPOSURE_SHORT | 可选。曝光时间(以秒为单位)。用于 HDR 传感器的短曝光帧。更多信息,请参阅曝光控制。 |
TEGRA_CAMERA_CID_HDR_ENABLE | 可选。布尔值;指示传感器是在 HDR 传感器模式下运行 (true) 还是在正常传感器模式下运行 (false)。 |
TEGRA_CAMERA_CID_EEPROM_DATA | 读取模块的 EEPROM 数据。 |
TEGRA_CAMERA_CID_OTP_DATA | 可选。读取模块的一次性可编程 (OTP) 内存数据。 |
TEGRA_CAMERA_CID_FUSE_ID | 可选。读取传感器chip ID。 |
TEGRA_CAMERA_CID_GROUP_HOLD | 布尔值。用于控制支持此功能的传感器的传感器组保持(寄存器保持)。 由 Jetson V4L2 相机框架提供。 |
TEGRA_CAMERA_CID_SENSOR_MODE_ID | 可选。强制 Jetson V4L2 相机框架使用特定的传感器模式,绕过其默认模式选择逻辑。 值是从零开始的索引,即传感器设备树 |
TEGRA_CAMERA_CID_VI_BYPASS_MODE | 布尔值。设置为 true 可绕过内核驱动程序中的 VI 设置。使用相机核心库时,默认值为 true。 由 NVIDIA V4L2 媒体控制器框架内核驱动程序提供。 |
TEGRA_CAMERA_CID_OVERRIDE_ENABLE | 覆盖默认传感器模式表中的增益和曝光设置。 由 NVIDIA V4L2 媒体控制器框架内核驱动程序提供。 |
imx185实现的ctrl list
59 static const u32 ctrl_cid_list[] = {
60 TEGRA_CAMERA_CID_GAIN,
61 TEGRA_CAMERA_CID_EXPOSURE,
62 TEGRA_CAMERA_CID_FRAME_RATE,
63 TEGRA_CAMERA_CID_FUSE_ID,
64 TEGRA_CAMERA_CID_HDR_EN,
65 TEGRA_CAMERA_CID_SENSOR_MODE_ID,
66 };
67
绑定注册V4L2 Ctrl对应的函数
464 static struct tegracam_ctrl_ops imx185_ctrl_ops = {
465 .numctrls = ARRAY_SIZE(ctrl_cid_list),
466 .ctrl_cid_list = ctrl_cid_list,
467 .string_ctrl_size = {0, IMX185_FUSE_ID_STR_SIZE},
468 .set_gain = imx185_set_gain,
469 .set_exposure = imx185_set_exposure,
470 .set_frame_rate = imx185_set_frame_rate,
471 .set_group_hold = imx185_set_group_hold,
472 .fill_string_ctrl = imx185_fill_string_ctrl,
473 };
描述Sensor的结构体
68 struct imx185 {
69 struct i2c_client *i2c_client;
70 struct v4l2_subdev *subdev;
71 u8 fuse_id[IMX185_FUSE_ID_SIZE];
72 u32 frame_length;
73 s64 last_wdr_et_val;
74 struct camera_common_data *s_data;
75 struct tegracam_device *tc_dev;
76 };
属性 | 值 |
---|---|
i2c_client |
|
subdev | V4L2 子设备的句柄,用于执行子设备操作(ops)。 |
fuse_id | 在此字符数组中保存传感器的chip ID 信息。 |
frame_length | 保留先前的值 |
last_wdr_et_val | 保留 WDR 模式的先前曝光时间。 |
s_data | 指向 struct 的指针 |
tc_dev | 指向 struct |
probe() 关键调用栈
nv_imx185_probe()
-
→ devm_kzalloc() //创建主结构体 imx185和tegracam_device。
-
初始化操作函数集,包括camera_common_sensor_ops, v4l2_subdev_internal_ops, tegracam_ctrl_ops。
-
→ tegracam_device_register() //注册tegracam设备,解析dts,获取power 属性,解析port属性,解析use_sensor_mode_id,解析i2c属性,注册debugfs,获取sensor_mode,signal_props,image_props,获取sensor尺寸格式,mclk,把tc_dev添加到已注册设备链表。
-
→ imx185_board_setup //() 初始化外设资源,设置mclk,上下电sensor,读取chip id。
-
→ tegracam_v4l2subdev_register() //V4L2 框架注册subdev,sd初始化, i2c client初始化, 异步注册v4l2 subdev, media entity初始化。
模式列表
模式表可以引用数千个寄存器。这会增加传感器开始流式传输之前的延迟,延迟时间相当于对所有寄存器进行编程所需的时间。在极端情况下,接收引擎可能会在传感器输出第一帧之前超时。
有几种可能的方法可以纠正这个问题:
-
减少模式表中引用的寄存器数量。您或许可以从传感器供应商处获取较小的模式表。大多数寄存器通常设置为默认值,无需更新。
-
将寄存器按小组排列,并设置连续的寄存器地址。NVIDIA 内核驱动程序支持
regmap()
批量写入多达 16 个连续寄存器,这可以减少 I2C/SPI 事务的数量。请咨询传感器供应商,确保执行此操作不会影响传感器的运行。 -
请求捕获引擎延长延迟时间,以防止超时。您可以将设备树属性添加
set_mode_delay_ms
到传感器.dtsi
文件,以延长第一帧的等待时间。 -
具体书写格式照葫芦画瓢即可,每种mode的寄存器值从sensor 厂商FAE处获取。
26 static imx185_reg imx185_start[] = { 27 {0x3000, 0x00 }, 28 {IMX185_TABLE_WAIT_MS, IMX185_WAIT_MS_START}, 29 {0x3002, 0x00}, 30 {0x3049, 0x02}, 31 {IMX185_TABLE_WAIT_MS, IMX185_WAIT_MS_STREAM}, 32 { IMX185_TABLE_END, 0x00 } 33 }; 34 35 static imx185_reg imx185_stop[] = { 36 {0x3000, 0x01 }, 37 {IMX185_TABLE_WAIT_MS, IMX185_WAIT_MS_STOP}, 38 {IMX185_TABLE_END, 0x00 } 39 }; 40 41 static imx185_reg tp_colorbars[] = { 42 {0x300A, 0x00},/*BLC for PG*/ 43 {0x300E, 0x00}, 44 {0x3089, 0x00}, 45 {0x308C, 0x13}, 46 /* 47 * bit 0: PG mode enable 48 * bit 1: Back Ground Transient: 49 * bit [4-7]: PG mode setting, Set at 0h to Fh, suggest 1 or 5 50 * raw12 max output FFEh 51 */ 52 {IMX185_TABLE_WAIT_MS, IMX185_WAIT_MS_STOP}, 53 {IMX185_TABLE_END, 0x00} 54 }; . . . 954 enum { 955 IMX185_MODE_1920X1080_CROP_30FPS, 956 IMX185_MODE_1920X1080_CROP_10BIT_30FPS, 957 IMX185_MODE_1920X1080_CROP_60FPS, 958 IMX185_MODE_1920X1080_CROP_10BIT_60FPS, 959 IMX185_MODE_1920X1080_CROP_HDR_30FPS, 960 IMX185_MODE_START_STREAM, 961 IMX185_MODE_STOP_STREAM, 962 IMX185_MODE_TEST_PATTERN 963 }; 964 965 static imx185_reg *mode_table[] = { 966 [IMX185_MODE_1920X1080_CROP_30FPS] = imx185_1920x1080_crop_30fps, 967 [IMX185_MODE_1920X1080_CROP_10BIT_30FPS] = 968 imx185_1920x1080_crop_10bit_30fps, 969 [IMX185_MODE_1920X1080_CROP_60FPS] = imx185_1920x1080_crop_60fps, 970 [IMX185_MODE_1920X1080_CROP_10BIT_60FPS] = 971 imx185_1920x1080_crop_10bit_60fps, 972 [IMX185_MODE_1920X1080_CROP_HDR_30FPS] = 973 imx185_1920x1080_hdr_crop_30fps, 974 [IMX185_MODE_START_STREAM] = imx185_start, 975 [IMX185_MODE_STOP_STREAM] = imx185_stop, 976 [IMX185_MODE_TEST_PATTERN] = tp_colorbars, 977 }; 987 /* 988 * WARNING: frmfmt ordering need to match mode definition in 989 * device tree! 990 */ 991 static const struct camera_common_frmfmt imx185_frmfmt[] = { 992 {{1920, 1080}, imx185_30fps, 1, 0, 993 IMX185_MODE_1920X1080_CROP_30FPS}, 994 {{1920, 1080}, imx185_30fps, 1, 0, 995 IMX185_MODE_1920X1080_CROP_10BIT_30FPS}, 996 {{1920, 1080}, imx185_60fps, 1, 0, 997 IMX185_MODE_1920X1080_CROP_60FPS}, 998 {{1920, 1080}, imx185_60fps, 1, 0, 999 IMX185_MODE_1920X1080_CROP_10BIT_60FPS}, 1000 {{1920, 1080}, imx185_30fps, 1, 1, 1001 IMX185_MODE_1920X1080_CROP_HDR_30FPS}, 1002 /* Add modes with no device tree support after below */ 1003 };