4. DTS设备树配置:sensor节点编写、clk/power/gpio资源绑定、pinctrl配置

设备树(Device Tree)是RK平台驱动开发的基石。说白了,它就是一块“硬件描述板”,告诉内核你的Sensor接在哪个I2C上、用什么时钟、怎么上电、中断脚是哪个。我见过不少新手,代码写得挺溜,结果DTS配错了,驱动死活不 probe。嗯,这一节咱们就把DTS这块啃透。

4.1 Sensor节点基本结构

一个标准的Camera Sensor节点,通常挂在I2C总线下。我个人习惯先写好骨架,再往里填资源。来看一个典型的OV5645节点:

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

    ov5645: camera-sensor@3c {
        compatible = "ovti,ov5645";
        reg = <0x3c>;
        status = "okay";

        clocks = <&cru SCLK_CIF_OUT>;
        clock-names = "xvclk";

        pinctrl-names = "default";
        pinctrl-0 = <&cif_clkout_m0>;

        power-domains = <&power RK3588_PD_VI>;

        avdd-supply = <&vcc_camera>;
        dvdd-supply = <&vcc_camera_dvdd>;
        dovdd-supply = <&vcc_camera_dovdd>;

        reset-gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_LOW>;
        pwdn-gpios = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>;

        rotation = <180>;
        orientation = <0>;

        port {
            ov5645_ep: endpoint {
                remote-endpoint = <&mipi_csi2_input>;
                data-lanes = <1 2>;
            };
        };
    };
};

关键字段速查表

字段含义常见坑
compatible驱动匹配字符串必须与驱动中of_match_table一致
regI2C设备地址7位地址,左对齐还是右对齐?RK默认7位
clocks时钟句柄别忘了clock-names要对应
pinctrl-0引脚复用配置不配的话,CLK可能出不来波形
reset-gpios复位引脚注意极性:ACTIVE_LOW还是HIGH

4.2 时钟资源绑定

Sensor的MCLK(主时钟)是命脉。没时钟,Sensor就是一坨硅。RK平台通常通过CRU(Clock & Reset Unit)提供时钟。

我曾经在一个项目里,Sensor死活不出图,示波器一量MCLK——没波形。查了半天,发现DTS里clock-names写成了"xvclk",驱动里却用"xvclk"去clk_get,但CRU输出的实际名字是"clk_cif_out"。对不上,时钟没开。

正确的做法是:

clocks = <&cru SCLK_CIF_OUT>;
clock-names = "xvclk";

驱动里这样拿:

sensor->xvclk = devm_clk_get(dev, "xvclk");
if (IS_ERR(sensor->xvclk)) {
    dev_err(dev, "failed to get xvclk\n");
    return PTR_ERR(sensor->xvclk);
}

小技巧: 调试时钟时,可以在/sys/kernel/debug/clk/clk_summary里看时钟有没有被enable。如果没开,检查clk_prepare_enable有没有被调用。

4.3 Power资源绑定

Sensor一般需要三路供电:AVDD(模拟)、DVDD(数字核心)、DOVDD(IO电压)。RK平台用regulator框架管理。

DTS里这样配:

avdd-supply = <&vcc_camera>;
dvdd-supply = <&vcc_camera_dvdd>;
dovdd-supply = <&vcc_camera_dovdd>;

驱动里获取:

sensor->avdd = devm_regulator_get(dev, "avdd");
if (IS_ERR(sensor->avdd))
    return PTR_ERR(sensor->avdd);

ret = regulator_set_voltage(sensor->avdd, 2800000, 2800000);
if (ret)
    dev_warn(dev, "failed to set avdd voltage\n");

注意: 上电时序很重要!有些Sensor要求先上DOVDD,再上AVDD,最后上DVDD。如果顺序错了,Sensor可能无法正常初始化。我遇到过一款GC系列Sensor,上电顺序反了,I2C通信都建立不起来。

4.4 GPIO资源绑定

GPIO主要用于复位(RESET)和掉电(PWDN)。RK平台用gpio descriptor API。

DTS配置:

reset-gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_LOW>;
pwdn-gpios = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>;

驱动里操作:

sensor->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(sensor->reset_gpio))
    return PTR_ERR(sensor->reset_gpio);

// 复位:拉低再拉高
gpiod_set_value(sensor->reset_gpio, 0);
usleep_range(1000, 2000);
gpiod_set_value(sensor->reset_gpio, 1);

GPIO极性对照表

GPIO标志含义驱动中初始值
GPIO_ACTIVE_LOW低电平有效GPIOD_OUT_HIGH(默认非复位状态)
GPIO_ACTIVE_HIGH高电平有效GPIOD_OUT_LOW(默认非复位状态)

4.5 pinctrl配置

pinctrl决定了芯片引脚的功能复用。比如某个引脚是当GPIO用,还是当I2C用,还是当CLK输出用。

RK平台通常在pinctrl节点里定义好function和group:

&pinctrl {
    cif_clkout_m0: cif-clkout-m0 {
        rockchip,pins =
            <1 RK_PB2 2 &pcfg_pull_none>;
    };
};

然后在Sensor节点里引用:

pinctrl-names = "default";
pinctrl-0 = <&cif_clkout_m0>;

为什么需要pinctrl?你想想看,如果不配pinctrl,内核不知道这个引脚要当CLK用,可能默认就是GPIO模式,CLK信号根本出不来。

调试方法: 可以在/sys/kernel/debug/pinctrl/pinctrl-handles里查看当前引脚复用状态。如果发现引脚模式不对,检查pinctrl节点是否写对了。

4.6 知识体系总览

下面这张图总结了DTS配置的核心流程和资源关系:

DTS Sensor节点配置知识体系 Camera Sensor 节点 I2C 总线挂载 clocks 时钟绑定 regulator 电源 GPIO 复位/掉电 pinctrl 引脚复用 port 数据通道 MCLK / PCLK / SCLK AVDD/DVDD/DOVDD RESET / PWDN / INT function + group data-lanes / endpoint 核心原则:compatible匹配驱动,reg确定地址,clk/power/gpio/pinctrl缺一不可 调试时按 I2C → 时钟 → 电源 → GPIO → pinctrl 顺序排查

4.7 常见问题与避坑

  • compatible不匹配: 驱动里of_match_table写的是"ovti,ov5645",DTS里写成了"ovti,ov5645-v1",对不上,驱动不probe。我曾经花了一下午查这个问题,最后发现就是多了一个"-v1"。
  • I2C地址错误: Sensor datasheet给的地址通常是8位(含读写位),DTS里要填7位地址。比如8位地址0x78,7位就是0x3c。
  • 时钟频率不对: 有些Sensor对MCLK频率很敏感,比如OV5645要求24MHz,你配成了27MHz,Sensor可能无法正常输出图像。
  • 上电时序: 如果Sensor初始化失败,先检查电源有没有按datasheet要求的顺序上电。用示波器抓一下波形,一目了然。
  • pinctrl冲突: 同一个引脚被两个设备用了,会导致pinctrl申请失败。检查dmesg里有没有"pin already requested"的报错。

重要提醒: 修改DTS后,一定要重新编译并烧录dtb文件。我见过有人改了DTS源码,但没重新编译,结果还是老配置在跑。用fdtdump或者dtc -I dtb -O dts可以反编译dtb,确认修改是否生效。