4. Sensor驱动初始化流程:从Probe到ID验证

Sensor驱动初始化,是整个Camera驱动栈的起点。说白了,就是让主控芯片和Sensor芯片互相认识一下。我见过不少工程师,一上来就追着ISP的bug跑,结果查了半天,发现Sensor压根就没正常工作。嗯,这章我们就来把初始化流程彻底捋一遍。

核心原则:Sensor初始化失败,后面全是白搭。Probe函数是入口,Power On是命脉,MCLK/PCLK是心跳,Register Dump是照妖镜。

4.1 Sensor Probe函数调用栈

Probe函数,是驱动加载的入口。Kernel在I2C总线上发现设备后,就会调用你注册的Probe回调。我个人习惯,拿到一个新Sensor驱动,第一件事就是看Probe的调用栈。

一个典型的Probe调用栈长这样:

sensor_probe()
  ├── 解析dts配置 (of_property_read_xxx)
  ├── 分配私有数据结构 (kzalloc)
  ├── 初始化I2C客户端 (i2c_check_functionality)
  ├── 上电序列 (sensor_power_up)
  ├── 初始化MCLK/PCLK (clk_prepare_enable)
  ├── 读取Sensor ID (sensor_read_id)
  ├── 注册V4L2子设备 (v4l2_i2c_subdev_init)
  └── 注册中断/其他 (request_threaded_irq)

这里有个坑,我踩过好几次。有些Sensor的Probe里,上电和读ID之间没有加延时。结果ID读出来是0xFF或者0x00。为什么?因为Sensor内部PLL还没稳定。我曾经在一个项目里,加了20ms的延时,问题就解决了。

我的习惯:在Probe函数里,每步操作后都加个dev_dbg打印。这样出问题时,看log就知道卡在哪一步了。

4.2 Power On序列与GPIO控制

Power On序列,是Sensor初始化的重中之重。每个Sensor都有自己的上电时序要求,比如AVDD先上,然后IOVDD,最后Reset拉高。时序不对,Sensor可能无法正常工作,甚至烧坏。

我建议,把Power On序列做成一个独立函数,方便调试和复用。下面是一个典型的Power On序列:

static int sensor_power_up(struct sensor_device *sensor)
{
    // 1. 配置GPIO为输出,初始为低
    gpio_direction_output(sensor->reset_gpio, 0);
    gpio_direction_output(sensor->pwdn_gpio, 1); // 先进入Power Down

    // 2. 按顺序上电
    regulator_enable(sensor->avdd);   // 模拟电压 2.8V
    mdelay(1);                        // 等待1ms
    regulator_enable(sensor->iovdd);  // IO电压 1.8V
    mdelay(1);
    regulator_enable(sensor->dvdd);   // 数字电压 1.2V
    mdelay(5);                        // 等待电压稳定

    // 3. 释放Reset
    gpio_set_value(sensor->pwdn_gpio, 0); // 退出Power Down
    mdelay(1);
    gpio_set_value(sensor->reset_gpio, 1); // Reset拉高
    mdelay(20);                             // 等待内部初始化

    return 0;
}

你想想看,如果AVDD和IOVDD的顺序搞反了,会发生什么?有些Sensor内部有ESD保护二极管,顺序反了会导致电流倒灌,轻则工作异常,重则烧毁Sensor。我曾经在一个项目中,因为时序问题,连续烧了3块Sensor板子。后来查datasheet才发现,AVDD必须比IOVDD先上电至少1ms。

避坑指南:GPIO的初始电平一定要和datasheet一致。有些Sensor的Reset是低电平有效,有些是高电平有效。搞反了,Sensor永远无法退出复位状态。

4.3 MCLK与PCLK频率配置

MCLK是Sensor的主时钟,PCLK是像素时钟。这两个时钟的频率,直接决定了Sensor的输出帧率和数据带宽。

MCLK通常由主控提供,常见频率有24MHz、27MHz、48MHz等。PCLK则由Sensor内部PLL生成,和MCLK有固定的倍数关系。

配置MCLK时,要注意以下几点:

  • 频率精度:MCLK的精度要在±1%以内,否则Sensor内部PLL可能失锁。
  • 占空比:通常要求45%~55%,否则影响时钟质量。
  • 抖动:时钟抖动过大会导致图像出现条纹噪声。

下面是一个MCLK配置的示例:

static int sensor_init_clk(struct sensor_device *sensor)
{
    int ret;

    // 获取MCLK句柄
    sensor->mclk = devm_clk_get(sensor->dev, "mclk");
    if (IS_ERR(sensor->mclk)) {
        dev_err(sensor->dev, "Failed to get MCLK\n");
        return PTR_ERR(sensor->mclk);
    }

    // 设置频率为24MHz
    ret = clk_set_rate(sensor->mclk, 24000000);
    if (ret) {
        dev_err(sensor->dev, "Failed to set MCLK rate\n");
        return ret;
    }

    // 使能时钟
    ret = clk_prepare_enable(sensor->mclk);
    if (ret) {
        dev_err(sensor->dev, "Failed to enable MCLK\n");
        return ret;
    }

    // 等待时钟稳定
    usleep_range(1000, 2000);

    return 0;
}

PCLK的配置,通常在Sensor的初始化寄存器序列里完成。比如,通过设置PLL倍频系数,让PCLK达到目标频率。我建议,在调试阶段,用示波器实测一下MCLK和PCLK的波形。有一次,我发现MCLK的波形有毛刺,查了半天,原来是PCB走线太长,加了终端匹配电阻就好了。

4.4 Register Dump与ID读取验证

Register Dump,是验证Sensor是否正常工作的最直接手段。通过I2C读取Sensor的寄存器值,和datasheet对比,就能判断I2C通信是否正常,Sensor内部逻辑是否正常。

ID读取,是Register Dump的一个特例。每个Sensor都有一个唯一的ID寄存器,比如0x0000地址存放芯片ID。Probe函数里,必须读取这个ID,验证是否和预期一致。

下面是一个ID读取的示例:

static int sensor_check_id(struct sensor_device *sensor)
{
    u16 chip_id;
    int ret;

    // 读取芯片ID寄存器
    ret = sensor_i2c_read(sensor, 0x0000, &chip_id);
    if (ret) {
        dev_err(sensor->dev, "Failed to read chip ID\n");
        return ret;
    }

    dev_info(sensor->dev, "Chip ID: 0x%04x\n", chip_id);

    // 验证ID
    if (chip_id != SENSOR_EXPECTED_ID) {
        dev_err(sensor->dev, "Chip ID mismatch: expected 0x%04x, got 0x%04x\n",
                SENSOR_EXPECTED_ID, chip_id);
        return -ENODEV;
    }

    return 0;
}

如果ID读出来不对,怎么办?我一般按以下步骤排查:

  1. 检查I2C地址:Sensor的I2C地址是否正确?有些Sensor有多个地址,通过引脚电平选择。
  2. 检查I2C通信:用示波器抓I2C波形,看是否有ACK信号。
  3. 检查电源:用万用表量一下各电源引脚,看电压是否正常。
  4. 检查时钟:用示波器看MCLK是否有波形。
  5. 检查Reset:Reset引脚的电平是否正确?
我的调试技巧:写一个简单的I2C读写工具,可以在用户空间直接操作Sensor寄存器。这样调试时,不用每次都编译内核。

4.5 知识结构总览

下面这张图,把Sensor初始化流程的核心逻辑串起来了。你可以把它当作调试时的路线图。

Sensor驱动初始化流程 sensor_probe() 解析dts配置 Power On序列 MCLK/PCLK配置 Register Dump & ID验证 ID匹配? 注册V4L2子设备 返回 -ENODEV 调试要点:每步都加打印,用示波器验证时序,用I2C工具验证通信

4.6 常见问题与排查思路

现象 可能原因 排查方法
Probe函数未调用 dts配置错误、I2C地址不匹配 检查dts文件,核对I2C地址
ID读取为0xFF I2C通信失败、Sensor未上电 用示波器抓I2C波形,量电源电压
ID读取为0x00 Sensor处于复位状态、时钟未稳定 检查Reset引脚电平,增加延时
MCLK无波形 时钟配置错误、GPIO复用冲突 检查clk_set_rate返回值,检查pinmux
图像有条纹 MCLK抖动过大、电源纹波过大 用示波器测时钟抖动,加滤波电容

嗯,Sensor初始化这块,说难不难,说简单也不简单。关键是要把每一步都验证到位。我见过太多人,跳过ID验证直接调图像,结果浪费了好几天。记住,基础不牢,地动山摇。