diff options
| author | Tom Rini <trini@konsulko.com> | 2025-04-22 09:36:13 -0600 | 
|---|---|---|
| committer | Tom Rini <trini@konsulko.com> | 2025-04-22 09:36:13 -0600 | 
| commit | 15951d3f21645ce949e6ac89e917cf4bce824621 (patch) | |
| tree | 03986f2465584ead5a19367153729547e6e1997a /drivers | |
| parent | 8ab3cd0229a0ebf204cb5fd94f8a09e62825ffb4 (diff) | |
| parent | 28d78a53c72c4ac3d5033a0c21396cadf7438bee (diff) | |
Merge tag 'i2cfixes-for-2025.07-rc1' of https://source.denx.de/u-boot/custodians/u-boot-i2c
i2c updates for v2025.07-rc1
- omap24xx_i2c: Enable Repeated Start functionality
  add Repeated Start functionality for the DM_I2C xfer
  API (omap_i2c_xfer()
  from Aniket Limaye
- mediatek i2c driver
  fixes from Martin
  - add end marker for struct udevice_id mtk_i2c_ids
  - remove duplicate entry in mt_i2c_regs_v1
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/i2c/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/i2c/mtk_i2c.c | 3 | ||||
| -rw-r--r-- | drivers/i2c/omap24xx_i2c.c | 165 | 
3 files changed, 145 insertions, 32 deletions
| diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 46e76385961..146bc621c7e 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -510,6 +510,15 @@ config SYS_I2C_OMAP24XX  	help  	  Add support for the OMAP2+ I2C driver. +config SYS_I2C_OMAP24XX_REPEATED_START +	bool "Enable I2C repeated start" +	depends on SYS_I2C_OMAP24XX +	default y if ARCH_K3 +	help +	  Enable support for repeated start. Updates driver defaults to not +	  send a Stop condition and issue Repeated Start (Sr) for subsequent +	  i2c msgs. +  config SYS_I2C_RCAR_I2C  	bool "Renesas R-Car I2C driver"  	depends on (RCAR_GEN2 || RCAR_64) && DM_I2C diff --git a/drivers/i2c/mtk_i2c.c b/drivers/i2c/mtk_i2c.c index 3450177741a..55381dbeced 100644 --- a/drivers/i2c/mtk_i2c.c +++ b/drivers/i2c/mtk_i2c.c @@ -143,7 +143,6 @@ static const uint mt_i2c_regs_v1[] = {  	[REG_RSV_DEBUG] = 0x44,  	[REG_HS] = 0x48,  	[REG_SOFTRESET] = 0x50, -	[REG_SOFTRESET] = 0x50,  	[REG_DCM_EN] = 0x54,  	[REG_DEBUGSTAT] = 0x64,  	[REG_DEBUGCTRL] = 0x68, @@ -879,7 +878,7 @@ static const struct udevice_id mtk_i2c_ids[] = {  	}, {  		.compatible = "mediatek,mt8518-i2c",  		.data = (ulong)&mt8518_soc_data, -	} +	}, {}  };  U_BOOT_DRIVER(mtk_i2c) = { diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index ebe472e20cd..a6361d3d17d 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -535,12 +535,16 @@ pr_exit:  	return res;  } +#if !CONFIG_IS_ENABLED(DM_I2C) +/* + * The legacy I2C functions. These need to get removed once + * all users of this driver are converted to DM. + */ +  /*   * i2c_read: Function now uses a single I2C read transaction with bulk transfer   *           of the requested number of bytes (note that the 'i2c md' command - *           limits this to 16 bytes anyway). If CONFIG_I2C_REPEATED_START is - *           defined in the board config header, this transaction shall be with - *           Repeated Start (Sr) between the address and data phases; otherwise + *           limits this to 16 bytes anyway).   *           Stop-Start (P-S) shall be used (some I2C chips do require a P-S).   *           The address (reg offset) may be 0, 1 or 2 bytes long.   *           Function now reads correctly from chips that return more than one @@ -608,16 +612,10 @@ static int __omap24_i2c_read(void __iomem *i2c_base, int ip_rev, int waitdelay,  	if (alen) {  		/* Must write reg offset first */ -#ifdef CONFIG_I2C_REPEATED_START -		/* No stop bit, use Repeated Start (Sr) */ -		omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST | -				   I2C_CON_STT | I2C_CON_TRX, OMAP_I2C_CON_REG); -#else  		/* Stop - Start (P-S) */  		omap_i2c_write_reg(i2c_base, ip_rev, I2C_CON_EN | I2C_CON_MST |  				   I2C_CON_STT | I2C_CON_STP | I2C_CON_TRX,  				   OMAP_I2C_CON_REG); -#endif  		/* Send register offset */  		while (1) {  			status = wait_for_event(i2c_base, ip_rev, waitdelay); @@ -836,11 +834,6 @@ wr_exit:  	return i2c_error;  } -#if !CONFIG_IS_ENABLED(DM_I2C) -/* - * The legacy I2C functions. These need to get removed once - * all users of this driver are converted to DM. - */  static void __iomem *omap24_get_base(struct i2c_adapter *adap)  {  	switch (adap->hwadapnr) { @@ -971,28 +964,140 @@ U_BOOT_I2C_ADAP_COMPLETE(omap24_4, omap24_i2c_init, omap24_i2c_probe,  #else /* CONFIG_DM_I2C */ +static int __omap24_i2c_xfer_msg(void __iomem *i2c_base, int ip_rev, int waitdelay, +				 uchar chip, uchar *buffer, int len, u16 i2c_con_reg) +{ +	int i; +	u16 status; +	int i2c_error = 0; +	int timeout = I2C_TIMEOUT; + +	if (len < 0) { +		printf("%s: data len < 0\n", __func__); +		return -EINVAL; +	} + +	if (!buffer) { +		printf("%s: NULL pointer passed\n", __func__); +		return -EINVAL; +	} + +	if (!(i2c_con_reg & I2C_CON_EN)) { +		printf("%s: I2C_CON_EN not set\n", __func__); +		return -EINVAL; +	} + +	/* Set slave address */ +	omap_i2c_write_reg(i2c_base, ip_rev, chip, OMAP_I2C_SA_REG); +	/* Read/Write len bytes data */ +	omap_i2c_write_reg(i2c_base, ip_rev, len, OMAP_I2C_CNT_REG); +	/* Configure the I2C_CON register */ +	omap_i2c_write_reg(i2c_base, ip_rev, i2c_con_reg, OMAP_I2C_CON_REG); + +	/* read/write data bytewise */ +	for (i = 0; i < len; i++) { +		status = wait_for_event(i2c_base, ip_rev, waitdelay); +		/* Ignore I2C_STAT_RRDY in transmitter mode */ +		if (i2c_con_reg & I2C_CON_TRX) +			status &= ~I2C_STAT_RRDY; +		else +			status &= ~I2C_STAT_XRDY; + +		/* Try to identify bus that is not padconf'd for I2C */ +		if (status == I2C_STAT_XRDY) { +			i2c_error = -EREMOTEIO; +			printf("%s: pads on bus probably not configured (status=0x%x)\n", +			       __func__, status); +			goto xfer_exit; +		} +		if (status == 0 || (status & I2C_STAT_NACK)) { +			i2c_error = -EREMOTEIO; +			printf("%s: error waiting for ACK (status=0x%x)\n", +			       __func__, status); +			goto xfer_exit; +		} +		if (status & I2C_STAT_XRDY) { +			/* Transmit data */ +			omap_i2c_write_reg(i2c_base, ip_rev, +					   buffer[i], OMAP_I2C_DATA_REG); +			omap_i2c_write_reg(i2c_base, ip_rev, +					   I2C_STAT_XRDY, OMAP_I2C_STAT_REG); +		} +		if (status & I2C_STAT_RRDY) { +			/* Receive data */ +			*buffer++ = omap_i2c_read_reg(i2c_base, ip_rev, +							OMAP_I2C_DATA_REG); +			omap_i2c_write_reg(i2c_base, ip_rev, +					   I2C_STAT_RRDY, OMAP_I2C_STAT_REG); +		} +	} + +	/* +	 * poll ARDY bit for making sure that last byte really has been +	 * transferred on the bus. +	 */ +	do { +		status = wait_for_event(i2c_base, ip_rev, waitdelay); +	} while (!(status & I2C_STAT_ARDY) && timeout--); +	if (timeout <= 0) { +		printf("%s: timed out on last byte!\n", __func__); +		i2c_error = -EREMOTEIO; +		goto xfer_exit; +	} else { +		omap_i2c_write_reg(i2c_base, ip_rev, I2C_STAT_ARDY, OMAP_I2C_STAT_REG); +	} + +	/* If Stop bit set, flush FIFO. */ +	if (i2c_con_reg & I2C_CON_STP) +		goto xfer_exit; + +	return 0; + +xfer_exit: +	flush_fifo(i2c_base, ip_rev); +	omap_i2c_write_reg(i2c_base, ip_rev, 0xFFFF, OMAP_I2C_STAT_REG); +	return i2c_error; +} +  static int omap_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)  {  	struct omap_i2c *priv = dev_get_priv(bus);  	int ret; +	u16 i2c_con_reg = 0; -	debug("i2c_xfer: %d messages\n", nmsgs); -	for (; nmsgs > 0; nmsgs--, msg++) { -		debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); -		if (msg->flags & I2C_M_RD) { -			ret = __omap24_i2c_read(priv->regs, priv->ip_rev, -						priv->waitdelay, -						msg->addr, 0, 0, msg->buf, -						msg->len); -		} else { -			ret = __omap24_i2c_write(priv->regs, priv->ip_rev, -						 priv->waitdelay, -						 msg->addr, 0, 0, msg->buf, -						 msg->len); -		} +	debug("%s: %d messages\n", __func__, nmsgs); +	for (int i = 0; i < nmsgs; i++, msg++) { +		/* +		 * If previous msg sent a Stop or if this is the first msg +		 * Wait until bus not busy +		 */ +		if ((i2c_con_reg & I2C_CON_STP) || (i == 0)) +			if (wait_for_bb(priv->regs, priv->ip_rev, priv->waitdelay)) +				return -EREMOTEIO; + +		/* Set Controller mode with Start bit */ +		i2c_con_reg = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT; +		/* Set Transmitter/Receiver mode if it is a write/read msg */ +		if (msg->flags & I2C_M_RD) +			i2c_con_reg &= ~I2C_CON_TRX; +		else +			i2c_con_reg |= I2C_CON_TRX; +		/* Send Stop condition (P) by default */ +		if (!IS_ENABLED(CONFIG_SYS_I2C_OMAP24XX_REPEATED_START)) +			i2c_con_reg |= I2C_CON_STP; +		/* Send Stop if explicitly requested or if this is the last msg */ +		if ((msg->flags & I2C_M_STOP) || (i == nmsgs - 1)) +			i2c_con_reg |= I2C_CON_STP; + +		debug("%s: chip=0x%x, len=0x%x, i2c_con_reg=0x%x\n", +		      __func__, msg->addr, msg->len, i2c_con_reg); + +		ret = __omap24_i2c_xfer_msg(priv->regs, priv->ip_rev, priv->waitdelay, +					    msg->addr, msg->buf, msg->len, +					    i2c_con_reg);  		if (ret) { -			debug("i2c_write: error sending\n"); -			return -EREMOTEIO; +			printf("%s: errored out at msg %d: %d\n", __func__, i, ret); +			return ret;  		}  	} | 
