目录
2. 匹配到驱动后通过 probe 函数进行 spi_master 的注册
3. SPI 子设备也是通过 spi_master 进行解析和注册
SPI控制器一般工作在主模式,接有多个SPI子设备。
一、SPI设备树文件
1、spi_master设备节点
设备树也会有一个节点对应spi_master,spi_master里也会有多个节点,对应多个spi_device。
一个典型的spi_master设备树节点如下所示:
ecspi1: ecspi@02008000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";
reg = <0x02008000 0x4000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_ECSPI1>,
<&clks IMX6UL_CLK_ECSPI1>;
clock-names = "ipg", "per";
dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
dma-names = "rx", "tx";
status = "disabled";
};
ecspi1即为设备节点的标签,用于在设备树的其他地方引用此节点。
ecspi@02008000是设备节点的名称,ecspi代表设备类型,02008000该设备的基地址。
后面有三个关键的属性信息:
- #address-cells = <1>;代表设定子节点地址信息所占用的 32 位单元数量,这里为 1 个单元。
- #size-cells = <0>;代表设定子节点大小信息所占用的 32 位单元数量,这里为 0 个单元,意味着子节点不提供大小信息。
- compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";属性给出了一系列字符串,用于表明该设备与哪些驱动程序兼容。通过这个属性来找到对应的驱动程序。
2、spi_master扩展配置
在其他的设备树文件通过引用这个spi_master来进行更详细的设备树编写,如下所示:
&ecspi1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi1>;
fsl,spi-num-chipselects = <2>;
cs-gpios = <&gpio4 26 GPIO_ACTIVE_LOW>, <&gpio4 24 GPIO_ACTIVE_LOW>;
status = "okay";
dac: dac {
compatible = "spidev";
reg = <0>;
spi-max-frequency = <20000000>;
};
};
这段代码是设备树中对之前定义的ecspi1节点进行的扩展配置,为其添加了引脚控制、片选信号、设备状态等信息,同时还定义了SPI从设备。
- fsl,spi-num-chipselects表明该 SPI 控制器支持的片选信号数量为 2 个。
- cs-gpios定义了这两个片选信号对应的 GPIO 引脚。
&gpio4
是对 GPIO 控制器 4 的引用,26
和24
分别是 GPIO 引脚编号,GPIO_ACTIVE_LOW
表示片选信号为低电平有效。
3、spi_device设备节点
上述的扩展配置还定义了一个子设备节点。
dac: dac {
compatible = "spidev";
reg = <0>;
spi-max-frequency = <20000000>;
};
- compatible 指定该设备与
"spidev"
驱动兼容 - reg 表示示该设备在 SPI 总线上的片选编号为 0。
- spi-max-frequency 设定该设备支持的最大 SPI 通信频率为 20 MHz。
上述的三个书写时spi子设备节点的必要属性,如需要更详细的配置,也需要在设备树文件中详细的提供,如:通过配置spi_cpol来配置极性。
二、SPI设备树处理过程
在介绍SPI设备树处理过程之前, 我们先来看看SPI设备相关的结构体。我们以上述设备树文件的spi_master设备节点对应的驱动程序为例。
1、platform_driver
platform_driver类型的结构体如下
platform_driver结构体里的.id_table注册的是spi_imx_devtype结构体数组,它是一个platform_device_id类型的结构体数组。
2、platform_device_id
platform_device_id结构体数组主要用于平台设备驱动,在驱动注册时可以指定这个数组,内核会依据设备名称来匹配相应的驱动。
可以看到,这个结构体数组的最后一个元素的.name为"imx6il-ecspi"。
当内核发现名称匹配的平台设备时,就会调用spi_imx_probe函数。
3、spi_imx_probe
当平台的设备和驱动匹配后,会调用.probe函数。
spi_imx_probe函数的主要实现有以下几点
spi_alloc_master
这个probe函数会去分配一个 spi_master。
spi_bitbang_start
此函数用于启动SPI通信
通过spi_bitbang_start去注册spi_master。
spi_register_master
通过spi_register_master去注册master的相关内容。
of_spi_register_master
这个函数里的 的of_gpio_named_count函数就可以把设备树文件里的cs-gpios定义的两个片选信号对应的 GPIO 引脚记录下来。
of_register_spi_devices
这个函数就会把设备树里的spi_device进行注册。
总结
1. 通过平台总线模型匹配 SPI 控制器设备和对应的驱动
在 Linux 内核里,SPI 控制器设备可以借助平台总线模型来实现与对应驱动的匹配。平台总线模型是一种用于连接设备和驱动的抽象机制,它借助设备树(Device Tree)或者传统的设备注册方式来描述设备信息,然后依据 compatible 属性或者设备名称来完成设备和驱动的匹配。
2. 匹配到驱动后通过 probe 函数进行 spi_master 的注册
当平台总线模型成功匹配到设备和驱动后,会调用驱动的 probe
函数。在 probe
函数中,通常会完成 spi_master
结构体的初始化和注册工作。spi_master
代表着一个 SPI 主机控制器,它负责管理和控制连接到该控制器的所有 SPI 从设备。
3. SPI 子设备也是通过 spi_master 进行解析和注册
SPI 子设备指的是连接到 SPI 主机控制器上的具体设备,如传感器、存储器等。这些子设备的解析和注册通常是通过spi_master来完成的。在设备树中,SPI 子设备会作为 SPI 控制器节点的子节点来定义。当spi_master注册成功后,内核会依据设备树信息解析出这些子设备,并通过spi_register_device函数将它们注册到系统中。