I2C HID驱动实战手记:从触摸屏INT引脚抖动到/dev/input/eventX稳定上报
去年在调试一款国产电容式车载中控屏时,我连续三天卡在一个看似简单的问题上:手指轻触屏幕,evtest /dev/input/event2有时能打出ABS_X,ABS_Y,有时却只输出零值;更诡异的是,用示波器抓INT引脚,发现中断信号明明很干净,但内核日志里反复出现i2c_hid i2c-GT911: failed to get report: -110(ETIMEDOUT)。直到翻到GT911数据手册第47页角落一行小字:“Report buffer is not atomic across I2C read — use0x814Eregister to lock buffer before reading”,才恍然大悟——原来不是驱动写错了,而是我们一直把I2C当成USB来用。
这件事让我意识到:I2C HID不是“把USB HID协议搬上I2C线”,而是一场需要重新校准底层直觉的系统工程。它要求你既懂SCL高电平时间如何被从机拉长,也得明白HID报告描述符里一个95 02(Report Count=2)写成95 03会导致整个多点触控解析错位两字节。下面这些内容,是我踩过坑、调通板子、读透内核源码后整理出的真实经验,没有教科书式的定义堆砌,只有工程师在现场会问的问题和能立刻用上的解法。
真实世界里的I2C:别再迷信“标准模式”了
很多资料说“I2C支持100kbps/400kbps/1Mbps”,但当你把GT911接到RK3399的I2C2总线上,用i2cdetect -y 2能扫到地址,i2cget -y 2 0x5d 0x00却总超时,第一反应往往是“是不是接线松了?”——其实更大概率是:你的I2C控制器时钟配置与从机电气特性不匹配。
以常见的Goodix GT911为例,其Datasheet明确标注:
- SCL低电平时间 ≥ 4.7μs
- SCL高电平时间 ≥ 4.0μs
- SDA建立时间 ≥ 250ns
- 总线最大电容 ≤ 400pF
而RK3399的I2C控制器在Linux 5.10下默认按“标准模式”配置:SCL周期10μs(即100kHz),但实际生成的高/低电平并不严格对称,且未考虑PCB走线带来的额外电容。结果就是:通信初期偶尔成功(靠容差),稍一加大负载(比如同时跑GUI),时序就飘移,i2c_smbus_read_word_data()直接返回-EREMOTEIO。
✅现场解决方案(非理论,可直接粘贴进dts):
&i2c2 { status = "okay"; clock-frequency = <400000>; // 强制设为400kHz(Fast Mode) i2c-scl-hold-time-ns = <500>; // 主动延长SCL低电平保持时间 i2c-scl-falling-time-ns = <150>; i2c-sda-falling-time-ns = <150>; gt911@5d { compatible = "goodix,gt911"