3、设备树中Camera节点定义:标准属性、时钟电源与GPIO控制
好,咱们进入正题。Camera节点的设备树怎么写?说白了,就是告诉内核三件事:你是谁、怎么找到你、怎么让你干活。这三件事分别对应标准属性、时钟电源属性和GPIO控制属性。我一个个拆开讲。
3.1 标准属性:compatible、reg、interrupts
这三个属性是设备节点的身份证。没有它们,内核根本认不出你的Camera。
3.1.1 compatible:驱动匹配的关键
compatible属性决定了内核用哪个驱动来绑定这个设备。格式是"厂商,型号"。比如:
compatible = "sony,imx219", "ovti,ov5640";
这里我写两个,是给内核一个备选方案。第一个匹配不上,就试第二个。我在项目中遇到过,某款Sensor的驱动只认"ovti,ov5640",但硬件上贴的是另一家的片子,结果驱动死活加载不上。后来发现是compatible写错了。
3.1.2 reg:I2C地址或片选
对于Camera来说,reg通常就是I2C从设备地址。比如:
reg = <0x10>;
这个0x10是7位地址。注意,有些Sensor手册给的是8位地址(比如0x20),你需要右移一位再填进去。嗯,这里容易踩坑。
如果Camera接在SPI总线上,reg就是片选号。比如:
reg = <0>; // 片选CS0
3.1.3 interrupts:中断引脚
Camera通常用中断来通知SoC有数据准备好了。比如:
interrupt-parent = <&gpio1>;
interrupts = <5 IRQ_TYPE_EDGE_RISING>;
这里GPIO1_5作为中断源,上升沿触发。我个人的习惯是,如果Sensor支持,尽量用边沿触发而不是电平触发,能省不少CPU资源。
3.2 时钟与电源属性
Camera是耗电大户,时钟和电源必须配好。否则Sensor要么不工作,要么图像有纹波。
3.2.1 时钟属性:clocks与clock-names
Camera需要外部时钟源,通常是24MHz或27MHz的MCLK。设备树里这样写:
clocks = <&clkc 15>;
clock-names = "xvclk";
clocks指向时钟控制器,后面的数字是时钟ID。clock-names是给驱动用的标签,驱动通过名字来获取时钟句柄。
我记得有一次,Sensor输出的图像一直有条纹干扰。查了半天,发现是MCLK的精度不够。后来换了一个高精度的PLL时钟源,问题就解决了。所以时钟质量很重要,别随便找个GPIO模拟时钟就往上怼。
3.2.2 电源属性:AVDD、DVDD、IOVDD
Camera通常需要三路电源:模拟电源AVDD(2.8V)、数字核心电源DVDD(1.2V或1.8V)、IO电源IOVDD(1.8V或3.3V)。设备树里用regulator来定义:
avdd-supply = <®_cam_avdd>;
dvdd-supply = <®_cam_dvdd>;
iovdd-supply = <®_cam_iovdd>;
这些regulator需要在设备树的其他地方定义好电压值。驱动在probe时会按顺序上电,你想想看,如果上电顺序错了,Sensor可能初始化失败。
3.3 GPIO控制属性
Camera的GPIO控制,说白了就是复位和使能。这两个引脚控制不好,Sensor就跟你耍脾气。
3.3.1 复位引脚:reset-gpios
复位引脚用于将Sensor恢复到初始状态。设备树里这样写:
reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
GPIO_ACTIVE_LOW表示低电平复位。驱动在初始化时会先拉低复位引脚,保持一段时间,再拉高释放。这个保持时间,不同Sensor要求不一样,有的要1ms,有的要10ms。我建议你看完datasheet再写代码。
3.3.2 使能引脚:powerdown-gpios或enable-gpios
使能引脚控制Sensor是否进入工作模式。有些Sensor叫PWDN(Power Down),有些叫STANDBY。写法类似:
powerdown-gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>;
这里GPIO_ACTIVE_HIGH表示高电平进入掉电模式。驱动在初始化时需要拉低这个引脚,让Sensor退出掉电状态。
3.3.3 其他GPIO:闪光灯、聚焦等
有些Camera模组还带有闪光灯控制或自动聚焦功能,也需要GPIO:
flash-gpios = <&gpio4 0 GPIO_ACTIVE_HIGH>;
focus-gpios = <&gpio4 1 GPIO_ACTIVE_HIGH>;
这些不是必须的,但如果你要支持闪光灯或AF,就得加上。
3.4 完整示例:一个典型的Camera节点
说了这么多,咱们看一个完整的例子。以OV5640为例:
&i2c2 {
status = "okay";
ov5640: camera@3c {
compatible = "ovti,ov5640";
reg = <0x3c>;
interrupt-parent = <&gpio1>;
interrupts = <5 IRQ_TYPE_EDGE_RISING>;
clocks = <&clkc 15>;
clock-names = "xvclk";
avdd-supply = <®_cam_avdd>;
dvdd-supply = <®_cam_dvdd>;
iovdd-supply = <®_cam_iovdd>;
reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
powerdown-gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>;
port {
ov5640_ep: endpoint {
remote-endpoint = <&csi_ep>;
bus-type = <4>; // MIPI CSI-2
data-lanes = <1 2>;
};
};
};
};
这个节点包含了我们刚才讲的所有内容。port部分定义的是数据接口,这个后面章节会详细讲。
好了,Camera节点的标准属性、时钟电源和GPIO控制就讲到这里。下一节咱们聊聊数据接口——MIPI CSI-2和并行接口在设备树里怎么配。那个更有意思。