RE: [PATCH 2/2] i2c: qup: support SMBus block read
From: Sricharan <hidden>
Date: 2016-05-10 07:13:31
Also in:
linux-arm-kernel, linux-arm-msm, lkml
+additional lists
quoted hunk ↗ jump to hunk
I2C QUP driver relies on SMBus emulation support from the framework. To handle SMBus block reads, the driver should check I2C_M_RECV_LEN flag and should read the first byte received as the message length. The driver configures the QUP hardware to read one byte. Once the message length is known from this byte, the QUP hardware is configured to read the rest. Signed-off-by: Naveen Kaje <redacted> --- drivers/i2c/busses/i2c-qup.c | 95 ++++++++++++++++++++++++++++++------- ------- 1 file changed, 66 insertions(+), 29 deletions(-)diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index
quoted hunk ↗ jump to hunk
ef31b26..2658b67 100644--- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c@@ -526,38 +526,49 @@ static int qup_i2c_set_tags(u8 *tags, structqup_i2c_dev *qup, int last = (qup->blk.pos == (qup->blk.count - 1)) && (qup->is_last); - if (qup->blk.pos == 0) { - tags[len++] = QUP_TAG_V2_START; - tags[len++] = addr & 0xff; + /* Handle SMBus block data read */ + if ((msg->flags & I2C_M_RD) && (msg->flags & I2C_M_RECV_LEN) && + (msg->len > 1)) { + tags[len++] = QUP_TAG_V2_DATARD_STOP; + data_len = qup_i2c_get_data_len(qup); + tags[len++] = data_len - 1; + } else { + if (qup->blk.pos == 0) { + tags[len++] = QUP_TAG_V2_START; + tags[len++] = addr & 0xff; - if (msg->flags & I2C_M_TEN) - tags[len++] = addr >> 8; - } + if (msg->flags & I2C_M_TEN) + tags[len++] = addr >> 8; + } - /* Send _STOP commands for the last block */ - if (last) { - if (msg->flags & I2C_M_RD) - tags[len++] = QUP_TAG_V2_DATARD_STOP; - else - tags[len++] = QUP_TAG_V2_DATAWR_STOP; - } else { - if (msg->flags & I2C_M_RD) + /* Send _STOP commands for the last block */ + if ((msg->flags & I2C_M_RD) + && (msg->flags & I2C_M_RECV_LEN)) { tags[len++] = QUP_TAG_V2_DATARD; - else - tags[len++] = QUP_TAG_V2_DATAWR; - } + } else if (last) { + if (msg->flags & I2C_M_RD) + tags[len++] = QUP_TAG_V2_DATARD_STOP; + else + tags[len++] = QUP_TAG_V2_DATAWR_STOP; + } else { + if (msg->flags & I2C_M_RD) + tags[len++] = QUP_TAG_V2_DATARD; + else + tags[len++] = QUP_TAG_V2_DATAWR; + } - data_len = qup_i2c_get_data_len(qup); + data_len = qup_i2c_get_data_len(qup); - /* 0 implies 256 bytes */ - if (data_len == QUP_READ_LIMIT) - tags[len++] = 0; - else - tags[len++] = data_len; + /* 0 implies 256 bytes */ + if (data_len == QUP_READ_LIMIT) + tags[len++] = 0; + else + tags[len++] = data_len; - if ((msg->flags & I2C_M_RD) && last && is_dma) { - tags[len++] = QUP_BAM_INPUT_EOT; - tags[len++] = QUP_BAM_FLUSH_STOP; + if ((msg->flags & I2C_M_RD) && last && is_dma) { + tags[len++] = QUP_BAM_INPUT_EOT; + tags[len++] = QUP_BAM_FLUSH_STOP; + } }
Will it look simpler if we add a qup_i2c_set_tags_smb instead and add an Comment ? Here it is not clear how this is different from a normal read. <snip..>
+
+ /* Handle SMBus block read length */
+ if ((msg->flags & I2C_M_RECV_LEN) && (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_read_mode_v2(qup, msg->len);
+ qup_i2c_issue_xfer_v2(qup, msg);
+ ret = qup_i2c_wait_for_complete(qup, msg);
+ if (ret)
+ goto err;
+ qup_i2c_set_blk_data(qup, msg);
+ }
} while (qup->blk.pos < qup->blk.count);
When v2 mode is not supported this should return an error,
in qup_i2c_xfer for msg->flags & I2C_M_RECV_LEN
Regards,
Sricharan