ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GT9XX触摸屏驱动移植指南:从I2C设备树到Android坐标上报

GT9XX触摸屏驱动移植指南:从I2C设备树到Android坐标上报 简介这套汇顶GT9XX触摸屏驱动代码与配套资料面向Android平台驱动开发及触控方案移植工程师适用于GT9XX系列含GT9157的内核驱动适配、调试和固件维护。资源共7个文件约2.5MB以C/H源码为主覆盖驱动主程序、固件升级代码、设备头文件同时提供移植说明书PDF和APK调试工具便于结合汇顶GT9XX规格书理解寄存器配置、中断处理与电源管理流程。源码中probe注册、设备节点创建、I2C/SPI读写和电源管理接口均有迹可循适合在真实项目里对照排查。对于需要快速接入Android触摸屏的开发者可直接参考已有目录结构缩短从驱动注册到触摸事件上报的移植周期。该资源已有806人学习下载属于汇顶GT9XX开发中少见的成体系资料包适合对照HAL架构逐层分析提升触摸驱动稳定性与用户体验。1. GT9XX驱动资料包先认识这是一套能直接改的完整方案如果你手头有一块汇顶GT9XX系列的电容触摸屏比如GT911或GT9147想在Android设备上让它正常出点最耗时的不是画原理图而是找不到一份能直接改的驱动参照。这套GT9XX驱动代码与规格书资料的定位就是把驱动源码、GT9XX规格书、Android适配工程和寄存器配置说明打包在一起让你从拿到模组到系统里能滑动少走弯路。它适合三类人做Android BSP的驱动工程师、给工控屏做Linux移植的嵌入式工程师以及需要评估GT9XX方案的硬件工程师。下文按我拆这套资料时的顺序来讲先从代码包里哪些文件能改说起。2. 代码包结构解析从gt9xx.c到规格书先分清文件职责2.1 驱动文件构成哪些是核心哪些只是参考拿到驱动代码压缩包你先别急着导入编译。解压后第一件事是列目录把文件按“必改、可参考、不用管”分三类。常见的做法是代码包解压后看到如下文件gt9xx/ ├── gt9xx.c # 主驱动注册、中断、上报、sysfs节点 ├── gt9xx.h # 头文件寄存器地址、产品ID、I2C地址定义 ├── gt9xx_firmware.c # 固件数组与升级流程 ├── gt9xx_update.c # 固件升级入口常独立编译成工具 ├── gt9xx_cfg.h # 默认配置表分辨率/灵敏度/扫描周期 └── Makefile上面这个清单是我按多数发行版驱动整理出来的实际包内文件名可能有差异比如有的把更新逻辑并入 gt9xx.c有的单独给一个 goodix_gt9xx.c。你需要关注的是 gt9xx.c 和 gt9xx.h因为 I2C 驱动注册、中断处理、坐标上报都在主文件里gt9xx_cfg.h 对应的是模组的触控配置由 TP 厂提供通常用汇顶的调试工具生成。规格书 PDF 一般单独放在 docs 目录后面会在 2.2 里讲先读哪些部分。接着看 gt9xx.c 里的主线逻辑。最核心的几个函数是static int gt9xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { // 申请 GPIO复位触摸芯片并等待上电稳定 gt9xx_reset_chip(client); // 读取芯片 ID校验是否为 GT911、GT9147、GT9271 等型号 ret gt9xx_check_product_id(client); // 将 config 数据和固件写入芯片 ret gt9xx_init_panel(client); // 注册输入设备和中断 ret input_register_device(ts-input_dev); ret request_threaded_irq(client-irq, NULL, gt9xx_irq_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client-name, ts); return ret; }这段代码反映的是驱动工作的主线probe 里按“复位 → 读ID → 写配置 → 注册输入设备 → 注册中断”的顺序执行。参数上要注意的是中断标志IRQF_TRIGGER_FALLINGGT9XX 的中断线在触摸时拉低所以中断触发方式必须是下降沿或低电平。如果写成高电平触发你会看到系统里中断号反复触发但 input 事件层却收不到坐标。另一个参数是IRQF_ONESHOT它保证在 threaded irq 处理过程中中断不会重入这对触摸这种需要连续读多字节寄存器的场景是必要的。模块对应文件主要职责主驱动gt9xx.c / gt9xx.hI2C 注册、中断处理、坐标上报、sysfs 节点固件升级gt9xx_update.c通过 I2C 写固件、版本校验、升级流程模组配置gt9xx_cfg.h分辨率、扫描周期、灵敏度、驱动配置表这里要提醒一句厂商给的代码包不是一解压就能编过的。很多包带的是旧内核的 API比如早期的input_allocate_deviceinput_set_abs_params和现在没啥区别但gpio_request在 4.14 内核里要换成devm_gpiod_get那套probe 里的资源释放方式也不同。拿到代码先看头文件里的内核版本注释再决定要不要动接口能省不少编译报错。2.2 规格书先读这几页I2C地址、寄存器地图和上报格式GT9XX 规格书不是让你从头翻到尾的。我一般拿到 PDF 先查四个部分I2C 设备地址、寄存器地图、触摸上报数据格式、上电时序。这四个直接决定驱动能不能跑起来谁先谁后有讲究。GT9XX 的 I2C 地址比较特殊同一颗芯片可能工作在 0x14 或 0x287 位地址由复位期间的地址引脚电平决定。规格书的 I2C 章节会给出地址选择电路。调试时如果你用 i2cdetect 扫描只有 0x5d8 位表示或者根本扫不到先量一下地址选择引脚有没有接对。我遇到过一次原理图上绑定的是 ADDR 引脚接高代码里却用 0x28 去探测结果驱动 probe 一直返回 ENXIO。这种问题不是寄存器配错是地址定义错了查规格书第一节就能定位。寄存器地图主要是两个区域0x8040~0x8100 是芯片配置区驱动通过 I2C 写入 config 数据0x8140~0x8150 是触摸坐标缓冲区。GT9XX 的上报格式在规格书的“数据报格式”一节有明确说明驱动读回来的 buffer 结构大概是byte0: 状态位bit7 表示是否有点bit6 表示 buffer 是否更新 byte1: 第1个点的 X 坐标高字节 byte2: 第1个点的 X 坐标低字节 byte3: 第1个点的 Y 坐标高字节 byte4: 第1个点的 Y 坐标低字节这个格式看着简单但坑在字节序上。驱动里常见的解析写法是用get_unaligned_be16把两个字节拼成坐标如果你按小端序去读坐标会放大 256 倍或完全乱掉。规格书的字节序章节一定要看大多数 GT9XX 驱动都是大端序上报。上电时序在规格书的“Power On Sequence”段落。GT9XX 要求先给 VDD 供电然后拉高复位引脚等待至少 10ms再拉低复位等待芯片 ready这一步在量产时经常导致触摸初始化失败。后面第 4 章我会给出一个我常用的时序参数表可以直接照抄。3. 移植到Android内核设备树、I2C地址与中断配置三板斧3.1 设备树节点先让系统能枚举到设备Android 内核尤其是 4.9 之后的内核几乎都用设备树描述硬件。GT9XX 的 I2C 从设备节点要挂在对应 I2C 总线下常见写法i2c3 { status okay; goodix_gt9xx: gt9xx5d { compatible goodix,gt911; reg 0x5d; interrupt-parent pio; interrupts 13 IRQ_TYPE_EDGE_FALLING; goodix,reset-gpio pio 14 GPIO_ACTIVE_LOW; goodix,irq-gpio pio 13 GPIO_ACTIVE_LOW; touchscreen-size-x 1024; touchscreen-size-y 768; touchscreen-max-pressure 255; goodix,cfg-data /bits/ 8 0x44 0x20 0x03 0x00 0x04 0x0C 0x08 ... ; }; };参数说明reg 0x5d用的是 8 位 I2C 地址对应 7 位地址 0x28interrupts里的触发标志要跟驱动里的IRQF_TRIGGER_FALLING保持一致如果用IRQ_TYPE_LEVEL_LOW驱动端也要改成低电平触发否则中断标志两处打架会出现很诡异的问题。goodix,reset-gpio和goodix,irq-gpio是驱动自定义的 GPIO 属性gpio 编号要跟具体 SoC 的 pinctrl 手册对照不能照抄其他平台这是移植踩坑第一高发区。touchscreen-size-x/y是坐标分辨率这个值必须跟模组规格书一致分辨率不对会出现滑到底但光标走一半的现象。配置数据goodix,cfg-data也可以用数组直接写在 dts 里但更常见的是用汇顶的配置工具生成头文件再编译进内核。如果你拿到的代码包里有gt9xx_cfg.h优先改它因为 dts 里的数组和头文件里的配置在驱动加载时会二次校验两边不一致时以最后一次写进去的为准。这里有一个容易被忽略的坑设备树节点名字里的5d只是节点名不影响匹配真正生效的是reg和compatible。有些人把reg写成 0x285d也写成 0x28看起来一致但 8 位地址和 7 位地址混着用i2cdetect 扫描出来的 0x5d 对不上驱动里的 0x28导致 probe 失败。建议统一按“7 位地址写 reg / 8 位地址写注释”的方式管理避免后面看代码的人被绕晕。3.2 驱动注册i2c_driver 的匹配过程设备树写好后驱动这边靠of_match_table或i2c_device_id匹配。GT9XX 驱动里常见的匹配方式static const struct of_device_id gt9xx_of_match[] { { .compatible goodix,gt911, .data (void *)GT911 }, { .compatible goodix,gt9147, .data (void *)GT9147 }, { .compatible goodix,gt9271, .data (void *)GT9271 }, { } }; static const struct i2c_device_id gt9xx_ts_id[] { { goodix,gt911, GT911 }, { goodix,gt9147, GT9147 }, { goodix,gt9271, GT9271 }, { } }; MODULE_DEVICE_TABLE(i2c, gt9xx_ts_id); static struct i2c_driver gt9xx_i2c_driver { .driver { .name gt9xx, .of_match_table gt9xx_of_match, }, .id_table gt9xx_ts_id, .probe gt9xx_probe, };这里有一个特别容易被忽略的点i2c_device_id的名字和 dts 的compatible必须对齐。很多移植者只改了 dts没改驱动里的 id_table导致 probe 函数进不去。系统日志里看到的是i2c i2c-3: of_i2c_notify: fail to attach或者/sys/bus/i2c/devices/3-005d/目录不出现。排查顺序是先ls /sys/bus/i2c/devices/看设备有没有被枚举再cat /sys/bus/i2c/devices/3-005d/name看匹配的名字两者对得上才轮到 probe 函数里的 GPIO 初始化。另外Android 内核里 I2C 驱动通常要注册到drivers/input/touchscreen/目录Makefile 要加一行obj-$(CONFIG_TOUCHSCREEN_GT9XX) gt9xx.oKconfig 也要加对应的 config 项。这步漏了的话即使代码编译过了驱动也不会进内核。我习惯的做法是先在 dts 里把 status 改为 disabled等驱动编译进内核后再打开避免一起加入时很难定位是设备树问题还是驱动问题。4. 固件下载与坐标上报初始化时序、报点格式与灵敏度调参4.1 上电时序与固件初始化先复位置中原厂配置GT9XX 上电初始化有个硬性要求复位引脚要拉低再拉高完成一次掉电复位之后等待芯片 ready。常用流程static int gt9xx_reset_chip(struct i2c_client *client) { gpiod_set_value(reset_gpio, 0); // 复位脚拉低 msleep(20); // 至少 20ms规格书要求 10ms 以上 gpiod_set_value(reset_gpio, 1); // 拉高退出复位 msleep(50); // 等待内部固件启动和 I2C 就绪 return gt9xx_i2c_read(client, 0x8140, buf, 2); // 读状态寄存器试探 }这些时序参数是从规格书“上电时序”章节搬来的但实际量产我会把每个延时放到 1.5 倍以上因为模组上电容充电和 LDO 上电有个斜坡严格按最小时序在低温环境容易翻车。0x8140是状态寄存器读一次如果返回非零值说明芯片已经可以响应 I2C。读不到就用示波器抓一下 SDA/SCL确认硬件上有应答信号。固件下载不是每次启动都做。量产时如果模组出厂已烧录固件驱动里应该跳过固件写入只下发 config。常见做法是先读产品 ID再读固件版本跟代码包里的固件版本比对不一致才升级ret gt9xx_read_version(client, ver); if (ver ! GT9XX_FIRMWARE_VERSION) { gt9xx_update_firmware(client, gt9xx_firmware, sizeof(gt9xx_firmware)); }这里容易踩的坑是每次启动都强制写固件会把 chip 的 flash 寿命耗掉而且升级过程中如果复位脚被系统 suspend 打断芯片可能变砖。第 5 章会具体讲。4.2 上报格式解析坐标怎么读、状态位怎么判断驱动在中断里读坐标核心代码如下static irqreturn_t gt9xx_irq_handler(int irq, void *data) { u8 buf[11]; int x, y, id; // 读 0x8140 开始的 11 字节包含状态和第一个触摸点的坐标 gt9xx_i2c_read(client, 0x8140, buf, 11); if (!(buf[0] 0x80)) // bit7 为 0 表示无触点 goto out; if (buf[0] 0x80 (buf[1] 0x80)) // buffer 更新标志 goto out; id (buf[3] 0xf0) 4; // 触点 ID 在高四位 x ((buf[1] 0x0f) 8) | buf[2]; y ((buf[3] 0x0f) 8) | buf[4]; input_report_abs(ts-input_dev, ABS_MT_SLOT, id); input_report_abs(ts-input_dev, ABS_MT_POSITION_X, x); input_report_abs(ts-input_dev, ABS_MT_POSITION_Y, y); input_report_abs(ts-input_dev, ABS_MT_TRACKING_ID, id); input_mt_sync(ts-input_dev); input_sync(ts-input_dev); return IRQ_HANDLED; }注意坐标的高位被放在了buf[1]的低四位里所以读取时要先做掩码再移位。这段写法是 GT9XX 驱动里最常见的大端模式也是容易写错的地方。有人直接把buf[1]8 | buf[2]当坐标结果高位带上了状态位坐标误差在几百以内表现就是触摸点漂移。多触点模式下驱动要循环读每一触点的 6 字节数据。以 5 触点为例buf 总长是 1 5*6 31 字节。通过buf[0]的低 4 位可以判断当前上报了几个点。灵敏度调参方面主要改两个寄存器扫描周期0x8040 附近的 config 里和灵敏度阈值。扫描周期越长越省电但触点响应变慢一般设置在 10ms 左右灵敏度阈值太大容易断线太小会乱报。代码包里gt9xx_cfg.h中有个数组厂商注释里通常会标出 offset配合规格书的 config 表可以逐个字段改。这里没有通用公式只能根据实际触摸体验反复试建议用 GTI 调试工具在线调整确认后再回写进配置数组。我一般会先调大阈值看乱报是否消失再逐步减小到临界值留 20% 余量给温度和湿度变化。5. GT9XX驱动避坑与常见问题排查五个真实翻车现场5.1 现象i2cdetect 扫不到设备probe 返回 ENXIO原因I2C 设备地址不对或复位脚没拉高导致芯片处于复位状态。GT9XX 的上电时序里复位脚保持低电平超过 10ms 会让芯片掉电地址选择引脚状态也就失效了。解决先用万用表量 VDD 是否有电再量复位脚是否被拉高然后用i2cdetect -y 3扫描 3 号总线确认地址是 0x14 还是 0x288 位表示是 0x28/0x50 之类。如果扫描地址跟 dts 里不一致改 dts 的reg和驱动的i2c_device_id不改原理图。5.2 现象触摸有反应但坐标反向或整体偏移原因坐标旋转方向、分辨率与实际模组不一致。Android 里如果屏幕是竖屏而触摸 sensor 是横屏安装需要进行坐标旋转映射驱动里通常有swap/x invert/y invert宏定义。解决在驱动里找到坐标映射部分逐个试四个方向的组合或者在 dts 里加touchscreen-inverted-x、touchscreen-inverted-y属性。这个没有捷径只能硬件怎么摆就怎么映射试的时候用一根手指画圆看轨迹落在哪个象限一次就能判断。5.3 现象中断风暴系统卡死CPU 占用 100%原因中断触发方式配置成低电平而驱动在读坐标时没有及时清中断导致中断不断重入。或者 GPIO 上拉电阻没接悬空电平抖动。解决把中断触发方式改为下降沿IRQF_TRIGGER_FALLING确保 GPIO 内部上拉开启。如果还是风暴在中断 handler 第一步读回状态寄存器等 chip 释放中断线再继续处理。5.4 现象休眠唤醒后触摸没反应必须重启原因suspend 时系统把 GPIO 和 I2C 时钟关了resume 后没有重新写 config芯片还停留在低功耗模式或者 reset 脚状态被 pinctrl 恢复错误。解决在驱动的 resume 回调里完整执行一次gt9xx_reset_chipgt9xx_init_panel重新下发 config。不要只开时钟不写寄存器这块没有后悔药可吃。5.5 现象固件升级中途失败芯片 I2C 无响应原因升级过程耗时较长期间被高优先级中断打断或 watchdog 超时复位。GT9XX 的固件升级需要连续 I2C 写操作被打断后 flash 里的镜像不完整。解决升级函数里关掉触摸中断把线程优先级拉高必要时关掉 watchdog。升级失败后先重新上电再尝试用旧版本固件回刷厂商工具通常是最后的救命手段。6. 用getevent验证并固化走查流程驱动写完先做这三件事6.1 getevent 验证报点链路adb shell getevent -r /dev/input/event2用-r可以看到带绝对坐标的事件。如果驱动正确注册了input_dev触摸屏幕时终端会滚出ABS_MT_POSITION_X和ABS_MT_POSITION_Y事件。看不到事件时先用cat /proc/bus/input/devices确认 event 节点对应的设备名再确认 Handlers 里有没有event2避免看错节点。6.2 固件版本与配置回读确认驱动真正生效cat /sys/bus/i2c/devices/3-005d/gt9xx_firmware_version不同驱动这个 sysfs 节点名可能不一样没有节点就从 dmesg 里找gt9xx firmware version的打印。确认版本号跟你写入的固件一致再检查 dmesg 里有没有gt9xx init panel success之类的日志有才说明 config 下发成功。验证完成后我会习惯性做一次完整走查先看 dts 的 GPIO 编号再跑 i2cdetect 确认地址然后加载驱动看 dmesg最后 getevent 滑动测试。这套流程走完触摸驱动基本就稳了。两年前我调一个 GT9271 的模组折腾了两天没反应最后发现是 dts 里的复位 GPIO 在 pinctrl 里被复用成了其他功能。从那以后我每次拿到新触控模组都强制先验证 GPIO 复用状态、I2C 地址、中断标志这三项再动代码。希望帮到你。本文还有配套的精品资源点击获取
返回列表