3. GPIO中断触发按键事件
任务目标
在瑞芯微RK3588平台上,将一个GPIO引脚配置为中断输入模式,连接按键。当按键按下时,GPIO电平变化触发中断,在中断处理函数中记录按键事件(打印日志或更新计数器)。本案例使用Linux内核GPIO子系统标准API实现,不依赖具体板级私有驱动。
环境与依赖
- 内核版本:Linux 5.10+(RK3588 SDK默认内核)
- 硬件连接:按键一端接GPIO(本例以GPIO0_A5为例,对应bank 0,pin 5),另一端接GND,GPIO内部使能上拉
- 内核配置:需开启CONFIG_GPIOLIB(默认开启)
关键完整代码
以下为完整的按键中断驱动模块,采用platform driver模型,通过设备树获取GPIO编号并注册中断:
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/of.h>
static struct gpio_desc *key_gpio;
static int irq_num;
static unsigned long press_count;
static irqreturn_t key_irq_handler(int irq, void *dev_id)
{
press_count++;
pr_info("Key pressed! Total: %lu\n", press_count);
return IRQ_HANDLED;
}
static int key_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret;
key_gpio = devm_gpiod_get(dev, "key", GPIOD_IN);
if (IS_ERR(key_gpio)) {
dev_err(dev, "Failed to get key gpio\n");
return PTR_ERR(key_gpio);
}
gpiod_direction_input(key_gpio);
irq_num = gpiod_to_irq(key_gpio);
if (irq_num < 0) {
dev_err(dev, "Failed to get irq number\n");
return irq_num;
}
ret = devm_request_irq(dev, irq_num, key_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_SHARED,
"rk3588-key", &press_count);
if (ret) {
dev_err(dev, "Failed to request irq %d\n", irq_num);
return ret;
}
dev_info(dev, "Key driver probed, irq=%d\n", irq_num);
return 0;
}
static const struct of_device_id key_of_match[] = {
{ .compatible = "rk3588,gpio-key-irq" },
{ }
};
MODULE_DEVICE_TABLE(of, key_of_match);
static struct platform_driver key_driver = {
.probe = key_probe,
.driver = {
.name = "rk3588_gpio_key",
.of_match_table = key_of_match,
},
};
module_platform_driver(key_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RK3588 GPIO interrupt key driver");
设备树配置
在板级设备树(如rk3588-evb.dtsi)中添加节点:
&pinctrl {
key_int: key-int {
rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
key_demo {
compatible = "rk3588,gpio-key-irq";
key-gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&key_int>;
status = "okay";
};
编译与加载
- 将驱动源码放入内核drivers/input/misc/目录,并添加Makefile条目:
obj-m += rk3588_key_irq.o - 编译模块:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- M=drivers/input/misc/ - 将生成的.ko文件拷贝到目标板,加载:
insmod rk3588_key_irq.ko - 确认设备树节点匹配后,probe成功会打印:
Key driver probed, irq=xxx
验证方法
- 加载模块后执行
cat /proc/interrupts | grep rk3588-key,应能看到对应中断号及触发次数统计 - 按下按键,执行
dmesg | tail,每次按下应输出一条Key pressed! Total: N日志,N逐次递增 - 判定通过条件:每次按键均产生中断日志,且计数连续递增无丢失;释放按键不产生中断(因配置为下降沿触发)
常见问题
- 若probe失败提示gpio获取失败,检查设备树中
key-gpios属性名与驱动中devm_gpiod_get第二个参数是否一致(此处为"key") - 若中断不触发,检查pinctrl配置中GPIO功能是否被复用为其他功能,以及按键接线是否与设备树pin一致
- IRQF_SHARED标志用于兼容同GPIO上多个中断源,若确认独占可去掉