|
@@ -530,6 +530,33 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
|
|
|
return data_len;
|
|
|
}
|
|
|
|
|
|
+static bool qup_i2c_check_msg_len(struct i2c_msg *msg)
|
|
|
+{
|
|
|
+ return ((msg->flags & I2C_M_RD) && (msg->flags & I2C_M_RECV_LEN));
|
|
|
+}
|
|
|
+
|
|
|
+static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup,
|
|
|
+ struct i2c_msg *msg)
|
|
|
+{
|
|
|
+ int len = 0;
|
|
|
+
|
|
|
+ if (msg->len > 1) {
|
|
|
+ tags[len++] = QUP_TAG_V2_DATARD_STOP;
|
|
|
+ tags[len++] = qup_i2c_get_data_len(qup) - 1;
|
|
|
+ } else {
|
|
|
+ tags[len++] = QUP_TAG_V2_START;
|
|
|
+ tags[len++] = addr & 0xff;
|
|
|
+
|
|
|
+ if (msg->flags & I2C_M_TEN)
|
|
|
+ tags[len++] = addr >> 8;
|
|
|
+
|
|
|
+ tags[len++] = QUP_TAG_V2_DATARD;
|
|
|
+ /* Read 1 byte indicating the length of the SMBus message */
|
|
|
+ tags[len++] = 1;
|
|
|
+ }
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
|
|
|
struct i2c_msg *msg, int is_dma)
|
|
|
{
|
|
@@ -539,6 +566,10 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
|
|
|
|
|
|
int last = (qup->blk.pos == (qup->blk.count - 1)) && (qup->is_last);
|
|
|
|
|
|
+ /* Handle tags for SMBus block read */
|
|
|
+ if (qup_i2c_check_msg_len(msg))
|
|
|
+ return qup_i2c_set_tags_smb(addr, tags, qup, msg);
|
|
|
+
|
|
|
if (qup->blk.pos == 0) {
|
|
|
tags[len++] = QUP_TAG_V2_START;
|
|
|
tags[len++] = addr & 0xff;
|
|
@@ -1061,9 +1092,17 @@ static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup,
|
|
|
struct i2c_msg *msg)
|
|
|
{
|
|
|
u32 val;
|
|
|
- int idx, pos = 0, ret = 0, total;
|
|
|
+ int idx, pos = 0, ret = 0, total, msg_offset = 0;
|
|
|
|
|
|
+ /*
|
|
|
+ * If the message length is already read in
|
|
|
+ * the first byte of the buffer, account for
|
|
|
+ * that by setting the offset
|
|
|
+ */
|
|
|
+ if (qup_i2c_check_msg_len(msg) && (msg->len > 1))
|
|
|
+ msg_offset = 1;
|
|
|
total = qup_i2c_get_data_len(qup);
|
|
|
+ total -= msg_offset;
|
|
|
|
|
|
/* 2 extra bytes for read tags */
|
|
|
while (pos < (total + 2)) {
|
|
@@ -1083,8 +1122,8 @@ static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup,
|
|
|
|
|
|
if (pos >= (total + 2))
|
|
|
goto out;
|
|
|
-
|
|
|
- msg->buf[qup->pos++] = val & 0xff;
|
|
|
+ msg->buf[qup->pos + msg_offset] = val & 0xff;
|
|
|
+ qup->pos++;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1124,6 +1163,20 @@ static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
|
|
|
goto err;
|
|
|
|
|
|
qup->blk.pos++;
|
|
|
+
|
|
|
+ /* Handle SMBus block read length */
|
|
|
+ if (qup_i2c_check_msg_len(msg) && (msg->len == 1)) {
|
|
|
+ if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX) {
|
|
|
+ ret = -EPROTO;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ msg->len += msg->buf[0];
|
|
|
+ qup->pos = 0;
|
|
|
+ qup_i2c_set_blk_data(qup, msg);
|
|
|
+ /* set tag length for block read */
|
|
|
+ qup->blk.tx_tag_len = 2;
|
|
|
+ qup_i2c_set_read_mode_v2(qup, msg->buf[0]);
|
|
|
+ }
|
|
|
} while (qup->blk.pos < qup->blk.count);
|
|
|
|
|
|
err:
|
|
@@ -1209,6 +1262,11 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+ if (qup_i2c_check_msg_len(&msgs[idx])) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
if (msgs[idx].flags & I2C_M_RD)
|
|
|
ret = qup_i2c_read_one(qup, &msgs[idx]);
|
|
|
else
|