Thread (6 messages) 6 messages, 2 authors, 2016-05-11

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, struct
qup_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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help