summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorCoben Han <[email protected]>2026-06-11 12:06:46 +0900
committerHeiko Schocher <[email protected]>2026-07-08 11:23:25 +0200
commitb8487e7e2d10f83bd356f42b0cc29134eafe97ca (patch)
tree8d0daeaca8e40541f01c797ae7b0ac58b6089375 /drivers
parenta8d40f922d10da8b25973dd786380190a8ecb89e (diff)
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 <[email protected]>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/designware_i2c.c44
1 files 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;
}