实验日志:
[root@100ask:/proc/device-tree]# find -name "oled"./soc/aips-bus@02000000/spba-bus@02000000/ecspi@02008000/oled[root@100ask:/proc/device-tree]# cd /root/[root@100ask:~]# insmod oled_drv.ko[119.745706]100ask_spi_oled_drv spi0.0: SPI Master Bus Num:0[119.770832]100ask_spi_oled_drv spi0.0: SPI Master Name: spi0[119.788172]100ask_spi_oled_drv spi0.0: Current Device Chip Select:0第一部分:深度解析实验日志
1. 设备树路径的秘密
[root@100ask:/proc/device-tree]# find -name "oled"./soc/aips-bus@02000000/spba-bus@02000000/ecspi@02008000/oled这条路径暴露了 i.MX6ULL 芯片内部的物理拓扑结构:
soc:片上系统根节点。aips-bus/spba-bus:这是 ARM 内部的高速外设总线。ecspi@02008000:这是关键!0x02008000是 i.MX6ULL 手册中ECSPI1控制器的物理基地址。- 这证明 OLED 节点正确地挂载在ECSPI1控制器下。
- 如果这里是
ecspi@0200c000,那就是 ECSPI2。这个地址决定了下面的Master Bus Num是多少。
2. 驱动加载日志解码
[ 119.745706] 100ask_spi_oled_drv spi0.0: SPI Master Bus Num: 0spi0.0:这是 Linux 为该设备生成的唯一 ID。- 前一个
0:代表Bus Number(总线号)。对应上面的 ECSPI1。 - 后一个
.0:代表Chip Select(片选号)。说明硬件上您使用的是 CS0 引脚。
- 前一个
Bus Num: 0:验证了驱动程序正确读取到了 Master 的编号。在 i.MX6ULL 的设备树别名(aliases)中,通常有spi0 = &ecspi1;,所以物理上的 ECSPI1 被映射为逻辑上的 Bus 0。
[ 119.770832] 100ask_spi_oled_drv spi0.0: SPI Master Name: spi0- 这里 Master 的名字叫
spi0。在不同的内核版本中,这里可能会显示为2008000.spi(物理地址)或spi_master。显示为spi0说明内核的 SPI 子系统已经为这个控制器分配了标准的逻辑名称。
[ 119.788172] 100ask_spi_oled_drv spi0.0: Current Device Chip Select: 0- 再次确认为片选 0。如果您在设备树里把
reg = <0>;改成reg = <1>;,这里就会变成 1。
第二部分:如何进行“三方对应”验证(Master、Device、Driver)
在 Linux 驱动开发中,**“匹配成功”**是指三个独立的部分完美咬合。只要其中任何一方掉链子,probe函数就不会执行。
我们将通过Sysfs 文件系统和Debugfs来进行地毯式排查。
角色一:Master (SPI 控制器)
它的任务:提供物理通信舞台。如果 Master 没就位,在这个舞台上的一切都是空谈。
在终端输入:
ls -l /sys/bus/platform/drivers/spi_imx/输出:
total 0 lrwxrwxrwx 1 root root 0 Jan 1 03:48 2008000.ecspi -> ../../../../devices/soc0/soc/2000000.aips-bus/2000000.spba-bus/2008000.ecspi lrwxrwxrwx 1 root root 0 Jan 1 03:48 2010000.ecspi -> ../../../../devices/soc0/soc/2000000.aips-bus/2000000.spba-bus/2010000.ecspi --w------- 1 root root 4096 Jan 1 03:48 bind --w------- 1 root root 4096 Jan 1 03:48 uevent --w------- 1 root root 4096 Jan 1 03:48 unbind进入该目录,查看driver链接:
[root@100ask:/sys/bus/platform/drivers/spi_imx/2008000.ecspi/driver]# ls2008000.ecspi2010000.ecspibinduevent unbind- 成功含义:表示
spi-imx.c驱动已经成功接管了0x02008000这个硬件控制器。Master 已激活。
角色二:Device (设备树节点 / SPI Slave)
它的任务:告诉内核“我是谁,我在哪”。由设备树(.dts)生成。
查看 SPI 总线下的设备:
ls /sys/bus/spi/devices/判断标准:
你必须看到
spi0.0这个目录。- 如果没有:说明
ecspi@02008000下的oled节点解析失败,或者 Master 初始化失败导致没去扫描子节点。
- 如果没有:说明
进入目录查看
modalias(这是匹配的关键凭证):Bash
cat /sys/bus/spi/devices/spi0.0/modalias- 输出内容:应该是
spi:oled(或者是设备树里 compatible 去掉前缀后的部分)。如果这个字符串和你的驱动代码里的名字对不上,驱动永远不会加载。
- 输出内容:应该是
角色三:Driver (你的字符设备驱动oled_drv.ko)
它的任务:提供操作逻辑。
查看已注册的 SPI 驱动:
ls /sys/bus/spi/drivers/判断标准:
你应该看到你的驱动名,例如
100ask_oled(取决于你的struct spi_driver里的 name 字段)。终极验证(绑定成功):
查看该驱动目录下的内容:
ls -l /sys/bus/spi/drivers/100ask_oled/如果匹配成功,你会在这里看到一个指向
spi0.0的符号链接!Plaintext
spi0.0 -> ../../../../devices/platform/soc/2000000.bus/.../spi0.0- 如果你看到了这个链接:恭喜你,Master、Device、Driver 三方已成功“联姻”。
- 如果里面是空的:说明驱动加载了,但是没找到对应的设备(名字匹配失败)。
总结图解:三方握手流程
为了方便记忆,请看这张逻辑流向图:
Step 1: Master Ready?
- 检查
/sys/bus/platform/devices/2008000.spi是否存在。 - (对应你的日志:Master Bus Num: 0, Name: spi0)
- 检查
Step 2: Device Created?
- 检查
/sys/bus/spi/devices/spi0.0是否存在。 - (对应你的日志:find -name “oled” 找到了节点)
- 检查
Step 3: Name Matching?
Driver 代码:
staticconststructof_device_idoled_of_match[]={{.compatible="100ask,oled"},// 这里的名字{}};Device Tree:
DTS
compatible="100ask,oled";// 必须和这里完全一致如果两者一致,内核会调用
probe,然后你就能在/sys/bus/spi/drivers/100ask_oled/下看到spi0.0。w