mirror of
https://github.com/torvalds/linux.git
synced 2024-12-06 11:01:43 +00:00
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;
|
||||
int irq;
|
||||
bool msg_read;
|
||||
bool len_recv;
|
||||
bool client_pec;
|
||||
u32 __iomem *base;
|
||||
u32 msg_buf_remaining;
|
||||
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)
|
||||
{
|
||||
u32 len, i;
|
||||
u8 *buf = priv->msg_buf;
|
||||
u8 rlen, *buf = priv->msg_buf;
|
||||
|
||||
len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
|
||||
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);
|
||||
for (i = 0; i < len; i++, buf++)
|
||||
*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)
|
||||
{
|
||||
unsigned long timeleft;
|
||||
u32 intr_mask, cmd, val;
|
||||
u32 intr_mask, cmd, val, len;
|
||||
|
||||
priv->msg_buf = msg->buf;
|
||||
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
|
||||
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 */
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* update msg->len with actual received length */
|
||||
if (msg->flags & I2C_M_RECV_LEN)
|
||||
msg->len = priv->msg_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user