You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

为何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读取请求。

解决要点

  1. 添加复位后延时:在probe函数中释放复位GPIO后,根据ST1232 datasheet给出的复位就绪时间,添加足够延时(比如msleep(100),具体值参考芯片手册),等待芯片完成内部初始化后再执行I2C读取。
  2. 增加读取重试机制:在probe中对寄存器读取操作进行重试,比如最多重试3次,每次间隔一定延时,避免单次读取失败导致无法获取固件版本。
  3. 确认复位流程正确性:检查复位GPIO的电平控制逻辑是否符合芯片要求(比如低电平复位还是高电平复位),确保复位操作执行完整后再释放复位信号。

内容的提问来源于stack exchange,提问作者wangt13

火山引擎 最新活动