4、设备树配置:DTS节点编写、时钟与电源属性、GPIO与复位时序、MIPI DPHY参数配置

设备树(Device Tree)这东西,说白了就是告诉内核“你的硬件长什么样”。Sensor驱动能不能跑起来,一半的功夫都在DTS配置上。我见过太多人花好几天调代码,最后发现是DTS里一个GPIO极性写反了——嗯,这种坑我自己也踩过。

这一节我们聚焦Sensor驱动最关键的几个DTS配置点:节点怎么写、时钟和电源怎么给、GPIO和复位时序怎么控制、MIPI DPHY参数怎么设。你把这些搞清楚了,Sensor在硬件层面就算“站稳”了。

核心原则: DTS不是写给人看的,是写给内核解析的。每个属性都要精确对应硬件手册,少一个、错一个,Sensor可能就不工作。

4.1 Sensor DTS节点结构

一个标准的Sensor节点,通常挂在I2C总线下。我个人习惯把节点名写成@,这样一看就知道对应哪个器件。

// 基本节点骨架
&i2c2 {
    status = "okay";
    clock-frequency = <400000>;  // 400KHz快速模式

    ov5640: camera@3c {
        compatible = "ovti,ov5640";
        reg = <0x3c>;
        // ... 其他属性
    };
};

这里要注意几点:

  • compatible:必须和驱动里的of_match_table完全一致,大小写都不能错。
  • reg:Sensor的I2C地址,通常是7位地址左移1位后的值。比如OV5640的7位地址是0x3C,写0x3C就行。
  • status:默认写"okay",如果硬件没焊或者调试阶段想屏蔽,改成"disabled"。
小技巧: 我习惯在节点里加一个status-gpios属性,用来指示Sensor的电源好信号。虽然这不是标准属性,但驱动里可以自己解析,调试时特别有用。

4.2 时钟与电源属性

Sensor需要外部时钟源(MCLK/XCLK)和稳定的供电。这两个配不对,Sensor要么不初始化,要么图像有纹波。

4.2.1 时钟配置

时钟属性通常用clocks和clock-names来描述。Sensor的主时钟频率一般在6MHz到27MHz之间,具体看Sensor手册。

clocks = <&clkc CLK_SENSOR>;
clock-names = "xvclk";
clock-frequency = <24000000>;  // 24MHz

为什么时钟频率这么重要?我遇到过一个问题:Sensor输出帧率不对,图像一卡一卡的。查了半天,发现是时钟源实际输出23.8MHz,但Sensor内部PLL是按24MHz算的,导致帧同步偏差。后来加了assigned-clock-rates强制锁定频率才解决。

属性 说明 常见值
clocks 时钟源句柄 &clkc CLK_SENSOR
clock-names 时钟名称,驱动通过它获取时钟 "xvclk", "mclk"
clock-frequency 期望的时钟频率(Hz) 24000000
assigned-clock-rates 强制设定时钟频率 <24000000>

4.2.2 电源配置

Sensor通常需要多路电源:模拟电压(AVDD)、数字电压(DVDD)、IO电压(IOVDD)。电压值必须精确,偏差超过±5%就可能出问题。

avdd-supply = <&reg_avdd>;
dvdd-supply = <&reg_dvdd>;
iovdd-supply = <&reg_iovdd>;
注意: 电源上电顺序很重要!很多Sensor要求先上AVDD,再上DVDD,最后上IOVDD。如果顺序反了,轻则初始化失败,重则烧坏Sensor。我建议在驱动里用regulator_set_load和regulator_enable手动控制顺序,不要依赖DTS的默认行为。

4.3 GPIO与复位时序

GPIO控制是Sensor驱动里最容易出bug的地方。复位时序、电源使能、中断检测,每个GPIO的极性、延迟、顺序都要精确。

4.3.1 GPIO属性定义

reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
power-gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>;
standby-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;

这里GPIO_ACTIVE_LOW和GPIO_ACTIVE_HIGH决定了驱动里怎么操作。我曾经犯过一个错:把复位引脚设成GPIO_ACTIVE_HIGH,但Sensor手册写的是低电平复位。结果每次复位都变成解除复位,Sensor一直处于复位状态——图像全黑,我还以为是Sensor坏了。

4.3.2 复位时序要求

复位时序通常包含以下几个阶段:

  1. 上电稳定:电源稳定后,等待至少1ms(有些Sensor需要10ms)。
  2. 复位拉低:将复位引脚拉低,保持至少1ms。
  3. 复位释放:将复位引脚拉高,等待Sensor内部初始化完成(通常5-20ms)。
  4. I2C通信:复位释放后才能开始I2C读写。
// 驱动中的复位时序示例
gpiod_set_value(sensor->reset_gpio, 0);  // 拉低复位
usleep_range(2000, 3000);                // 保持2ms
gpiod_set_value(sensor->reset_gpio, 1);  // 释放复位
usleep_range(10000, 15000);              // 等待10ms初始化
避坑指南: 我曾经遇到一个Sensor,手册说复位保持1ms就行,但实际测试发现需要3ms才能稳定。后来我养成了一个习惯:所有时序参数都留50%的余量。手册写1ms,我就设2ms;手册写10ms,我就设15ms。多等几毫秒不会影响性能,但能省去很多排查时间。

4.4 MIPI DPHY参数配置

MIPI DPHY参数是Sensor和SoC之间高速数据传输的关键。配错了,图像会有条纹、花屏,甚至完全没数据。

4.4.1 DPHY基本参数

参数 说明 典型值
data-lanes 使用的数据通道数 1, 2, 4
clock-lanes 时钟通道索引 0
hs-clk-rate 高速时钟频率(Hz) 336000000
lp-clk-rate 低功耗时钟频率(Hz) 10000000
port {
    sensor_ep: endpoint {
        remote-endpoint = <&csi_ep>;
        data-lanes = <1 2>;          // 使用2条数据通道
        clock-lanes = <0>;           // 时钟在lane 0
        hs-clk-rate = <336000000>;   // 336MHz高速时钟
        link-frequencies = /bits/ 64 <336000000>;
    };
};

4.4.2 时钟频率计算

高速时钟频率怎么算?公式其实不复杂:

hs_clk = (pixel_width × pixel_rate × bits_per_pixel) / (2 × data_lanes)

举个例子:1080p@30fps,RGB888(24bit),使用2条lane:

  • 像素时钟 = 1920 × 1080 × 30 ≈ 62.2MHz
  • hs_clk = (62.2 × 24) / (2 × 2) ≈ 373MHz

嗯,这里要注意,实际值还要考虑消隐区(blanking)的开销。我一般会在计算值上加10%-15%的余量。

重要: link-frequencies属性必须用/bits/ 64修饰,因为频率值可能超过32位范围。我见过有人写成32位,结果内核解析出来的值完全不对,图像全是噪声。

4.5 完整DTS节点示例

把上面所有内容整合起来,一个完整的Sensor DTS节点大概长这样:

&i2c2 {
    status = "okay";
    clock-frequency = <400000>;

    imx219: camera@10 {
        compatible = "sony,imx219";
        reg = <0x10>;

        // 时钟
        clocks = <&clkc CLK_SENSOR>;
        clock-names = "xvclk";
        clock-frequency = <24000000>;
        assigned-clock-rates = <24000000>;

        // 电源
        avdd-supply = <&reg_avdd_2v8>;
        dvdd-supply = <&reg_dvdd_1v2>;
        iovdd-supply = <&reg_iovdd_1v8>;

        // GPIO
        reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
        power-gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>;

        // MIPI DPHY
        port {
            imx219_ep: endpoint {
                remote-endpoint = <&csi_ep>;
                data-lanes = <1 2>;
                clock-lanes = <0>;
                hs-clk-rate = <336000000>;
                link-frequencies = /bits/ 64 <336000000>;
            };
        };
    };
};
调试建议: 第一次调DTS时,先把所有GPIO和电源配好,确认Sensor能正常复位和I2C通信。然后再配MIPI参数。分步验证,不要一次性全配完——否则出了问题你根本不知道是哪一步错了。
Sensor DTS配置核心流程 I2C总线节点 Sensor设备节点 时钟与电源 clocks / regulators GPIO与复位 reset / power / standby MIPI DPHY data-lanes / hs-clk 驱动初始化成功 ⚠ 关键检查点: 1. compatible与驱动匹配 2. 电源上电顺序 3. 复位时序余量 4. hs-clk-rate计算准确 5. GPIO极性正确 6. link-frequencies使用64位 7. remote-endpoint连接正确