3. 内核源码结构解析:设备树与 SPI 关键目录
在开始设备树移植与 SPI 驱动适配之前,必须精准定位内核源码中三个核心目录:设备树源文件目录、SPI 控制器驱动目录、SPI 子系统头文件目录。本章将逐一拆解其功能、文件组织方式与协作关系。
3.1 arch/arm/boot/dts —— 设备树源文件仓库
该目录存放 ARM 架构下所有已支持的 SoC 与开发板的设备树源文件(.dts)及其包含头文件(.dtsi)。设备树是描述硬件拓扑与资源分配的数据结构,内核在启动时通过 Flattened Device Tree (FDT) 解析硬件信息。
3.1.1 文件命名与层级规则
| 文件类型 | 命名示例 | 作用 |
|---|---|---|
| SoC 级 .dtsi | imx6ull.dtsi |
定义 SoC 内部所有外设节点(SPI、I2C、UART、时钟等),不包含板级差异 |
| 板级 .dts | imx6ull-14x14-evk.dts |
通过 #include 引用 SoC .dtsi,并添加板级外设、GPIO 复用、引脚配置 |
| 头文件 .h | imx6ull-pinfunc.h |
定义引脚复用宏(如 MX6UL_PAD_UART1_TX__GPIO1_IO16),供 .dts 引用 |
移植要点: 当为新板卡添加支持时,优先查找最接近的 SoC .dtsi 文件,然后新建板级 .dts 并
#include 该 .dtsi,避免重复定义 SoC 级节点。
3.1.2 设备树节点结构示例(SPI 控制器)
/* imx6ull.dtsi 中的 SPI 控制器节点 */
spi1: spi@02010000 {
compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";
reg = <0x02010000 0x4000>;
interrupts = <GIC_SPI 33 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";
#address-cells = <1>;
#size-cells = <0>;
};
关键字段说明:
compatible:驱动匹配的核心字符串,必须与 SPI 控制器驱动中的of_match_table一致。reg:寄存器基地址与长度,驱动通过platform_get_resource()获取。status = "disabled":默认关闭,板级 .dts 中需显式设置为"okay"并添加引脚复用。
3.1.3 设备树文件层级关系图
3.2 drivers/spi —— SPI 控制器驱动实现
该目录包含所有 SPI 控制器(SPI Master)的驱动代码,以及 SPI 子系统核心层(spi.c)与通用传输接口。每个 SPI 控制器驱动通常对应一个 .c 文件,命名规则为 spi-<controller>.c。
3.2.1 目录文件分类
| 文件/目录 | 功能 | 典型示例 |
|---|---|---|
spi.c |
SPI 子系统核心:总线注册、设备与驱动匹配、传输队列管理 | — |
spi-mem.c |
SPI 内存协议层(SPINOR/SPINAND 共用) | — |
spi-imx.c |
i.MX 系列 ECSPI 控制器驱动 | i.MX6ULL / i.MX8M |
spi-bcm2835.c |
BCM2835(Raspberry Pi)SPI 控制器驱动 | Raspberry Pi 3/4 |
spi-rockchip.c |
Rockchip SPI 控制器驱动 | RK3399 / RK3568 |
3.2.2 驱动与设备树的匹配机制
SPI 控制器驱动通过 of_match_table 与设备树节点中的 compatible 属性进行匹配。以下为 spi-imx.c 中的匹配表示例:
static const struct of_device_id spi_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, },
{ .compatible = "fsl,imx21-cspi", .data = &imx21_cspi_devtype_data, },
{ .compatible = "fsl,imx27-cspi", .data = &imx27_cspi_devtype_data, },
{ .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, },
{ .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, },
{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
{ .compatible = "fsl,imx6ul-ecspi", .data = &imx6ul_ecspi_devtype_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
常见错误: 设备树中
compatible 字符串与驱动表中的字符串必须完全一致(包括大小写与逗号后空格)。例如 "fsl,imx6ul-ecspi" 不能写成 "fsl,imx6ul-ecspi "(尾部空格)或 "fsl,imx6ul-ecspi1"。
3.2.3 SPI 控制器驱动注册流程
3.3 include/linux/spi —— SPI 子系统头文件
该目录定义了 SPI 子系统对外暴露的数据结构、接口函数与宏。无论是 SPI 控制器驱动还是 SPI 设备驱动,都需要引用这些头文件。
3.3.1 核心头文件清单
| 头文件 | 核心定义 | 使用场景 |
|---|---|---|
spi.h |
struct spi_master、struct spi_device、struct spi_transfer、struct spi_message |
所有 SPI 驱动必须包含 |
spi-mem.h |
struct spi_mem、struct spi_mem_op、SPI 内存操作接口 |
SPI NOR / NAND 驱动 |
spi-gpio.h |
GPIO 模拟 SPI 的板级配置结构 | 软件 SPI 位操作驱动 |
3.3.2 关键数据结构关系
3.4 三个目录的协作关系
设备树、SPI 控制器驱动、SPI 子系统头文件三者构成完整的 SPI 硬件支持链路:
- 设备树(
arch/arm/boot/dts)描述 SPI 控制器的寄存器地址、中断、时钟、引脚复用。 - SPI 控制器驱动(
drivers/spi/spi-*.c)解析设备树节点,初始化硬件,并通过include/linux/spi/spi.h中的接口注册到 SPI 核心。 - SPI 核心(
spi.c+spi.h)管理总线、设备枚举、传输队列,向上层提供统一的spi_write_then_read()等 API。
实战建议: 在移植 SPI 驱动时,应同时打开以下三个目录的终端窗口:
arch/arm/boot/dts/ —— 修改设备树drivers/spi/ —— 调试控制器驱动include/linux/spi/ —— 查阅数据结构定义