ACPI环境下SPI客户端驱动内核模块自动加载故障求助
问题
在Linux内核中,通过ACPI SSDT获取设备配置数据的SPI客户端驱动无法自动加载(probe函数未执行),但platform_driver的内核模块自动加载功能正常(可成功从_DSD获取属性)。已知需要定义spi_device_id,且驱动仅能通过spi_device_id实现自动加载,现咨询:
- 是否有已知的解决方法?
- spi_device_id结构体是否关联有ACPI命名对象?
相关代码与操作
ACPI SSDT表
DefinitionBlock ("ili9488.aml", "SSDT", 5, "", "ILI9488", 0x1) { Device (TFTD) { Name (_HID, "ILI9488") // _HID: 硬件ID Name (_CID, "ILI9488") // _CID: 兼容ID Name (_UID, One) // _UID: 唯一ID Name (_DSD, Package() { // 设备特定数据 - 用于向驱动返回EC静态资源(定义于_CRS) /* * 设备属性UUID * Linux内核ACPI子系统可识别的通用UUID,会自动处理关联的数据包,并将数据作为"设备属性"提供给驱动 */ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package() { // 定义compatible属性(实际未启用CONFIG_OF,所以没用) Package () { "compatible", Package () { "garosa,garosanvkr25fawd" } }, } }) Method (_CRS, 0, Serialized) { local0 = ResourceTemplate() { // 当前资源设置(ACPI资源转Buffer函数) SpiSerialBus( 0, // 片选 PolarityLow, // 片选低电平有效 FourWireMode, // 全双工模式(MISO未使用) 8, // 每字8位(1字节) ControllerInitiated, // 从模式 32000000, // 32 MHz ClockPolarityLow, // SPI模式0 ClockPhaseFirst, // SPI模式0 "\\EC17.SPI0", // SPI总线主机控制器名称(未确认) 0 // 资源索引,应为0 ) // _SB.GPIO: GPIO总线主机控制器(未确认) GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionOutputOnly, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 40 } // 引脚13 GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly, "\\_SB.GPI0", 0, ResourceConsumer, , ) { 45 } // 引脚15 } Return(local0) } } }
驱动代码片段
static int ili9488_probe(struct spi_device *spidev) { struct device *device; const char *compatible_propery; device = &spidev->dev; device_property_read_string(device, "compatible", &compatible_propery); dev_warn(device, "compatible: %s", compatible_propery); return 0; } static void ili9488_remove(struct spi_device *spidev) { dev_warn(&spidev->dev, "ENTER ili9488_remove function driver bound to ACPI table"); return; } /* 兼容的设备树节点 */ static const struct of_device_id ili9488_of_match[] = { { .compatible = "garosa,garosanvkr25fawd" }, {}, }; MODULE_DEVICE_TABLE(of, ili9488_of_match); /* * 通过兼容ID(_CID)命名对象适配ACPI SSDT */ static const struct acpi_device_id ili9488_acpi_match[] = { { "ILI9488", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, ili9488_acpi_match); static const struct spi_device_id ili9488_spi_devid[] = { { "ILI9488", 0 }, { } }; MODULE_DEVICE_TABLE(spi, ili9488_spi_devid); /* 驱动声明 */ static struct spi_driver ili9488_spi_driver = { .driver = { .name = "ili9488", .acpi_match_table = ili9488_acpi_match, .of_match_table = ili9488_of_match, // 没必要,CONFIG_OF甚至没开启 }, .id_table = ili9488_spi_devid, .probe = ili9488_probe, .remove = ili9488_remove, }; module_spi_driver(ili9488_spi_driver);
操作步骤与报错
编译ACPI表和内核模块后执行以下操作:
$ mount -t configfs none /sys/kernel/config $ modprobe acpi-configfs $ mkdir -p /sys/kernel/config/acpi/table/ili9488 $ cat "ili9488.aml" > "/sys/kernel/config/acpi/table/ili9488/aml"
加载模块时出现报错:
$ insmod ili9488.ko ; rmmod ili9488.ko SPI driver ili9488 has no spi_device_id for garosa,garosanvkr25fawd
注:添加ACPI_PTR或移除of_match_table后不会出现该警告。
解决方法与解答
1. 解决方法
针对当前问题,有几个可行的处理方式:
- 移除无用的of_match_table:既然内核未开启
CONFIG_OF,设备树匹配表完全没必要存在。移除后内核不会尝试从ACPI的_DSD中读取compatible属性去匹配设备树ID,也就不会触发警告,同时ACPI匹配可以正常工作。 - 添加ACPI_PTR标记:给
acpi_match_table添加ACPI_PTR宏(即.acpi_match_table = ACPI_PTR(ili9488_acpi_match)),告知内核该匹配表是针对ACPI的,避免和设备树匹配逻辑混淆,解决警告问题并触发ACPI匹配流程。 - 检查SPI控制器路径:确认ACPI表中
\\EC17.SPI0的路径是否正确,只有SPI主机控制器被内核正确识别,挂载在该总线上的设备才能被枚举并匹配驱动。
2. spi_device_id与ACPI命名对象的关联
spi_device_id本身不直接关联ACPI命名对象,它是用于传统SPI设备的匹配逻辑(如基于平台数据的旧版匹配方式)。但在ACPI场景下,内核会通过以下逻辑建立间接关联:
- ACPI设备枚举时,优先通过
acpi_match_table匹配设备的_HID/_CID。 - 如果驱动同时提供了
spi_device_id表,内核会尝试将ACPI设备的_HID/_CID与spi_device_id中的name字段做匹配,作为 fallback 机制。 - 当前报错的本质是设备树匹配逻辑与ACPI匹配逻辑的冲突:内核读取了_DSD中的
compatible属性,尝试匹配of_match_table,但该值没有对应的spi_device_id,因此触发警告,并非spi_device_id与ACPI命名对象直接关联的问题。
内容的提问来源于stack exchange,提问作者EasyIP2023
相关产品推荐
相关产品推荐

