forked from OERV-BSP/u-boot
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:
committed by
Heiko Schocher
parent
640f9f33a1
commit
520b57ee47
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user