RK3568 Android11双屏触摸实战:一份驱动搞定两个GT911,附完整DTS配置与避坑记录
RK3568 Android11双屏触摸实战单驱动多实例架构设计与DTS优化全解析在工业控制、智能零售等嵌入式场景中双屏交互系统正成为提升用户体验的重要硬件方案。当两块相同型号的GT911触摸屏需要协同工作时传统复制驱动重命名的解决方案不仅增加维护成本更可能引入难以排查的兼容性问题。本文将深入探讨基于RK3568平台的单驱动多实例实现方案通过设备树(DTS)的巧妙配置与驱动程序的架构优化实现一次编写多处使用的优雅设计。1. 硬件架构分析与设计挑战RK3568作为Rockchip旗下中高端处理器其灵活的I2C控制器配置为多触摸屏方案提供了硬件基础。典型双屏系统中两块GT911触摸屏往往通过不同I2C总线连接主屏通常连接I2C1作为主要人机交互界面副屏连接I2C3或其他可用总线用于扩展显示区域面对相同型号设备的驱动适配开发者常遇到三个核心难题I2C地址冲突相同型号触摸屏出厂默认地址相同(0x14)中断信号处理多个中断引脚需要正确映射和区分输入子系统识别Android需要明确区分主副屏输入源// 典型GT911硬件连接示意图 --------------- | RK3568 | | | | I2C1_SCL/PB1 |-----[GT911主屏] | I2C1_SDA/PB2 | SCL:PB1 | IRQ0/PB5 | SDA:PB2 | RST0/PB6 | INT:PB5 | | RST:PB6 | I2C3_SCL/PA1 |-----[GT911副屏] | I2C3_SDA/PA2 | SCL:PA1 | IRQ3/PA3 | SDA:PA2 | RST3/PA4 | INT:PA3 --------------- RST:PA42. 设备树(DTS)的精细化配置设备树作为硬件描述的核心需要精确表达双屏系统的硬件差异。相比简单的节点复制我们采用属性继承与差异化配置相结合的方式2.1 基础I2C节点定义i2c1 { status okay; clock-frequency 400000; gt911_main: gt91114 { compatible goodix,gt911; reg 0x14; interrupt-parent gpio0; interrupts RK_PB5 IRQ_TYPE_LEVEL_LOW; reset-gpios gpio0 RK_PB6 GPIO_ACTIVE_HIGH; touchscreen-size-x 1920; touchscreen-size-y 1080; goodix,config-version main_v1.0; }; }; i2c3 { status okay; clock-frequency 400000; gt911_sub: gt91114 { compatible goodix,gt911; reg 0x14; interrupt-parent gpio3; interrupts RK_PA3 IRQ_TYPE_LEVEL_LOW; reset-gpios gpio3 RK_PA4 GPIO_ACTIVE_HIGH; touchscreen-size-x 1920; touchscreen-size-y 1080; goodix,config-version sub_v1.0; }; };关键配置技巧相同reg地址处理虽然物理地址相同但通过不同I2C总线隔离中断差异化明确指定各自的中断父节点和引脚编号版本标识通过自定义属性区分主副屏固件配置2.2 引脚控制(pinctrl)优化pinctrl { gt911 { gt911_main_int: gt911-main-int { rockchip,pins 0 RK_PB5 RK_FUNC_GPIO pcfg_pull_up; }; gt911_main_rst: gt911-main-rst { rockchip,pins 0 RK_PB6 RK_FUNC_GPIO pcfg_pull_none; }; gt911_sub_int: gt911-sub-int { rockchip,pins 3 RK_PA3 RK_FUNC_GPIO pcfg_pull_up; }; gt911_sub_rst: gt911-sub-rst { rockchip,pins 3 RK_PA4 RK_FUNC_GPIO pcfg_pull_none; }; }; };注意中断引脚建议配置为上拉模式避免悬空状态导致误触发3. 驱动程序的架构重构传统复制驱动的方式存在维护困难的问题我们通过以下改造实现单驱动支持多实例3.1 设备上下文隔离struct gt911_device { struct i2c_client *client; struct input_dev *input; struct gpio_desc *reset_gpio; struct gpio_desc *irq_gpio; int screen_type; // MAIN_SCREEN or SUB_SCREEN char cfg_version[20]; struct work_struct work; spinlock_t irq_lock; // 其他实例特定数据... }; static int gt911_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct gt911_device *ts; struct device_node *np client-dev.of_node; ts devm_kzalloc(client-dev, sizeof(*ts), GFP_KERNEL); if (!ts) return -ENOMEM; // 从DTS读取实例特定参数 if (of_property_read_string(np, goodix,config-version, ts-cfg_version)) strlcpy(ts-cfg_version, default, sizeof(ts-cfg_version)); if (of_property_read_bool(np, is-main-screen)) ts-screen_type MAIN_SCREEN; else ts-screen_type SUB_SCREEN; // 初始化实例特定资源 ts-reset_gpio devm_gpiod_get(client-dev, reset, GPIOD_OUT_LOW); ts-irq_gpio devm_gpiod_get(client-dev, irq, GPIOD_IN); // 注册输入设备时根据screen_type设置不同名称 input_dev-name ts-screen_type MAIN_SCREEN ? Goodix-TS-Main : Goodix-TS-Sub; // 保存实例上下文 i2c_set_clientdata(client, ts); ... }3.2 中断处理的实例区分static irqreturn_t gt911_irq_handler(int irq, void *dev_id) { struct gt911_device *ts dev_id; unsigned long flags; spin_lock_irqsave(ts-irq_lock, flags); // 通过ts指针区分具体实例 if (ts-screen_type MAIN_SCREEN) { // 主屏特定处理 } else { // 副屏特定处理 } spin_unlock_irqrestore(ts-irq_lock, flags); return IRQ_HANDLED; }4. Android输入系统配置Android系统需要通过输入设备配置(.idc)文件正确识别主副屏输入源4.1 主屏输入配置/system/usr/idc/Goodix-TS-Main.idc:# 主屏配置 device.internal 1 touch.deviceType touchScreen touch.orientationAware 14.2 副屏输入配置/system/usr/idc/Goodix-TS-Sub.idc:# 副屏配置 device.internal 0 touch.deviceType touchScreen touch.orientationAware 1 touch.displayId 1 # 对应副屏的display ID4.3 构建系统集成在设备Makefile中确保正确部署配置文件PRODUCT_COPY_FILES \ device/rockchip/rk3568/Goodix-TS-Main.idc:system/usr/idc/Goodix-TS-Main.idc \ device/rockchip/rk3568/Goodix-TS-Sub.idc:system/usr/idc/Goodix-TS-Sub.idc5. 调试技巧与问题排查双屏触摸系统调试需要系统化的验证方法5.1 基础状态检查# 查看I2C设备是否成功注册 adb shell ls /sys/bus/i2c/devices/ # 检查中断统计信息 adb shell cat /proc/interrupts | grep Goodix # 查看输入设备列表 adb shell getevent -l5.2 常见问题解决方案问题现象可能原因解决方案副屏无响应I2C地址冲突检查DTS中reg属性是否正确主副屏触摸错乱idc配置错误确认device.internal属性区分触摸坐标偏移分辨率配置错误核对DTS中touchscreen-size-x/y频繁误触发中断引脚配置不当检查pinctrl上拉/下拉设置5.3 高级调试手段// 在驱动中添加调试打印 #define DEBUG_SWITCH 1 #define GTP_DEBUG_ON 1 if (DEBUG_SWITCH) { dev_dbg(client-dev, Probing %s screen, cfg: %s, ts-screen_type MAIN_SCREEN ? Main : Sub, ts-cfg_version); }通过内核日志过滤特定信息adb shell dmesg | grep -E GTP|Goodix在实际项目中验证这套方案时发现通过合理设计驱动架构不仅减少了50%的代码重复更显著提高了系统稳定性。特别是在固件升级场景下单驱动多实例的方案使得版本管理变得更加清晰可控。