在 Linux 内核中,通过设备树(DTS 文件)定义设备时,节点的上下文(即设备节点挂载的位置)直接反映了设备的总线关系。以下是一些具体的例子,说明如何通过设备树的总线关系区分 platform_device
和特定硬件总线设备(例如 I2C 或 SPI 设备)。
1. platform_device
示例
platform_device
通常用于描述那些 没有明确硬件总线 的设备。它们的节点通常直接挂载在设备树的根节点下,或者挂载在某个 platform_bus
节点下。例如:
a. 没有明确总线关系的设备
Dts
/ { gpio0: gpio@40020000 { // 设备直接挂载在根节点下 compatible = "my-vendor,my-gpio-controller"; reg = <0x40020000 0x100>; interrupts = <5>; }; timer0: timer@40030000 { // 定时器设备直接挂载在根节点下 compatible = "my-vendor,my-timer"; reg = <0x40030000 0x100>; }; };
- 关键点:
gpio@40020000
和timer@40030000
节点直接挂载在根节点/
下,没有明确的父节点(如 I2C 或 SPI 控制器节点)。- 这种设备通常被解析为
platform_device
,并挂载到platform_bus
上。
b. platform_bus
下的设备
Dts
/ { platform-bus { // 一个虚拟的 platform 总线节点 compatible = "simple-bus"; device1: device@50000000 { compatible = "my-vendor,my-device1"; reg = <0x50000000 0x100>; }; device2: device@50010000 { compatible = "my-vendor,my-device2"; reg = <0x50010000 0x100>; }; }; };
- 关键点:
device1
和device2
挂载在一个platform-bus
节点下。- 这种设备也会被解析为
platform_device
,并挂载到platform_bus
。
2. 特定硬件总线设备示例
对于明确硬件总线的设备(如 I2C、SPI),设备树节点通常挂载在对应的总线控制器节点下。这种设备会被解析为总线设备(如 i2c_client
或 spi_device
)。
a. I2C 设备
Dts
/ { i2c1: i2c@40005400 { // I2C 控制器节点 compatible = "my-vendor,my-i2c-controller"; reg = <0x40005400 0x100>; #address-cells = <1>; #size-cells = <0>; // I2C 子设备 sensor@50 { // I2C 地址为 0x50 的从设备 compatible = "my-vendor,my-i2c-sensor"; reg = <0x50>; }; eeprom@51 { // I2C 地址为 0x51 的从设备 compatible = "my-vendor,my-eeprom"; reg = <0x51>; }; }; };
- 关键点:
sensor@50
和eeprom@51
节点挂载在i2c@40005400
节点下。i2c@40005400
是 I2C 控制器节点,它的compatible
属性标识这是一个 I2C 总线。sensor@50
和eeprom@51
是 I2C 总线的子设备,会被解析为i2c_client
类型的设备,而非platform_device
。
b. SPI 设备
Dts
/ { spi1: spi@40003800 { // SPI 控制器节点 compatible = "my-vendor,my-spi-controller"; reg = <0x40003800 0x100>; #address-cells = <1>; #size-cells = <0>; // SPI 子设备 flash@0 { // SPI 从设备,chip-select 为 0 compatible = "my-vendor,my-spi-flash"; reg = <0>; spi-max-frequency = <1000000>; }; adc@1 { // SPI 从设备,chip-select 为 1 compatible = "my-vendor,my-adc"; reg = <1>; spi-max-frequency = <2000000>; }; }; };
- 关键点:
flash@0
和adc@1
节点挂载在spi@40003800
节点下。spi@40003800
是 SPI 控制器节点,它的compatible
属性标识这是一个 SPI 总线。flash@0
和adc@1
是 SPI 总线的子设备,会被解析为spi_device
类型的设备,而非platform_device
。
3. Platform Device 与总线设备的对比
a. 总线关系
设备类型 | 挂载位置 | 解析的设备类型 |
---|---|---|
platform_device | 直接挂载在根节点或 platform_bus 节点下 | platform_device |
I2C 设备 | 挂载在 i2c_controller 节点下 | i2c_client |
SPI 设备 | 挂载在 spi_controller 节点下 | spi_device |
b. 驱动匹配方式
设备类型 | 匹配方式 |
---|---|
platform_device | 使用 compatible 属性,匹配 platform_driver |
I2C 设备 | 使用 compatible 属性,匹配 I2C 驱动的 of_match_table |
SPI 设备 | 使用 compatible 属性,匹配 SPI 驱动的 of_match_table |
4. 具体解析过程
a. Platform Device 的解析
- 内核通过
of_platform_populate()
遍历设备树节点。 - 如果节点没有明确的硬件总线上下文(例如 I2C 或 SPI 控制器),会调用
of_platform_device_create()
将其解析为platform_device
。
b. I2C/SPI 设备的解析
- I2C 或 SPI 控制器驱动会解析其子节点。
- 根据子节点的
compatible
属性和父总线的上下文,创建对应的i2c_client
或spi_device
。
5. 总结
Platform Device 示例
设备直接挂载在根节点或 platform_bus
节点下,没有明确的硬件总线关系:
Dts
gpio@40020000 { compatible = "my-vendor,my-gpio-controller"; reg = <0x40020000 0x100>; };
I2C Device 示例
设备挂载在 I2C 控制器节点下,明确属于 I2C 总线:
Dts
i2c@40005400 { sensor@50 { compatible = "my-vendor,my-i2c-sensor"; reg = <0x50>; }; };
SPI Device 示例
设备挂载在 SPI 控制器节点下,明确属于 SPI 总线:
Dts
spi@40003800 { flash@0 { compatible = "my-vendor,my-spi-flash"; }; };
通过设备树的上下文(节点的挂载位置)和属性(如 compatible
),内核可以明确区分 platform_device
和特定硬件总线设备。