4. RK平台Sensor驱动框架概述:V4L2子系统、Media Controller、Sensor子设备驱动模型
在瑞芯微RK平台上,Camera Sensor驱动并非孤立存在,而是深度嵌入Linux内核的视频处理生态中。整个驱动框架由三层核心组件构成:V4L2子系统提供用户空间接口与流管理,Media Controller负责内部拓扑与数据路由,Sensor子设备驱动模型则封装了硬件操作细节。理解这三者的协作关系,是编写稳定、可移植Sensor驱动的基石。
4.1 V4L2子系统:视频设备的标准抽象层
V4L2(Video for Linux 2)是Linux内核中为视频设备提供统一访问接口的子系统。在RK平台上,它承担了以下核心职责:
- 设备节点管理:为每个视频设备创建/dev/videoX节点,供用户空间通过ioctl、mmap等系统调用操作。
- 数据流控制:管理视频缓冲区的申请、入队、出队,实现零拷贝或有限拷贝的数据传输。
- 格式协商:提供标准化的格式描述结构(如v4l2_pix_format),支持分辨率、像素格式、帧率的协商。
- 控制接口:通过v4l2_ctrl框架统一管理曝光、增益、白平衡等Sensor控制参数。
V4L2子系统的核心数据结构关系如下表所示:
| 数据结构 | 作用 | 对应设备节点 |
|---|---|---|
video_device |
代表一个V4L2视频设备,注册到内核后生成/dev/videoX | /dev/videoX |
v4l2_device |
顶层V4L2设备实例,管理所有子设备 | 无直接节点 |
v4l2_subdev |
代表一个子设备(如Sensor、ISP),挂载到v4l2_device下 | /dev/v4l-subdevX |
vb2_queue |
视频缓冲队列,管理DMA缓冲区生命周期 | 内部使用 |
下图展示了V4L2子系统中设备节点与内核模块的层次关系:
4.2 Media Controller:动态拓扑与数据路由
Media Controller是V4L2的扩展框架,用于描述设备内部复杂的拓扑结构。在RK平台上,一个Camera通路可能包含Sensor、MIPI DPHY、ISP、DMA引擎等多个硬件模块,Media Controller通过实体(entity)和链路(link)模型清晰表达这些模块的连接关系。
Media Controller的核心概念:
- 实体(media_entity):代表一个硬件模块或软件处理单元,如Sensor实体、ISP实体。
- 垫(pad):实体的输入/输出端口,分为source pad(源端)和sink pad(接收端)。
- 链路(media_link):连接两个实体的pad,表示数据流路径。
- 管道(pipeline):从源端到接收端的完整数据流路径。
用户空间通过/dev/mediaX节点使用Media Controller API,典型操作流程如下:
- 枚举所有实体,获取其pad信息。
- 根据需求建立或断开实体间的链路。
- 设置每个实体的格式、裁剪、缩放等参数。
- 启动数据流,Media Controller确保管道内所有实体状态一致。
下图展示了一个典型的RK Camera Media Controller拓扑:
4.3 Sensor子设备驱动模型
在V4L2框架中,Sensor被抽象为一个子设备(subdev),通过v4l2_subdev结构体注册到系统中。Sensor子设备驱动模型的核心是回调函数表(v4l2_subdev_ops),它定义了Sensor需要实现的标准操作接口。
Sensor子设备驱动的主要职责:
- 硬件初始化:包括上电时序、复位、I2C寄存器配置。
- 格式与帧率设置:通过
set_fmt回调配置输出分辨率、像素格式、帧率。 - 控制参数管理:通过
s_ctrl回调处理曝光、增益、白平衡等控制。 - 流管理:通过
s_stream回调启动/停止数据输出。 - 电源管理:通过
s_power回调控制Sensor的电源状态。
Sensor子设备驱动模型的核心数据结构与回调关系如下表:
| 数据结构/回调 | 类型 | 功能描述 |
|---|---|---|
v4l2_subdev |
结构体 | 子设备实例,包含名称、所属v4l2_device、ops指针等 |
v4l2_subdev_ops |
结构体 | 回调函数集合,包含core、video、pad、ctrl等子集 |
v4l2_subdev_video_ops |
回调子集 | s_stream(流开关)、g_frame_interval(帧率获取)等 |
v4l2_subdev_pad_ops |
回调子集 | set_fmt(格式设置)、get_fmt(格式获取)、enum_mbus_code(枚举格式)等 |
v4l2_ctrl_handler |
结构体 | 控制参数处理器,管理曝光、增益等控制项 |
v4l2_subdev_power_ops |
回调子集 | s_power(电源控制),用于上电/下电时序 |
Sensor子设备驱动的注册流程通常如下:
- 在probe函数中分配并初始化
v4l2_subdev结构体。 - 设置
v4l2_subdev_ops回调函数表。 - 初始化
v4l2_ctrl_handler,注册所有支持的Sensor控制参数。 - 调用
v4l2_i2c_subdev_init或v4l2_spi_subdev_init将子设备与I2C/SPI总线绑定。 - 调用
media_entity_pads_init初始化Media Controller的pad。 - 调用
v4l2_async_register_subdev注册为异步子设备,等待与ISP等主设备绑定。
下面是一个简化的Sensor子设备驱动注册代码示例:
static int sensor_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct sensor_priv *priv;
struct v4l2_subdev *sd;
int ret;
// 1. 分配私有数据结构
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
sd = &priv->subdev;
// 2. 初始化V4L2子设备
v4l2_i2c_subdev_init(sd, client, &sensor_subdev_ops);
// 3. 初始化控制处理器
v4l2_ctrl_handler_init(&priv->ctrl_handler, 5);
priv->exposure = v4l2_ctrl_new_std(&priv->ctrl_handler,
&sensor_ctrl_ops,
V4L2_CID_EXPOSURE,
0, 65535, 1, 1000);
priv->gain = v4l2_ctrl_new_std(&priv->ctrl_handler,
&sensor_ctrl_ops,
V4L2_CID_GAIN,
0, 255, 1, 64);
sd->ctrl_handler = &priv->ctrl_handler;
if (priv->ctrl_handler.error) {
dev_err(&client->dev, "ctrl handler error\n");
ret = priv->ctrl_handler.error;
goto free_ctrl;
}
// 4. 初始化Media Controller pad
priv->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&sd->entity, 1, &priv->pad);
if (ret < 0)
goto free_ctrl;
// 5. 注册为异步子设备
ret = v4l2_async_register_subdev(sd);
if (ret < 0)
goto free_entity;
dev_info(&client->dev, "Sensor probe success\n");
return 0;
free_entity:
media_entity_cleanup(&sd->entity);
free_ctrl:
v4l2_ctrl_handler_free(&priv->ctrl_handler);
return ret;
}
- Sensor子设备的probe函数中通常不执行硬件初始化(如写寄存器),因为此时电源可能尚未稳定。硬件初始化应放在
s_power或s_stream回调中。 - 异步注册机制(v4l2_async_register_subdev)允许Sensor驱动在ISP驱动尚未加载时先行注册,系统会在ISP驱动加载后自动完成绑定。
- 控制参数(v4l2_ctrl)的初始化顺序会影响默认值,建议在注册子设备前完成所有控制项的初始化。
4.4 三层框架的协作关系
V4L2子系统、Media Controller和Sensor子设备驱动模型在RK平台上协同工作,形成一个完整的Camera驱动栈。下图展示了这三层框架在数据流和控制流中的协作关系:
三层框架的协作流程可以总结为以下步骤:
| 步骤 | 操作 | 涉及框架 | 关键函数/接口 |
|---|---|---|---|
| 1 | 枚举设备拓扑 | Media Controller | media_entity_enum_init / MEDIA_IOC_ENUM_ENTITIES |
| 2 | 配置数据链路 | Media Controller | media_create_pad_link / MEDIA_IOC_SETUP_LINK |
| 3 | 设置Sensor格式 | V4L2 + Sensor子设备 | v4l2_subdev_call(sd, pad, set_fmt) |
| 4 | 设置ISP格式 | V4L2 + ISP子设备 | v4l2_subdev_call(isp, pad, set_fmt) |
| 5 | 申请缓冲区 | V4L2核心 | VIDIOC_REQBUFS / vb2_queue_init |
| 6 | 启动数据流 | V4L2 + 所有子设备 | v4l2_subdev_call(sd, video, s_stream, 1) |
| 7 | 数据采集与处理 | V4L2核心 + DMA | VIDIOC_DQBUF / vb2_buffer_done |
| 8 | 停止数据流 | V4L2 + 所有子设备 | v4l2_subdev_call(sd, video, s_stream, 0) |
- 使用
media-ctl -p确认拓扑结构是否正确。 - 使用
v4l2-ctl --list-formats确认Sensor支持的格式。 - 使用
v4l2-ctl --set-fmt-video设置格式后,检查dmesg中是否有错误。 - 使用
v4l2-ctl --stream-mmap测试数据流是否正常。
4.5 本章小结
本章介绍了RK平台Camera Sensor驱动框架的三大核心组件:
- V4L2子系统提供了标准化的视频设备接口,包括设备节点管理、缓冲区队列和控制框架。
- Media Controller通过实体-链路模型描述了设备内部的拓扑结构,支持动态配置数据通路。
- Sensor子设备驱动模型将Sensor硬件操作封装为标准的回调函数,实现了与平台无关的驱动设计。