From b8487e7e2d10f83bd356f42b0cc29134eafe97ca Mon Sep 17 00:00:00 2001 From: Coben Han Date: Thu, 11 Jun 2026 12:06:46 +0900 Subject: i2c: designware: fix i2c probe error Probing i2c slave device just needs its device address. A certain type of chipsets such as RTC S35390A have no offset, which means address length should be 0. But the current designware_i2c_probe_chip function requires offset 0 and its length 1. This causes the designware-i2c to be initialized again and again. Furthermore, after booting into kernel, the designware-i2c kernel driver complains its controller timeout. This patch fixes this misbehaviour in such way that only device address is issued, no reinitialization needs when target device not detected, the designware-i2c kernel driver continues working. Signed-off-by: Coben Han --- drivers/i2c/designware_i2c.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index 8ad716f410e..8d290acefda 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -740,13 +740,47 @@ static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr, { struct dw_i2c *i2c = dev_get_priv(bus); struct i2c_regs *i2c_base = i2c->regs; - u32 tmp; - int ret; + u32 start_time, ic_status; + int ret = 0; - /* Try to read the first location of the chip */ - ret = __dw_i2c_read(i2c_base, chip_addr, 0, 1, (uchar *)&tmp, 1); + ret = i2c_wait_for_bb(i2c_base); if (ret) - __dw_i2c_init(i2c_base, 0, 0); + return ret; + + dw_i2c_enable(i2c_base, false); + writel(chip_addr, &i2c_base->ic_tar); + dw_i2c_enable(i2c_base, true); + + writel(IC_STOP, &i2c_base->ic_cmd_data); + + start_time = get_timer(0); + while (1) { + ic_status = readl(&i2c_base->ic_status); + + if ((ic_status & IC_STATUS_TFE) && !(ic_status & IC_STATUS_MA)) + break; + + if (readl(&i2c_base->ic_raw_intr_stat) & IC_TX_ABRT) { + readl(&i2c_base->ic_clr_tx_abrt); + ret = -EREMOTEIO; + break; + } + + if (get_timer(start_time) > I2C_BYTE_TO) { + ret = -ETIMEDOUT; + break; + } + } + + start_time = get_timer(0); + while (1) { + if ((readl(&i2c_base->ic_raw_intr_stat) & IC_STOP_DET)) { + readl(&i2c_base->ic_clr_stop_det); + break; + } else if (get_timer(start_time) > I2C_STOPDET_TO) { + break; + } + } return ret; } -- cgit v1.3.1