为何ST1232在probe函数中读取I2C寄存器失败,中断处理中成功?
ST1232触控IC I2C寄存器读取问题分析
问题背景
基于kernel-5.10.188版本的嵌入式Linux系统开发,搭载的触摸屏使用ST1232触控IC,尝试在驱动probe函数中读取0x0地址寄存器获取固件版本时失败(错误码-145);将读取操作移至中断处理函数后,成功读取到固件版本0x6。
代码修改对比
--- a/kernel/kernel-5.10/drivers/input/touchscreen/st1232.c +++ b/kernel/kernel-5.10/drivers/input/touchscreen/st1232.c @@ -45,9 +45,36 @@ struct st1232_ts_data { struct gpio_desc *reset_gpio; const struct st_chip_info *chip_info; int read_buf_len; + u32 fw_rev; u8 *read_buf; }; +static int st1232_ts_read_ver(struct st1232_ts_data *ts) +{ + struct i2c_client *client = ts->client; + u8 start_reg = 0x0; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .len = sizeof(start_reg), + .buf = &start_reg, + }, + { + .addr = client->addr, + .flags = I2C_M_RD | I2C_M_DMA_SAFE, + .len = 1, + .buf = (u8 *)&ts->fw_rev, + } + }; + int ret; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) + return ret < 0 ? ret : -EIO; + + return 0; +} + static int st1232_ts_read_data(struct st1232_ts_data *ts) { struct i2c_client *client = ts->client; @@ -122,11 +149,19 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id) struct st1232_ts_data *ts = dev_id; int count; int error; +static int xx = 0; error = st1232_ts_read_data(ts); if (error) goto out; +if (xx < 5) { + error = st1232_ts_read_ver(ts); + memcpy(&ts->input_dev->id.version, &ts->fw_rev, 2); + printk("xxxxxxxxxxxxx fw_rev: 0x%x, error: %d\n", ts->fw_rev, error); +} +xx++; + count = st1232_ts_parse_and_report(ts); if (!count) { if (ts->low_latency_req.dev) { @@ -276,6 +311,9 @@ static int st1232_ts_probe(struct i2c_client *client, i2c_set_clientdata(client, ts); + error = st1232_ts_read_ver(ts); + memcpy(&ts->input_dev->id.version, &ts->fw_rev, 2); + printk("xxxxxxxxxxxxx fw_rev: 0x%x, error: %d\n", ts->fw_rev, error); return 0; }
内核日志
# dmesg | grep xxxx [ 1.150101] xxxxxxxxxxxxx fw_rev: 0x0, error: -145 [ 1.195555] xxxxxxxxxxxxx fw_rev: 0x6, error: 0
原因分析与解决要点
核心原因
错误码-145对应Linux内核中的EREMOTEIO,表示I2C从设备未响应主机传输请求,本质是probe阶段ST1232尚未完成初始化就绪:
- probe函数执行时机较早,此时触控IC可能刚完成复位操作,内部固件仍在启动初始化,尚未进入可响应I2C命令的状态;
- 中断触发时,系统已启动一段时间,ST1232完成全部初始化流程,能够正常响应I2C读取请求。
解决要点
- 添加复位后延时:在probe函数中释放复位GPIO后,根据ST1232 datasheet给出的复位就绪时间,添加足够延时(比如
msleep(100),具体值参考芯片手册),等待芯片完成内部初始化后再执行I2C读取。 - 增加读取重试机制:在probe中对寄存器读取操作进行重试,比如最多重试3次,每次间隔一定延时,避免单次读取失败导致无法获取固件版本。
- 确认复位流程正确性:检查复位GPIO的电平控制逻辑是否符合芯片要求(比如低电平复位还是高电平复位),确保复位操作执行完整后再释放复位信号。
内容的提问来源于stack exchange,提问作者wangt13




