在嵌入式系统中,GPIO(通用输入输出)是一类极其基础但又不可或缺的资源。它是连接处理器与外部世界的桥梁,广泛用于读取传感器状态、控制 LED、驱动蜂鸣器、复位外设等。在嵌入式 Linux 系统中,GPIO 通常通过设备树进行初始化,并由内核提供统一的接口进行控制。尤其是在高通 QRB5165 这类集成度极高的平台上,GPIO 不再是简单的“引脚电平控制”,而是牵涉到 TLMM(Top Level Mode Multiplexer)配置、引脚复用、多功能子系统等复杂机制。
本文将结合 QRB5165 平台的实际开发经验,从硬件结构到驱动框架、从设备树配置到用户态调试,系统地讲解如何高效掌握 GPIO 的开发技巧与调试方法。
QRB5165 平台基于 Qualcomm 的 Snapdragon 865 SoC,内部集成了丰富的 IO 接口,GPIO 控制由 TLMM(Top Level Mode Multiplexer)模块完成。TLMM 的职责包括:
GPIO 编号并不等于 SoC 的物理引脚编号,而是通过 GPIO 映射表管理。开发者通常使用设备树中的 TLMM 节点来配置 GPIO 参数,例如:
&tlmm {
gpio_keys {
compatible = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = <&gpio_key_pins>;
key_vol_up {
label = "volume_up";
gpios = <&tlmm 74 GPIO_ACTIVE_LOW>;
linux,code = ;
};
};
gpio_key_pins: gpio_key_pins {
pins = "gpio74";
function = "gpio";
drive-strength = <2>;
bias-pull-up;
};
};
Linux 提供了统一的 GPIO 子系统,主要由以下几个部分组成:
gpiochip
,管理具体引脚的控制操作。gpio_direction_output()
、gpio_set_value()
)。GPIO 在系统中被抽象为 gpiochip
设备,每个 chip 拥有多个编号的 GPIO。用户空间可以通过 /sys/class/gpio/
或 /dev/gpiochipX
接口与之交互。
TLMM 驱动注册过程:
qcom_pinctrl
结构体gpiochip
驱动中最关键的操作包括:
gpiochip_add()
:注册 GPIO 控制器pinctrl_register()
:注册引脚复用配置器irq_domain_add_linear()
:为 GPIO 分配中断资源在 QRB5165 的设备树中,GPIO 通常配置在 &tlmm
节点下,每个引脚都需要通过 pinctrl
子节点指定:
gpio_output_low: gpio_output_low {
pins = "gpio45";
function = "gpio";
drive-strength = <2>;
output-low;
};
常用属性说明:
function
: 设为 gpio
表示通用 IO 模式drive-strength
: 输出驱动强度(单位 mA)bias-disable
: 禁用上下拉bias-pull-up
: 上拉bias-pull-down
: 下拉output-high/output-low
: 默认输出电平每个设备使用 GPIO 时,都需要指定 <&tlmm X FLAG>
:
X
:GPIO 编号(非物理编号)FLAG
:电平激活方式,如 GPIO_ACTIVE_HIGH
或 GPIO_ACTIVE_LOW
当 GPIO 用于中断输入时,需要设置 interrupts
属性,如:
interrupt-parent = <&tlmm>;
interrupts = <74 IRQ_TYPE_EDGE_BOTH>;
echo 74 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio74/direction
echo 1 > /sys/class/gpio/gpio74/value
推荐使用 libgpiod
提供的工具或 C 接口:
gpioinfo # 查看所有 GPIO 信息
gpioget gpiochip0 74
示例代码:
#include
struct gpiod_chip *chip = gpiod_chip_open_by_name("gpiochip0");
struct gpiod_line *line = gpiod_chip_get_line(chip, 74);
gpiod_line_request_output(line, "myapp", 1);
gpiod_line_set_value(line, 0);
gpiod_chip_close(chip);
leds {
compatible = "gpio-leds";
red {
label = "status_red";
gpios = <&tlmm 91 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
例如:
leds-gpio-aerora {
compatible = "gpio-leds-aerora";
...
};
驱动中通过 of_device_id
匹配并扩展控制逻辑。
当接入按钮、IR 传感器等需要中断响应的外设时,GPIO 可配置为输入 + 中断:
button_int_pin: button_int_pin {
pins = "gpio86";
function = "gpio";
bias-pull-down;
};
驱动中注册中断:
irq = gpio_to_irq(86);
request_irq(irq, button_irq_handler, IRQF_TRIGGER_RISING, "btn", NULL);
为降低功耗,GPIO 需要在 suspend 状态正确配置:
gpio_pins_sleep: gpio_pins_sleep {
pins = "gpio86";
function = "gpio";
bias-disable;
drive-strength = <2>;
input-enable;
};
wakeup-source;
wakeup-gpios = <&tlmm 86 GPIO_ACTIVE_HIGH>;
drive-strength
bias-pull-up
高通 QRB5165 平台上的 GPIO 配置远不止简单的高低电平控制,它涉及设备树结构、驱动框架、Pinmux 多功能引脚配置、电源管理及中断系统的协同。掌握这些机制可以帮助开发者快速实现复杂的 IO 控制逻辑,也为系统的稳定性与低功耗设计打下基础。建议开发中多利用 libgpiod
进行测试,并编写统一的 GPIO 封装接口模块,提升可维护性。