|
@@ -554,6 +554,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|
|
intr_mask = DW_IC_INTR_DEFAULT_MASK;
|
|
|
|
|
|
for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
|
|
|
+ u32 flags = msgs[dev->msg_write_idx].flags;
|
|
|
+
|
|
|
/*
|
|
|
* if target address has changed, we need to
|
|
|
* reprogram the target address in the i2c
|
|
@@ -599,8 +601,15 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|
|
* detected from the registers so we set it always
|
|
|
* when writing/reading the last byte.
|
|
|
*/
|
|
|
+
|
|
|
+ /*
|
|
|
+ * i2c-core.c always sets the buffer length of
|
|
|
+ * I2C_FUNC_SMBUS_BLOCK_DATA to 1. The length will
|
|
|
+ * be adjusted when receiving the first byte.
|
|
|
+ * Thus we can't stop the transaction here.
|
|
|
+ */
|
|
|
if (dev->msg_write_idx == dev->msgs_num - 1 &&
|
|
|
- buf_len == 1)
|
|
|
+ buf_len == 1 && !(flags & I2C_M_RECV_LEN))
|
|
|
cmd |= BIT(9);
|
|
|
|
|
|
if (need_restart) {
|
|
@@ -625,7 +634,12 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|
|
dev->tx_buf = buf;
|
|
|
dev->tx_buf_len = buf_len;
|
|
|
|
|
|
- if (buf_len > 0) {
|
|
|
+ /*
|
|
|
+ * Because we don't know the buffer length in the
|
|
|
+ * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop
|
|
|
+ * the transaction here.
|
|
|
+ */
|
|
|
+ if (buf_len > 0 || flags & I2C_M_RECV_LEN) {
|
|
|
/* more bytes to be written */
|
|
|
dev->status |= STATUS_WRITE_IN_PROGRESS;
|
|
|
break;
|
|
@@ -646,6 +660,24 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
|
|
dw_writel(dev, intr_mask, DW_IC_INTR_MASK);
|
|
|
}
|
|
|
|
|
|
+static u8
|
|
|
+i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
|
|
|
+{
|
|
|
+ struct i2c_msg *msgs = dev->msgs;
|
|
|
+ u32 flags = msgs[dev->msg_read_idx].flags;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Adjust the buffer length and mask the flag
|
|
|
+ * after receiving the first byte.
|
|
|
+ */
|
|
|
+ len += (flags & I2C_CLIENT_PEC) ? 2 : 1;
|
|
|
+ dev->tx_buf_len = len - min_t(u8, len, dev->rx_outstanding);
|
|
|
+ msgs[dev->msg_read_idx].len = len;
|
|
|
+ msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN;
|
|
|
+
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
i2c_dw_read(struct dw_i2c_dev *dev)
|
|
|
{
|
|
@@ -670,7 +702,15 @@ i2c_dw_read(struct dw_i2c_dev *dev)
|
|
|
rx_valid = dw_readl(dev, DW_IC_RXFLR);
|
|
|
|
|
|
for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
|
|
|
- *buf++ = dw_readl(dev, DW_IC_DATA_CMD);
|
|
|
+ u32 flags = msgs[dev->msg_read_idx].flags;
|
|
|
+
|
|
|
+ *buf = dw_readl(dev, DW_IC_DATA_CMD);
|
|
|
+ /* Ensure length byte is a valid value */
|
|
|
+ if (flags & I2C_M_RECV_LEN &&
|
|
|
+ *buf <= I2C_SMBUS_BLOCK_MAX && *buf > 0) {
|
|
|
+ len = i2c_dw_recv_len(dev, *buf);
|
|
|
+ }
|
|
|
+ buf++;
|
|
|
dev->rx_outstanding--;
|
|
|
}
|
|
|
|