4、Sensor驱动开发(上):I2C通信调试、Sensor寄存器读写、PDAF与OTP读取、驱动probe流程
各位同学,欢迎来到Sensor驱动开发的上半场。这节课内容很实在,全是咱们做车载影像时天天要打交道的硬功夫。I2C怎么调通?寄存器怎么读写?PDAF和OTP又是啥?驱动probe流程到底怎么走?别急,我一个一个给你拆开讲。
4.1 I2C通信调试:别让总线卡住你
做Sensor驱动,第一步就是让主控和Sensor能说上话。MTK平台上,I2C是最常用的通信方式。说白了,就是两根线:SCL(时钟)和SDA(数据)。
我个人习惯,拿到一块新Sensor模组,第一件事不是写驱动,而是先拿示波器抓I2C波形。为什么?因为硬件连接可能就有问题。我曾经在一个项目里,折腾了两天I2C读写总是超时,最后发现是Sensor那边的上拉电阻没焊,信号根本拉不起来。
调试I2C,你心里要有个谱:
- 地址对不对? Sensor的I2C地址通常是7位或10位,MTK平台默认用7位。记得左移一位,因为Linux内核里地址是8位表示的。比如Sensor地址是0x30,你在驱动里要写0x60。
- 时序对不对? 标准模式100kHz,快速模式400kHz。别上来就设400k,有些Sensor扛不住。我建议先从100k开始,调通了再提速度。
- ACK信号有没有? 发送完地址字节后,Sensor会拉低SDA表示应答。如果没看到ACK,要么地址错了,要么Sensor没上电。
i2cget -y 2 0x60 0x00。先确保命令行能通,再写驱动代码,效率高很多。
4.2 Sensor寄存器读写:驱动里的基本功
I2C调通之后,接下来就是读写Sensor内部的寄存器。每个Sensor都有一堆寄存器,用来配置分辨率、帧率、增益、曝光时间等等。
在MTK平台上,我们通常用struct i2c_msg来构造读写消息。嗯,这里要注意,读操作和写操作的流程不一样:
- 写操作: 先发寄存器地址,再发要写的数据。一次传输搞定。
- 读操作: 先发寄存器地址(写操作),然后重新发起始条件,再读数据。这叫“重复起始条件”。
我见过不少新手,读寄存器时忘了发寄存器地址,结果读回来的数据全是乱的。你想想看,Sensor都不知道你要读哪个寄存器,它怎么给你数据?
下面是一个典型的寄存器读写函数示例:
static int sensor_i2c_write(struct i2c_client *client, u16 reg, u8 val)
{
struct i2c_msg msg;
u8 buf[3];
int ret;
buf[0] = (reg >> 8) & 0xFF; // 寄存器高8位
buf[1] = reg & 0xFF; // 寄存器低8位
buf[2] = val; // 要写入的数据
msg.addr = client->addr;
msg.flags = 0; // 写标志
msg.len = 3;
msg.buf = buf;
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret != 1) {
dev_err(&client->dev, "I2C write failed, reg=0x%04x\n", reg);
return -EIO;
}
return 0;
}
static int sensor_i2c_read(struct i2c_client *client, u16 reg, u8 *val)
{
struct i2c_msg msg[2];
u8 reg_buf[2];
u8 data_buf[1];
int ret;
reg_buf[0] = (reg >> 8) & 0xFF;
reg_buf[1] = reg & 0xFF;
msg[0].addr = client->addr;
msg[0].flags = 0; // 写寄存器地址
msg[0].len = 2;
msg[0].buf = reg_buf;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD; // 读数据
msg[1].len = 1;
msg[1].buf = data_buf;
ret = i2c_transfer(client->adapter, msg, 2);
if (ret != 2) {
dev_err(&client->dev, "I2C read failed, reg=0x%04x\n", reg);
return -EIO;
}
*val = data_buf[0];
return 0;
}
4.3 PDAF与OTP读取:相位对焦和出厂校准
现在车载摄像头越来越高级,PDAF(相位检测自动对焦)基本成了标配。PDAF说白了,就是Sensor上有一部分像素被用来检测相位差,从而快速算出对焦方向。
PDAF的校准数据,通常存在Sensor的OTP(一次性可编程)存储器里。OTP里不光有PDAF校准数据,还有镜头阴影校正、白平衡参数、坏点坐标等等。这些数据是模组厂在出厂时烧录进去的,我们驱动工程师要做的就是把它读出来,然后传给ISP(图像信号处理器)。
读取OTP的流程一般是:
- 向Sensor发送特定命令,进入OTP读取模式。
- 按地址读取OTP数据,通常是一页一页读,每页128字节或256字节。
- 读取完成后,退出OTP模式,恢复正常工作模式。
- 校验数据完整性,比如检查CRC校验和。
我记得有一次,读出来的OTP数据总是有几个字节不对。排查了半天,发现是读取时序问题——OTP读取需要等待一定时间(比如10ms),让Sensor内部准备好数据。我之前的代码里没加这个延时,读出来的就是乱码。
PDAF数据在OTP里的存储格式,各家Sensor厂商都不一样。有的用线性表,有的用网格表。你需要根据数据手册解析出每个相位检测点的校正值。这部分工作很繁琐,但必须做对,否则对焦精度会受影响。
4.4 驱动probe流程:从设备树到设备节点
终于到了驱动probe流程。这是Sensor驱动初始化的核心环节。在MTK平台上,probe函数是驱动加载的入口,它负责完成以下工作:
- 解析设备树: 从设备树节点中获取I2C地址、复位GPIO、电源控制等信息。
- 初始化硬件: 上电、复位、初始化I2C通信。
- 读取Sensor ID: 读取Sensor的芯片ID寄存器,确认硬件是否正确。
- 加载初始配置: 写入一组初始化寄存器序列,让Sensor进入工作状态。
- 读取OTP数据: 读取校准数据并保存到驱动私有数据结构中。
- 注册V4L2子设备: 将Sensor注册为V4L2(Video for Linux 2)子设备,供上层调用。
- 创建media entity: 在media controller框架中创建实体,建立数据通路。
probe函数的执行顺序很关键。我见过一个案例,有人把OTP读取放在了Sensor初始化之前,结果读出来的全是0。为什么?因为Sensor还没初始化,OTP模块根本没上电。你想想看,这能读到数据吗?
下面是一个简化的probe流程伪代码:
static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct sensor_priv *priv;
int ret;
// 1. 分配私有数据结构
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
// 2. 解析设备树,获取GPIO和电源信息
ret = sensor_parse_dt(&client->dev, priv);
if (ret)
return ret;
// 3. 硬件上电和复位
sensor_power_on(priv);
sensor_reset(priv);
msleep(20); // 等待Sensor稳定
// 4. 读取芯片ID,确认硬件
ret = sensor_read_id(client);
if (ret) {
dev_err(&client->dev, "Sensor ID mismatch\n");
goto power_off;
}
// 5. 加载初始化序列
ret = sensor_init_seq(client);
if (ret)
goto power_off;
// 6. 读取OTP数据
ret = sensor_read_otp(client, priv);
if (ret)
dev_warn(&client->dev, "OTP read failed, use default\n");
// 7. 注册V4L2子设备
ret = sensor_register_subdev(priv);
if (ret)
goto power_off;
i2c_set_clientdata(client, priv);
return 0;
power_off:
sensor_power_off(priv);
return ret;
}
dev_info(&client->dev, "Step X: ...")。这样调试时,通过dmesg就能一眼看出probe卡在了哪一步。别小看这个习惯,它能帮你省下大量排查时间。
好了,这节课的内容就到这里。我们讲了I2C调试、寄存器读写、PDAF与OTP读取,还有驱动probe流程。这些都是Sensor驱动开发的基础,也是你后面做全景影像的基石。下节课,我们会继续深入,讲Sensor驱动开发的下半部分——包括流控、帧同步、以及如何对接MTK的ISP pipeline。到时候见。