Linux GPIO 驱动用 gpiod 接口(新)或 legacy gpio 接口(旧);设备树里定义 gpios 属性,驱动用 devm_gpiod_get 获取 gpio_desc,gpiod_direction_input/output 设置方向,gpiod_get_value/set_value 读写;旧接口用 of_get_named_gpio+gpio_request+gpio_direction_*;用户态通过 sysfs(/sys/class/gpio/export)或 libgpiod(gpiodetect/gpioget)访问。
本文概述
GPIO 是 Linux 最基础驱动,面试常考:gpiod 接口、设备树、sysfs、libgpiod。回答要给新旧接口对比和代码。
核心要点
新接口 gpiod(Linux 4.8+):devm_gpiod_get 获取描述符,gpiod_get_value/set_value 读写
旧接口 legacy:of_get_named_gpio 获取编号,gpio_request 申请,gpio_set_value 读写
设备树:gpios = <&gpioX Y GPIO_ACTIVE_HIGH>; 或 named-gpios
用户态:sysfs(/sys/class/gpio,已弃用但仍常用)、libgpiod(gpiodetect/gpioget/gpioset,新)
中断:gpio_to_irq 获取中断号,request_irq 注册;或 gpiod_to_irq

面试官考察点
Linux 驱动基础题。面试官看你是否写过 GPIO 驱动。重点听:gpiod 接口、设备树、用户态。
回答思路
讲 gpiod 新接口和 legacy 旧接口,设备树绑定,用户态访问,中断。
参考回答
gpiod 新接口(推荐,Linux 4.8+)。
// 设备树
my_device {
compatible = "vendor,mydevice";
led-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
key-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
};
// 驱动 probe
struct gpio_desc *led = devm_gpiod_get(dev, "led", GPIOD_OUT_LOW);
struct gpio_desc *key = devm_gpiod_get(dev, "key", GPIOD_IN);
gpiod_set_value(led, 1); // 点亮 LED
int val = gpiod_get_value(key); // 读按键
devm_gpiod_get 自动管理资源(remove 时自动释放),不需要手动 gpiod_put;
第二个参数是设备树里 gpios 属性的前缀("led" 对应 led-gpios);
方向参数:GPIOD_IN、GPIOD_OUT_LOW、GPIOD_OUT_HIGH;
gpiod_set_value / gpiod_get_value 读写;
gpiod_direction_input / gpiod_direction_output 改方向。
legacy 旧接口(仍大量存在)。
int led_gpio = of_get_named_gpio(np, "led-gpios", 0);
gpio_request(led_gpio, "my_led");
gpio_direction_output(led_gpio, 0);
gpio_set_value(led_gpio, 1);
gpio_free(led_gpio); // remove 时释放
of_get_named_gpio 从设备树获取 GPIO 编号(整数);
gpio_request 申请,gpio_free 释放(必须配对,否则泄漏);
gpio_direction_input/output 设置方向;
gpio_get_value/set_value 读写;
旧接口已被标记弃用,但很多老驱动还在用,新代码用 gpiod。
gpiod vs legacy。
| 项目 | gpiod(新) | legacy(旧) |
|---|---|---|
| 句柄 | gpio_desc 指针 | int 编号 |
| 资源管理 | devm 自动释放 | 手动 gpio_free |
| 极性处理 | 自动(ACTIVE_LOW 自动翻转) | 手动处理 |
| 获取函数 | devm_gpiod_get | of_get_named_gpio + gpio_request |
| 状态 | 推荐 | 弃用但兼容 |
用户态访问 GPIO。
sysfs(旧,已弃用):
echo 3 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio3/direction
echo 1 > /sys/class/gpio/gpio3/value
简单但慢、无并发保护,新内核可能默认关闭;libgpiod(新,推荐):
gpiodetect(列出 GPIO 控制器)
gpioinfo(查看引脚状态)
gpioset gpiochip1 3=1(设置输出)
gpioget gpiochip2 5(读取输入)
C 库 libgpiod 可直接在程序里调用;设备驱动+字符设备:驱动创建 cdev,用户态 read/write/ioctl,适合复杂逻辑。
GPIO 中断。
// gpiod 接口
int irq = gpiod_to_irq(key);
request_irq(irq, my_irq_handler, IRQF_TRIGGER_FALLING, "my_key", dev);
// 设备树里可以定义中断
key-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio2>;
interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
按键、传感器中断常用 GPIO 中断;
触发方式:上升沿、下降沿、双边沿、高电平、低电平;
中断处理函数要快(顶半部分),耗时工作用 workqueue/threaded_irq。
注意。
GPIO 编号不是全局唯一,不同控制器独立编号,用 gpio_chip 区分;
设备树里 GPIO_ACTIVE_LOW 表示低电平有效,gpiod 接口自动处理极性;
有些引脚复用为其他功能(I2C/SPI),要先确认 pinmux 配置为 GPIO;
输出 GPIO 要考虑驱动能力(一般 mA 级),驱动 LED 要加限流电阻;
输入 GPIO 要加上下拉(防止悬空),设备树或寄存器配置。

扫码关注




























