☰
GT9XX触摸屏驱动移植指南:从I2C设备树到Android坐标上报
2026/10/8 4:52:44 网站建设 项目流程

简介:这套汇顶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_FALLING,GT9XX 的中断线在触摸时拉低,所以中断触发方式必须是下降沿或低电平。如果写成高电平触发,你会看到系统里中断号反复触发,但 input 事件层却收不到坐标。另一个参数是IRQF_ONESHOT,它保证在 threaded irq 处理过程中中断不会重入,这对触摸这种需要连续读多字节寄存器的场景是必要的。

模块对应文件主要职责
主驱动gt9xx.c / gt9xx.hI2C 注册、中断处理、坐标上报、sysfs 节点
固件升级gt9xx_update.c通过 I2C 写固件、版本校验、升级流程
模组配置gt9xx_cfg.h分辨率、扫描周期、灵敏度、驱动配置表

这里要提醒一句:厂商给的代码包不是一解压就能编过的。很多包带的是旧内核的 API,比如早期的input_allocate_device+input_set_abs_params和现在没啥区别,但gpio_request在 4.14+ 内核里要换成devm_gpiod_get那套,probe 里的资源释放方式也不同。拿到代码先看头文件里的内核版本注释,再决定要不要动接口,能省不少编译报错。

2.2 规格书先读这几页:I2C地址、寄存器地图和上报格式

GT9XX 规格书不是让你从头翻到尾的。我一般拿到 PDF 先查四个部分:I2C 设备地址、寄存器地图、触摸上报数据格式、上电时序。这四个直接决定驱动能不能跑起来,谁先谁后有讲究。

GT9XX 的 I2C 地址比较特殊,同一颗芯片可能工作在 0x14 或 0x28(7 位地址),由复位期间的地址引脚电平决定。规格书的 I2C 章节会给出地址选择电路。调试时如果你用 i2cdetect 扫描只有 0x5d(8 位表示)或者根本扫不到,先量一下地址选择引脚有没有接对。我遇到过一次:原理图上绑定的是 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: gt9xx@5d { 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 位地址 0x28;interrupts里的触发标志要跟驱动里的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写成 0x28,@5d也写成 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.o,Kconfig 也要加对应的 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 还是 0x28(8 位表示是 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_chip+gt9xx_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 地址、中断标志这三项,再动代码。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询