内核空间如何正确使用新的gpiod_export()函数导出GPIO?
内核v5.10中如何使用新的GPIO描述符接口导出GPIO?
在Linux内核v4.14中,我们通过以下代码从内核驱动导出GPIO,之后可在用户空间通过cat /sys/kernel/debug/gpio查看所有导出的GPIO:
static struct gpio ct_gen2_gpios[] __initdata = { {22, GPIOF_OUT_INIT_LOW, "gpo1" }, {23, GPIOF_OUT_INIT_LOW, "gpo0" }, // ... 其他GPIO定义 }; gpio_request_array(my_gpios, ARRAY_SIZE(my_gpios)); for (i = 0; i < ARRAY_SIZE(my_gpios); i++) { gpio_export(ct_gen2_gpios[i].gpio, 1); // 升级内核后此方法失效 }
升级到内核v5.10后,传统gpio.h被弃用,上述代码无法再导出GPIO。我们看到新的接口:
int gpiod_export(struct gpio_desc *desc, bool direction_may_change); struct gpio_desc { struct gpio_device *gdev; unsigned long flags; /* Connection label */ const char *label; /* Name of the GPIO */ const char *name; // ... 其他字段 };
但找不到获取或创建struct gpio_desc(特别是struct gpio_device *gdev字段)的示例,请问如何使用新的描述符接口正确导出GPIO?
解决方案
你需要替换传统的gpio_request_array和gpio_export为基于GPIO描述符的接口,核心步骤是先获取对应GPIO的struct gpio_desc实例,再配置属性后导出。以下是适配v5.10内核的完整实现:
1. 定义GPIO信息
不再使用旧的struct gpio数组,改用struct gpiod_lookup_table统一管理GPIO映射关系:
#include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> // 定义GPIO映射:[gpio控制器名, GPIO编号, 别名, 电平属性] static struct gpiod_lookup_table ct_gen2_gpio_table = { .dev_id = "my_driver", // 你的驱动设备标识 .table = { GPIO_LOOKUP("gpiochip0", 22, "gpo1", GPIO_ACTIVE_HIGH), GPIO_LOOKUP("gpiochip0", 23, "gpo0", GPIO_ACTIVE_HIGH), // ... 其他GPIO定义 GPIO_LOOKUP_END, }, };
注:
gpiochip0是系统中GPIO控制器的名称,可通过cat /sys/class/gpio/查看实际存在的控制器。
2. 请求并配置GPIO描述符
批量注册映射表后,逐个获取GPIO描述符并设置初始状态:
struct gpio_desc *descs[2]; // 对应上面定义的2个GPIO,可根据实际数量调整 int i, ret; // 注册GPIO映射表 gpiod_add_lookup_table(&ct_gen2_gpio_table); // 逐个获取GPIO描述符并配置初始输出低电平 for (i = 0; i < ARRAY_SIZE(descs); i++) { descs[i] = gpiod_get(dev, ct_gen2_gpio_table.table[i].con_id, GPIOD_OUT_LOW); if (IS_ERR(descs[i])) { ret = PTR_ERR(descs[i]); goto err_cleanup; } // 设置GPIO标签,会在/sys/kernel/debug/gpio中显示 gpiod_set_label(descs[i], ct_gen2_gpio_table.table[i].con_id); }
3. 导出GPIO到用户空间
使用gpiod_export完成导出,第二个参数设为1表示允许用户空间修改GPIO方向:
for (i = 0; i < ARRAY_SIZE(descs); i++) { ret = gpiod_export(descs[i], 1); if (ret) { dev_err(dev, "Failed to export GPIO %s\n", ct_gen2_gpio_table.table[i].con_id); goto err_export_cleanup; } // 可选:在驱动目录下创建GPIO的符号链接,方便用户空间访问 gpiod_export_link(dev, ct_gen2_gpio_table.table[i].con_id, descs[i]); }
4. 驱动卸载时清理资源
err_export_cleanup: for (i = 0; i < ARRAY_SIZE(descs); i++) { if (!IS_ERR_OR_NULL(descs[i])) { gpiod_unexport(descs[i]); gpiod_put(descs[i]); } } err_cleanup: gpiod_remove_lookup_table(&ct_gen2_gpio_table);
关键说明
gpiod_get是获取GPIO描述符的核心接口,第三个参数GPIOD_OUT_LOW对应旧接口的GPIOF_OUT_INIT_LOW,用于指定初始状态。- 导出后,用户空间可通过
/sys/class/gpio/gpioX/节点操作GPIO,同时/sys/kernel/debug/gpio中会显示该GPIO的信息。
内容的提问来源于stack exchange,提问作者Glen G
相关产品推荐
相关产品推荐

