我有一个基于 iMX8 CPU 的嵌入式 Linux 系统。我正在升级 yocto 版本,从而升级内核版本。
我在两条 SPI 总线上有两个 SPI 设备。第二条总线上的设备有一个驱动程序创建/dev/spidevX.X
node
,另一个不创建/dev/*
node
.
我注意到 SPI 设备的地址在内核升级期间似乎不一致:在以前的 yocto 版本中Kernel 5.4.24
,第二个硬件 SPI 总线上的我的设备显示为/dev/spidev1.0
一致。
升级到内核 5.15.71 后,节点大多显示为/dev/spidev2.0
,但我也看到过/dev/spidev1.0
。
我的谷歌结果表明 / dev/spidevX.Y
v 意味着X = bus
, Y = device/CS
。
如何确保某个硬件总线始终获得某个总线号?
答案1
spidev (drivers/spi/spidev.c) 创建 /dev/spidevB.C,其中 B 是总线号,C 是片选:
dev = device_create(spidev_class, &spi->dev, spidev->devt,
spidev, "spidev%d.%d",
spi->master->bus_num, spi->chip_select);
考虑SPI内核如何drivers/spi/spi.c
int spi_register_controller(struct spi_controller *ctlr)
分配控制器总线号(代码如下所示),有多种方法可以遇到内核之间的不一致问题(尽管不太可能)。
比较两个内核版本之间 SoC 设备树中的 SPI 控制器,看看定义是否不一致并解决:
例如,缺少在一个版本中定义某些控制器。
如果不存在此类不一致,则检查设备树别名是否存在任何不一致并解决它(其中of_alias_get_id
和of_alias_get_highest_id
在下面的代码中可以发挥作用):
只是一个想象的例子,
在 SoC 的 5.4.y 中
aliases {
:
spi0 = &ecspi1;
spi1 = &ecspi2;
spi2 = &ecspi3;
};
但在 SoC 5.15.y 中
aliases {
:
spi0 = &ecspi3;
spi1 = &ecspi1;
spi2 = &ecspi2;
};
如果您的设备树没有任何 SPI 别名,并且您遇到不一致的情况,请尝试在控制器的两个树中使用相同的编号添加 SPI 别名:
例如,
aliases {
:
spi0 = &lpspi1;
};
所以,这里我们使用数字0茎后SPI所以of_alias_get_id
或者of_alias_get_highest_id
可以选择那个。
我没有具体检查您提到的内核版本,并且您没有提到 iMX8 SoC(但通过查看 lf-5.4.y 和 lf-5.15.y 很可能是 iMX8QXP,因为我没有看到 SPI 控制器在 DT 中,因此您必须定义它们,因此可能会遇到不一致的情况,但我不确定)。
SPI 控制器总线编号分配来自drivers/spi/spi.c
int spi_register_controller(struct spi_controller *ctlr)
{
if (ctlr->bus_num >= 0) {
/* devices with a fixed bus num must check-in with the num */
mutex_lock(&board_lock);
id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
ctlr->bus_num + 1, GFP_KERNEL);
mutex_unlock(&board_lock);
if (WARN(id < 0, "couldn't get idr"))
return id == -ENOSPC ? -EBUSY : id;
ctlr->bus_num = id;
} else if (ctlr->dev.of_node) {
/* allocate dynamic bus number using Linux idr */
id = of_alias_get_id(ctlr->dev.of_node, "spi");
if (id >= 0) {
ctlr->bus_num = id;
mutex_lock(&board_lock);
id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
ctlr->bus_num + 1, GFP_KERNEL);
mutex_unlock(&board_lock);
if (WARN(id < 0, "couldn't get idr"))
return id == -ENOSPC ? -EBUSY : id;
}
}
if (ctlr->bus_num < 0) {
first_dynamic = of_alias_get_highest_id("spi");
if (first_dynamic < 0)
first_dynamic = 0;
else
first_dynamic++;
mutex_lock(&board_lock);
id = idr_alloc(&spi_master_idr, ctlr, first_dynamic,
0, GFP_KERNEL);
mutex_unlock(&board_lock);
if (WARN(id < 0, "couldn't get idr"))
return id;
ctlr->bus_num = id;
}
}