3. SPI控制器驱动注册流程:platform_driver_register、spi_alloc_master、spi_register_master的调用链与参数配置
在车载Linux系统中,SPI控制器驱动通常以平台驱动(platform driver)的形式存在,通过标准的内核驱动模型完成注册。核心调用链涉及三个关键函数:platform_driver_register、spi_alloc_master和spi_register_master。理解这一调用链及其参数配置,是编写稳定、高效的车载SPI驱动的基础。
3.1 调用链全景
SPI控制器驱动的注册流程遵循“平台设备绑定 → 主控制器分配 → 主控制器注册”的三步范式。下图展示了完整的调用链与数据流关系:
3.2 三步核心调用详解
3.2.1 platform_driver_register:驱动入口注册
SPI控制器驱动首先需要注册为一个平台驱动。通常在模块初始化函数中调用,并填充struct platform_driver结构体:
static struct platform_driver spi_imx_driver = {
.driver = {
.name = "imx6ul-spi",
.of_match_table = spi_imx_of_match,
.pm = &spi_imx_pm_ops,
},
.probe = spi_imx_probe,
.remove = spi_imx_remove,
.id_table = spi_imx_devtype,
};
module_platform_driver(spi_imx_driver);
| 字段 | 说明 | 车载场景注意事项 |
|---|---|---|
| .driver.name | 驱动名称,用于和设备树 compatible 匹配 | 建议与芯片手册命名一致,便于调试 |
| .of_match_table | 设备树匹配表,定义 compatible 字符串 | 车载多平台需包含所有变体 |
| .probe | 设备匹配成功后的初始化回调 | 需包含时钟、复位、DMA等初始化 |
| .id_table | 传统平台设备ID表(非设备树时使用) | 车载新平台优先使用设备树 |
3.2.2 spi_alloc_master:主控制器对象分配
在probe回调中,驱动调用spi_alloc_master分配一个struct spi_master对象。该函数接受struct device *dev和unsigned size两个参数:
struct spi_master *master;
int ret;
master = spi_alloc_master(&pdev->dev, sizeof(struct imx_spi_devdata));
if (!master) {
dev_err(&pdev->dev, "Failed to allocate SPI master\n");
return -ENOMEM;
}
// 获取私有数据指针
struct imx_spi_devdata *devdata = spi_master_get_devdata(master);
参数说明:
- dev:父设备指针,通常传入平台设备的 &pdev->dev
- size:附加私有数据区大小,用于存放控制器硬件相关结构体
分配成功后,通过 spi_master_get_devdata(master) 获取私有数据指针,避免全局变量。
3.2.3 spi_register_master:主控制器注册
完成参数配置后,调用spi_register_master将master注册到SPI核心层。注册成功后,内核会自动扫描设备树中该SPI总线的子节点,并创建对应的SPI从设备:
// 配置master参数(见3.3节)
master->bus_num = pdev->id;
master->num_chipselect = 2;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->min_speed_hz = 100000;
master->max_speed_hz = 50000000;
master->setup = imx_spi_setup;
master->transfer_one = imx_spi_transfer_one;
// 注册master
ret = spi_register_master(master);
if (ret) {
dev_err(&pdev->dev, "Failed to register SPI master: %d\n", ret);
spi_master_put(master);
return ret;
}
platform_set_drvdata(pdev, master);
3.3 关键参数配置详解
在spi_alloc_master和spi_register_master之间,驱动必须正确配置struct spi_master的各个字段。下表列出了车载场景下最关键的参数:
| 参数 | 类型 | 说明 | 车载典型值 |
|---|---|---|---|
| bus_num | u16 | SPI总线编号,-1表示动态分配 | 0, 1, 2(与硬件对应) |
| num_chipselect | u16 | 支持的片选信号数量 | 2~4(车载传感器/执行器数量) |
| mode_bits | u32 | 支持的SPI模式位掩码 | SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
| bits_per_word_mask | u32 | 支持的每字位数掩码 | SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
| min_speed_hz | u32 | 最低时钟频率 | 100000 (100kHz) |
| max_speed_hz | u32 | 最高时钟频率 | 50000000 (50MHz) |
| setup | 函数指针 | 每次传输前配置硬件寄存器 | 实现时钟极性/相位配置 |
| transfer_one | 函数指针 | 单次SPI传输处理函数 | 实现FIFO/DMA传输 |
| auto_runtime_pm | bool | 是否启用运行时电源管理 | true(车载低功耗要求) |
3.4 车载场景下的参数配置要点
车载工程避坑指南:
- bus_num冲突:多SOC平台需确保总线编号不重复,建议从设备树获取或使用动态分配(-1)
- num_chipselect不足:车载T-Box可能同时挂载GPS、加速度计、陀螺仪等多个SPI设备,需预留足够片选
- 速率范围过窄:高速传感器(如车载摄像头)可能需要50MHz以上,低速设备(如温度传感器)仅需1MHz,需合理设置min/max_speed_hz
- mode_bits遗漏:部分车载SPI设备使用SPI_3WIRE模式,需在mode_bits中包含
3.5 完整调用链代码模板
以下是一个车载SPI控制器驱动的probe函数模板,展示了完整的调用链与参数配置:
static int imx_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct imx_spi_devdata *devdata;
struct resource *res;
int ret;
// 1. 分配spi_master及私有数据
master = spi_alloc_master(&pdev->dev, sizeof(struct imx_spi_devdata));
if (!master)
return -ENOMEM;
devdata = spi_master_get_devdata(master);
platform_set_drvdata(pdev, master);
// 2. 获取硬件资源(时钟、IO内存、中断等)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
devdata->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(devdata->base)) {
ret = PTR_ERR(devdata->base);
goto err_out;
}
devdata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(devdata->clk)) {
ret = PTR_ERR(devdata->clk);
goto err_out;
}
// 3. 配置spi_master参数(车载典型配置)
master->bus_num = pdev->id; // 使用平台设备ID
master->num_chipselect = 2; // 2个片选
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->min_speed_hz = 100000; // 100kHz
master->max_speed_hz = 50000000; // 50MHz
master->setup = imx_spi_setup;
master->transfer_one = imx_spi_transfer_one;
master->auto_runtime_pm = true; // 启用运行时PM
// 4. 注册spi_master
ret = spi_register_master(master);
if (ret) {
dev_err(&pdev->dev, "spi_register_master failed: %d\n", ret);
goto err_out;
}
dev_info(&pdev->dev, "SPI controller registered, bus_num=%d\n", master->bus_num);
return 0;
err_out:
spi_master_put(master);
return ret;
}
3.6 调用链时序图
下图以时序方式展示了从驱动加载到设备枚举的完整交互过程:
关键要点回顾:
- platform_driver_register 是驱动入口,通过设备树匹配触发probe
- spi_alloc_master 分配主控制器对象,同时分配私有数据区
- 参数配置必须在 spi_register_master 之前完成,注册后不可修改
- spi_register_master 触发设备枚举,自动创建设备节点
- 车载场景需特别关注 bus_num、num_chipselect、mode_bits 和 速率范围