i2c: omap24xx_i2c: Use new function __omap24_i2c_xfer_msg()

Remove __omap24_i2c_read/write() usage from omap_i2c_xfer() in favour of
the more flexible __omap24_i2c_xfer_msg().
Consequently, these are also no longer needed when DM_I2C is enabled.

New function __omap24_i2c_xfer_msg() will take care of individual read
OR write transfers with a target device. It goes through below sequence:
- Program the provided Target Chip address (OMAP_I2C_SA_REG)
- Program the provided Data len (OMAP_I2C_CNT_REG)
- Program the provided Control register flags (OMAP_I2C_CON_REG)
- Read from or Write to the provided Data buffer (OMAP_I2C_DATA_REG)

For a detailed programming guide, refer to the TRM[0] (12.1.3.4 I2C
Programming Guide).

This patch by itself should be a transparent change. However this is
needed for implementing a proper Repeated Start (Sr) functionality for
i2c_msgs.

Previous implementation for omap_i2c_xfer called __omap24_i2c_read/write
functions, with hardcoded addr=0 and alen=0 for each i2c_msg. Each of
these calls would program the registers always with a Stop bit set, not
allowing for a repeated start between i2c_msgs in the same xfer().

[0]: https://www.ti.com/lit/zip/spruj28 (TRM)

Signed-off-by: Aniket Limaye <a-limaye@ti.com>
Reviewed-by: Heiko Schocher <hs@denx.de>
This commit is contained in:
Aniket Limaye
2025-04-22 15:49:50 +05:30
committed by Heiko Schocher
parent 640f9f33a1
commit 520b57ee47

View File

@@ -535,6 +535,12 @@ 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
@@ -828,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) {
@@ -963,28 +964,130 @@ 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);
debug("%s: %d messages\n", __func__, 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);
}
if (ret) {
debug("i2c_write: error sending\n");
/* Wait until bus not busy */
if (wait_for_bb(priv->regs, priv->ip_rev, priv->waitdelay))
return -EREMOTEIO;
/* Set Controller mode with Start and Stop bit */
i2c_con_reg = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
/* 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;
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) {
printf("%s: errored out at msg %d: %d\n", __func__, i, ret);
return ret;
}
}