@@ -62,6 +62,7 @@ enum xiic_endian {
* @singlemaster: Indicates bus is single master
* @dynamic: Mode of controller
* @prev_msg_tx: Previous message is Tx
+ * @smbus_block_read: Flag to handle block read
*/
struct xiic_i2c {
struct device *dev;
@@ -80,6 +81,7 @@ struct xiic_i2c {
bool singlemaster;
bool dynamic;
bool prev_msg_tx;
+ bool smbus_block_read;
};
#define XIIC_MSB_OFFSET 0
@@ -339,6 +341,54 @@ static void xiic_deinit(struct xiic_i2c *i2c)
xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & ~XIIC_CR_ENABLE_DEVICE_MASK);
}
+static void xiic_smbus_block_read_setup(struct xiic_i2c *i2c)
+{
+ u8 rxmsg_len;
+ u8 rfd_set = 0;
+
+ /*
+ * Clear the I2C_M_RECV_LEN flag to avoid setting
+ * message length again
+ */
+ i2c->rx_msg->flags &= ~I2C_M_RECV_LEN;
+
+ /* Set smbus_block_read flag to identify in isr */
+ i2c->smbus_block_read = true;
+
+ /* Read byte from rx fifo and set message length */
+ rxmsg_len = xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+
+ i2c->rx_msg->buf[i2c->rx_pos++] = rxmsg_len;
+
+ /* Check if received length is valid */
+ if (rxmsg_len <= I2C_SMBUS_BLOCK_MAX) {
+ /* Set Receive fifo depth */
+ if (rxmsg_len > IIC_RX_FIFO_DEPTH) {
+ rfd_set = IIC_RX_FIFO_DEPTH - 1;
+ i2c->rx_msg->len = rxmsg_len + 1;
+ } else if ((rxmsg_len == 1) ||
+ (rxmsg_len == 0)) {
+ /*
+ * Minimum of 3 bytes required to exit cleanly. 1 byte
+ * already received, Second byte is being received. Have
+ * to set NACK in read_rx before receiving the last byte
+ */
+ i2c->rx_msg->len = 3;
+ } else {
+ rfd_set = rxmsg_len - 2;
+ i2c->rx_msg->len = rxmsg_len + 1;
+ }
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rfd_set);
+
+ return;
+ }
+
+ /* Invalid message length, trigger STATE_ERROR with tx_msg_len in ISR */
+ i2c->tx_msg->len = 3;
+ i2c->smbus_block_read = false;
+ dev_err(i2c->adap.dev.parent, "smbus_block_read Invalid msg length\n");
+}
+
static void xiic_read_rx(struct xiic_i2c *i2c)
{
u8 bytes_in_fifo, cr = 0, bytes_to_read = 0;
@@ -361,6 +411,12 @@ static void xiic_read_rx(struct xiic_i2c *i2c)
if (!i2c->dynamic) {
bytes_rem = xiic_rx_space(i2c) - bytes_in_fifo;
+ /* Set msg length if smbus_block_read */
+ if (i2c->rx_msg->flags & I2C_M_RECV_LEN) {
+ xiic_smbus_block_read_setup(i2c);
+ return;
+ }
+
if (bytes_rem > IIC_RX_FIFO_DEPTH) {
bytes_to_read = bytes_in_fifo;
} else if (bytes_rem > 1) {
@@ -638,6 +694,12 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
/* The bus is not busy, disable BusNotBusy interrupt */
xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK);
+ if (i2c->tx_msg && i2c->smbus_block_read) {
+ i2c->smbus_block_read = false;
+ /* Set requested message len=1 to indicate STATE_DONE */
+ i2c->tx_msg->len = 1;
+ }
+
if (!i2c->tx_msg)
goto out;
@@ -777,8 +839,12 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
rfd_set = IIC_RX_FIFO_DEPTH - 1;
} else if ((rx_watermark == 1) || (rx_watermark == 0)) {
rfd_set = rx_watermark - 1;
- /* Handle single byte transfer separately */
- cr |= XIIC_CR_NO_ACK_MASK;
+
+ /* Set No_ACK, except for smbus_block_read */
+ if (!(i2c->rx_msg->flags & I2C_M_RECV_LEN)) {
+ /* Handle single byte transfer separately */
+ cr |= XIIC_CR_NO_ACK_MASK;
+ }
} else {
rfd_set = rx_watermark - 2;
}
@@ -970,10 +1036,14 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
/* Initialize prev message type */
i2c->prev_msg_tx = false;
- /* Enter standard mode only when read length is > 255 bytes */
+ /*
+ * Enter standard mode only when read length is > 255 bytes or
+ * for smbus_block_read transaction
+ */
for (count = 0; count < i2c->nmsgs; count++) {
- if ((i2c->tx_msg[count].flags & I2C_M_RD) &&
- i2c->tx_msg[count].len > MAX_READ_LENGTH_DYNAMIC) {
+ if (((i2c->tx_msg[count].flags & I2C_M_RD) &&
+ i2c->tx_msg[count].len > MAX_READ_LENGTH_DYNAMIC) ||
+ (i2c->tx_msg[count].flags & I2C_M_RECV_LEN)) {
i2c->dynamic = false;
break;
}
@@ -1007,7 +1077,7 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
static u32 xiic_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
}
static const struct i2c_algorithm xiic_algorithm = {