一、挂载扩展芯片(以 TCA6424 为例)
1.1 修改设备树
首先查看芯片的电路原理图,以下图为例所示:
可以看到扩展芯片为tca6424
系列,通过I2C2
进行扩展,并且该芯片的 I2C
的十六进制地址为 0x22
。则我们就可以在内核的源代码中搜索 tca6424
,找到使用了该系列芯片的设备树文件,在该文件中搜索 tca6424
,找到该设备树文件对于tca6424
芯片的gpio
的定义方法:
gpio9: gpio@22 {
compatible = "ti,tca6424";
reg = <0x22>;
gpio-controller;
#gpio-cells = <2>;
};
然后在我们需要使用到的设备树文件中找到对应的 I2C
节点,如上述芯片使用到的是 I2C2,则我们就可以在需要使用的设备树文件(OK8MP-C.dts)中找到该节点:
将上述的关于对tca6424
芯片的gpio
的定义的相关代码粘贴到I2C2
节点下面,作为该节点的子节点存在,并将地址改为板卡扩展芯片对应的地址,同时在 OK8MP-C.dts 引用的文件(imx8mp.dtsi
)中可以看到,原有设备树对于 gpio 的使用已经使用到了 gpio5
了,故该节点的 gpio
标号则应该大于5,从而避免冲突。
故我们在设备树的I2C2
节点下添加子节点如下:
gpio6: gpio@22 {
compatible = "ti,tca6424";
reg = <0x22>;
gpio-controller;
#gpio-cells = <2>;
};
其他扩展芯片的挂载也类似,修改为该芯片的相应的地址之后,再把其定义在对应的 I2C
节点下即可。
对于i2c
节点下的子节点存在与扩展芯片的地址有冲突的,则应把与扩展芯片地址冲突的子节点的 status
改成 disabled
,将该节点给关掉,不然会导致地址冲突的扩展芯片无法挂载上去。
&i2c3 {
...
gpio8: gpio@22 {
compatible = "ti,tca6424";
reg = <0x22>;
gpio-controller;
#gpio-cells = <2>;
status = "okay";
};
fusb302: typec-portc@22 {
...
interrupts = <19 IRQ_TYPE_LEVEL_LOW>;
status = "disabled";
...
};
...
};
修改完设备树之后,再在内核源代码中找到 tca6424
芯片对应的驱动:
在该驱动程序中找到 probe
函数,在该函数结束的地方用 printk
打印一些日志信息,如果芯片成功挂载的话,则在板子启动的时候,系统日志就会将这些信息打印出来,如果没有挂载成功,这些信息则不会打印出来。
static int pca953x_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
...
if (chip == NULL){
return -ENOMEM;
}
printk(KERN_INFO "tca6424 is start !!!!!!!!!!!!!!!!!!!\n");
pdata = dev_get_platdata(&client->dev);
...
printk(KERN_INFO "tca6424 mount success\n");
return 0;
err_exit:
if (chip->regulator)
regulator_disable(chip->regulator);
return ret;
}
修改完代码之后,将源代码重新进行编译,将编译之后的程序烧录到板子上,板子成功启动之后,使用 dmesg
命令打印日志信息,然后就可以在日志上看到我们 printk
的信息了。如下图所示,我挂载了四块拓展芯片,所以该信息就打印了四次。
进入到/sys/class/gpio
目录下使用 ls -l
命令,即可查看到挂载的芯片的信息:
使用命令 cat /sys/kernel/debug/gpio
即可查看各个 gpio
芯片的管脚的使用信息:
1.2 操作 GPIO
查看挂载的扩展芯片的管脚的使用信息,对于要操作的 GPIO
,选择一个该芯片未使用的一个管脚对应的管脚号 X,执行以下命令,如果能看到相应目录的值发生预期的改变的话,则说明该 GPIO
是可操作的。
1. 导出
/sys/class/gpio# echo X> export
2. 设置方向
/sys/class/gpio/gpioX# echo out > direction
3. 查看方向
/sys/class/gpio/gpioX# cat direction
4. 设置输出
/sys/class/gpio/gpioX# echo 1 > value
5. 查看输出值
/sys/class/gpio/gpioX# cat value
6. 取消导出
/sys/class/gpio# echo X > unexport
X 导出gpio号 > 芯片基号 < 可扩展io号
二、添加扩展 I/O
2.1 在扩展芯片上添加扩展 IO
确认要添加的 gpio
的 io
,我的要添加的 io
如下图所示:
在硬件原理图上找到这些 io
对应的管脚,以 far_short
为例,其在硬件原理图的位置如下图所示:
我们就可以在我们要使用的设备树文件中的 leds
节点中添加我们要添加的 io
管脚作为 led
的子节点:
far_short {
lable = "far_short";
gpios = <&gpio6 0 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
代码中 lable
的内容即是在板卡中的文件系统中显示的该 io
文件的名字,对于第三行的 gpios
的赋值,&gpio6
的取值要与该 io
所在的芯片在系统挂载的 gpio
相对应,即刚刚挂载的四个扩展芯片在设备树中对应的gpio
。后面跟着的值(0) 则要与该 io
在芯片上的位置相对应,如上述的 io
在芯片上对应的标号为 1,GPIO_ACTIVE_HIGH
表示该 io
为高电平有效,若取值为 GPIO_ACTIVE_LOW
则表示该 io
为低电平有效。
把要添加的 io
管脚全部都添加到 leds
节点下的子节点之后,重新编译设备树,然后把编译后的 .dtb
文件拷贝到板子上,替换掉板子原有的设备树文件,重新启动板子后,就可以在 /sys/class/leds
下看到我们添加的 io
的驱动目录了。
- 通过io 驱动实际空置开发板对应管脚
在这些io
的目录下存在如下一些文件,通过修改brightness
的值即可控制该io
管脚的闭合,如果是继电器类型的管脚,开闭该io
听到声音则表示该io
管脚可以控制,其他类型的io
管脚也类似。对于无法直观观察到io
的开闭的,则可以通过万用表测量通过该管脚的电平的高低来判断驱动是否可以有效控制该管脚。
2.2 GPIO 的 IO 复用
在添加 io 的过程中可能会使用到在核心板上的管脚,这个就涉及到 io
的复用了,如上述的 kl30_on
管脚,其在电路中对应的管脚如下:
可以看到 kl30_on
对应的开发板功能为 SAI3_TXC
,在板卡的 GPIO
使用表中找到该功能,内容如下所示:
由此可得知该管脚复用为gpio
的话,则对应为 gpio5
的 0
号 io
,同时可以在我们使用的设备树文件的 &iomuxc
节点下看到类似于如下的一些代码:
我们随便选取一串(以MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK
为例)在内核源代码中进行搜索,找到定义它们的 .h
文件:
在该 .h
文件中有一系列宏定义,这些宏定义了引脚的复用功能,在其中找到关于 gpio5
的 0
号 io
的定义,可以看到如下代码:
#define MX8MP_IOMUXC_SAI3_TXC__GPIO5_IO00 0x1C8 0x428 0x000 0x5 0x0
每一个宏定义后面都有 5个参数,再加上刚刚在&iomuxc
节点下配置的参数一共是 6个参数,通过它们就可以完成一个 GPIO
的配置了。在我们使用的设备树文件的 &iomuxc
节点下添加一个子节点,并将上述关于 GPIO5_IO00
定义的那以长串宏复制到该子节点下,同时添加配置参数,得到如下代码:
pinctrl_kl30_on: kl30ongrp {
fsl,pins = <
MX8MP_IOMUXC_SAI3_TXC__GPIO5_IO00 0x19
>;
};
在 leds
节点下添加关于 kl30_on
的子节点,代码如下:
kl30_on {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_kl30_on>;
lable = "kl30_on";
gpios = <&gpio5 0 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
同时还要在原设备树文件中找到其他关于 SAI3_TXC
功能的宏的应用,将其对应的语句给注释掉,然后将该宏控制的节点的状态改为 disabled
,这样就可以避免功能的冲突了。
&sai3 {
...
fsl,sai-mclk-direction-output;
status = "disabled";
};
将修改好的设备树重新编译之后,将对应的 .dtb
文件拷贝到开发板上替换掉原来的设备树文件,重启开发板即可通过驱动来控制开发板上的 KL30
管脚了。