触摸屏驱动
本文档介绍 RK3588 I2C 接口电容触摸屏控制器(如 GT911)在 Linux 6.1 内核中的 evdev / input 子系统、设备树配置和用户态调试。
适用范围: RK3588 Linux 6.1 Debian 12 / Ubuntu 22.04 系统,C-3588LQ V1.0 + SHIMETAPI-M5-R2A V1.0 底板。
1. 概念基础
1.1 触摸屏接口
RK3588 通过 I2C + 中断 GPIO 与触摸控制器通信:
- I2C:读写寄存器(坐标、状态、配置)
- GPIO:中断(触摸发生 / 释放)
- 复位:可选 GPIO 或上电自动
也就是说,平时 CPU 什么都不用做,手指按下去时触摸 IC 拉一下中断脚,驱动再通过 I2C 去读坐标。
1.2 内核子系统
input 子系统是内核统一管理按键、触摸、鼠标等输入设备的框架;evdev 是它面向用户态的事件层,应用程序从 /dev/input/eventN 读取原始事件。整条链路是:
触摸 IC
↓ I2C 注册 + 中断 IRQ
input 子系统
↓ /dev/input/eventN
应用(Qt / libinput / tslib)1.3 多指触摸
报点用 MT protocol type B(Linux 的多点触摸协议,每根手指一条独立事件流):每个触摸点独立 ABS*MT*\* 事件。Linux 6.1+ 主用此协议。
2. 准备工作
2.1 硬件清单
| 组件 | 型号/规格 | 数量 | 备注 |
|---|---|---|---|
| 主控板 | C-3588LQ 核心板 + SHIMETAPI-M5-R2A 底板 | 1 | |
| 调试串口线 | USB 转 TTL(3.3V) | 1 | 波特率 1500000 |
| 触摸屏 | GT911 / FT5406 + LCD | 1 | I2C + 中断 GPIO |
| FPC 排线 | 4 pin / 6 pin | 1 |
出厂镜像的这台板子没有装配触摸面板,要实践本章内容,需要按底板接口规格自行加装。
2.2 引脚(示例 I2C3 + GPIO)
| 主控板引脚 | 触摸 IC 引脚 | 功能说明 |
|---|---|---|
| I2C3_SDA | SDA | I2C 数据 |
| I2C3_SCL | SCL | I2C 时钟 |
| GPIO / INT | INT | 触摸中断(上升沿) |
| GPIO / RST | RST | 触摸 IC 复位 |
| 3.3V | VCC | 电源 |
| GND | GND | 共地 |
3. 软件准备
3.1 内核配置
CONFIG_INPUT=y
CONFIG_INPUT_EVDEV=y /* 输入事件核心 */
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_GT911=y /* Goodix GT911 */
CONFIG_TOUCHSCREEN_EDT_FT5X06=y /* EDT / FocalTech 系列 */
CONFIG_I2C=y
CONFIG_OF=y触摸 IC 驱动一般自带 GPIO 中断与 I2C probe(探测)逻辑,内核里打开对应型号即可。
3.2 设备树
设备树节点要交代清楚四件事:挂在哪条 I2C 总线、I2C 地址是多少、中断脚和复位脚是哪个,以及触摸面板的尺寸(要与 LCD 分辨率一致):
&i2c3 {
status = "okay";
clock-frequency = <400000>;
touchscreen@14 {
compatible = "goodix,gt911";
reg = <0x14>;
interrupt-parent = <&gpio3>;
interrupts = <RK_PB1 IRQ_TYPE_LEVEL_LOW>; /* 中断 GPIO */
reset-gpios = <&gpio3 RK_PA0 GPIO_ACTIVE_LOW>;
/* 触摸面板尺寸(与 LCD 分辨率一致) */
touchscreen-size-x = <1024>;
touchscreen-size-y = <600>;
status = "okay";
};
};4. 设备端输入设备
以下命令在板子上执行,先看系统里有哪些输入设备,再监听事件验证链路。
4.1 查看全部输入设备
cat /proc/bus/input/devices
# 或
ls /dev/input/实机共有 6 类 input 设备:
| eventN | 名称 | 来源 |
|---|---|---|
| event0 | rk805 pwrkey | 电源按键 |
| event1 | headset-keys | 耳机按键 |
| event2 | rockchip-es8388 Headset | ES8388 耳机 |
| event3 | bt-powerkey | 蓝牙电源键 |
| event4 | adc-keys | ADC 按键 |
| event5 | rockchip-hdmi1 | HDMI CEC |
出厂镜像没有识别到触摸 IC,因为底板没配 TP。要使用触摸,先确认触摸屏已正确连接到 I2C3,并在设备树里 enable
&i2c3和触摸 IC 节点。
4.2 监听触摸事件
# 安装工具
apt install -y evtest
# 监测 input 设备(替换 eventX 为对应设备)
evtest /dev/input/event0evtest 会实时打印事件,按 Ctrl+C 退出。输出示例:
Input driver version: 1.0.1
Input device ID: bus 0x19 vendor 0x0 product 0x0 version 0x0
Input device name: "rk805 pwrkey"
...
Event type 0001 EV_KEY
Event code 0116 (KEY_POWER)4.3 触摸事件演示(无触摸屏也可演示)
手头没有触摸屏时,可以用工具直接注入一个触摸事件,验证应用层能否收到:
# 用 evemu-tools 模拟触摸事件(调试用)
evemu-event /dev/input/eventX --type EV_ABS --code ABS_MT_POSITION_X --value 500 --sync4.4 libinput 调试
libinput 是图形栈常用的输入事件处理库,debug-events 子命令能实时打印所有输入事件:
apt install -y libinput-tools
libinput debug-events5. 多点触摸坐标 / 手势
应用侧用 libinput 或 tslib 读取,例如 Qt / LVGL / Weston。
5.1 QT 应用示例
Qt 应用里处理 QTouchEvent,就能拿到每个触点的 id 和坐标:
#include <QTouchEvent>
bool MyWidget::event(QEvent *e) {
if (e->type() == QEvent::TouchBegin ||
e->type() == QEvent::TouchUpdate ||
e->type() == QEvent::TouchEnd) {
QTouchEvent *te = static_cast<QTouchEvent *>(e);
for (const QTouchEvent::TouchPoint &p : te->points()) {
qDebug() << "id=" << p.id() << "pos=" << p.position();
}
return true;
}
return QWidget::event(e);
}5.2 tslib 校准(如果需要)
某些场景需手动校准触摸:
apt install -y tslib
TSLIB_CONFFILE=/etc/ts.conf ts_calibrate
TSLIB_CONFFILE=/etc/ts.conf ts_testtslib 主要用于电阻屏或非标准触控 IC,与 goodix/egalax 配套使用较少。
6. 设备树添加(PC 端)
[电脑端] 板级 .dts 中添加触摸 IC:
&i2c3 {
status = "okay";
clock-frequency = <400000>;
touchscreen@14 {
compatible = "goodix,gt911";
reg = <0x14>;
interrupt-parent = <&gpio3>;
interrupts = <RK_PB1 IRQ_TYPE_LEVEL_LOW>;
reset-gpios = <&gpio3 RK_PA0 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <1024>;
touchscreen-size-y = <600>;
status = "okay";
};
};中断 GPIO、RESET GPIO、I2C 地址需与底板原理图一致。
电脑端 编译烧录:
./build.sh kernel
./mkfirmware.sh烧录重启后,按 8.1 的方法用 i2cdetect 能扫到地址,就说明硬件和设备树都对上了。
7. 代码解读
7.1 驱动注册
GT911 驱动是一个 i2c_driver,内核同样通过 compatible 字符串把它和设备树节点配对:
// drivers/input/touchscreen/goodix.c(简化)
static const struct of_device_id goodix_dt_ids[] = {
{ .compatible = "goodix,gt911" },
{ /* sentinel */ }
};
static struct i2c_driver goodix_ts_driver = {
.driver = {
.name = "goodix-ts",
.of_match_table = goodix_dt_ids,
},
.probe = goodix_ts_probe,
.remove = goodix_ts_remove,
};7.2 调用链
从手指按下到应用读到事件,中间经过这些环节:
触摸 IC 检出中断
→ GPIO 中断处理
→ input_report_abs() /* input core */
→ 报 ABS_MT_POSITION_X / Y
→ 唤醒 evdev
用户态: read(/dev/input/eventN)
→ evdev_read() /* evdev */
→ 读出触摸事件8. 故障排除
8.1 触摸 IC 探测失败
i2cdetect -y 3 # 应见 0x14 或 0x38 等地址
dmesg | grep -i goodix # 驱动 probe 日志常见原因:I2C 地址错、RESET 没拉、I2C 上拉缺失。
8.2 触摸只支持单点
- 设备树缺失
touchscreen-size-x/y - 驱动不支持 MT(应选支持 type B 的型号)
8.3 坐标反向 / 旋转错误
设备树加 rotation 属性:
touchscreen@14 {
...
touchscreen-size-x = <1024>;
touchscreen-size-y = <600>;
touchscreen-swapped-x-y; /* X/Y 互换 */
/* touchscreen-inverted-x; /* X 反向 */
};或应用层旋转坐标系。
