i2c: xlp9xx: Handle I2C_M_RECV_LEN in msg->flags
The driver needs to handle the flag I2C_M_RECV_LEN during receive to support SMBus emulation. Update receive logic to handle the case where the length is received as the first byte of a transaction. Also update the code to handle I2C_CLIENT_PEC, which is set when the client sends a packet error checking code byte. Signed-off-by: Jayachandran C <jnair@caviumnetworks.com> Signed-off-by: Kamlakant Patel <kamlakant.patel@cavium.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
parent
c347b8fc22
commit
5515ae1121
@ -82,6 +82,8 @@ struct xlp9xx_i2c_dev {
|
|||||||
struct completion msg_complete;
|
struct completion msg_complete;
|
||||||
int irq;
|
int irq;
|
||||||
bool msg_read;
|
bool msg_read;
|
||||||
|
bool len_recv;
|
||||||
|
bool client_pec;
|
||||||
u32 __iomem *base;
|
u32 __iomem *base;
|
||||||
u32 msg_buf_remaining;
|
u32 msg_buf_remaining;
|
||||||
u32 msg_len;
|
u32 msg_len;
|
||||||
@ -143,10 +145,25 @@ static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv)
|
|||||||
static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
|
static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
|
||||||
{
|
{
|
||||||
u32 len, i;
|
u32 len, i;
|
||||||
u8 *buf = priv->msg_buf;
|
u8 rlen, *buf = priv->msg_buf;
|
||||||
|
|
||||||
len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
|
len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
|
||||||
XLP9XX_I2C_FIFO_WCNT_MASK;
|
XLP9XX_I2C_FIFO_WCNT_MASK;
|
||||||
|
if (!len)
|
||||||
|
return;
|
||||||
|
if (priv->len_recv) {
|
||||||
|
/* read length byte */
|
||||||
|
rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
|
||||||
|
*buf++ = rlen;
|
||||||
|
len--;
|
||||||
|
if (priv->client_pec)
|
||||||
|
++rlen;
|
||||||
|
/* update remaining bytes and message length */
|
||||||
|
priv->msg_buf_remaining = rlen;
|
||||||
|
priv->msg_len = rlen + 1;
|
||||||
|
priv->len_recv = false;
|
||||||
|
}
|
||||||
|
|
||||||
len = min(priv->msg_buf_remaining, len);
|
len = min(priv->msg_buf_remaining, len);
|
||||||
for (i = 0; i < len; i++, buf++)
|
for (i = 0; i < len; i++, buf++)
|
||||||
*buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
|
*buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
|
||||||
@ -230,7 +247,7 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
|
|||||||
int last_msg)
|
int last_msg)
|
||||||
{
|
{
|
||||||
unsigned long timeleft;
|
unsigned long timeleft;
|
||||||
u32 intr_mask, cmd, val;
|
u32 intr_mask, cmd, val, len;
|
||||||
|
|
||||||
priv->msg_buf = msg->buf;
|
priv->msg_buf = msg->buf;
|
||||||
priv->msg_buf_remaining = priv->msg_len = msg->len;
|
priv->msg_buf_remaining = priv->msg_len = msg->len;
|
||||||
@ -263,9 +280,13 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
|
|||||||
else
|
else
|
||||||
val &= ~XLP9XX_I2C_CTRL_ADDMODE;
|
val &= ~XLP9XX_I2C_CTRL_ADDMODE;
|
||||||
|
|
||||||
|
priv->len_recv = msg->flags & I2C_M_RECV_LEN;
|
||||||
|
len = priv->len_recv ? XLP9XX_I2C_FIFO_SIZE : msg->len;
|
||||||
|
priv->client_pec = msg->flags & I2C_CLIENT_PEC;
|
||||||
|
|
||||||
/* set data length to be transferred */
|
/* set data length to be transferred */
|
||||||
val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
|
val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
|
||||||
(msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
|
(len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
|
||||||
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
|
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
|
||||||
|
|
||||||
/* fill fifo during tx */
|
/* fill fifo during tx */
|
||||||
@ -312,6 +333,9 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
|
|||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* update msg->len with actual received length */
|
||||||
|
if (msg->flags & I2C_M_RECV_LEN)
|
||||||
|
msg->len = priv->msg_len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user