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-lim...@ti.com>
---

v2:
- Use proper error codes in __omap24_i2c_xfer_msg()
- Use proper error prints to indicate omap24xx i2c driver
- Link to v1: 
https://lore.kernel.org/u-boot/20250304220546.866602-2-a-lim...@ti.com/

---
 drivers/i2c/omap24xx_i2c.c | 143 +++++++++++++++++++++++++++++++------
 1 file changed, 123 insertions(+), 20 deletions(-)

diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 1fd5f5cc224..7c5d786e8e9 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -535,6 +535,107 @@ pr_exit:
        return res;
 }
 
+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;
+}
+
+#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 +929,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) {
@@ -967,24 +1063,31 @@ 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;
                }
        }
 
-- 
2.48.1

Reply via email to