项目场景以及问题描述:
最近在用正点原子的阿尔法开发板复刻一个智能家居的项目,该项目使用ap3216c传感器获取红外、光照、距离。该项目采用设备树定义各个传感器的硬件信息。当我编译好驱动,将ko文件加载进内核。发现ap3216c的probe函数并没有运行。
探索过程:
我首先是检查了驱动程序和设备树的compatible是否一致,发现是一致的没错。接下来用如下命令,检查了i2c总线上是否存在设备节点。
# cd /sys/bus/i2c/devices
# ls
0-001a 0-001e 1-001a 1-0038 1-003c 1-005d i2c-0 i2c-1
-
i2c-0
和i2c-1
表示系统中的两个 I2C 总线。 -
0-001e
表示 I2C 总线 0 上有一个地址为0x1e
的设备
其中1e就是ap3216c在设备树中定义的i2c地址。所以其实ap3216c节点是有被解析出来的。我当时也很疑惑,我的驱动明明没有运行probe函数,但是却有ap3216c的节点。 后来问DeepSeek,排除了一些可能性,并且还有一个小红书上的大佬指点,很有可能是内核里存在一个ap3216c的驱动,在开机时,就自动匹配上了设备树的节点,从而导致我的驱动无法匹配上这个节点,因为一个设备树的节点只能匹配一个驱动。
解决方案:
方案一
小红书那位大佬给了一个测试方案,就是通过运行以下命令,手动解绑ap3216c的驱动。
echo "0-001e" > /sys/bus/i2c/drivers/ap3216c/unbind
解绑以后,我再加载驱动,我的驱动就probe上了。
方案二
他还建议我重新编译内核,取消勾选ap3216c驱动的选项。但当时我刚上手,每次搞内核就一堆问题,于是就搁置了。这几天重新启动,目标是重新编译内核,取消勾选ap3216c选项。
探索过程
从当前运行的内核里提取内核配置文件重新在虚拟机上编译内核,看能不能得到一个完好的内核镜像。
1、首先导出原装内核配置
zcat /proc/config.gz > running_kernel.config
2、将配置的内容更换到ubuntu虚拟机的内核源码目录下的.config里。
3、在内核源码目录下应用老配置文件,并重新编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- oldconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j12
4、加载到板子,测试,发现没有问题,能够正常进入系统。
下一步就是修改内核配置,关闭ap3216c驱动。但事情并不是很顺利,测试后发现都不用改了,我可以直接就装载ap3216驱动。不知道是不是因为我新换了内核,还是因为新设备树。将原zImage加载进板子,是需要先解绑ap3216c节点。所以原内核里是有ap3216c驱动的。但是我新内核的配置是从旧内核导出的,怎么会原内核有,新内核没有?查找了一下,我虽然导出的配置文件里有ap3216c,但我内核源码里的menuconfig是没有ap3216c选项,估计是这个原因。
我继续进行代码测试(因为我已经跑通代码了,现在换了个内核,看能不能跑通)。问题接踵而至。新内核无法使用触摸屏。我重新编译了内核时,添加goodix的触摸屏驱动(我用的这块触摸屏闲鱼上买的,是gt911驱动,是goodix公司的)还是没用。发现导出的内核配置有gt9xx,但我的内核源码并没有这个设置。我很疑惑,咋可能我的内核又没有?后续通过uname -r查询了原内核版本和新内核版本,发现了问题。原内核版本4.1.15-g3dc0a4b,而新内核是4.1.15。
后续查找正点原子的资料目录找到问题了,正点原子提供了两套源码。一份是出厂的,一份学习的。而我一直使用的是学习的源码,内核是出厂源码编译出来的。
使用出厂源码进行配置,就发现了内核是勾选了ap3216驱动,这边应该取消勾选,否则会导致内核里的ap3216驱动跟设备树节点绑定,从而使得我的ap3216驱动无法probe。在这个源码里,也是找到了gt9xx触摸芯片驱动。
重新编译内核以后,经过测试,无需通过方案一的echo,驱动就可以直接挂载上,问题解决。