Linux下通过sysfs读写GPIO的一个注意事项
背景
我司一个项目用的zynq-7000平台,PL端将一个硬件开关状态通过EMIO路由到PS端的GPIO控制器,PS计划通过sysfs访问,这样就不必写驱动了。
PL选择的EMIO编号为0,对应zynq gpio控制器的118个IO口的第54个,于是按照网上的这篇文章操作步骤,执行
echo 54 > /sys/class/gpio/export
结果报错
-sh: echo: write error: Invalid argument
于是定位了2天,终于找到原因。
gpio device和gpio chip的关系
内核的gpio驱动中间件gpiolib为所有类型的gpio控制器抽象出了一个硬件无关的对象struct gpio_device,即每个struct gpio_chip创建一个,但是二者的引脚编号有差异:前者是所有gpio_device共享同一套编号,不会重复,后者是各自有独立的编号,不同的gpio_chip内的号段可能重复。
gpio_chip的base字段注释:
identifies the first GPIO number handled by this chip;
or, if negative during registration, requests dynamic ID allocation.
DEPRECATION: providing anything non-negative and nailing the base
offset of GPIO chips is deprecated. Please pass -1 as base to
let gpiolib select the chip base in all possible cases. We want to
get rid of the static GPIO number space in the long run.
gpio_device的base字段注释:
GPIO base in the DEPRECATED global Linux GPIO numberspace, assigned
at device creation time.
于是我们可以这么理解:

当系统存在多个GPIO控制器时,这种管理方案是非常合理的。
解决
echo 960 > /sys/class/gpio/export
这次就会执行成功
正点原子开发板的坑
有些朋友如果用的正点原子的开发板里的设备树,则EMIO0恰好分配给了led,则上述命令会报错
-sh: echo: write error: Device or resource busy
解决办法就是删除project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi文件里的led内容,或者分配到别的IO上。
export成功后,当作输入还是输出,都可以按照网上教程来了,略。
总结
- sysfs这种GPIO编号貌似要被废弃了,所以仅在5.4以下的老内核适用
- gpio_device引脚的最大编号是1023,这让我怀疑它分配引脚号时,是倒序分配的😏
