All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V4 0/7]  i2c: qup: Add support for v2 tags and bam dma
@ 2015-07-09  3:25 ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov-NEYub+7Iv8PQT0dZR+AlfA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, agross-sgV2jX0FEOL9JmXXK+q4OQ,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: sricharan-sgV2jX0FEOL9JmXXK+q4OQ

QUP from version 2.1.1 onwards, supports a new format of i2c command tags.
Tag codes instructs the controller to perform a operation like read/write.
This new tagging version supports and is required for adding bam dma
capabilities. V2 tags supports transfer of more than 256 bytes in a single
i2c transaction. Also adding bam dma support facilitates transferring each
i2c_msg in i2c_msgs without a 'stop' bit in between which is required for some
of the clients.

Tested this series on apq8074 dragon board eeprom client on i2c bus1

[V4] Added a patch to factor out some common code.
     Removed support for freq > 400KHZ as per comments.
     Addressed comments from Ivan T. Ivanov to keep the code for
     V2 support in a separate path. 
     Changed the authorship of V2 tags support patch.

[V3] Added support to coalesce each i2c_msg in i2c_msgs for fifo and
     block mode in Patch 2. Also addressed further code comments.

     http://comments.gmane.org/gmane.linux.drivers.i2c/22497

[V2] Addressed comments from Ivan T. Ivanov, Andy Gross [v1] Initial Version

Sricharan R (7):
  i2c: qup: Change qup_wait_writeready function to use for all timeouts
  qup: i2c: factor out common code for reuse
  i2c: qup: Add V2 tags support
  i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
  i2c: qup: Add bam dma capabilities
  dts: msm8974: Add blsp2_bam dma node
  dts: msm8974: Add dma channels for blsp2_i2c1 node

 arch/arm/boot/dts/qcom-msm8974.dtsi |  14 +-
 drivers/i2c/busses/i2c-qup.c        | 943 +++++++++++++++++++++++++++++++++---
 2 files changed, 880 insertions(+), 77 deletions(-)

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 0/7]  i2c: qup: Add support for v2 tags and bam dma
@ 2015-07-09  3:25 ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov, devicetree, linux-arm-msm, galak, linux-kernel,
	linux-i2c, agross, dmaengine, linux-arm-kernel
  Cc: sricharan

QUP from version 2.1.1 onwards, supports a new format of i2c command tags.
Tag codes instructs the controller to perform a operation like read/write.
This new tagging version supports and is required for adding bam dma
capabilities. V2 tags supports transfer of more than 256 bytes in a single
i2c transaction. Also adding bam dma support facilitates transferring each
i2c_msg in i2c_msgs without a 'stop' bit in between which is required for some
of the clients.

Tested this series on apq8074 dragon board eeprom client on i2c bus1

[V4] Added a patch to factor out some common code.
     Removed support for freq > 400KHZ as per comments.
     Addressed comments from Ivan T. Ivanov to keep the code for
     V2 support in a separate path. 
     Changed the authorship of V2 tags support patch.

[V3] Added support to coalesce each i2c_msg in i2c_msgs for fifo and
     block mode in Patch 2. Also addressed further code comments.

     http://comments.gmane.org/gmane.linux.drivers.i2c/22497

[V2] Addressed comments from Ivan T. Ivanov, Andy Gross [v1] Initial Version

Sricharan R (7):
  i2c: qup: Change qup_wait_writeready function to use for all timeouts
  qup: i2c: factor out common code for reuse
  i2c: qup: Add V2 tags support
  i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
  i2c: qup: Add bam dma capabilities
  dts: msm8974: Add blsp2_bam dma node
  dts: msm8974: Add dma channels for blsp2_i2c1 node

 arch/arm/boot/dts/qcom-msm8974.dtsi |  14 +-
 drivers/i2c/busses/i2c-qup.c        | 943 +++++++++++++++++++++++++++++++++---
 2 files changed, 880 insertions(+), 77 deletions(-)

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 0/7]  i2c: qup: Add support for v2 tags and bam dma
@ 2015-07-09  3:25 ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: linux-arm-kernel

QUP from version 2.1.1 onwards, supports a new format of i2c command tags.
Tag codes instructs the controller to perform a operation like read/write.
This new tagging version supports and is required for adding bam dma
capabilities. V2 tags supports transfer of more than 256 bytes in a single
i2c transaction. Also adding bam dma support facilitates transferring each
i2c_msg in i2c_msgs without a 'stop' bit in between which is required for some
of the clients.

Tested this series on apq8074 dragon board eeprom client on i2c bus1

[V4] Added a patch to factor out some common code.
     Removed support for freq > 400KHZ as per comments.
     Addressed comments from Ivan T. Ivanov to keep the code for
     V2 support in a separate path. 
     Changed the authorship of V2 tags support patch.

[V3] Added support to coalesce each i2c_msg in i2c_msgs for fifo and
     block mode in Patch 2. Also addressed further code comments.

     http://comments.gmane.org/gmane.linux.drivers.i2c/22497

[V2] Addressed comments from Ivan T. Ivanov, Andy Gross [v1] Initial Version

Sricharan R (7):
  i2c: qup: Change qup_wait_writeready function to use for all timeouts
  qup: i2c: factor out common code for reuse
  i2c: qup: Add V2 tags support
  i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
  i2c: qup: Add bam dma capabilities
  dts: msm8974: Add blsp2_bam dma node
  dts: msm8974: Add dma channels for blsp2_i2c1 node

 arch/arm/boot/dts/qcom-msm8974.dtsi |  14 +-
 drivers/i2c/busses/i2c-qup.c        | 943 +++++++++++++++++++++++++++++++++---
 2 files changed, 880 insertions(+), 77 deletions(-)

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 1/7] i2c: qup: Change qup_wait_writeready function to use for all timeouts
  2015-07-09  3:25 ` Sricharan R
  (?)
@ 2015-07-09  3:25     ` Sricharan R
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov-NEYub+7Iv8PQT0dZR+AlfA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, agross-sgV2jX0FEOL9JmXXK+q4OQ,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: sricharan-sgV2jX0FEOL9JmXXK+q4OQ

qup_wait_writeready waits only on a output fifo empty event.
Change the same function to accept the event and data length
to wait as parameters. This way the same function can be used for
timeouts in otherplaces as well.

Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
 drivers/i2c/busses/i2c-qup.c | 67 +++++++++++++++++++++++++++++++-------------
 1 file changed, 48 insertions(+), 19 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index fdcbdab..81ed120 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -98,6 +98,9 @@
 #define QUP_STATUS_ERROR_FLAGS		0x7c
 
 #define QUP_READ_LIMIT			256
+#define SET_BIT				0x1
+#define RESET_BIT			0x0
+#define ONE_BYTE			0x1
 
 struct qup_i2c_dev {
 	struct device		*dev;
@@ -221,26 +224,42 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state)
 	return 0;
 }
 
-static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup)
+/**
+ * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path
+ * @qup: The qup_i2c_dev device
+ * @op: The bit/event to wait on
+ * @val: value of the bit to wait on, 0 or 1
+ * @len: The length the bytes to be transferred
+ */
+static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
+			      int len)
 {
 	unsigned long timeout;
 	u32 opflags;
 	u32 status;
+	u32 shift = __ffs(op);
 
-	timeout = jiffies + HZ;
+	len *= qup->one_byte_t;
+	/* timeout after a wait of twice the max time */
+	timeout = jiffies + len * 4;
 
 	for (;;) {
 		opflags = readl(qup->base + QUP_OPERATIONAL);
 		status = readl(qup->base + QUP_I2C_STATUS);
 
-		if (!(opflags & QUP_OUT_NOT_EMPTY) &&
-		    !(status & I2C_STATUS_BUS_ACTIVE))
-			return 0;
+		if (((opflags & op) >> shift) == val) {
+			if (op == QUP_OUT_NOT_EMPTY) {
+				if (!(status & I2C_STATUS_BUS_ACTIVE))
+					return 0;
+			} else {
+				return 0;
+			}
+		}
 
 		if (time_after(jiffies, timeout))
 			return -ETIMEDOUT;
 
-		usleep_range(qup->one_byte_t, qup->one_byte_t * 2);
+		usleep_range(len, len * 2);
 	}
 }
 
@@ -261,13 +280,13 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	}
 }
 
-static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	u32 addr = msg->addr << 1;
 	u32 qup_tag;
-	u32 opflags;
 	int idx;
 	u32 val;
+	int ret = 0;
 
 	if (qup->pos == 0) {
 		val = QUP_TAG_START | addr;
@@ -279,9 +298,10 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	while (qup->pos < msg->len) {
 		/* Check that there's space in the FIFO for our pair */
-		opflags = readl(qup->base + QUP_OPERATIONAL);
-		if (opflags & QUP_OUT_FULL)
-			break;
+		ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL, RESET_BIT,
+					 4 * ONE_BYTE);
+		if (ret)
+			return ret;
 
 		if (qup->pos == msg->len - 1)
 			qup_tag = QUP_TAG_STOP;
@@ -300,6 +320,8 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		qup->pos++;
 		idx++;
 	}
+
+	return ret;
 }
 
 static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
@@ -325,7 +347,9 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		if (ret)
 			goto err;
 
-		qup_i2c_issue_write(qup, msg);
+		ret = qup_i2c_issue_write(qup, msg);
+		if (ret)
+			goto err;
 
 		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 		if (ret)
@@ -347,7 +371,7 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	} while (qup->pos < msg->len);
 
 	/* Wait for the outstanding data in the fifo to drain */
-	ret = qup_i2c_wait_writeready(qup);
+	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
 
 err:
 	disable_irq(qup->irq);
@@ -384,18 +408,19 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 }
 
 
-static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
-	u32 opflags;
 	u32 val = 0;
 	int idx;
+	int ret = 0;
 
 	for (idx = 0; qup->pos < msg->len; idx++) {
 		if ((idx & 1) == 0) {
 			/* Check that FIFO have data */
-			opflags = readl(qup->base + QUP_OPERATIONAL);
-			if (!(opflags & QUP_IN_NOT_EMPTY))
-				break;
+			ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
+						 SET_BIT, 4 * ONE_BYTE);
+			if (ret)
+				return ret;
 
 			/* Reading 2 words at time */
 			val = readl(qup->base + QUP_IN_FIFO_BASE);
@@ -405,6 +430,8 @@ static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 			msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
 		}
 	}
+
+	return ret;
 }
 
 static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
@@ -450,7 +477,9 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 			goto err;
 		}
 
-		qup_i2c_read_fifo(qup, msg);
+		ret = qup_i2c_read_fifo(qup, msg);
+		if (ret)
+			goto err;
 	} while (qup->pos < msg->len);
 
 err:
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 1/7] i2c: qup: Change qup_wait_writeready function to use for all timeouts
@ 2015-07-09  3:25     ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov, devicetree, linux-arm-msm, galak, linux-kernel,
	linux-i2c, agross, dmaengine, linux-arm-kernel
  Cc: sricharan

qup_wait_writeready waits only on a output fifo empty event.
Change the same function to accept the event and data length
to wait as parameters. This way the same function can be used for
timeouts in otherplaces as well.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 67 +++++++++++++++++++++++++++++++-------------
 1 file changed, 48 insertions(+), 19 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index fdcbdab..81ed120 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -98,6 +98,9 @@
 #define QUP_STATUS_ERROR_FLAGS		0x7c
 
 #define QUP_READ_LIMIT			256
+#define SET_BIT				0x1
+#define RESET_BIT			0x0
+#define ONE_BYTE			0x1
 
 struct qup_i2c_dev {
 	struct device		*dev;
@@ -221,26 +224,42 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state)
 	return 0;
 }
 
-static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup)
+/**
+ * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path
+ * @qup: The qup_i2c_dev device
+ * @op: The bit/event to wait on
+ * @val: value of the bit to wait on, 0 or 1
+ * @len: The length the bytes to be transferred
+ */
+static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
+			      int len)
 {
 	unsigned long timeout;
 	u32 opflags;
 	u32 status;
+	u32 shift = __ffs(op);
 
-	timeout = jiffies + HZ;
+	len *= qup->one_byte_t;
+	/* timeout after a wait of twice the max time */
+	timeout = jiffies + len * 4;
 
 	for (;;) {
 		opflags = readl(qup->base + QUP_OPERATIONAL);
 		status = readl(qup->base + QUP_I2C_STATUS);
 
-		if (!(opflags & QUP_OUT_NOT_EMPTY) &&
-		    !(status & I2C_STATUS_BUS_ACTIVE))
-			return 0;
+		if (((opflags & op) >> shift) == val) {
+			if (op == QUP_OUT_NOT_EMPTY) {
+				if (!(status & I2C_STATUS_BUS_ACTIVE))
+					return 0;
+			} else {
+				return 0;
+			}
+		}
 
 		if (time_after(jiffies, timeout))
 			return -ETIMEDOUT;
 
-		usleep_range(qup->one_byte_t, qup->one_byte_t * 2);
+		usleep_range(len, len * 2);
 	}
 }
 
@@ -261,13 +280,13 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	}
 }
 
-static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	u32 addr = msg->addr << 1;
 	u32 qup_tag;
-	u32 opflags;
 	int idx;
 	u32 val;
+	int ret = 0;
 
 	if (qup->pos == 0) {
 		val = QUP_TAG_START | addr;
@@ -279,9 +298,10 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	while (qup->pos < msg->len) {
 		/* Check that there's space in the FIFO for our pair */
-		opflags = readl(qup->base + QUP_OPERATIONAL);
-		if (opflags & QUP_OUT_FULL)
-			break;
+		ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL, RESET_BIT,
+					 4 * ONE_BYTE);
+		if (ret)
+			return ret;
 
 		if (qup->pos == msg->len - 1)
 			qup_tag = QUP_TAG_STOP;
@@ -300,6 +320,8 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		qup->pos++;
 		idx++;
 	}
+
+	return ret;
 }
 
 static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
@@ -325,7 +347,9 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		if (ret)
 			goto err;
 
-		qup_i2c_issue_write(qup, msg);
+		ret = qup_i2c_issue_write(qup, msg);
+		if (ret)
+			goto err;
 
 		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 		if (ret)
@@ -347,7 +371,7 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	} while (qup->pos < msg->len);
 
 	/* Wait for the outstanding data in the fifo to drain */
-	ret = qup_i2c_wait_writeready(qup);
+	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
 
 err:
 	disable_irq(qup->irq);
@@ -384,18 +408,19 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 }
 
 
-static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
-	u32 opflags;
 	u32 val = 0;
 	int idx;
+	int ret = 0;
 
 	for (idx = 0; qup->pos < msg->len; idx++) {
 		if ((idx & 1) == 0) {
 			/* Check that FIFO have data */
-			opflags = readl(qup->base + QUP_OPERATIONAL);
-			if (!(opflags & QUP_IN_NOT_EMPTY))
-				break;
+			ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
+						 SET_BIT, 4 * ONE_BYTE);
+			if (ret)
+				return ret;
 
 			/* Reading 2 words at time */
 			val = readl(qup->base + QUP_IN_FIFO_BASE);
@@ -405,6 +430,8 @@ static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 			msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
 		}
 	}
+
+	return ret;
 }
 
 static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
@@ -450,7 +477,9 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 			goto err;
 		}
 
-		qup_i2c_read_fifo(qup, msg);
+		ret = qup_i2c_read_fifo(qup, msg);
+		if (ret)
+			goto err;
 	} while (qup->pos < msg->len);
 
 err:
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 1/7] i2c: qup: Change qup_wait_writeready function to use for all timeouts
@ 2015-07-09  3:25     ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: linux-arm-kernel

qup_wait_writeready waits only on a output fifo empty event.
Change the same function to accept the event and data length
to wait as parameters. This way the same function can be used for
timeouts in otherplaces as well.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 67 +++++++++++++++++++++++++++++++-------------
 1 file changed, 48 insertions(+), 19 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index fdcbdab..81ed120 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -98,6 +98,9 @@
 #define QUP_STATUS_ERROR_FLAGS		0x7c
 
 #define QUP_READ_LIMIT			256
+#define SET_BIT				0x1
+#define RESET_BIT			0x0
+#define ONE_BYTE			0x1
 
 struct qup_i2c_dev {
 	struct device		*dev;
@@ -221,26 +224,42 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state)
 	return 0;
 }
 
-static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup)
+/**
+ * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path
+ * @qup: The qup_i2c_dev device
+ * @op: The bit/event to wait on
+ * @val: value of the bit to wait on, 0 or 1
+ * @len: The length the bytes to be transferred
+ */
+static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
+			      int len)
 {
 	unsigned long timeout;
 	u32 opflags;
 	u32 status;
+	u32 shift = __ffs(op);
 
-	timeout = jiffies + HZ;
+	len *= qup->one_byte_t;
+	/* timeout after a wait of twice the max time */
+	timeout = jiffies + len * 4;
 
 	for (;;) {
 		opflags = readl(qup->base + QUP_OPERATIONAL);
 		status = readl(qup->base + QUP_I2C_STATUS);
 
-		if (!(opflags & QUP_OUT_NOT_EMPTY) &&
-		    !(status & I2C_STATUS_BUS_ACTIVE))
-			return 0;
+		if (((opflags & op) >> shift) == val) {
+			if (op == QUP_OUT_NOT_EMPTY) {
+				if (!(status & I2C_STATUS_BUS_ACTIVE))
+					return 0;
+			} else {
+				return 0;
+			}
+		}
 
 		if (time_after(jiffies, timeout))
 			return -ETIMEDOUT;
 
-		usleep_range(qup->one_byte_t, qup->one_byte_t * 2);
+		usleep_range(len, len * 2);
 	}
 }
 
@@ -261,13 +280,13 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	}
 }
 
-static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	u32 addr = msg->addr << 1;
 	u32 qup_tag;
-	u32 opflags;
 	int idx;
 	u32 val;
+	int ret = 0;
 
 	if (qup->pos == 0) {
 		val = QUP_TAG_START | addr;
@@ -279,9 +298,10 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	while (qup->pos < msg->len) {
 		/* Check that there's space in the FIFO for our pair */
-		opflags = readl(qup->base + QUP_OPERATIONAL);
-		if (opflags & QUP_OUT_FULL)
-			break;
+		ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL, RESET_BIT,
+					 4 * ONE_BYTE);
+		if (ret)
+			return ret;
 
 		if (qup->pos == msg->len - 1)
 			qup_tag = QUP_TAG_STOP;
@@ -300,6 +320,8 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		qup->pos++;
 		idx++;
 	}
+
+	return ret;
 }
 
 static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
@@ -325,7 +347,9 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		if (ret)
 			goto err;
 
-		qup_i2c_issue_write(qup, msg);
+		ret = qup_i2c_issue_write(qup, msg);
+		if (ret)
+			goto err;
 
 		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 		if (ret)
@@ -347,7 +371,7 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	} while (qup->pos < msg->len);
 
 	/* Wait for the outstanding data in the fifo to drain */
-	ret = qup_i2c_wait_writeready(qup);
+	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
 
 err:
 	disable_irq(qup->irq);
@@ -384,18 +408,19 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 }
 
 
-static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
-	u32 opflags;
 	u32 val = 0;
 	int idx;
+	int ret = 0;
 
 	for (idx = 0; qup->pos < msg->len; idx++) {
 		if ((idx & 1) == 0) {
 			/* Check that FIFO have data */
-			opflags = readl(qup->base + QUP_OPERATIONAL);
-			if (!(opflags & QUP_IN_NOT_EMPTY))
-				break;
+			ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
+						 SET_BIT, 4 * ONE_BYTE);
+			if (ret)
+				return ret;
 
 			/* Reading 2 words at time */
 			val = readl(qup->base + QUP_IN_FIFO_BASE);
@@ -405,6 +430,8 @@ static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 			msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
 		}
 	}
+
+	return ret;
 }
 
 static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
@@ -450,7 +477,9 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 			goto err;
 		}
 
-		qup_i2c_read_fifo(qup, msg);
+		ret = qup_i2c_read_fifo(qup, msg);
+		if (ret)
+			goto err;
 	} while (qup->pos < msg->len);
 
 err:
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 2/7] qup: i2c: factor out common code for reuse
  2015-07-09  3:25 ` Sricharan R
@ 2015-07-09  3:25   ` Sricharan R
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov, devicetree, linux-arm-msm, galak, linux-kernel,
	linux-i2c, agross, dmaengine, linux-arm-kernel
  Cc: sricharan

The qup_i2c_write/read_one functions can be split to have
the common initialization code and function to loop around
the data bytes separately. This way the initialization code
can be reused while adding v2 tags functionality.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 147 +++++++++++++++++++++++++------------------
 1 file changed, 87 insertions(+), 60 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 81ed120..131dc28 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -324,53 +324,72 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	return ret;
 }
 
-static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
+				     struct i2c_msg *msg)
 {
 	unsigned long left;
-	int ret;
-
-	qup->msg = msg;
-	qup->pos = 0;
+	int ret = 0;
 
-	enable_irq(qup->irq);
+	left = wait_for_completion_timeout(&qup->xfer, HZ);
+	if (!left) {
+		writel(1, qup->base + QUP_SW_RESET);
+		ret = -ETIMEDOUT;
+	}
 
-	qup_i2c_set_write_mode(qup, msg);
+	if (qup->bus_err || qup->qup_err) {
+		if (qup->bus_err & QUP_I2C_NACK_FLAG) {
+			dev_err(qup->dev, "NACK from %x\n", msg->addr);
+			ret = -EIO;
+		}
+	}
 
-	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-	if (ret)
-		goto err;
+	return ret;
+}
 
-	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret = 0;
 
 	do {
 		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
 		if (ret)
-			goto err;
+			return ret;
 
 		ret = qup_i2c_issue_write(qup, msg);
 		if (ret)
-			goto err;
+			return ret;
 
 		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 		if (ret)
-			goto err;
-
-		left = wait_for_completion_timeout(&qup->xfer, HZ);
-		if (!left) {
-			writel(1, qup->base + QUP_SW_RESET);
-			ret = -ETIMEDOUT;
-			goto err;
-		}
+			return ret;
 
-		if (qup->bus_err || qup->qup_err) {
-			if (qup->bus_err & QUP_I2C_NACK_FLAG)
-				dev_err(qup->dev, "NACK from %x\n", msg->addr);
-			ret = -EIO;
-			goto err;
-		}
+		ret = qup_i2c_wait_for_complete(qup, msg);
+		if (ret)
+			return ret;
 	} while (qup->pos < msg->len);
 
-	/* Wait for the outstanding data in the fifo to drain */
+	return ret;
+}
+
+static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret;
+
+	qup->msg = msg;
+	qup->pos = 0;
+	enable_irq(qup->irq);
+	qup_i2c_set_write_mode(qup, msg);
+
+	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+	if (ret)
+		goto err;
+
+	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+	ret = qup_i2c_write_one(qup, msg);
+	if (ret)
+		goto err;
+
 	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
 
 err:
@@ -436,51 +455,59 @@ static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
-	unsigned long left;
-	int ret;
+	int ret = 0;
 
-	qup->msg = msg;
-	qup->pos  = 0;
+	/*
+	 * The QUP block will issue a NACK and STOP on the bus when reaching
+	 * the end of the read, the length of the read is specified as one byte
+	 * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
+	 */
+	if (msg->len > QUP_READ_LIMIT) {
+		dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
+			QUP_READ_LIMIT);
+		return -EINVAL;
+	}
 
-	enable_irq(qup->irq);
+	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+	if (ret)
+		return ret;
 
-	qup_i2c_set_read_mode(qup, msg->len);
+	qup_i2c_issue_read(qup, msg);
 
 	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 	if (ret)
-		goto err;
+		return ret;
 
-	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+	do {
+		ret = qup_i2c_wait_for_complete(qup, msg);
+		if (ret)
+			return ret;
+		ret = qup_i2c_read_fifo(qup, msg);
+		if (ret)
+			return ret;
+	} while (qup->pos < msg->len);
 
-	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
-	if (ret)
-		goto err;
+	return ret;
+}
 
-	qup_i2c_issue_read(qup, msg);
+static int qup_i2c_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret;
+
+	qup->msg = msg;
+	qup->pos  = 0;
+
+	enable_irq(qup->irq);
+
+	qup_i2c_set_read_mode(qup, msg->len);
 
 	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 	if (ret)
 		goto err;
 
-	do {
-		left = wait_for_completion_timeout(&qup->xfer, HZ);
-		if (!left) {
-			writel(1, qup->base + QUP_SW_RESET);
-			ret = -ETIMEDOUT;
-			goto err;
-		}
-
-		if (qup->bus_err || qup->qup_err) {
-			if (qup->bus_err & QUP_I2C_NACK_FLAG)
-				dev_err(qup->dev, "NACK from %x\n", msg->addr);
-			ret = -EIO;
-			goto err;
-		}
+	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
-		ret = qup_i2c_read_fifo(qup, msg);
-		if (ret)
-			goto err;
-	} while (qup->pos < msg->len);
+	ret = qup_i2c_read_one(qup, msg);
 
 err:
 	disable_irq(qup->irq);
@@ -520,9 +547,9 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 		}
 
 		if (msgs[idx].flags & I2C_M_RD)
-			ret = qup_i2c_read_one(qup, &msgs[idx]);
+			ret = qup_i2c_read(qup, &msgs[idx]);
 		else
-			ret = qup_i2c_write_one(qup, &msgs[idx]);
+			ret = qup_i2c_write(qup, &msgs[idx]);
 
 		if (ret)
 			break;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 2/7] qup: i2c: factor out common code for reuse
@ 2015-07-09  3:25   ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: linux-arm-kernel

The qup_i2c_write/read_one functions can be split to have
the common initialization code and function to loop around
the data bytes separately. This way the initialization code
can be reused while adding v2 tags functionality.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 147 +++++++++++++++++++++++++------------------
 1 file changed, 87 insertions(+), 60 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 81ed120..131dc28 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -324,53 +324,72 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	return ret;
 }
 
-static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
+				     struct i2c_msg *msg)
 {
 	unsigned long left;
-	int ret;
-
-	qup->msg = msg;
-	qup->pos = 0;
+	int ret = 0;
 
-	enable_irq(qup->irq);
+	left = wait_for_completion_timeout(&qup->xfer, HZ);
+	if (!left) {
+		writel(1, qup->base + QUP_SW_RESET);
+		ret = -ETIMEDOUT;
+	}
 
-	qup_i2c_set_write_mode(qup, msg);
+	if (qup->bus_err || qup->qup_err) {
+		if (qup->bus_err & QUP_I2C_NACK_FLAG) {
+			dev_err(qup->dev, "NACK from %x\n", msg->addr);
+			ret = -EIO;
+		}
+	}
 
-	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-	if (ret)
-		goto err;
+	return ret;
+}
 
-	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret = 0;
 
 	do {
 		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
 		if (ret)
-			goto err;
+			return ret;
 
 		ret = qup_i2c_issue_write(qup, msg);
 		if (ret)
-			goto err;
+			return ret;
 
 		ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 		if (ret)
-			goto err;
-
-		left = wait_for_completion_timeout(&qup->xfer, HZ);
-		if (!left) {
-			writel(1, qup->base + QUP_SW_RESET);
-			ret = -ETIMEDOUT;
-			goto err;
-		}
+			return ret;
 
-		if (qup->bus_err || qup->qup_err) {
-			if (qup->bus_err & QUP_I2C_NACK_FLAG)
-				dev_err(qup->dev, "NACK from %x\n", msg->addr);
-			ret = -EIO;
-			goto err;
-		}
+		ret = qup_i2c_wait_for_complete(qup, msg);
+		if (ret)
+			return ret;
 	} while (qup->pos < msg->len);
 
-	/* Wait for the outstanding data in the fifo to drain */
+	return ret;
+}
+
+static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret;
+
+	qup->msg = msg;
+	qup->pos = 0;
+	enable_irq(qup->irq);
+	qup_i2c_set_write_mode(qup, msg);
+
+	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+	if (ret)
+		goto err;
+
+	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+	ret = qup_i2c_write_one(qup, msg);
+	if (ret)
+		goto err;
+
 	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
 
 err:
@@ -436,51 +455,59 @@ static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
-	unsigned long left;
-	int ret;
+	int ret = 0;
 
-	qup->msg = msg;
-	qup->pos  = 0;
+	/*
+	 * The QUP block will issue a NACK and STOP on the bus when reaching
+	 * the end of the read, the length of the read is specified as one byte
+	 * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
+	 */
+	if (msg->len > QUP_READ_LIMIT) {
+		dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
+			QUP_READ_LIMIT);
+		return -EINVAL;
+	}
 
-	enable_irq(qup->irq);
+	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+	if (ret)
+		return ret;
 
-	qup_i2c_set_read_mode(qup, msg->len);
+	qup_i2c_issue_read(qup, msg);
 
 	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 	if (ret)
-		goto err;
+		return ret;
 
-	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+	do {
+		ret = qup_i2c_wait_for_complete(qup, msg);
+		if (ret)
+			return ret;
+		ret = qup_i2c_read_fifo(qup, msg);
+		if (ret)
+			return ret;
+	} while (qup->pos < msg->len);
 
-	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
-	if (ret)
-		goto err;
+	return ret;
+}
 
-	qup_i2c_issue_read(qup, msg);
+static int qup_i2c_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret;
+
+	qup->msg = msg;
+	qup->pos  = 0;
+
+	enable_irq(qup->irq);
+
+	qup_i2c_set_read_mode(qup, msg->len);
 
 	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
 	if (ret)
 		goto err;
 
-	do {
-		left = wait_for_completion_timeout(&qup->xfer, HZ);
-		if (!left) {
-			writel(1, qup->base + QUP_SW_RESET);
-			ret = -ETIMEDOUT;
-			goto err;
-		}
-
-		if (qup->bus_err || qup->qup_err) {
-			if (qup->bus_err & QUP_I2C_NACK_FLAG)
-				dev_err(qup->dev, "NACK from %x\n", msg->addr);
-			ret = -EIO;
-			goto err;
-		}
+	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
-		ret = qup_i2c_read_fifo(qup, msg);
-		if (ret)
-			goto err;
-	} while (qup->pos < msg->len);
+	ret = qup_i2c_read_one(qup, msg);
 
 err:
 	disable_irq(qup->irq);
@@ -520,9 +547,9 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 		}
 
 		if (msgs[idx].flags & I2C_M_RD)
-			ret = qup_i2c_read_one(qup, &msgs[idx]);
+			ret = qup_i2c_read(qup, &msgs[idx]);
 		else
-			ret = qup_i2c_write_one(qup, &msgs[idx]);
+			ret = qup_i2c_write(qup, &msgs[idx]);
 
 		if (ret)
 			break;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 3/7] i2c: qup: Add V2 tags support
  2015-07-09  3:25 ` Sricharan R
@ 2015-07-09  3:25   ` Sricharan R
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov, devicetree, linux-arm-msm, galak, linux-kernel,
	linux-i2c, agross, dmaengine, linux-arm-kernel
  Cc: sricharan

QUP from version 2.1.1 onwards, supports a new format of
i2c command tags. Tag codes instructs the controller to
perform a operation like read/write. This new tagging version
supports bam dma and transfers of more than 256 bytes without 'stop'
in between. Adding the support for the same.

For each block a data_write/read tag and data_len tag is added to
the output fifo. For the final block of data write_stop/read_stop
tag is used.

Signed-off-by: Andy Gross <agross@codeaurora.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 330 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 323 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 131dc28..a4e20d9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -43,6 +43,8 @@
 #define QUP_I2C_CLK_CTL		0x400
 #define QUP_I2C_STATUS		0x404
 
+#define QUP_I2C_MASTER_GEN	0x408
+
 /* QUP States and reset values */
 #define QUP_RESET_STATE		0
 #define QUP_RUN_STATE		1
@@ -69,6 +71,8 @@
 #define QUP_CLOCK_AUTO_GATE	BIT(13)
 #define I2C_MINI_CORE		(2 << 8)
 #define I2C_N_VAL		15
+#define I2C_N_VAL_V2		7
+
 /* Most significant word offset in FIFO port */
 #define QUP_MSW_SHIFT		(I2C_N_VAL + 1)
 
@@ -79,6 +83,7 @@
 #define QUP_PACK_EN		BIT(15)
 
 #define QUP_REPACK_EN		(QUP_UNPACK_EN | QUP_PACK_EN)
+#define QUP_V2_TAGS_EN		1
 
 #define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03)
 #define QUP_OUTPUT_FIFO_SIZE(x)	(((x) >> 2) & 0x07)
@@ -91,6 +96,13 @@
 #define QUP_TAG_STOP		(3 << 8)
 #define QUP_TAG_REC		(4 << 8)
 
+/* QUP v2 tags */
+#define QUP_TAG_V2_START               0x81
+#define QUP_TAG_V2_DATAWR              0x82
+#define QUP_TAG_V2_DATAWR_STOP         0x83
+#define QUP_TAG_V2_DATARD              0x85
+#define QUP_TAG_V2_DATARD_STOP         0x87
+
 /* Status, Error flags */
 #define I2C_STATUS_WR_BUFFER_FULL	BIT(0)
 #define I2C_STATUS_BUS_ACTIVE		BIT(8)
@@ -102,6 +114,15 @@
 #define RESET_BIT			0x0
 #define ONE_BYTE			0x1
 
+struct qup_i2c_block {
+	int	count;
+	int	pos;
+	int	tx_tag_len;
+	int	rx_tag_len;
+	int	data_len;
+	u8	tags[6];
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -117,6 +138,7 @@ struct qup_i2c_dev {
 	int			in_blk_sz;
 
 	unsigned long		one_byte_t;
+	struct qup_i2c_block	blk;
 
 	struct i2c_msg		*msg;
 	/* Current posion in user message buffer */
@@ -126,6 +148,14 @@ struct qup_i2c_dev {
 	/* QUP core errors */
 	u32			qup_err;
 
+	int			use_v2_tags;
+
+	int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
+				 struct i2c_msg *msg);
+
+	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
+				struct i2c_msg *msg);
+
 	struct completion	xfer;
 };
 
@@ -266,7 +296,7 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
 static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	/* Number of entries to shift out, including the start */
-	int total = msg->len + 1;
+	int total = msg->len + qup->blk.tx_tag_len;
 
 	if (total < qup->out_fifo_sz) {
 		/* FIFO mode */
@@ -324,6 +354,134 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	return ret;
 }
 
+static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
+				 struct i2c_msg *msg)
+{
+	memset(&qup->blk, 0, sizeof(qup->blk));
+
+	if (!qup->use_v2_tags) {
+		if (!(msg->flags & I2C_M_RD))
+			qup->blk.tx_tag_len = 1;
+		return;
+	}
+
+	qup->blk.data_len = msg->len;
+	qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT;
+
+	/* 4 bytes for first block and 2 writes for rest */
+	qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
+
+	/* There are 2 tag bytes that are read in to fifo for every block */
+	if (msg->flags & I2C_M_RD)
+		qup->blk.rx_tag_len = qup->blk.count * 2;
+}
+
+static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf,
+			     int dlen, u8 *dbuf)
+{
+	u32 val = 0, idx = 0, pos = 0, i = 0, t;
+	int  len = tlen + dlen;
+	u8 *buf = tbuf;
+	int ret = 0;
+
+	while (len > 0) {
+		ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL,
+					 RESET_BIT, 4 * ONE_BYTE);
+		if (ret) {
+			dev_err(qup->dev, "timeout for fifo out full");
+			return ret;
+		}
+
+		t = (len >= 4) ? 4 : len;
+
+		while (idx < t) {
+			if (!i && (pos >= tlen)) {
+				buf = dbuf;
+				pos = 0;
+				i = 1;
+			}
+			val |= buf[pos++] << (idx++ * 8);
+		}
+
+		writel(val, qup->base + QUP_OUT_FIFO_BASE);
+		idx  = 0;
+		val = 0;
+		len -= 4;
+	}
+
+	return ret;
+}
+
+static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
+{
+	int data_len;
+
+	if (qup->blk.data_len > QUP_READ_LIMIT)
+		data_len = QUP_READ_LIMIT;
+	else
+		data_len = qup->blk.data_len;
+
+	return data_len;
+}
+
+static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
+			    struct i2c_msg *msg)
+{
+	u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
+	int len = 0;
+	int data_len;
+
+	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;
+	}
+
+	/* Send _STOP commands for the last block */
+	if (qup->blk.pos == (qup->blk.count - 1)) {
+		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);
+
+	/* 0 implies 256 bytes */
+	if (data_len == QUP_READ_LIMIT)
+		tags[len++] = 0;
+	else
+		tags[len++] = data_len;
+
+	return len;
+}
+
+static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int data_len = 0, tag_len, index;
+	int ret;
+
+	tag_len = qup_i2c_get_tags(qup->blk.tags, qup, msg);
+	index = msg->len - qup->blk.data_len;
+
+	/* only tags are written for read */
+	if (!(msg->flags & I2C_M_RD))
+		data_len = qup_i2c_get_data_len(qup);
+
+	ret = qup_i2c_send_data(qup, tag_len, qup->blk.tags,
+				data_len, &msg->buf[index]);
+	qup->blk.data_len -= data_len;
+
+	return ret;
+}
+
 static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
 				     struct i2c_msg *msg)
 {
@@ -346,7 +504,27 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
 	return ret;
 }
 
-static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int qup_i2c_write_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret = 0;
+
+	do {
+		ret = qup_i2c_issue_xfer_v2(qup, msg);
+		if (ret)
+			goto err;
+
+		ret = qup_i2c_wait_for_complete(qup, msg);
+		if (ret)
+			goto err;
+
+		qup->blk.pos++;
+	} while (qup->blk.pos < qup->blk.count);
+
+err:
+	return ret;
+}
+
+static int qup_i2c_write_one_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	int ret = 0;
 
@@ -378,6 +556,8 @@ static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	qup->msg = msg;
 	qup->pos = 0;
 	enable_irq(qup->irq);
+	qup_i2c_get_blk_data(qup, msg);
+
 	qup_i2c_set_write_mode(qup, msg);
 
 	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
@@ -386,7 +566,7 @@ static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
-	ret = qup_i2c_write_one(qup, msg);
+	ret = qup->qup_i2c_write_one(qup, msg);
 	if (ret)
 		goto err;
 
@@ -401,15 +581,21 @@ err:
 
 static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 {
+	int tx_len = qup->blk.tx_tag_len;
+
+	len += qup->blk.rx_tag_len;
+
 	if (len < qup->in_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
 		writel(len, qup->base + QUP_MX_READ_CNT);
+		writel(tx_len, qup->base + QUP_MX_WRITE_CNT);
 	} else {
 		/* BLOCK mode (transfer data on chunks) */
 		writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
 		       qup->base + QUP_IO_MODE);
 		writel(len, qup->base + QUP_MX_INPUT_CNT);
+		writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT);
 	}
 }
 
@@ -426,7 +612,6 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	writel(val, qup->base + QUP_OUT_FIFO_BASE);
 }
 
-
 static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	u32 val = 0;
@@ -453,7 +638,68 @@ static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	return ret;
 }
 
-static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+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;
+
+	total = qup_i2c_get_data_len(qup);
+
+	/* 2 extra bytes for read tags */
+	while (pos < (total + 2)) {
+		/* Check that FIFO have data */
+		ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
+					 SET_BIT, 4 * ONE_BYTE);
+		if (ret) {
+			dev_err(qup->dev, "timeout for fifo not empty");
+			return ret;
+		}
+		val = readl(qup->base + QUP_IN_FIFO_BASE);
+
+		for (idx = 0; idx < 4; idx++, val >>= 8, pos++) {
+			/* first 2 bytes are tag bytes */
+			if (pos < 2)
+				continue;
+
+			if (pos >= (total + 2))
+				goto out;
+
+			msg->buf[qup->pos++] = val & 0xff;
+		}
+	}
+
+out:
+	qup->blk.data_len -= total;
+
+	return ret;
+}
+
+static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret = 0;
+
+	do {
+		ret = qup_i2c_issue_xfer_v2(qup, msg);
+		if (ret)
+			goto err;
+
+		ret = qup_i2c_wait_for_complete(qup, msg);
+		if (ret)
+			goto err;
+
+		ret = qup_i2c_read_fifo_v2(qup, msg);
+		if (ret)
+			goto err;
+
+		qup->blk.pos++;
+	} while (qup->blk.pos < qup->blk.count);
+
+err:
+	return ret;
+}
+
+static int qup_i2c_read_one_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	int ret = 0;
 
@@ -498,6 +744,7 @@ static int qup_i2c_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	qup->pos  = 0;
 
 	enable_irq(qup->irq);
+	qup_i2c_get_blk_data(qup, msg);
 
 	qup_i2c_set_read_mode(qup, msg->len);
 
@@ -507,7 +754,7 @@ static int qup_i2c_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
-	ret = qup_i2c_read_one(qup, msg);
+	ret = qup->qup_i2c_read_one(qup, msg);
 
 err:
 	disable_irq(qup->irq);
@@ -569,6 +816,60 @@ out:
 	return ret;
 }
 
+static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
+			   struct i2c_msg msgs[],
+			   int num)
+{
+	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
+	int ret, idx;
+
+	ret = pm_runtime_get_sync(qup->dev);
+	if (ret < 0)
+		goto out;
+
+	writel(1, qup->base + QUP_SW_RESET);
+	ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
+	if (ret)
+		goto out;
+
+	/* Configure QUP as I2C mini core */
+	writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
+	writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
+
+	for (idx = 0; idx < num; idx++) {
+		if (msgs[idx].len == 0) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (qup_i2c_poll_state_i2c_master(qup)) {
+			ret = -EIO;
+			goto out;
+		}
+
+		reinit_completion(&qup->xfer);
+
+		if (msgs[idx].flags & I2C_M_RD)
+			ret = qup_i2c_read(qup, &msgs[idx]);
+		else
+			ret = qup_i2c_write(qup, &msgs[idx]);
+
+		if (!ret)
+			ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
+
+		if (ret)
+			break;
+	}
+
+	if (ret == 0)
+		ret = num;
+out:
+	pm_runtime_mark_last_busy(qup->dev);
+	pm_runtime_put_autosuspend(qup->dev);
+
+	return ret;
+}
+
 static u32 qup_i2c_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
@@ -588,6 +889,11 @@ static struct i2c_adapter_quirks qup_i2c_quirks = {
 	.max_read_len = QUP_READ_LIMIT,
 };
 
+static const struct i2c_algorithm qup_i2c_algo_v2 = {
+	.master_xfer	= qup_i2c_xfer_v2,
+	.functionality	= qup_i2c_func,
+};
+
 static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
 {
 	clk_prepare_enable(qup->clk);
@@ -628,6 +934,17 @@ static int qup_i2c_probe(struct platform_device *pdev)
 
 	of_property_read_u32(node, "clock-frequency", &clk_freq);
 
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
+		qup->adap.algo = &qup_i2c_algo;
+		qup->qup_i2c_write_one = qup_i2c_write_one_v1;
+		qup->qup_i2c_read_one = qup_i2c_read_one_v1;
+	} else {
+		qup->adap.algo = &qup_i2c_algo_v2;
+		qup->qup_i2c_write_one = qup_i2c_write_one_v2;
+		qup->qup_i2c_read_one = qup_i2c_read_one_v2;
+		qup->use_v2_tags = 1;
+	}
+
 	/* We support frequencies up to FAST Mode (400KHz) */
 	if (!clk_freq || clk_freq > 400000) {
 		dev_err(qup->dev, "clock frequency not supported %d\n",
@@ -723,7 +1040,6 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		qup->out_blk_sz, qup->out_fifo_sz);
 
 	i2c_set_adapdata(&qup->adap, qup);
-	qup->adap.algo = &qup_i2c_algo;
 	qup->adap.quirks = &qup_i2c_quirks;
 	qup->adap.dev.parent = qup->dev;
 	qup->adap.dev.of_node = pdev->dev.of_node;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 3/7] i2c: qup: Add V2 tags support
@ 2015-07-09  3:25   ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: linux-arm-kernel

QUP from version 2.1.1 onwards, supports a new format of
i2c command tags. Tag codes instructs the controller to
perform a operation like read/write. This new tagging version
supports bam dma and transfers of more than 256 bytes without 'stop'
in between. Adding the support for the same.

For each block a data_write/read tag and data_len tag is added to
the output fifo. For the final block of data write_stop/read_stop
tag is used.

Signed-off-by: Andy Gross <agross@codeaurora.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 330 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 323 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 131dc28..a4e20d9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -43,6 +43,8 @@
 #define QUP_I2C_CLK_CTL		0x400
 #define QUP_I2C_STATUS		0x404
 
+#define QUP_I2C_MASTER_GEN	0x408
+
 /* QUP States and reset values */
 #define QUP_RESET_STATE		0
 #define QUP_RUN_STATE		1
@@ -69,6 +71,8 @@
 #define QUP_CLOCK_AUTO_GATE	BIT(13)
 #define I2C_MINI_CORE		(2 << 8)
 #define I2C_N_VAL		15
+#define I2C_N_VAL_V2		7
+
 /* Most significant word offset in FIFO port */
 #define QUP_MSW_SHIFT		(I2C_N_VAL + 1)
 
@@ -79,6 +83,7 @@
 #define QUP_PACK_EN		BIT(15)
 
 #define QUP_REPACK_EN		(QUP_UNPACK_EN | QUP_PACK_EN)
+#define QUP_V2_TAGS_EN		1
 
 #define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03)
 #define QUP_OUTPUT_FIFO_SIZE(x)	(((x) >> 2) & 0x07)
@@ -91,6 +96,13 @@
 #define QUP_TAG_STOP		(3 << 8)
 #define QUP_TAG_REC		(4 << 8)
 
+/* QUP v2 tags */
+#define QUP_TAG_V2_START               0x81
+#define QUP_TAG_V2_DATAWR              0x82
+#define QUP_TAG_V2_DATAWR_STOP         0x83
+#define QUP_TAG_V2_DATARD              0x85
+#define QUP_TAG_V2_DATARD_STOP         0x87
+
 /* Status, Error flags */
 #define I2C_STATUS_WR_BUFFER_FULL	BIT(0)
 #define I2C_STATUS_BUS_ACTIVE		BIT(8)
@@ -102,6 +114,15 @@
 #define RESET_BIT			0x0
 #define ONE_BYTE			0x1
 
+struct qup_i2c_block {
+	int	count;
+	int	pos;
+	int	tx_tag_len;
+	int	rx_tag_len;
+	int	data_len;
+	u8	tags[6];
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -117,6 +138,7 @@ struct qup_i2c_dev {
 	int			in_blk_sz;
 
 	unsigned long		one_byte_t;
+	struct qup_i2c_block	blk;
 
 	struct i2c_msg		*msg;
 	/* Current posion in user message buffer */
@@ -126,6 +148,14 @@ struct qup_i2c_dev {
 	/* QUP core errors */
 	u32			qup_err;
 
+	int			use_v2_tags;
+
+	int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
+				 struct i2c_msg *msg);
+
+	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
+				struct i2c_msg *msg);
+
 	struct completion	xfer;
 };
 
@@ -266,7 +296,7 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
 static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	/* Number of entries to shift out, including the start */
-	int total = msg->len + 1;
+	int total = msg->len + qup->blk.tx_tag_len;
 
 	if (total < qup->out_fifo_sz) {
 		/* FIFO mode */
@@ -324,6 +354,134 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	return ret;
 }
 
+static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
+				 struct i2c_msg *msg)
+{
+	memset(&qup->blk, 0, sizeof(qup->blk));
+
+	if (!qup->use_v2_tags) {
+		if (!(msg->flags & I2C_M_RD))
+			qup->blk.tx_tag_len = 1;
+		return;
+	}
+
+	qup->blk.data_len = msg->len;
+	qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT;
+
+	/* 4 bytes for first block and 2 writes for rest */
+	qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
+
+	/* There are 2 tag bytes that are read in to fifo for every block */
+	if (msg->flags & I2C_M_RD)
+		qup->blk.rx_tag_len = qup->blk.count * 2;
+}
+
+static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf,
+			     int dlen, u8 *dbuf)
+{
+	u32 val = 0, idx = 0, pos = 0, i = 0, t;
+	int  len = tlen + dlen;
+	u8 *buf = tbuf;
+	int ret = 0;
+
+	while (len > 0) {
+		ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL,
+					 RESET_BIT, 4 * ONE_BYTE);
+		if (ret) {
+			dev_err(qup->dev, "timeout for fifo out full");
+			return ret;
+		}
+
+		t = (len >= 4) ? 4 : len;
+
+		while (idx < t) {
+			if (!i && (pos >= tlen)) {
+				buf = dbuf;
+				pos = 0;
+				i = 1;
+			}
+			val |= buf[pos++] << (idx++ * 8);
+		}
+
+		writel(val, qup->base + QUP_OUT_FIFO_BASE);
+		idx  = 0;
+		val = 0;
+		len -= 4;
+	}
+
+	return ret;
+}
+
+static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
+{
+	int data_len;
+
+	if (qup->blk.data_len > QUP_READ_LIMIT)
+		data_len = QUP_READ_LIMIT;
+	else
+		data_len = qup->blk.data_len;
+
+	return data_len;
+}
+
+static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
+			    struct i2c_msg *msg)
+{
+	u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
+	int len = 0;
+	int data_len;
+
+	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;
+	}
+
+	/* Send _STOP commands for the last block */
+	if (qup->blk.pos == (qup->blk.count - 1)) {
+		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);
+
+	/* 0 implies 256 bytes */
+	if (data_len == QUP_READ_LIMIT)
+		tags[len++] = 0;
+	else
+		tags[len++] = data_len;
+
+	return len;
+}
+
+static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int data_len = 0, tag_len, index;
+	int ret;
+
+	tag_len = qup_i2c_get_tags(qup->blk.tags, qup, msg);
+	index = msg->len - qup->blk.data_len;
+
+	/* only tags are written for read */
+	if (!(msg->flags & I2C_M_RD))
+		data_len = qup_i2c_get_data_len(qup);
+
+	ret = qup_i2c_send_data(qup, tag_len, qup->blk.tags,
+				data_len, &msg->buf[index]);
+	qup->blk.data_len -= data_len;
+
+	return ret;
+}
+
 static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
 				     struct i2c_msg *msg)
 {
@@ -346,7 +504,27 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
 	return ret;
 }
 
-static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int qup_i2c_write_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret = 0;
+
+	do {
+		ret = qup_i2c_issue_xfer_v2(qup, msg);
+		if (ret)
+			goto err;
+
+		ret = qup_i2c_wait_for_complete(qup, msg);
+		if (ret)
+			goto err;
+
+		qup->blk.pos++;
+	} while (qup->blk.pos < qup->blk.count);
+
+err:
+	return ret;
+}
+
+static int qup_i2c_write_one_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	int ret = 0;
 
@@ -378,6 +556,8 @@ static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	qup->msg = msg;
 	qup->pos = 0;
 	enable_irq(qup->irq);
+	qup_i2c_get_blk_data(qup, msg);
+
 	qup_i2c_set_write_mode(qup, msg);
 
 	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
@@ -386,7 +566,7 @@ static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
-	ret = qup_i2c_write_one(qup, msg);
+	ret = qup->qup_i2c_write_one(qup, msg);
 	if (ret)
 		goto err;
 
@@ -401,15 +581,21 @@ err:
 
 static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 {
+	int tx_len = qup->blk.tx_tag_len;
+
+	len += qup->blk.rx_tag_len;
+
 	if (len < qup->in_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
 		writel(len, qup->base + QUP_MX_READ_CNT);
+		writel(tx_len, qup->base + QUP_MX_WRITE_CNT);
 	} else {
 		/* BLOCK mode (transfer data on chunks) */
 		writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
 		       qup->base + QUP_IO_MODE);
 		writel(len, qup->base + QUP_MX_INPUT_CNT);
+		writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT);
 	}
 }
 
@@ -426,7 +612,6 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	writel(val, qup->base + QUP_OUT_FIFO_BASE);
 }
 
-
 static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	u32 val = 0;
@@ -453,7 +638,68 @@ static int qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	return ret;
 }
 
-static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+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;
+
+	total = qup_i2c_get_data_len(qup);
+
+	/* 2 extra bytes for read tags */
+	while (pos < (total + 2)) {
+		/* Check that FIFO have data */
+		ret = qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY,
+					 SET_BIT, 4 * ONE_BYTE);
+		if (ret) {
+			dev_err(qup->dev, "timeout for fifo not empty");
+			return ret;
+		}
+		val = readl(qup->base + QUP_IN_FIFO_BASE);
+
+		for (idx = 0; idx < 4; idx++, val >>= 8, pos++) {
+			/* first 2 bytes are tag bytes */
+			if (pos < 2)
+				continue;
+
+			if (pos >= (total + 2))
+				goto out;
+
+			msg->buf[qup->pos++] = val & 0xff;
+		}
+	}
+
+out:
+	qup->blk.data_len -= total;
+
+	return ret;
+}
+
+static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	int ret = 0;
+
+	do {
+		ret = qup_i2c_issue_xfer_v2(qup, msg);
+		if (ret)
+			goto err;
+
+		ret = qup_i2c_wait_for_complete(qup, msg);
+		if (ret)
+			goto err;
+
+		ret = qup_i2c_read_fifo_v2(qup, msg);
+		if (ret)
+			goto err;
+
+		qup->blk.pos++;
+	} while (qup->blk.pos < qup->blk.count);
+
+err:
+	return ret;
+}
+
+static int qup_i2c_read_one_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	int ret = 0;
 
@@ -498,6 +744,7 @@ static int qup_i2c_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	qup->pos  = 0;
 
 	enable_irq(qup->irq);
+	qup_i2c_get_blk_data(qup, msg);
 
 	qup_i2c_set_read_mode(qup, msg->len);
 
@@ -507,7 +754,7 @@ static int qup_i2c_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
-	ret = qup_i2c_read_one(qup, msg);
+	ret = qup->qup_i2c_read_one(qup, msg);
 
 err:
 	disable_irq(qup->irq);
@@ -569,6 +816,60 @@ out:
 	return ret;
 }
 
+static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
+			   struct i2c_msg msgs[],
+			   int num)
+{
+	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
+	int ret, idx;
+
+	ret = pm_runtime_get_sync(qup->dev);
+	if (ret < 0)
+		goto out;
+
+	writel(1, qup->base + QUP_SW_RESET);
+	ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
+	if (ret)
+		goto out;
+
+	/* Configure QUP as I2C mini core */
+	writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
+	writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
+
+	for (idx = 0; idx < num; idx++) {
+		if (msgs[idx].len == 0) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (qup_i2c_poll_state_i2c_master(qup)) {
+			ret = -EIO;
+			goto out;
+		}
+
+		reinit_completion(&qup->xfer);
+
+		if (msgs[idx].flags & I2C_M_RD)
+			ret = qup_i2c_read(qup, &msgs[idx]);
+		else
+			ret = qup_i2c_write(qup, &msgs[idx]);
+
+		if (!ret)
+			ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
+
+		if (ret)
+			break;
+	}
+
+	if (ret == 0)
+		ret = num;
+out:
+	pm_runtime_mark_last_busy(qup->dev);
+	pm_runtime_put_autosuspend(qup->dev);
+
+	return ret;
+}
+
 static u32 qup_i2c_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
@@ -588,6 +889,11 @@ static struct i2c_adapter_quirks qup_i2c_quirks = {
 	.max_read_len = QUP_READ_LIMIT,
 };
 
+static const struct i2c_algorithm qup_i2c_algo_v2 = {
+	.master_xfer	= qup_i2c_xfer_v2,
+	.functionality	= qup_i2c_func,
+};
+
 static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
 {
 	clk_prepare_enable(qup->clk);
@@ -628,6 +934,17 @@ static int qup_i2c_probe(struct platform_device *pdev)
 
 	of_property_read_u32(node, "clock-frequency", &clk_freq);
 
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
+		qup->adap.algo = &qup_i2c_algo;
+		qup->qup_i2c_write_one = qup_i2c_write_one_v1;
+		qup->qup_i2c_read_one = qup_i2c_read_one_v1;
+	} else {
+		qup->adap.algo = &qup_i2c_algo_v2;
+		qup->qup_i2c_write_one = qup_i2c_write_one_v2;
+		qup->qup_i2c_read_one = qup_i2c_read_one_v2;
+		qup->use_v2_tags = 1;
+	}
+
 	/* We support frequencies up to FAST Mode (400KHz) */
 	if (!clk_freq || clk_freq > 400000) {
 		dev_err(qup->dev, "clock frequency not supported %d\n",
@@ -723,7 +1040,6 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		qup->out_blk_sz, qup->out_fifo_sz);
 
 	i2c_set_adapdata(&qup->adap, qup);
-	qup->adap.algo = &qup_i2c_algo;
 	qup->adap.quirks = &qup_i2c_quirks;
 	qup->adap.dev.parent = qup->dev;
 	qup->adap.dev.of_node = pdev->dev.of_node;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
  2015-07-09  3:25 ` Sricharan R
  (?)
@ 2015-07-09  3:25     ` Sricharan R
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov-NEYub+7Iv8PQT0dZR+AlfA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, agross-sgV2jX0FEOL9JmXXK+q4OQ,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: sricharan-sgV2jX0FEOL9JmXXK+q4OQ

The definition of i2c_msg says that

"If this is the last message in a group, it is followed by a STOP.
Otherwise it is followed by the next @i2c_msg transaction segment,
beginning with a (repeated) START"

So the expectation is that there is no 'STOP' bit inbetween individual
i2c_msg segments with repeated 'START'. The QUP i2c hardware has no way
to inform that there should not be a 'STOP' at the end of transaction.
The only way to implement this is to coalesce all the i2c_msg in i2c_msgs
in to one transaction and transfer them. Adding the support for the same.

This is required for some clients like touchscreen which keeps
incrementing counts across individual transfers and 'STOP' bit inbetween
resets the counter, which is not required.

This patch adds the support in non-dma mode.

Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
 drivers/i2c/busses/i2c-qup.c | 40 ++++++++++++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index a4e20d9..c0757d9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -113,6 +113,7 @@
 #define SET_BIT				0x1
 #define RESET_BIT			0x0
 #define ONE_BYTE			0x1
+#define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
 
 struct qup_i2c_block {
 	int	count;
@@ -121,6 +122,7 @@ struct qup_i2c_block {
 	int	rx_tag_len;
 	int	data_len;
 	u8	tags[6];
+	int     config_run;
 };
 
 struct qup_i2c_dev {
@@ -152,6 +154,10 @@ struct qup_i2c_dev {
 
 	int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
 				 struct i2c_msg *msg);
+	/* Current i2c_msg in i2c_msgs */
+	int			cmsg;
+	/* total num of i2c_msgs */
+	int			num;
 
 	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
 				struct i2c_msg *msg);
@@ -278,7 +284,8 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
 		status = readl(qup->base + QUP_I2C_STATUS);
 
 		if (((opflags & op) >> shift) == val) {
-			if (op == QUP_OUT_NOT_EMPTY) {
+			if ((op == QUP_OUT_NOT_EMPTY) &&
+			    (qup->cmsg == (qup->num - 1))) {
 				if (!(status & I2C_STATUS_BUS_ACTIVE))
 					return 0;
 			} else {
@@ -301,12 +308,14 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	if (total < qup->out_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
-		writel(total, qup->base + QUP_MX_WRITE_CNT);
+		writel(total | qup->blk.config_run,
+		       qup->base + QUP_MX_WRITE_CNT);
 	} else {
 		/* BLOCK mode (transfer data on chunks) */
 		writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
 		       qup->base + QUP_IO_MODE);
-		writel(total, qup->base + QUP_MX_OUTPUT_CNT);
+		writel(total | qup->blk.config_run,
+		       qup->base + QUP_MX_OUTPUT_CNT);
 	}
 }
 
@@ -374,6 +383,9 @@ static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
 	/* There are 2 tag bytes that are read in to fifo for every block */
 	if (msg->flags & I2C_M_RD)
 		qup->blk.rx_tag_len = qup->blk.count * 2;
+
+	if (qup->cmsg)
+		qup->blk.config_run = QUP_I2C_MX_CONFIG_DURING_RUN;
 }
 
 static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf,
@@ -440,7 +452,8 @@ static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
 	}
 
 	/* Send _STOP commands for the last block */
-	if (qup->blk.pos == (qup->blk.count - 1)) {
+	if (qup->blk.pos == (qup->blk.count - 1)
+	    && (qup->cmsg == (qup->num - 1))) {
 		if (msg->flags & I2C_M_RD)
 			tags[len++] = QUP_TAG_V2_DATARD_STOP;
 		else
@@ -571,7 +584,6 @@ static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		goto err;
 
 	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
-
 err:
 	disable_irq(qup->irq);
 	qup->msg = NULL;
@@ -584,18 +596,19 @@ static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 	int tx_len = qup->blk.tx_tag_len;
 
 	len += qup->blk.rx_tag_len;
+	tx_len |= qup->blk.config_run;
 
 	if (len < qup->in_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
-		writel(len, qup->base + QUP_MX_READ_CNT);
 		writel(tx_len, qup->base + QUP_MX_WRITE_CNT);
+		writel(len | qup->blk.config_run, qup->base + QUP_MX_READ_CNT);
 	} else {
 		/* BLOCK mode (transfer data on chunks) */
 		writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
 		       qup->base + QUP_IO_MODE);
-		writel(len, qup->base + QUP_MX_INPUT_CNT);
 		writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT);
+		writel(len | qup->blk.config_run, qup->base + QUP_MX_INPUT_CNT);
 	}
 }
 
@@ -770,6 +783,8 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
 	int ret, idx;
 
+	qup->num = 1;
+
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
 		goto out;
@@ -823,6 +838,9 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
 	int ret, idx;
 
+	qup->num = num;
+	qup->cmsg = 0;
+
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
 		goto out;
@@ -854,13 +872,15 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 		else
 			ret = qup_i2c_write(qup, &msgs[idx]);
 
-		if (!ret)
-			ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
-
 		if (ret)
 			break;
+
+		qup->cmsg++;
 	}
 
+	if (!ret)
+		ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
+
 	if (ret == 0)
 		ret = num;
 out:
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
@ 2015-07-09  3:25     ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov, devicetree, linux-arm-msm, galak, linux-kernel,
	linux-i2c, agross, dmaengine, linux-arm-kernel
  Cc: sricharan

The definition of i2c_msg says that

"If this is the last message in a group, it is followed by a STOP.
Otherwise it is followed by the next @i2c_msg transaction segment,
beginning with a (repeated) START"

So the expectation is that there is no 'STOP' bit inbetween individual
i2c_msg segments with repeated 'START'. The QUP i2c hardware has no way
to inform that there should not be a 'STOP' at the end of transaction.
The only way to implement this is to coalesce all the i2c_msg in i2c_msgs
in to one transaction and transfer them. Adding the support for the same.

This is required for some clients like touchscreen which keeps
incrementing counts across individual transfers and 'STOP' bit inbetween
resets the counter, which is not required.

This patch adds the support in non-dma mode.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 40 ++++++++++++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index a4e20d9..c0757d9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -113,6 +113,7 @@
 #define SET_BIT				0x1
 #define RESET_BIT			0x0
 #define ONE_BYTE			0x1
+#define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
 
 struct qup_i2c_block {
 	int	count;
@@ -121,6 +122,7 @@ struct qup_i2c_block {
 	int	rx_tag_len;
 	int	data_len;
 	u8	tags[6];
+	int     config_run;
 };
 
 struct qup_i2c_dev {
@@ -152,6 +154,10 @@ struct qup_i2c_dev {
 
 	int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
 				 struct i2c_msg *msg);
+	/* Current i2c_msg in i2c_msgs */
+	int			cmsg;
+	/* total num of i2c_msgs */
+	int			num;
 
 	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
 				struct i2c_msg *msg);
@@ -278,7 +284,8 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
 		status = readl(qup->base + QUP_I2C_STATUS);
 
 		if (((opflags & op) >> shift) == val) {
-			if (op == QUP_OUT_NOT_EMPTY) {
+			if ((op == QUP_OUT_NOT_EMPTY) &&
+			    (qup->cmsg == (qup->num - 1))) {
 				if (!(status & I2C_STATUS_BUS_ACTIVE))
 					return 0;
 			} else {
@@ -301,12 +308,14 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	if (total < qup->out_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
-		writel(total, qup->base + QUP_MX_WRITE_CNT);
+		writel(total | qup->blk.config_run,
+		       qup->base + QUP_MX_WRITE_CNT);
 	} else {
 		/* BLOCK mode (transfer data on chunks) */
 		writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
 		       qup->base + QUP_IO_MODE);
-		writel(total, qup->base + QUP_MX_OUTPUT_CNT);
+		writel(total | qup->blk.config_run,
+		       qup->base + QUP_MX_OUTPUT_CNT);
 	}
 }
 
@@ -374,6 +383,9 @@ static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
 	/* There are 2 tag bytes that are read in to fifo for every block */
 	if (msg->flags & I2C_M_RD)
 		qup->blk.rx_tag_len = qup->blk.count * 2;
+
+	if (qup->cmsg)
+		qup->blk.config_run = QUP_I2C_MX_CONFIG_DURING_RUN;
 }
 
 static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf,
@@ -440,7 +452,8 @@ static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
 	}
 
 	/* Send _STOP commands for the last block */
-	if (qup->blk.pos == (qup->blk.count - 1)) {
+	if (qup->blk.pos == (qup->blk.count - 1)
+	    && (qup->cmsg == (qup->num - 1))) {
 		if (msg->flags & I2C_M_RD)
 			tags[len++] = QUP_TAG_V2_DATARD_STOP;
 		else
@@ -571,7 +584,6 @@ static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		goto err;
 
 	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
-
 err:
 	disable_irq(qup->irq);
 	qup->msg = NULL;
@@ -584,18 +596,19 @@ static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 	int tx_len = qup->blk.tx_tag_len;
 
 	len += qup->blk.rx_tag_len;
+	tx_len |= qup->blk.config_run;
 
 	if (len < qup->in_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
-		writel(len, qup->base + QUP_MX_READ_CNT);
 		writel(tx_len, qup->base + QUP_MX_WRITE_CNT);
+		writel(len | qup->blk.config_run, qup->base + QUP_MX_READ_CNT);
 	} else {
 		/* BLOCK mode (transfer data on chunks) */
 		writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
 		       qup->base + QUP_IO_MODE);
-		writel(len, qup->base + QUP_MX_INPUT_CNT);
 		writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT);
+		writel(len | qup->blk.config_run, qup->base + QUP_MX_INPUT_CNT);
 	}
 }
 
@@ -770,6 +783,8 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
 	int ret, idx;
 
+	qup->num = 1;
+
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
 		goto out;
@@ -823,6 +838,9 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
 	int ret, idx;
 
+	qup->num = num;
+	qup->cmsg = 0;
+
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
 		goto out;
@@ -854,13 +872,15 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 		else
 			ret = qup_i2c_write(qup, &msgs[idx]);
 
-		if (!ret)
-			ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
-
 		if (ret)
 			break;
+
+		qup->cmsg++;
 	}
 
+	if (!ret)
+		ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
+
 	if (ret == 0)
 		ret = num;
 out:
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
@ 2015-07-09  3:25     ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: linux-arm-kernel

The definition of i2c_msg says that

"If this is the last message in a group, it is followed by a STOP.
Otherwise it is followed by the next @i2c_msg transaction segment,
beginning with a (repeated) START"

So the expectation is that there is no 'STOP' bit inbetween individual
i2c_msg segments with repeated 'START'. The QUP i2c hardware has no way
to inform that there should not be a 'STOP' at the end of transaction.
The only way to implement this is to coalesce all the i2c_msg in i2c_msgs
in to one transaction and transfer them. Adding the support for the same.

This is required for some clients like touchscreen which keeps
incrementing counts across individual transfers and 'STOP' bit inbetween
resets the counter, which is not required.

This patch adds the support in non-dma mode.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 40 ++++++++++++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index a4e20d9..c0757d9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -113,6 +113,7 @@
 #define SET_BIT				0x1
 #define RESET_BIT			0x0
 #define ONE_BYTE			0x1
+#define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
 
 struct qup_i2c_block {
 	int	count;
@@ -121,6 +122,7 @@ struct qup_i2c_block {
 	int	rx_tag_len;
 	int	data_len;
 	u8	tags[6];
+	int     config_run;
 };
 
 struct qup_i2c_dev {
@@ -152,6 +154,10 @@ struct qup_i2c_dev {
 
 	int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
 				 struct i2c_msg *msg);
+	/* Current i2c_msg in i2c_msgs */
+	int			cmsg;
+	/* total num of i2c_msgs */
+	int			num;
 
 	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
 				struct i2c_msg *msg);
@@ -278,7 +284,8 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
 		status = readl(qup->base + QUP_I2C_STATUS);
 
 		if (((opflags & op) >> shift) == val) {
-			if (op == QUP_OUT_NOT_EMPTY) {
+			if ((op == QUP_OUT_NOT_EMPTY) &&
+			    (qup->cmsg == (qup->num - 1))) {
 				if (!(status & I2C_STATUS_BUS_ACTIVE))
 					return 0;
 			} else {
@@ -301,12 +308,14 @@ static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	if (total < qup->out_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
-		writel(total, qup->base + QUP_MX_WRITE_CNT);
+		writel(total | qup->blk.config_run,
+		       qup->base + QUP_MX_WRITE_CNT);
 	} else {
 		/* BLOCK mode (transfer data on chunks) */
 		writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
 		       qup->base + QUP_IO_MODE);
-		writel(total, qup->base + QUP_MX_OUTPUT_CNT);
+		writel(total | qup->blk.config_run,
+		       qup->base + QUP_MX_OUTPUT_CNT);
 	}
 }
 
@@ -374,6 +383,9 @@ static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
 	/* There are 2 tag bytes that are read in to fifo for every block */
 	if (msg->flags & I2C_M_RD)
 		qup->blk.rx_tag_len = qup->blk.count * 2;
+
+	if (qup->cmsg)
+		qup->blk.config_run = QUP_I2C_MX_CONFIG_DURING_RUN;
 }
 
 static int qup_i2c_send_data(struct qup_i2c_dev *qup, int tlen, u8 *tbuf,
@@ -440,7 +452,8 @@ static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
 	}
 
 	/* Send _STOP commands for the last block */
-	if (qup->blk.pos == (qup->blk.count - 1)) {
+	if (qup->blk.pos == (qup->blk.count - 1)
+	    && (qup->cmsg == (qup->num - 1))) {
 		if (msg->flags & I2C_M_RD)
 			tags[len++] = QUP_TAG_V2_DATARD_STOP;
 		else
@@ -571,7 +584,6 @@ static int qup_i2c_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		goto err;
 
 	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, RESET_BIT, ONE_BYTE);
-
 err:
 	disable_irq(qup->irq);
 	qup->msg = NULL;
@@ -584,18 +596,19 @@ static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 	int tx_len = qup->blk.tx_tag_len;
 
 	len += qup->blk.rx_tag_len;
+	tx_len |= qup->blk.config_run;
 
 	if (len < qup->in_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
-		writel(len, qup->base + QUP_MX_READ_CNT);
 		writel(tx_len, qup->base + QUP_MX_WRITE_CNT);
+		writel(len | qup->blk.config_run, qup->base + QUP_MX_READ_CNT);
 	} else {
 		/* BLOCK mode (transfer data on chunks) */
 		writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
 		       qup->base + QUP_IO_MODE);
-		writel(len, qup->base + QUP_MX_INPUT_CNT);
 		writel(tx_len, qup->base + QUP_MX_OUTPUT_CNT);
+		writel(len | qup->blk.config_run, qup->base + QUP_MX_INPUT_CNT);
 	}
 }
 
@@ -770,6 +783,8 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
 	int ret, idx;
 
+	qup->num = 1;
+
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
 		goto out;
@@ -823,6 +838,9 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
 	int ret, idx;
 
+	qup->num = num;
+	qup->cmsg = 0;
+
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
 		goto out;
@@ -854,13 +872,15 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 		else
 			ret = qup_i2c_write(qup, &msgs[idx]);
 
-		if (!ret)
-			ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
-
 		if (ret)
 			break;
+
+		qup->cmsg++;
 	}
 
+	if (!ret)
+		ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
+
 	if (ret == 0)
 		ret = num;
 out:
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
  2015-07-09  3:25 ` Sricharan R
  (?)
@ 2015-07-09  3:25     ` Sricharan R
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov-NEYub+7Iv8PQT0dZR+AlfA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, agross-sgV2jX0FEOL9JmXXK+q4OQ,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: sricharan-sgV2jX0FEOL9JmXXK+q4OQ

QUP cores can be attached to a BAM module, which acts as a dma engine for the
QUP core. When DMA with BAM is enabled, the BAM consumer pipe transmitted data
is written to the output FIFO and the BAM producer pipe received data is read
from the input FIFO.

With BAM capabilities, qup-i2c core can transfer more than 256 bytes, without a
'stop' which is not possible otherwise.

Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
 drivers/i2c/busses/i2c-qup.c | 431 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 415 insertions(+), 16 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index c0757d9..810b021 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -24,6 +24,11 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/atomic.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
 
 /* QUP Registers */
 #define QUP_CONFIG		0x000
@@ -33,6 +38,7 @@
 #define QUP_OPERATIONAL		0x018
 #define QUP_ERROR_FLAGS		0x01c
 #define QUP_ERROR_FLAGS_EN	0x020
+#define QUP_OPERATIONAL_MASK	0x028
 #define QUP_HW_VERSION		0x030
 #define QUP_MX_OUTPUT_CNT	0x100
 #define QUP_OUT_FIFO_BASE	0x110
@@ -53,6 +59,7 @@
 
 #define QUP_STATE_VALID		BIT(2)
 #define QUP_I2C_MAST_GEN	BIT(4)
+#define QUP_I2C_FLUSH		BIT(6)
 
 #define QUP_OPERATIONAL_RESET	0x000ff0
 #define QUP_I2C_STATUS_RESET	0xfffffc
@@ -78,7 +85,10 @@
 
 /* Packing/Unpacking words in FIFOs, and IO modes */
 #define QUP_OUTPUT_BLK_MODE	(1 << 10)
+#define QUP_OUTPUT_BAM_MODE	(3 << 10)
 #define QUP_INPUT_BLK_MODE	(1 << 12)
+#define QUP_INPUT_BAM_MODE	(3 << 12)
+#define QUP_BAM_MODE		(QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE)
 #define QUP_UNPACK_EN		BIT(14)
 #define QUP_PACK_EN		BIT(15)
 
@@ -95,6 +105,8 @@
 #define QUP_TAG_DATA		(2 << 8)
 #define QUP_TAG_STOP		(3 << 8)
 #define QUP_TAG_REC		(4 << 8)
+#define QUP_BAM_INPUT_EOT		0x93
+#define QUP_BAM_FLUSH_STOP		0x96
 
 /* QUP v2 tags */
 #define QUP_TAG_V2_START               0x81
@@ -115,6 +127,12 @@
 #define ONE_BYTE			0x1
 #define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
 
+#define MX_TX_RX_LEN			SZ_64K
+#define MX_BLOCKS			(MX_TX_RX_LEN / QUP_READ_LIMIT)
+
+/* Max timeout in ms for 32k bytes */
+#define TOUT_MAX			300
+
 struct qup_i2c_block {
 	int	count;
 	int	pos;
@@ -125,6 +143,23 @@ struct qup_i2c_block {
 	int     config_run;
 };
 
+struct qup_i2c_tag {
+	u8 *start;
+	dma_addr_t addr;
+};
+
+struct qup_i2c_bam_rx {
+	struct	qup_i2c_tag scratch_tag;
+	struct	dma_chan *dma_rx;
+	struct	scatterlist *sg_rx;
+};
+
+struct qup_i2c_bam_tx {
+	struct	qup_i2c_tag footer_tag;
+	struct	dma_chan *dma_tx;
+	struct	scatterlist *sg_tx;
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -154,14 +189,20 @@ struct qup_i2c_dev {
 
 	int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
 				 struct i2c_msg *msg);
+	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
+				struct i2c_msg *msg);
+
 	/* Current i2c_msg in i2c_msgs */
 	int			cmsg;
 	/* total num of i2c_msgs */
 	int			num;
 
-	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
-				struct i2c_msg *msg);
-
+	/* dma parameters */
+	bool			is_dma;
+	struct			dma_pool *dpool;
+	struct			qup_i2c_tag start_tag;
+	struct			qup_i2c_bam_rx brx;
+	struct			qup_i2c_bam_tx btx;
 	struct completion	xfer;
 };
 
@@ -238,6 +279,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state)
 	return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK);
 }
 
+static void qup_i2c_flush(struct qup_i2c_dev *qup)
+{
+	u32 val = readl(qup->base + QUP_STATE);
+
+	val |= QUP_I2C_FLUSH;
+	writel(val, qup->base + QUP_STATE);
+}
+
 static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup)
 {
 	return qup_i2c_poll_state_mask(qup, 0, 0);
@@ -437,12 +486,15 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
 }
 
 static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
-			    struct i2c_msg *msg)
+			    struct i2c_msg *msg, int is_dma)
 {
 	u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
 	int len = 0;
 	int data_len;
 
+	int last = (qup->blk.pos == (qup->blk.count - 1)) &&
+		    (qup->cmsg == (qup->num - 1));
+
 	if (qup->blk.pos == 0) {
 		tags[len++] = QUP_TAG_V2_START;
 		tags[len++] = addr & 0xff;
@@ -452,8 +504,7 @@ static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
 	}
 
 	/* Send _STOP commands for the last block */
-	if (qup->blk.pos == (qup->blk.count - 1)
-	    && (qup->cmsg == (qup->num - 1))) {
+	if (last) {
 		if (msg->flags & I2C_M_RD)
 			tags[len++] = QUP_TAG_V2_DATARD_STOP;
 		else
@@ -473,6 +524,11 @@ static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
 	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;
+	}
+
 	return len;
 }
 
@@ -481,7 +537,7 @@ static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	int data_len = 0, tag_len, index;
 	int ret;
 
-	tag_len = qup_i2c_get_tags(qup->blk.tags, qup, msg);
+	tag_len = qup_i2c_get_tags(qup->blk.tags, qup, msg, 0);
 	index = msg->len - qup->blk.data_len;
 
 	/* only tags are written for read */
@@ -776,6 +832,257 @@ err:
 	return ret;
 }
 
+static void qup_i2c_bam_cb(void *data)
+{
+	struct qup_i2c_dev *qup = data;
+
+	complete(&qup->xfer);
+}
+
+void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct qup_i2c_tag *tg,
+		    unsigned int buflen, struct qup_i2c_dev *qup,
+		    int map, int dir)
+{
+	sg_set_buf(sg, buf, buflen);
+	dma_map_sg(qup->dev, sg, 1, dir);
+
+	if (!map)
+		sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start);
+}
+
+static void qup_i2c_rel_dma(struct qup_i2c_dev *qup)
+{
+	if (qup->btx.dma_tx)
+		dma_release_channel(qup->btx.dma_tx);
+	if (qup->brx.dma_rx)
+		dma_release_channel(qup->brx.dma_rx);
+	qup->btx.dma_tx = NULL;
+	qup->brx.dma_rx = NULL;
+}
+
+static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
+{
+	if (!qup->btx.dma_tx) {
+		qup->btx.dma_tx = dma_request_slave_channel(qup->dev, "tx");
+		if (!qup->btx.dma_tx) {
+			dev_err(qup->dev, "\n tx channel not available");
+			return -ENODEV;
+		}
+	}
+
+	if (!qup->brx.dma_rx) {
+		qup->brx.dma_rx = dma_request_slave_channel(qup->dev, "rx");
+		if (!qup->brx.dma_rx) {
+			dev_err(qup->dev, "\n rx channel not available");
+			qup_i2c_rel_dma(qup);
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	struct dma_async_tx_descriptor *txd, *rxd = NULL;
+	int ret = 0;
+	dma_cookie_t cookie_rx, cookie_tx;
+	u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
+	u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
+	u8 *tags;
+
+	while (qup->cmsg < qup->num) {
+		blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
+		rem = msg->len % QUP_READ_LIMIT;
+		tx_len = 0, len = 0, i = 0;
+
+		qup_i2c_get_blk_data(qup, msg);
+
+		if (msg->flags & I2C_M_RD) {
+			rx_nents += (blocks * 2) + 1;
+			tx_nents += 1;
+
+			while (qup->blk.pos < blocks) {
+				/* length set to '0' implies 256 bytes */
+				tlen = (i == (blocks - 1)) ? rem : 0;
+				tags = &qup->start_tag.start[off + len];
+				len += qup_i2c_get_tags(tags, qup, msg, 1);
+
+				/* scratch buf to read the start and len tags */
+				qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
+					       &qup->brx.scratch_tag.start[0],
+					       &qup->brx.scratch_tag,
+					       2, qup, 0, 0);
+
+				qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
+					       &msg->buf[QUP_READ_LIMIT * i],
+					       NULL, tlen, qup,
+					       1, DMA_FROM_DEVICE);
+				i++;
+				qup->blk.pos = i;
+			}
+			qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+				       &qup->start_tag.start[off],
+				       &qup->start_tag, len, qup, 0, 0);
+			off += len;
+			/* scratch buf to read the BAM EOT and FLUSH tags */
+			qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
+				       &qup->brx.scratch_tag.start[0],
+				       &qup->brx.scratch_tag, 2,
+				       qup, 0, 0);
+		} else {
+			tx_nents += (blocks * 2);
+
+			while (qup->blk.pos < blocks) {
+				tlen = (i == (blocks - 1)) ? rem : 0;
+				tags = &qup->start_tag.start[off + tx_len];
+				len = qup_i2c_get_tags(tags, qup, msg, 1);
+
+				qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+					       tags,
+					       &qup->start_tag, len,
+					       qup, 0, 0);
+
+				tx_len += len;
+				qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+					       &msg->buf[QUP_READ_LIMIT * i],
+					       NULL, tlen, qup, 1,
+					       DMA_TO_DEVICE);
+				i++;
+				qup->blk.pos = i;
+			}
+			off += tx_len;
+
+			if (qup->cmsg == (qup->num - 1)) {
+				qup->btx.footer_tag.start[0] =
+							  QUP_BAM_FLUSH_STOP;
+				qup->btx.footer_tag.start[1] =
+							  QUP_BAM_FLUSH_STOP;
+				qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+					       &qup->btx.footer_tag.start[0],
+					       &qup->btx.footer_tag, 2,
+					       qup, 0, 0);
+				tx_nents += 1;
+			}
+		}
+		qup->cmsg++;
+		msg++;
+	}
+
+	txd = dmaengine_prep_slave_sg(qup->btx.dma_tx, qup->btx.sg_tx, tx_nents,
+				      DMA_MEM_TO_DEV,
+				      DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
+	if (!txd) {
+		dev_err(qup->dev, "failed to get tx desc\n");
+		ret = -EINVAL;
+		goto desc_err;
+	}
+
+	if (!rx_nents) {
+		txd->callback = qup_i2c_bam_cb;
+		txd->callback_param = qup;
+	}
+
+	cookie_tx = dmaengine_submit(txd);
+	dma_async_issue_pending(qup->btx.dma_tx);
+
+	if (rx_nents) {
+		rxd = dmaengine_prep_slave_sg(qup->brx.dma_rx, qup->brx.sg_rx,
+					      rx_nents, DMA_DEV_TO_MEM,
+					      DMA_PREP_INTERRUPT);
+		if (!rxd) {
+			dev_err(qup->dev, "failed to get rx desc\n");
+			ret = -EINVAL;
+
+			/* abort TX descriptors */
+			dmaengine_terminate_all(qup->btx.dma_tx);
+			goto desc_err;
+		}
+
+		rxd->callback = qup_i2c_bam_cb;
+		rxd->callback_param = qup;
+		cookie_rx = dmaengine_submit(rxd);
+		dma_async_issue_pending(qup->brx.dma_rx);
+	}
+
+	if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
+		dev_err(qup->dev, "normal trans timed out\n");
+		ret = -ETIMEDOUT;
+	}
+
+	if (ret || qup->bus_err || qup->qup_err) {
+		if (qup->bus_err & QUP_I2C_NACK_FLAG) {
+			msg--;
+			dev_err(qup->dev, "NACK from %x\n", msg->addr);
+			ret = -EIO;
+
+			if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
+				dev_err(qup->dev, "change to run state timed out");
+				return ret;
+			}
+
+			if (rx_nents)
+				writel(QUP_BAM_INPUT_EOT,
+				       qup->base + QUP_OUT_FIFO_BASE);
+
+			writel(QUP_BAM_FLUSH_STOP,
+			       qup->base + QUP_OUT_FIFO_BASE);
+
+			qup_i2c_flush(qup);
+
+			/* wait for remaining interrupts to occur */
+			if (!wait_for_completion_timeout(&qup->xfer, HZ))
+				dev_err(qup->dev, "flush timed out\n");
+
+			qup_i2c_rel_dma(qup);
+		}
+	}
+
+	dma_unmap_sg(qup->dev, qup->btx.sg_tx, tx_nents, DMA_TO_DEVICE);
+
+	if (rx_nents)
+		dma_unmap_sg(qup->dev, qup->brx.sg_rx, rx_nents,
+			     DMA_FROM_DEVICE);
+desc_err:
+	return ret;
+}
+
+static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg)
+{
+	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
+	int ret = 0;
+
+	enable_irq(qup->irq);
+	if (qup_i2c_req_dma(qup))
+		goto out;
+
+	qup->bus_err = 0;
+	qup->qup_err = 0;
+
+	writel(0, qup->base + QUP_MX_INPUT_CNT);
+	writel(0, qup->base + QUP_MX_OUTPUT_CNT);
+
+	/* set BAM mode */
+	writel(QUP_REPACK_EN | QUP_BAM_MODE, qup->base + QUP_IO_MODE);
+
+	/* mask fifo irqs */
+	writel((0x3 << 8), qup->base + QUP_OPERATIONAL_MASK);
+
+	/* set RUN STATE */
+	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+	if (ret)
+		goto out;
+
+	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+	qup->msg = msg;
+	ret = bam_do_xfer(qup, qup->msg);
+out:
+	disable_irq(qup->irq);
+
+	qup->msg = NULL;
+	return ret;
+}
+
 static int qup_i2c_xfer(struct i2c_adapter *adap,
 			struct i2c_msg msgs[],
 			int num)
@@ -836,7 +1143,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 			   int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
-	int ret, idx;
+	int ret, idx, len, use_dma  = 0;
 
 	qup->num = num;
 	qup->cmsg = 0;
@@ -854,12 +1161,27 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 	writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
 	writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
 
-	for (idx = 0; idx < num; idx++) {
-		if (msgs[idx].len == 0) {
-			ret = -EINVAL;
-			goto out;
+	if ((qup->is_dma)) {
+		/* All i2c_msgs should be transferred using either dma or cpu */
+		for (idx = 0; idx < num; idx++) {
+			if (msgs[idx].len == 0) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			len = (msgs[idx].len > qup->out_fifo_sz) ||
+			      (msgs[idx].len > qup->in_fifo_sz);
+
+			if ((!is_vmalloc_addr(msgs[idx].buf)) && len) {
+				use_dma = 1;
+			 } else {
+				use_dma = 0;
+				break;
+			}
 		}
+	}
 
+	for (idx = 0; idx < num; idx++) {
 		if (qup_i2c_poll_state_i2c_master(qup)) {
 			ret = -EIO;
 			goto out;
@@ -867,10 +1189,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 
 		reinit_completion(&qup->xfer);
 
-		if (msgs[idx].flags & I2C_M_RD)
-			ret = qup_i2c_read(qup, &msgs[idx]);
-		else
-			ret = qup_i2c_write(qup, &msgs[idx]);
+		len = msgs[idx].len;
+
+		if (use_dma) {
+			ret = qup_bam_xfer(adap, &msgs[idx]);
+			idx = num;
+		} else {
+			if (msgs[idx].flags & I2C_M_RD)
+				ret = qup_i2c_read(qup, &msgs[idx]);
+			else
+				ret = qup_i2c_write(qup, &msgs[idx]);
+		}
 
 		if (ret)
 			break;
@@ -943,6 +1272,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	int ret, fs_div, hs_div;
 	int src_clk_freq;
 	u32 clk_freq = 100000;
+	int blocks;
 
 	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
 	if (!qup)
@@ -963,8 +1293,60 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		qup->qup_i2c_write_one = qup_i2c_write_one_v2;
 		qup->qup_i2c_read_one = qup_i2c_read_one_v2;
 		qup->use_v2_tags = 1;
+
+		if (qup_i2c_req_dma(qup))
+			goto nodma;
+
+		blocks = (MX_BLOCKS << 1) + 1;
+		qup->btx.sg_tx = devm_kzalloc(&pdev->dev,
+					      sizeof(*qup->btx.sg_tx) * blocks,
+					      GFP_KERNEL);
+		if (!qup->btx.sg_tx) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		sg_init_table(qup->btx.sg_tx, blocks);
+
+		qup->brx.sg_rx = devm_kzalloc(&pdev->dev,
+					      sizeof(*qup->btx.sg_tx) * blocks,
+					      GFP_KERNEL);
+		if (!qup->brx.sg_rx) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		sg_init_table(qup->brx.sg_rx, blocks);
+
+		/* 2 tag bytes for each block + 5 for start, stop tags */
+		size = blocks * 2 + 5;
+		qup->dpool = dma_pool_create("qup_i2c-dma-pool", &pdev->dev,
+					     size, 4, 0);
+
+		qup->start_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
+						      &qup->start_tag.addr);
+		if (!qup->start_tag.start) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		qup->brx.scratch_tag.start = dma_pool_alloc(qup->dpool,
+							    GFP_KERNEL,
+						&qup->brx.scratch_tag.addr);
+		if (!qup->brx.scratch_tag.start) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		qup->btx.footer_tag.start = dma_pool_alloc(qup->dpool,
+							   GFP_KERNEL,
+						&qup->btx.footer_tag.addr);
+		if (!qup->btx.footer_tag.start) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		qup->is_dma = 1;
 	}
 
+nodma:
 	/* We support frequencies up to FAST Mode (400KHz) */
 	if (!clk_freq || clk_freq > 400000) {
 		dev_err(qup->dev, "clock frequency not supported %d\n",
@@ -1080,6 +1462,11 @@ fail_runtime:
 	pm_runtime_disable(qup->dev);
 	pm_runtime_set_suspended(qup->dev);
 fail:
+	if (qup->btx.dma_tx)
+		dma_release_channel(qup->btx.dma_tx);
+	if (qup->brx.dma_rx)
+		dma_release_channel(qup->brx.dma_rx);
+
 	qup_i2c_disable_clocks(qup);
 	return ret;
 }
@@ -1088,6 +1475,18 @@ static int qup_i2c_remove(struct platform_device *pdev)
 {
 	struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
 
+	if (qup->is_dma) {
+		dma_pool_free(qup->dpool, qup->start_tag.start,
+			      qup->start_tag.addr);
+		dma_pool_free(qup->dpool, qup->brx.scratch_tag.start,
+			      qup->brx.scratch_tag.addr);
+		dma_pool_free(qup->dpool, qup->btx.footer_tag.start,
+			      qup->btx.footer_tag.addr);
+		dma_pool_destroy(qup->dpool);
+		dma_release_channel(qup->btx.dma_tx);
+		dma_release_channel(qup->brx.dma_rx);
+	}
+
 	disable_irq(qup->irq);
 	qup_i2c_disable_clocks(qup);
 	i2c_del_adapter(&qup->adap);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
@ 2015-07-09  3:25     ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov, devicetree, linux-arm-msm, galak, linux-kernel,
	linux-i2c, agross, dmaengine, linux-arm-kernel
  Cc: sricharan

QUP cores can be attached to a BAM module, which acts as a dma engine for the
QUP core. When DMA with BAM is enabled, the BAM consumer pipe transmitted data
is written to the output FIFO and the BAM producer pipe received data is read
from the input FIFO.

With BAM capabilities, qup-i2c core can transfer more than 256 bytes, without a
'stop' which is not possible otherwise.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 431 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 415 insertions(+), 16 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index c0757d9..810b021 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -24,6 +24,11 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/atomic.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
 
 /* QUP Registers */
 #define QUP_CONFIG		0x000
@@ -33,6 +38,7 @@
 #define QUP_OPERATIONAL		0x018
 #define QUP_ERROR_FLAGS		0x01c
 #define QUP_ERROR_FLAGS_EN	0x020
+#define QUP_OPERATIONAL_MASK	0x028
 #define QUP_HW_VERSION		0x030
 #define QUP_MX_OUTPUT_CNT	0x100
 #define QUP_OUT_FIFO_BASE	0x110
@@ -53,6 +59,7 @@
 
 #define QUP_STATE_VALID		BIT(2)
 #define QUP_I2C_MAST_GEN	BIT(4)
+#define QUP_I2C_FLUSH		BIT(6)
 
 #define QUP_OPERATIONAL_RESET	0x000ff0
 #define QUP_I2C_STATUS_RESET	0xfffffc
@@ -78,7 +85,10 @@
 
 /* Packing/Unpacking words in FIFOs, and IO modes */
 #define QUP_OUTPUT_BLK_MODE	(1 << 10)
+#define QUP_OUTPUT_BAM_MODE	(3 << 10)
 #define QUP_INPUT_BLK_MODE	(1 << 12)
+#define QUP_INPUT_BAM_MODE	(3 << 12)
+#define QUP_BAM_MODE		(QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE)
 #define QUP_UNPACK_EN		BIT(14)
 #define QUP_PACK_EN		BIT(15)
 
@@ -95,6 +105,8 @@
 #define QUP_TAG_DATA		(2 << 8)
 #define QUP_TAG_STOP		(3 << 8)
 #define QUP_TAG_REC		(4 << 8)
+#define QUP_BAM_INPUT_EOT		0x93
+#define QUP_BAM_FLUSH_STOP		0x96
 
 /* QUP v2 tags */
 #define QUP_TAG_V2_START               0x81
@@ -115,6 +127,12 @@
 #define ONE_BYTE			0x1
 #define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
 
+#define MX_TX_RX_LEN			SZ_64K
+#define MX_BLOCKS			(MX_TX_RX_LEN / QUP_READ_LIMIT)
+
+/* Max timeout in ms for 32k bytes */
+#define TOUT_MAX			300
+
 struct qup_i2c_block {
 	int	count;
 	int	pos;
@@ -125,6 +143,23 @@ struct qup_i2c_block {
 	int     config_run;
 };
 
+struct qup_i2c_tag {
+	u8 *start;
+	dma_addr_t addr;
+};
+
+struct qup_i2c_bam_rx {
+	struct	qup_i2c_tag scratch_tag;
+	struct	dma_chan *dma_rx;
+	struct	scatterlist *sg_rx;
+};
+
+struct qup_i2c_bam_tx {
+	struct	qup_i2c_tag footer_tag;
+	struct	dma_chan *dma_tx;
+	struct	scatterlist *sg_tx;
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -154,14 +189,20 @@ struct qup_i2c_dev {
 
 	int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
 				 struct i2c_msg *msg);
+	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
+				struct i2c_msg *msg);
+
 	/* Current i2c_msg in i2c_msgs */
 	int			cmsg;
 	/* total num of i2c_msgs */
 	int			num;
 
-	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
-				struct i2c_msg *msg);
-
+	/* dma parameters */
+	bool			is_dma;
+	struct			dma_pool *dpool;
+	struct			qup_i2c_tag start_tag;
+	struct			qup_i2c_bam_rx brx;
+	struct			qup_i2c_bam_tx btx;
 	struct completion	xfer;
 };
 
@@ -238,6 +279,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state)
 	return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK);
 }
 
+static void qup_i2c_flush(struct qup_i2c_dev *qup)
+{
+	u32 val = readl(qup->base + QUP_STATE);
+
+	val |= QUP_I2C_FLUSH;
+	writel(val, qup->base + QUP_STATE);
+}
+
 static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup)
 {
 	return qup_i2c_poll_state_mask(qup, 0, 0);
@@ -437,12 +486,15 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
 }
 
 static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
-			    struct i2c_msg *msg)
+			    struct i2c_msg *msg, int is_dma)
 {
 	u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
 	int len = 0;
 	int data_len;
 
+	int last = (qup->blk.pos == (qup->blk.count - 1)) &&
+		    (qup->cmsg == (qup->num - 1));
+
 	if (qup->blk.pos == 0) {
 		tags[len++] = QUP_TAG_V2_START;
 		tags[len++] = addr & 0xff;
@@ -452,8 +504,7 @@ static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
 	}
 
 	/* Send _STOP commands for the last block */
-	if (qup->blk.pos == (qup->blk.count - 1)
-	    && (qup->cmsg == (qup->num - 1))) {
+	if (last) {
 		if (msg->flags & I2C_M_RD)
 			tags[len++] = QUP_TAG_V2_DATARD_STOP;
 		else
@@ -473,6 +524,11 @@ static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
 	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;
+	}
+
 	return len;
 }
 
@@ -481,7 +537,7 @@ static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	int data_len = 0, tag_len, index;
 	int ret;
 
-	tag_len = qup_i2c_get_tags(qup->blk.tags, qup, msg);
+	tag_len = qup_i2c_get_tags(qup->blk.tags, qup, msg, 0);
 	index = msg->len - qup->blk.data_len;
 
 	/* only tags are written for read */
@@ -776,6 +832,257 @@ err:
 	return ret;
 }
 
+static void qup_i2c_bam_cb(void *data)
+{
+	struct qup_i2c_dev *qup = data;
+
+	complete(&qup->xfer);
+}
+
+void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct qup_i2c_tag *tg,
+		    unsigned int buflen, struct qup_i2c_dev *qup,
+		    int map, int dir)
+{
+	sg_set_buf(sg, buf, buflen);
+	dma_map_sg(qup->dev, sg, 1, dir);
+
+	if (!map)
+		sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start);
+}
+
+static void qup_i2c_rel_dma(struct qup_i2c_dev *qup)
+{
+	if (qup->btx.dma_tx)
+		dma_release_channel(qup->btx.dma_tx);
+	if (qup->brx.dma_rx)
+		dma_release_channel(qup->brx.dma_rx);
+	qup->btx.dma_tx = NULL;
+	qup->brx.dma_rx = NULL;
+}
+
+static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
+{
+	if (!qup->btx.dma_tx) {
+		qup->btx.dma_tx = dma_request_slave_channel(qup->dev, "tx");
+		if (!qup->btx.dma_tx) {
+			dev_err(qup->dev, "\n tx channel not available");
+			return -ENODEV;
+		}
+	}
+
+	if (!qup->brx.dma_rx) {
+		qup->brx.dma_rx = dma_request_slave_channel(qup->dev, "rx");
+		if (!qup->brx.dma_rx) {
+			dev_err(qup->dev, "\n rx channel not available");
+			qup_i2c_rel_dma(qup);
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	struct dma_async_tx_descriptor *txd, *rxd = NULL;
+	int ret = 0;
+	dma_cookie_t cookie_rx, cookie_tx;
+	u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
+	u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
+	u8 *tags;
+
+	while (qup->cmsg < qup->num) {
+		blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
+		rem = msg->len % QUP_READ_LIMIT;
+		tx_len = 0, len = 0, i = 0;
+
+		qup_i2c_get_blk_data(qup, msg);
+
+		if (msg->flags & I2C_M_RD) {
+			rx_nents += (blocks * 2) + 1;
+			tx_nents += 1;
+
+			while (qup->blk.pos < blocks) {
+				/* length set to '0' implies 256 bytes */
+				tlen = (i == (blocks - 1)) ? rem : 0;
+				tags = &qup->start_tag.start[off + len];
+				len += qup_i2c_get_tags(tags, qup, msg, 1);
+
+				/* scratch buf to read the start and len tags */
+				qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
+					       &qup->brx.scratch_tag.start[0],
+					       &qup->brx.scratch_tag,
+					       2, qup, 0, 0);
+
+				qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
+					       &msg->buf[QUP_READ_LIMIT * i],
+					       NULL, tlen, qup,
+					       1, DMA_FROM_DEVICE);
+				i++;
+				qup->blk.pos = i;
+			}
+			qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+				       &qup->start_tag.start[off],
+				       &qup->start_tag, len, qup, 0, 0);
+			off += len;
+			/* scratch buf to read the BAM EOT and FLUSH tags */
+			qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
+				       &qup->brx.scratch_tag.start[0],
+				       &qup->brx.scratch_tag, 2,
+				       qup, 0, 0);
+		} else {
+			tx_nents += (blocks * 2);
+
+			while (qup->blk.pos < blocks) {
+				tlen = (i == (blocks - 1)) ? rem : 0;
+				tags = &qup->start_tag.start[off + tx_len];
+				len = qup_i2c_get_tags(tags, qup, msg, 1);
+
+				qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+					       tags,
+					       &qup->start_tag, len,
+					       qup, 0, 0);
+
+				tx_len += len;
+				qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+					       &msg->buf[QUP_READ_LIMIT * i],
+					       NULL, tlen, qup, 1,
+					       DMA_TO_DEVICE);
+				i++;
+				qup->blk.pos = i;
+			}
+			off += tx_len;
+
+			if (qup->cmsg == (qup->num - 1)) {
+				qup->btx.footer_tag.start[0] =
+							  QUP_BAM_FLUSH_STOP;
+				qup->btx.footer_tag.start[1] =
+							  QUP_BAM_FLUSH_STOP;
+				qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+					       &qup->btx.footer_tag.start[0],
+					       &qup->btx.footer_tag, 2,
+					       qup, 0, 0);
+				tx_nents += 1;
+			}
+		}
+		qup->cmsg++;
+		msg++;
+	}
+
+	txd = dmaengine_prep_slave_sg(qup->btx.dma_tx, qup->btx.sg_tx, tx_nents,
+				      DMA_MEM_TO_DEV,
+				      DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
+	if (!txd) {
+		dev_err(qup->dev, "failed to get tx desc\n");
+		ret = -EINVAL;
+		goto desc_err;
+	}
+
+	if (!rx_nents) {
+		txd->callback = qup_i2c_bam_cb;
+		txd->callback_param = qup;
+	}
+
+	cookie_tx = dmaengine_submit(txd);
+	dma_async_issue_pending(qup->btx.dma_tx);
+
+	if (rx_nents) {
+		rxd = dmaengine_prep_slave_sg(qup->brx.dma_rx, qup->brx.sg_rx,
+					      rx_nents, DMA_DEV_TO_MEM,
+					      DMA_PREP_INTERRUPT);
+		if (!rxd) {
+			dev_err(qup->dev, "failed to get rx desc\n");
+			ret = -EINVAL;
+
+			/* abort TX descriptors */
+			dmaengine_terminate_all(qup->btx.dma_tx);
+			goto desc_err;
+		}
+
+		rxd->callback = qup_i2c_bam_cb;
+		rxd->callback_param = qup;
+		cookie_rx = dmaengine_submit(rxd);
+		dma_async_issue_pending(qup->brx.dma_rx);
+	}
+
+	if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
+		dev_err(qup->dev, "normal trans timed out\n");
+		ret = -ETIMEDOUT;
+	}
+
+	if (ret || qup->bus_err || qup->qup_err) {
+		if (qup->bus_err & QUP_I2C_NACK_FLAG) {
+			msg--;
+			dev_err(qup->dev, "NACK from %x\n", msg->addr);
+			ret = -EIO;
+
+			if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
+				dev_err(qup->dev, "change to run state timed out");
+				return ret;
+			}
+
+			if (rx_nents)
+				writel(QUP_BAM_INPUT_EOT,
+				       qup->base + QUP_OUT_FIFO_BASE);
+
+			writel(QUP_BAM_FLUSH_STOP,
+			       qup->base + QUP_OUT_FIFO_BASE);
+
+			qup_i2c_flush(qup);
+
+			/* wait for remaining interrupts to occur */
+			if (!wait_for_completion_timeout(&qup->xfer, HZ))
+				dev_err(qup->dev, "flush timed out\n");
+
+			qup_i2c_rel_dma(qup);
+		}
+	}
+
+	dma_unmap_sg(qup->dev, qup->btx.sg_tx, tx_nents, DMA_TO_DEVICE);
+
+	if (rx_nents)
+		dma_unmap_sg(qup->dev, qup->brx.sg_rx, rx_nents,
+			     DMA_FROM_DEVICE);
+desc_err:
+	return ret;
+}
+
+static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg)
+{
+	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
+	int ret = 0;
+
+	enable_irq(qup->irq);
+	if (qup_i2c_req_dma(qup))
+		goto out;
+
+	qup->bus_err = 0;
+	qup->qup_err = 0;
+
+	writel(0, qup->base + QUP_MX_INPUT_CNT);
+	writel(0, qup->base + QUP_MX_OUTPUT_CNT);
+
+	/* set BAM mode */
+	writel(QUP_REPACK_EN | QUP_BAM_MODE, qup->base + QUP_IO_MODE);
+
+	/* mask fifo irqs */
+	writel((0x3 << 8), qup->base + QUP_OPERATIONAL_MASK);
+
+	/* set RUN STATE */
+	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+	if (ret)
+		goto out;
+
+	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+	qup->msg = msg;
+	ret = bam_do_xfer(qup, qup->msg);
+out:
+	disable_irq(qup->irq);
+
+	qup->msg = NULL;
+	return ret;
+}
+
 static int qup_i2c_xfer(struct i2c_adapter *adap,
 			struct i2c_msg msgs[],
 			int num)
@@ -836,7 +1143,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 			   int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
-	int ret, idx;
+	int ret, idx, len, use_dma  = 0;
 
 	qup->num = num;
 	qup->cmsg = 0;
@@ -854,12 +1161,27 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 	writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
 	writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
 
-	for (idx = 0; idx < num; idx++) {
-		if (msgs[idx].len == 0) {
-			ret = -EINVAL;
-			goto out;
+	if ((qup->is_dma)) {
+		/* All i2c_msgs should be transferred using either dma or cpu */
+		for (idx = 0; idx < num; idx++) {
+			if (msgs[idx].len == 0) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			len = (msgs[idx].len > qup->out_fifo_sz) ||
+			      (msgs[idx].len > qup->in_fifo_sz);
+
+			if ((!is_vmalloc_addr(msgs[idx].buf)) && len) {
+				use_dma = 1;
+			 } else {
+				use_dma = 0;
+				break;
+			}
 		}
+	}
 
+	for (idx = 0; idx < num; idx++) {
 		if (qup_i2c_poll_state_i2c_master(qup)) {
 			ret = -EIO;
 			goto out;
@@ -867,10 +1189,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 
 		reinit_completion(&qup->xfer);
 
-		if (msgs[idx].flags & I2C_M_RD)
-			ret = qup_i2c_read(qup, &msgs[idx]);
-		else
-			ret = qup_i2c_write(qup, &msgs[idx]);
+		len = msgs[idx].len;
+
+		if (use_dma) {
+			ret = qup_bam_xfer(adap, &msgs[idx]);
+			idx = num;
+		} else {
+			if (msgs[idx].flags & I2C_M_RD)
+				ret = qup_i2c_read(qup, &msgs[idx]);
+			else
+				ret = qup_i2c_write(qup, &msgs[idx]);
+		}
 
 		if (ret)
 			break;
@@ -943,6 +1272,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	int ret, fs_div, hs_div;
 	int src_clk_freq;
 	u32 clk_freq = 100000;
+	int blocks;
 
 	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
 	if (!qup)
@@ -963,8 +1293,60 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		qup->qup_i2c_write_one = qup_i2c_write_one_v2;
 		qup->qup_i2c_read_one = qup_i2c_read_one_v2;
 		qup->use_v2_tags = 1;
+
+		if (qup_i2c_req_dma(qup))
+			goto nodma;
+
+		blocks = (MX_BLOCKS << 1) + 1;
+		qup->btx.sg_tx = devm_kzalloc(&pdev->dev,
+					      sizeof(*qup->btx.sg_tx) * blocks,
+					      GFP_KERNEL);
+		if (!qup->btx.sg_tx) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		sg_init_table(qup->btx.sg_tx, blocks);
+
+		qup->brx.sg_rx = devm_kzalloc(&pdev->dev,
+					      sizeof(*qup->btx.sg_tx) * blocks,
+					      GFP_KERNEL);
+		if (!qup->brx.sg_rx) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		sg_init_table(qup->brx.sg_rx, blocks);
+
+		/* 2 tag bytes for each block + 5 for start, stop tags */
+		size = blocks * 2 + 5;
+		qup->dpool = dma_pool_create("qup_i2c-dma-pool", &pdev->dev,
+					     size, 4, 0);
+
+		qup->start_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
+						      &qup->start_tag.addr);
+		if (!qup->start_tag.start) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		qup->brx.scratch_tag.start = dma_pool_alloc(qup->dpool,
+							    GFP_KERNEL,
+						&qup->brx.scratch_tag.addr);
+		if (!qup->brx.scratch_tag.start) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		qup->btx.footer_tag.start = dma_pool_alloc(qup->dpool,
+							   GFP_KERNEL,
+						&qup->btx.footer_tag.addr);
+		if (!qup->btx.footer_tag.start) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		qup->is_dma = 1;
 	}
 
+nodma:
 	/* We support frequencies up to FAST Mode (400KHz) */
 	if (!clk_freq || clk_freq > 400000) {
 		dev_err(qup->dev, "clock frequency not supported %d\n",
@@ -1080,6 +1462,11 @@ fail_runtime:
 	pm_runtime_disable(qup->dev);
 	pm_runtime_set_suspended(qup->dev);
 fail:
+	if (qup->btx.dma_tx)
+		dma_release_channel(qup->btx.dma_tx);
+	if (qup->brx.dma_rx)
+		dma_release_channel(qup->brx.dma_rx);
+
 	qup_i2c_disable_clocks(qup);
 	return ret;
 }
@@ -1088,6 +1475,18 @@ static int qup_i2c_remove(struct platform_device *pdev)
 {
 	struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
 
+	if (qup->is_dma) {
+		dma_pool_free(qup->dpool, qup->start_tag.start,
+			      qup->start_tag.addr);
+		dma_pool_free(qup->dpool, qup->brx.scratch_tag.start,
+			      qup->brx.scratch_tag.addr);
+		dma_pool_free(qup->dpool, qup->btx.footer_tag.start,
+			      qup->btx.footer_tag.addr);
+		dma_pool_destroy(qup->dpool);
+		dma_release_channel(qup->btx.dma_tx);
+		dma_release_channel(qup->brx.dma_rx);
+	}
+
 	disable_irq(qup->irq);
 	qup_i2c_disable_clocks(qup);
 	i2c_del_adapter(&qup->adap);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
@ 2015-07-09  3:25     ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: linux-arm-kernel

QUP cores can be attached to a BAM module, which acts as a dma engine for the
QUP core. When DMA with BAM is enabled, the BAM consumer pipe transmitted data
is written to the output FIFO and the BAM producer pipe received data is read
from the input FIFO.

With BAM capabilities, qup-i2c core can transfer more than 256 bytes, without a
'stop' which is not possible otherwise.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/i2c/busses/i2c-qup.c | 431 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 415 insertions(+), 16 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index c0757d9..810b021 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -24,6 +24,11 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/atomic.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
 
 /* QUP Registers */
 #define QUP_CONFIG		0x000
@@ -33,6 +38,7 @@
 #define QUP_OPERATIONAL		0x018
 #define QUP_ERROR_FLAGS		0x01c
 #define QUP_ERROR_FLAGS_EN	0x020
+#define QUP_OPERATIONAL_MASK	0x028
 #define QUP_HW_VERSION		0x030
 #define QUP_MX_OUTPUT_CNT	0x100
 #define QUP_OUT_FIFO_BASE	0x110
@@ -53,6 +59,7 @@
 
 #define QUP_STATE_VALID		BIT(2)
 #define QUP_I2C_MAST_GEN	BIT(4)
+#define QUP_I2C_FLUSH		BIT(6)
 
 #define QUP_OPERATIONAL_RESET	0x000ff0
 #define QUP_I2C_STATUS_RESET	0xfffffc
@@ -78,7 +85,10 @@
 
 /* Packing/Unpacking words in FIFOs, and IO modes */
 #define QUP_OUTPUT_BLK_MODE	(1 << 10)
+#define QUP_OUTPUT_BAM_MODE	(3 << 10)
 #define QUP_INPUT_BLK_MODE	(1 << 12)
+#define QUP_INPUT_BAM_MODE	(3 << 12)
+#define QUP_BAM_MODE		(QUP_OUTPUT_BAM_MODE | QUP_INPUT_BAM_MODE)
 #define QUP_UNPACK_EN		BIT(14)
 #define QUP_PACK_EN		BIT(15)
 
@@ -95,6 +105,8 @@
 #define QUP_TAG_DATA		(2 << 8)
 #define QUP_TAG_STOP		(3 << 8)
 #define QUP_TAG_REC		(4 << 8)
+#define QUP_BAM_INPUT_EOT		0x93
+#define QUP_BAM_FLUSH_STOP		0x96
 
 /* QUP v2 tags */
 #define QUP_TAG_V2_START               0x81
@@ -115,6 +127,12 @@
 #define ONE_BYTE			0x1
 #define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
 
+#define MX_TX_RX_LEN			SZ_64K
+#define MX_BLOCKS			(MX_TX_RX_LEN / QUP_READ_LIMIT)
+
+/* Max timeout in ms for 32k bytes */
+#define TOUT_MAX			300
+
 struct qup_i2c_block {
 	int	count;
 	int	pos;
@@ -125,6 +143,23 @@ struct qup_i2c_block {
 	int     config_run;
 };
 
+struct qup_i2c_tag {
+	u8 *start;
+	dma_addr_t addr;
+};
+
+struct qup_i2c_bam_rx {
+	struct	qup_i2c_tag scratch_tag;
+	struct	dma_chan *dma_rx;
+	struct	scatterlist *sg_rx;
+};
+
+struct qup_i2c_bam_tx {
+	struct	qup_i2c_tag footer_tag;
+	struct	dma_chan *dma_tx;
+	struct	scatterlist *sg_tx;
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -154,14 +189,20 @@ struct qup_i2c_dev {
 
 	int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
 				 struct i2c_msg *msg);
+	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
+				struct i2c_msg *msg);
+
 	/* Current i2c_msg in i2c_msgs */
 	int			cmsg;
 	/* total num of i2c_msgs */
 	int			num;
 
-	int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
-				struct i2c_msg *msg);
-
+	/* dma parameters */
+	bool			is_dma;
+	struct			dma_pool *dpool;
+	struct			qup_i2c_tag start_tag;
+	struct			qup_i2c_bam_rx brx;
+	struct			qup_i2c_bam_tx btx;
 	struct completion	xfer;
 };
 
@@ -238,6 +279,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state)
 	return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK);
 }
 
+static void qup_i2c_flush(struct qup_i2c_dev *qup)
+{
+	u32 val = readl(qup->base + QUP_STATE);
+
+	val |= QUP_I2C_FLUSH;
+	writel(val, qup->base + QUP_STATE);
+}
+
 static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup)
 {
 	return qup_i2c_poll_state_mask(qup, 0, 0);
@@ -437,12 +486,15 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
 }
 
 static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
-			    struct i2c_msg *msg)
+			    struct i2c_msg *msg, int is_dma)
 {
 	u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
 	int len = 0;
 	int data_len;
 
+	int last = (qup->blk.pos == (qup->blk.count - 1)) &&
+		    (qup->cmsg == (qup->num - 1));
+
 	if (qup->blk.pos == 0) {
 		tags[len++] = QUP_TAG_V2_START;
 		tags[len++] = addr & 0xff;
@@ -452,8 +504,7 @@ static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
 	}
 
 	/* Send _STOP commands for the last block */
-	if (qup->blk.pos == (qup->blk.count - 1)
-	    && (qup->cmsg == (qup->num - 1))) {
+	if (last) {
 		if (msg->flags & I2C_M_RD)
 			tags[len++] = QUP_TAG_V2_DATARD_STOP;
 		else
@@ -473,6 +524,11 @@ static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
 	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;
+	}
+
 	return len;
 }
 
@@ -481,7 +537,7 @@ static int qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	int data_len = 0, tag_len, index;
 	int ret;
 
-	tag_len = qup_i2c_get_tags(qup->blk.tags, qup, msg);
+	tag_len = qup_i2c_get_tags(qup->blk.tags, qup, msg, 0);
 	index = msg->len - qup->blk.data_len;
 
 	/* only tags are written for read */
@@ -776,6 +832,257 @@ err:
 	return ret;
 }
 
+static void qup_i2c_bam_cb(void *data)
+{
+	struct qup_i2c_dev *qup = data;
+
+	complete(&qup->xfer);
+}
+
+void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct qup_i2c_tag *tg,
+		    unsigned int buflen, struct qup_i2c_dev *qup,
+		    int map, int dir)
+{
+	sg_set_buf(sg, buf, buflen);
+	dma_map_sg(qup->dev, sg, 1, dir);
+
+	if (!map)
+		sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start);
+}
+
+static void qup_i2c_rel_dma(struct qup_i2c_dev *qup)
+{
+	if (qup->btx.dma_tx)
+		dma_release_channel(qup->btx.dma_tx);
+	if (qup->brx.dma_rx)
+		dma_release_channel(qup->brx.dma_rx);
+	qup->btx.dma_tx = NULL;
+	qup->brx.dma_rx = NULL;
+}
+
+static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
+{
+	if (!qup->btx.dma_tx) {
+		qup->btx.dma_tx = dma_request_slave_channel(qup->dev, "tx");
+		if (!qup->btx.dma_tx) {
+			dev_err(qup->dev, "\n tx channel not available");
+			return -ENODEV;
+		}
+	}
+
+	if (!qup->brx.dma_rx) {
+		qup->brx.dma_rx = dma_request_slave_channel(qup->dev, "rx");
+		if (!qup->brx.dma_rx) {
+			dev_err(qup->dev, "\n rx channel not available");
+			qup_i2c_rel_dma(qup);
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	struct dma_async_tx_descriptor *txd, *rxd = NULL;
+	int ret = 0;
+	dma_cookie_t cookie_rx, cookie_tx;
+	u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
+	u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
+	u8 *tags;
+
+	while (qup->cmsg < qup->num) {
+		blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
+		rem = msg->len % QUP_READ_LIMIT;
+		tx_len = 0, len = 0, i = 0;
+
+		qup_i2c_get_blk_data(qup, msg);
+
+		if (msg->flags & I2C_M_RD) {
+			rx_nents += (blocks * 2) + 1;
+			tx_nents += 1;
+
+			while (qup->blk.pos < blocks) {
+				/* length set to '0' implies 256 bytes */
+				tlen = (i == (blocks - 1)) ? rem : 0;
+				tags = &qup->start_tag.start[off + len];
+				len += qup_i2c_get_tags(tags, qup, msg, 1);
+
+				/* scratch buf to read the start and len tags */
+				qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
+					       &qup->brx.scratch_tag.start[0],
+					       &qup->brx.scratch_tag,
+					       2, qup, 0, 0);
+
+				qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
+					       &msg->buf[QUP_READ_LIMIT * i],
+					       NULL, tlen, qup,
+					       1, DMA_FROM_DEVICE);
+				i++;
+				qup->blk.pos = i;
+			}
+			qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+				       &qup->start_tag.start[off],
+				       &qup->start_tag, len, qup, 0, 0);
+			off += len;
+			/* scratch buf to read the BAM EOT and FLUSH tags */
+			qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
+				       &qup->brx.scratch_tag.start[0],
+				       &qup->brx.scratch_tag, 2,
+				       qup, 0, 0);
+		} else {
+			tx_nents += (blocks * 2);
+
+			while (qup->blk.pos < blocks) {
+				tlen = (i == (blocks - 1)) ? rem : 0;
+				tags = &qup->start_tag.start[off + tx_len];
+				len = qup_i2c_get_tags(tags, qup, msg, 1);
+
+				qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+					       tags,
+					       &qup->start_tag, len,
+					       qup, 0, 0);
+
+				tx_len += len;
+				qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+					       &msg->buf[QUP_READ_LIMIT * i],
+					       NULL, tlen, qup, 1,
+					       DMA_TO_DEVICE);
+				i++;
+				qup->blk.pos = i;
+			}
+			off += tx_len;
+
+			if (qup->cmsg == (qup->num - 1)) {
+				qup->btx.footer_tag.start[0] =
+							  QUP_BAM_FLUSH_STOP;
+				qup->btx.footer_tag.start[1] =
+							  QUP_BAM_FLUSH_STOP;
+				qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
+					       &qup->btx.footer_tag.start[0],
+					       &qup->btx.footer_tag, 2,
+					       qup, 0, 0);
+				tx_nents += 1;
+			}
+		}
+		qup->cmsg++;
+		msg++;
+	}
+
+	txd = dmaengine_prep_slave_sg(qup->btx.dma_tx, qup->btx.sg_tx, tx_nents,
+				      DMA_MEM_TO_DEV,
+				      DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
+	if (!txd) {
+		dev_err(qup->dev, "failed to get tx desc\n");
+		ret = -EINVAL;
+		goto desc_err;
+	}
+
+	if (!rx_nents) {
+		txd->callback = qup_i2c_bam_cb;
+		txd->callback_param = qup;
+	}
+
+	cookie_tx = dmaengine_submit(txd);
+	dma_async_issue_pending(qup->btx.dma_tx);
+
+	if (rx_nents) {
+		rxd = dmaengine_prep_slave_sg(qup->brx.dma_rx, qup->brx.sg_rx,
+					      rx_nents, DMA_DEV_TO_MEM,
+					      DMA_PREP_INTERRUPT);
+		if (!rxd) {
+			dev_err(qup->dev, "failed to get rx desc\n");
+			ret = -EINVAL;
+
+			/* abort TX descriptors */
+			dmaengine_terminate_all(qup->btx.dma_tx);
+			goto desc_err;
+		}
+
+		rxd->callback = qup_i2c_bam_cb;
+		rxd->callback_param = qup;
+		cookie_rx = dmaengine_submit(rxd);
+		dma_async_issue_pending(qup->brx.dma_rx);
+	}
+
+	if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
+		dev_err(qup->dev, "normal trans timed out\n");
+		ret = -ETIMEDOUT;
+	}
+
+	if (ret || qup->bus_err || qup->qup_err) {
+		if (qup->bus_err & QUP_I2C_NACK_FLAG) {
+			msg--;
+			dev_err(qup->dev, "NACK from %x\n", msg->addr);
+			ret = -EIO;
+
+			if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
+				dev_err(qup->dev, "change to run state timed out");
+				return ret;
+			}
+
+			if (rx_nents)
+				writel(QUP_BAM_INPUT_EOT,
+				       qup->base + QUP_OUT_FIFO_BASE);
+
+			writel(QUP_BAM_FLUSH_STOP,
+			       qup->base + QUP_OUT_FIFO_BASE);
+
+			qup_i2c_flush(qup);
+
+			/* wait for remaining interrupts to occur */
+			if (!wait_for_completion_timeout(&qup->xfer, HZ))
+				dev_err(qup->dev, "flush timed out\n");
+
+			qup_i2c_rel_dma(qup);
+		}
+	}
+
+	dma_unmap_sg(qup->dev, qup->btx.sg_tx, tx_nents, DMA_TO_DEVICE);
+
+	if (rx_nents)
+		dma_unmap_sg(qup->dev, qup->brx.sg_rx, rx_nents,
+			     DMA_FROM_DEVICE);
+desc_err:
+	return ret;
+}
+
+static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg)
+{
+	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
+	int ret = 0;
+
+	enable_irq(qup->irq);
+	if (qup_i2c_req_dma(qup))
+		goto out;
+
+	qup->bus_err = 0;
+	qup->qup_err = 0;
+
+	writel(0, qup->base + QUP_MX_INPUT_CNT);
+	writel(0, qup->base + QUP_MX_OUTPUT_CNT);
+
+	/* set BAM mode */
+	writel(QUP_REPACK_EN | QUP_BAM_MODE, qup->base + QUP_IO_MODE);
+
+	/* mask fifo irqs */
+	writel((0x3 << 8), qup->base + QUP_OPERATIONAL_MASK);
+
+	/* set RUN STATE */
+	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+	if (ret)
+		goto out;
+
+	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+	qup->msg = msg;
+	ret = bam_do_xfer(qup, qup->msg);
+out:
+	disable_irq(qup->irq);
+
+	qup->msg = NULL;
+	return ret;
+}
+
 static int qup_i2c_xfer(struct i2c_adapter *adap,
 			struct i2c_msg msgs[],
 			int num)
@@ -836,7 +1143,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 			   int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
-	int ret, idx;
+	int ret, idx, len, use_dma  = 0;
 
 	qup->num = num;
 	qup->cmsg = 0;
@@ -854,12 +1161,27 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 	writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
 	writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
 
-	for (idx = 0; idx < num; idx++) {
-		if (msgs[idx].len == 0) {
-			ret = -EINVAL;
-			goto out;
+	if ((qup->is_dma)) {
+		/* All i2c_msgs should be transferred using either dma or cpu */
+		for (idx = 0; idx < num; idx++) {
+			if (msgs[idx].len == 0) {
+				ret = -EINVAL;
+				goto out;
+			}
+
+			len = (msgs[idx].len > qup->out_fifo_sz) ||
+			      (msgs[idx].len > qup->in_fifo_sz);
+
+			if ((!is_vmalloc_addr(msgs[idx].buf)) && len) {
+				use_dma = 1;
+			 } else {
+				use_dma = 0;
+				break;
+			}
 		}
+	}
 
+	for (idx = 0; idx < num; idx++) {
 		if (qup_i2c_poll_state_i2c_master(qup)) {
 			ret = -EIO;
 			goto out;
@@ -867,10 +1189,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
 
 		reinit_completion(&qup->xfer);
 
-		if (msgs[idx].flags & I2C_M_RD)
-			ret = qup_i2c_read(qup, &msgs[idx]);
-		else
-			ret = qup_i2c_write(qup, &msgs[idx]);
+		len = msgs[idx].len;
+
+		if (use_dma) {
+			ret = qup_bam_xfer(adap, &msgs[idx]);
+			idx = num;
+		} else {
+			if (msgs[idx].flags & I2C_M_RD)
+				ret = qup_i2c_read(qup, &msgs[idx]);
+			else
+				ret = qup_i2c_write(qup, &msgs[idx]);
+		}
 
 		if (ret)
 			break;
@@ -943,6 +1272,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	int ret, fs_div, hs_div;
 	int src_clk_freq;
 	u32 clk_freq = 100000;
+	int blocks;
 
 	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
 	if (!qup)
@@ -963,8 +1293,60 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		qup->qup_i2c_write_one = qup_i2c_write_one_v2;
 		qup->qup_i2c_read_one = qup_i2c_read_one_v2;
 		qup->use_v2_tags = 1;
+
+		if (qup_i2c_req_dma(qup))
+			goto nodma;
+
+		blocks = (MX_BLOCKS << 1) + 1;
+		qup->btx.sg_tx = devm_kzalloc(&pdev->dev,
+					      sizeof(*qup->btx.sg_tx) * blocks,
+					      GFP_KERNEL);
+		if (!qup->btx.sg_tx) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		sg_init_table(qup->btx.sg_tx, blocks);
+
+		qup->brx.sg_rx = devm_kzalloc(&pdev->dev,
+					      sizeof(*qup->btx.sg_tx) * blocks,
+					      GFP_KERNEL);
+		if (!qup->brx.sg_rx) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		sg_init_table(qup->brx.sg_rx, blocks);
+
+		/* 2 tag bytes for each block + 5 for start, stop tags */
+		size = blocks * 2 + 5;
+		qup->dpool = dma_pool_create("qup_i2c-dma-pool", &pdev->dev,
+					     size, 4, 0);
+
+		qup->start_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
+						      &qup->start_tag.addr);
+		if (!qup->start_tag.start) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		qup->brx.scratch_tag.start = dma_pool_alloc(qup->dpool,
+							    GFP_KERNEL,
+						&qup->brx.scratch_tag.addr);
+		if (!qup->brx.scratch_tag.start) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		qup->btx.footer_tag.start = dma_pool_alloc(qup->dpool,
+							   GFP_KERNEL,
+						&qup->btx.footer_tag.addr);
+		if (!qup->btx.footer_tag.start) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+		qup->is_dma = 1;
 	}
 
+nodma:
 	/* We support frequencies up to FAST Mode (400KHz) */
 	if (!clk_freq || clk_freq > 400000) {
 		dev_err(qup->dev, "clock frequency not supported %d\n",
@@ -1080,6 +1462,11 @@ fail_runtime:
 	pm_runtime_disable(qup->dev);
 	pm_runtime_set_suspended(qup->dev);
 fail:
+	if (qup->btx.dma_tx)
+		dma_release_channel(qup->btx.dma_tx);
+	if (qup->brx.dma_rx)
+		dma_release_channel(qup->brx.dma_rx);
+
 	qup_i2c_disable_clocks(qup);
 	return ret;
 }
@@ -1088,6 +1475,18 @@ static int qup_i2c_remove(struct platform_device *pdev)
 {
 	struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
 
+	if (qup->is_dma) {
+		dma_pool_free(qup->dpool, qup->start_tag.start,
+			      qup->start_tag.addr);
+		dma_pool_free(qup->dpool, qup->brx.scratch_tag.start,
+			      qup->brx.scratch_tag.addr);
+		dma_pool_free(qup->dpool, qup->btx.footer_tag.start,
+			      qup->btx.footer_tag.addr);
+		dma_pool_destroy(qup->dpool);
+		dma_release_channel(qup->btx.dma_tx);
+		dma_release_channel(qup->brx.dma_rx);
+	}
+
 	disable_irq(qup->irq);
 	qup_i2c_disable_clocks(qup);
 	i2c_del_adapter(&qup->adap);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 6/7] dts: msm8974: Add blsp2_bam dma node
  2015-07-09  3:25 ` Sricharan R
@ 2015-07-09  3:25   ` Sricharan R
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov, devicetree, linux-arm-msm, galak, linux-kernel,
	linux-i2c, agross, dmaengine, linux-arm-kernel
  Cc: sricharan

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 arch/arm/boot/dts/qcom-msm8974.dtsi | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index 37b47b5..f138202 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -1,6 +1,6 @@
 /dts-v1/;
 
-#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/qcom,gcc-msm8974.h>
 #include "skeleton.dtsi"
 
@@ -301,5 +301,15 @@
 			interrupt-controller;
 			#interrupt-cells = <4>;
 		};
+
+		blsp2_dma: dma-controller@f9944000 {
+			compatible = "qcom,bam-v1.4.0";
+			reg = <0xf9944000 0x19000>;
+			interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&gcc GCC_BLSP2_AHB_CLK>;
+			clock-names = "bam_clk";
+			#dma-cells = <1>;
+			qcom,ee = <0>;
+		};
 	};
 };
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 6/7] dts: msm8974: Add blsp2_bam dma node
@ 2015-07-09  3:25   ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 arch/arm/boot/dts/qcom-msm8974.dtsi | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index 37b47b5..f138202 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -1,6 +1,6 @@
 /dts-v1/;
 
-#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/qcom,gcc-msm8974.h>
 #include "skeleton.dtsi"
 
@@ -301,5 +301,15 @@
 			interrupt-controller;
 			#interrupt-cells = <4>;
 		};
+
+		blsp2_dma: dma-controller at f9944000 {
+			compatible = "qcom,bam-v1.4.0";
+			reg = <0xf9944000 0x19000>;
+			interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&gcc GCC_BLSP2_AHB_CLK>;
+			clock-names = "bam_clk";
+			#dma-cells = <1>;
+			qcom,ee = <0>;
+		};
 	};
 };
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 7/7] dts: msm8974: Add dma channels for blsp2_i2c1 node
  2015-07-09  3:25 ` Sricharan R
@ 2015-07-09  3:25   ` Sricharan R
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: iivanov, devicetree, linux-arm-msm, galak, linux-kernel,
	linux-i2c, agross, dmaengine, linux-arm-kernel
  Cc: sricharan

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 arch/arm/boot/dts/qcom-msm8974.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index f138202..17dcda3 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -284,6 +284,8 @@
 			clock-names = "core", "iface";
 			#address-cells = <1>;
 			#size-cells = <0>;
+			dmas = <&blsp2_dma 20>, <&blsp2_dma 21>;
+			dma-names = "tx", "rx";
 		};
 
 		spmi_bus: spmi@fc4cf000 {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH V4 7/7] dts: msm8974: Add dma channels for blsp2_i2c1 node
@ 2015-07-09  3:25   ` Sricharan R
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan R @ 2015-07-09  3:25 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 arch/arm/boot/dts/qcom-msm8974.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index f138202..17dcda3 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -284,6 +284,8 @@
 			clock-names = "core", "iface";
 			#address-cells = <1>;
 			#size-cells = <0>;
+			dmas = <&blsp2_dma 20>, <&blsp2_dma 21>;
+			dma-names = "tx", "rx";
 		};
 
 		spmi_bus: spmi at fc4cf000 {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* Re: [PATCH V4 2/7] qup: i2c: factor out common code for reuse
  2015-07-09  3:25   ` Sricharan R
@ 2015-07-20  8:25     ` Ivan T. Ivanov
  -1 siblings, 0 replies; 41+ messages in thread
From: Ivan T. Ivanov @ 2015-07-20  8:25 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree, linux-arm-msm, galak, linux-kernel, linux-i2c,
	agross, dmaengine, linux-arm-kernel


Hi Sricharan, 

On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> 

>  static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>  {
> -       unsigned long left;
> -       int ret;
> +       int ret = 0;
> 
> -       qup->msg = msg;
> -       qup->pos  = 0;
> +       /*
> +               * The QUP block will issue a NACK and STOP on the bus when reaching
> +               * the end of the read, the length of the read is specified as one byte
> +               * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
> +               */
> +       if (msg->len > QUP_READ_LIMIT) {
> +               dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
> +                       QUP_READ_LIMIT);
> +               return -EINVAL;
> +       }
> 

This should be removed. Please see qup_i2c_quirks.

Regards,
Ivan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 2/7] qup: i2c: factor out common code for reuse
@ 2015-07-20  8:25     ` Ivan T. Ivanov
  0 siblings, 0 replies; 41+ messages in thread
From: Ivan T. Ivanov @ 2015-07-20  8:25 UTC (permalink / raw)
  To: linux-arm-kernel


Hi Sricharan, 

On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> 

>  static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>  {
> -       unsigned long left;
> -       int ret;
> +       int ret = 0;
> 
> -       qup->msg = msg;
> -       qup->pos  = 0;
> +       /*
> +               * The QUP block will issue a NACK and STOP on the bus when reaching
> +               * the end of the read, the length of the read is specified as one byte
> +               * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
> +               */
> +       if (msg->len > QUP_READ_LIMIT) {
> +               dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
> +                       QUP_READ_LIMIT);
> +               return -EINVAL;
> +       }
> 

This should be removed. Please see qup_i2c_quirks.

Regards,
Ivan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH V4 3/7] i2c: qup: Add V2 tags support
  2015-07-09  3:25   ` Sricharan R
@ 2015-07-20  9:44     ` Ivan T. Ivanov
  -1 siblings, 0 replies; 41+ messages in thread
From: Ivan T. Ivanov @ 2015-07-20  9:44 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree, linux-arm-msm, galak, linux-kernel, linux-i2c,
	agross, dmaengine, linux-arm-kernel


Hi Sricharan,

On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> QUP from version 2.1.1 onwards, supports a new format of
> i2c command tags. Tag codes instructs the controller to
> perform a operation like read/write. This new tagging version
> supports bam dma and transfers of more than 256 bytes without 'stop'
> in between. Adding the support for the same.

IIRC, more than 256 bytes in message is supported only in BAM(DMA)
mode, if this is true, please be more explicit in commit message.

You haven't tried to read more than 256 bytes with this
patch, right? See qup_i2c_quirks ;-) 

> 
> 
>  struct qup_i2c_dev {
>         struct device*dev;
>         void __iomem*base;
> @@ -117,6 +138,7 @@ struct qup_i2c_dev {
>         int     in_blk_sz;
> 
>         unsigned longone_byte_t;
> +       struct qup_i2c_blockblk;
> 
>         struct i2c_msg*msg;
>         /* Current posion in user message buffer */
> @@ -126,6 +148,14 @@ struct qup_i2c_dev {
>         /* QUP core errors */
>         u32     qup_err;
> 
> +       int     use_v2_tags;
> +
> +       int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> +                                       struct i2c_msg *msg);
> +
> +       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> +                               struct i2c_msg *msg);
> +

Do we really need additional level of indirection?

We have separate struct i2c_algorithm, then we have common 
qup_i2c_read/write methods and then we have different 
read/write sub functions. I don't think 3-4 lines code reuse
deserve increased complexity.

<snip>

> +static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
> +                                       struct i2c_msg *msg)
> +{

This is more like "set_blk_metadata". Second argument could fit line above.

> +       memset(&qup->blk, 0, sizeof(qup->blk));
> +
> +       if (!qup->use_v2_tags) {
> +               if (!(msg->flags & I2C_M_RD))
> +                       qup->blk.tx_tag_len = 1;
> +               return;
> +       }
> +
> +       qup->blk.data_len = msg->len;
> +       qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT;
> +
> +       /* 4 bytes for first block and 2 writes for rest */
> +       qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
> +
> +       /* There are 2 tag bytes that are read in to fifo for every block */
> +       if (msg->flags & I2C_M_RD)
> +               qup->blk.rx_tag_len = qup->blk.count * 2;
> +}
> +

<snip>

> +static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
> +                                                       struct i2c_msg *msg)
> +{

This is more like "set_tags".

> +       u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
> +       int len = 0;
> +       int data_len;
> +
> +       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;
> +       }
> +
> +       /* Send _STOP commands for the last block */
> +       if (qup->blk.pos == (qup->blk.count - 1)) {
> +               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);
> +
> +       /* 0 implies 256 bytes */
> +       if (data_len == QUP_READ_LIMIT)
> +               tags[len++] = 0;
> +       else
> +               tags[len++] = data_len;
> +
> +       return len;
> +}
> +

Regards,
Ivan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 3/7] i2c: qup: Add V2 tags support
@ 2015-07-20  9:44     ` Ivan T. Ivanov
  0 siblings, 0 replies; 41+ messages in thread
From: Ivan T. Ivanov @ 2015-07-20  9:44 UTC (permalink / raw)
  To: linux-arm-kernel


Hi Sricharan,

On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> QUP from version 2.1.1 onwards, supports a new format of
> i2c command tags. Tag codes instructs the controller to
> perform a operation like read/write. This new tagging version
> supports bam dma and transfers of more than 256 bytes without 'stop'
> in between. Adding the support for the same.

IIRC, more than 256 bytes in message is supported only in BAM(DMA)
mode, if this is true, please be more explicit in commit message.

You haven't tried to read more than 256 bytes with this
patch, right? See qup_i2c_quirks ;-) 

> 
> 
>  struct qup_i2c_dev {
>         struct device*dev;
>         void __iomem*base;
> @@ -117,6 +138,7 @@ struct qup_i2c_dev {
>         int     in_blk_sz;
> 
>         unsigned longone_byte_t;
> +       struct qup_i2c_blockblk;
> 
>         struct i2c_msg*msg;
>         /* Current posion in user message buffer */
> @@ -126,6 +148,14 @@ struct qup_i2c_dev {
>         /* QUP core errors */
>         u32     qup_err;
> 
> +       int     use_v2_tags;
> +
> +       int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> +                                       struct i2c_msg *msg);
> +
> +       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> +                               struct i2c_msg *msg);
> +

Do we really need additional level of indirection?

We have separate struct i2c_algorithm, then we have common 
qup_i2c_read/write methods and then we have different 
read/write sub functions. I don't think 3-4 lines code reuse
deserve increased complexity.

<snip>

> +static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
> +                                       struct i2c_msg *msg)
> +{

This is more like "set_blk_metadata". Second argument could fit line above.

> +       memset(&qup->blk, 0, sizeof(qup->blk));
> +
> +       if (!qup->use_v2_tags) {
> +               if (!(msg->flags & I2C_M_RD))
> +                       qup->blk.tx_tag_len = 1;
> +               return;
> +       }
> +
> +       qup->blk.data_len = msg->len;
> +       qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT;
> +
> +       /* 4 bytes for first block and 2 writes for rest */
> +       qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
> +
> +       /* There are 2 tag bytes that are read in to fifo for every block */
> +       if (msg->flags & I2C_M_RD)
> +               qup->blk.rx_tag_len = qup->blk.count * 2;
> +}
> +

<snip>

> +static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
> +                                                       struct i2c_msg *msg)
> +{

This is more like "set_tags".

> +       u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
> +       int len = 0;
> +       int data_len;
> +
> +       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;
> +       }
> +
> +       /* Send _STOP commands for the last block */
> +       if (qup->blk.pos == (qup->blk.count - 1)) {
> +               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);
> +
> +       /* 0 implies 256 bytes */
> +       if (data_len == QUP_READ_LIMIT)
> +               tags[len++] = 0;
> +       else
> +               tags[len++] = data_len;
> +
> +       return len;
> +}
> +

Regards,
Ivan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
  2015-07-09  3:25     ` Sricharan R
  (?)
@ 2015-07-20 11:22         ` Ivan T. Ivanov
  -1 siblings, 0 replies; 41+ messages in thread
From: Ivan T. Ivanov @ 2015-07-20 11:22 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, agross-sgV2jX0FEOL9JmXXK+q4OQ,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r


Hi, 

On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:

<snip>

>  #define ONE_BYTE                       0x1
> +#define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
> 
>  struct qup_i2c_block {
>         int     count;
> @@ -121,6 +122,7 @@ struct qup_i2c_block {
>         int     rx_tag_len;
>         int     data_len;
>         u8      tags[6];
> +       int     config_run;

This is not directly related to "block" control logic, right?
Could it made part of qup_i2c_dev structure?

>  };
> 
>  struct qup_i2c_dev {
> @@ -152,6 +154,10 @@ struct qup_i2c_dev {
> 
>         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
>                                         struct i2c_msg *msg);
> +       /* Current i2c_msg in i2c_msgs */
> +       int     cmsg;
> +       /* total num of i2c_msgs */
> +       int     num;

I think it will be simpler with just "bool is_last" evaluated in main xfer loop.

<snip>

> 
> @@ -374,6 +383,9 @@ static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
>         /* There are 2 tag bytes that are read in to fifo for every block */
>         if (msg->flags & I2C_M_RD)
>                 qup->blk.rx_tag_len = qup->blk.count * 2;
> +
> +       if (qup->cmsg)
> +               qup->blk.config_run = QUP_I2C_MX_CONFIG_DURING_RUN;

This could be moved to qup_i2c_xfer_v2() to avoid repeatedly setting it. 

>  }

Regards,
Ivan
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
@ 2015-07-20 11:22         ` Ivan T. Ivanov
  0 siblings, 0 replies; 41+ messages in thread
From: Ivan T. Ivanov @ 2015-07-20 11:22 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree, linux-arm-msm, galak, linux-kernel, linux-i2c,
	agross, dmaengine, linux-arm-kernel


Hi, 

On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:

<snip>

>  #define ONE_BYTE                       0x1
> +#define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
> 
>  struct qup_i2c_block {
>         int     count;
> @@ -121,6 +122,7 @@ struct qup_i2c_block {
>         int     rx_tag_len;
>         int     data_len;
>         u8      tags[6];
> +       int     config_run;

This is not directly related to "block" control logic, right?
Could it made part of qup_i2c_dev structure?

>  };
> 
>  struct qup_i2c_dev {
> @@ -152,6 +154,10 @@ struct qup_i2c_dev {
> 
>         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
>                                         struct i2c_msg *msg);
> +       /* Current i2c_msg in i2c_msgs */
> +       int     cmsg;
> +       /* total num of i2c_msgs */
> +       int     num;

I think it will be simpler with just "bool is_last" evaluated in main xfer loop.

<snip>

> 
> @@ -374,6 +383,9 @@ static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
>         /* There are 2 tag bytes that are read in to fifo for every block */
>         if (msg->flags & I2C_M_RD)
>                 qup->blk.rx_tag_len = qup->blk.count * 2;
> +
> +       if (qup->cmsg)
> +               qup->blk.config_run = QUP_I2C_MX_CONFIG_DURING_RUN;

This could be moved to qup_i2c_xfer_v2() to avoid repeatedly setting it. 

>  }

Regards,
Ivan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
@ 2015-07-20 11:22         ` Ivan T. Ivanov
  0 siblings, 0 replies; 41+ messages in thread
From: Ivan T. Ivanov @ 2015-07-20 11:22 UTC (permalink / raw)
  To: linux-arm-kernel


Hi, 

On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:

<snip>

>  #define ONE_BYTE                       0x1
> +#define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
> 
>  struct qup_i2c_block {
>         int     count;
> @@ -121,6 +122,7 @@ struct qup_i2c_block {
>         int     rx_tag_len;
>         int     data_len;
>         u8      tags[6];
> +       int     config_run;

This is not directly related to "block" control logic, right?
Could it made part of qup_i2c_dev structure?

>  };
> 
>  struct qup_i2c_dev {
> @@ -152,6 +154,10 @@ struct qup_i2c_dev {
> 
>         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
>                                         struct i2c_msg *msg);
> +       /* Current i2c_msg in i2c_msgs */
> +       int     cmsg;
> +       /* total num of i2c_msgs */
> +       int     num;

I think it will be simpler with just "bool is_last" evaluated in main xfer loop.

<snip>

> 
> @@ -374,6 +383,9 @@ static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
>         /* There are 2 tag bytes that are read in to fifo for every block */
>         if (msg->flags & I2C_M_RD)
>                 qup->blk.rx_tag_len = qup->blk.count * 2;
> +
> +       if (qup->cmsg)
> +               qup->blk.config_run = QUP_I2C_MX_CONFIG_DURING_RUN;

This could be moved to qup_i2c_xfer_v2() to avoid repeatedly setting it. 

>  }

Regards,
Ivan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
  2015-07-09  3:25     ` Sricharan R
@ 2015-07-20 14:46       ` Ivan T. Ivanov
  -1 siblings, 0 replies; 41+ messages in thread
From: Ivan T. Ivanov @ 2015-07-20 14:46 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree, linux-arm-msm, galak, linux-kernel, linux-i2c,
	agross, dmaengine, linux-arm-kernel


Hi Sricharan,

On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> QUP cores can be attached to a BAM module, which acts as a dma engine for the
> QUP core. When DMA with BAM is enabled, the BAM consumer pipe transmitted data
> is written to the output FIFO and the BAM producer pipe received data is read
> from the input FIFO.
> 
> With BAM capabilities, qup-i2c core can transfer more than 256 bytes, without a
> 'stop' which is not possible otherwise.
> 
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 431 +++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 415 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index c0757d9..810b021 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -24,6 +24,11 @@
>  #include <linux/of.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/scatterlist.h>
> +#include <linux/atomic.h>
> +#include <linux/dmaengine.h>
> +#include <linux/dmapool.h>

Keep includes sorted alphabetically.

<snip>

> +#define MX_TX_RX_LEN                   SZ_64K
> +#define MX_BLOCKS                      (MX_TX_RX_LEN / QUP_READ_LIMIT)
> +
> +/* Max timeout in ms for 32k bytes */
> +#define TOUT_MAX                       300
> +
>  struct qup_i2c_block {
>         int     count;
>         int     pos;
> @@ -125,6 +143,23 @@ struct qup_i2c_block {
>         int     config_run;
>  };
> 
> +struct qup_i2c_tag {
> +       u8 *start;
> +       dma_addr_t addr;
> +};
> +
> +struct qup_i2c_bam_rx {
> +       struct  qup_i2c_tag scratch_tag;
> +       struct  dma_chan *dma_rx;
> +       struct  scatterlist *sg_rx;
> +};
> +
> +struct qup_i2c_bam_tx {
> +       struct  qup_i2c_tag footer_tag;
> +       struct  dma_chan *dma_tx;
> +       struct  scatterlist *sg_tx;
> +};
> +

The only difference between above 2 structures is name of the fields.
Please, just define one struct qup_i2c_bam and instantiate it twice.

>  struct qup_i2c_dev {
>         struct device*dev;
>         void __iomem*base;
> @@ -154,14 +189,20 @@ struct qup_i2c_dev {
> 
>         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
>                                         struct i2c_msg *msg);
> +       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> +                               struct i2c_msg *msg);
> +
>         /* Current i2c_msg in i2c_msgs */
>         int     cmsg;
>         /* total num of i2c_msgs */
>         int     num;
> 
> -       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> -                               struct i2c_msg *msg);
> -
> +       /* dma parameters */
> +       bool    is_dma;
> +       struct  dma_pool *dpool;
> +       struct  qup_i2c_tag start_tag;
> +       struct  qup_i2c_bam_rx brx;
> +       struct  qup_i2c_bam_tx btx;
>         struct completionxfer;
>  };
> 
> @@ -238,6 +279,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state)
>         return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK);
>  }
> 
> +static void qup_i2c_flush(struct qup_i2c_dev *qup)
> +{
> +       u32 val = readl(qup->base + QUP_STATE);
> +
> +       val |= QUP_I2C_FLUSH;
> +       writel(val, qup->base + QUP_STATE);
> +}
> +

Used in only one place.

<snip>

> 
> +static void qup_i2c_bam_cb(void *data)
> +{
> +       struct qup_i2c_dev *qup = data;
> +
> +       complete(&qup->xfer);
> +}
> +
> +void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct qup_i2c_tag *tg,
> +                                               unsigned int buflen, struct qup_i2c_dev *qup,
> +                                               int map, int dir)
> +{
> +       sg_set_buf(sg, buf, buflen);
> +       dma_map_sg(qup->dev, sg, 1, dir);
> +
> +       if (!map)
> +               sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start);

Changing DMA address that we just mapped?

> +}
> +
> +static void qup_i2c_rel_dma(struct qup_i2c_dev *qup)
> +{
> +       if (qup->btx.dma_tx)
> +               dma_release_channel(qup->btx.dma_tx);
> +       if (qup->brx.dma_rx)
> +               dma_release_channel(qup->brx.dma_rx);
> +       qup->btx.dma_tx = NULL;
> +       qup->brx.dma_rx = NULL;
> +}
> +
> +static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
> +{
> +       if (!qup->btx.dma_tx) {
> +               qup->btx.dma_tx = dma_request_slave_channel(qup->dev, "tx");

Please use dma_request_slave_channel_reason() and let deferred probe work.

> +               if (!qup->btx.dma_tx) {
> +                       dev_err(qup->dev, "\n tx channel not available");
> +                       return -ENODEV;
> +               }
> +       }
> +
> +       if (!qup->brx.dma_rx) {
> +               qup->brx.dma_rx = dma_request_slave_channel(qup->dev, "rx");
> +               if (!qup->brx.dma_rx) {
> +                       dev_err(qup->dev, "\n rx channel not available");
> +                       qup_i2c_rel_dma(qup);
> +                       return -ENODEV;
> +               }
> +       }
> +       return 0;
> +}
> +
> +static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +{

Please use consistent naming convention.

> +       struct dma_async_tx_descriptor *txd, *rxd = NULL;
> +       int ret = 0;
> +       dma_cookie_t cookie_rx, cookie_tx;
> +       u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
> +       u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
> +       u8 *tags;
> +
> +       while (qup->cmsg < qup->num) {
> +               blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
> +               rem = msg->len % QUP_READ_LIMIT;
> +               tx_len = 0, len = 0, i = 0;
> +
> +               qup_i2c_get_blk_data(qup, msg);
> +
> +               if (msg->flags & I2C_M_RD) {
> +                       rx_nents += (blocks * 2) + 1;
> +                       tx_nents += 1;
> +
> +                       while (qup->blk.pos < blocks) {
> +                               /* length set to '0' implies 256 bytes */
> +                               tlen = (i == (blocks - 1)) ? rem : 0;
> +                               tags = &qup->start_tag.start[off + len];
> +                               len += qup_i2c_get_tags(tags, qup, msg, 1);
> +
> +                               /* scratch buf to read the start and len tags */
> +                               qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> +                                                                                               &qup->brx.scratch_tag.start[0],
> +                                                                                               &qup->brx.scratch_tag,
> +                                                                                               2, qup, 0, 0);
> +
> +                               qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> +                                                                                               &msg->buf[QUP_READ_LIMIT * i],
> +                                                                                               NULL, tlen, qup,
> +                                                                                               1, DMA_FROM_DEVICE);
> +                               i++;
> +                               qup->blk.pos = i;
> +                       }
> +                       qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> +                                                                                       &qup->start_tag.start[off],
> +                                                                                       &qup->start_tag, len, qup, 0, 0);
> +                       off += len;
> +                       /* scratch buf to read the BAM EOT and FLUSH tags */
> +                       qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> +                                                                                       &qup->brx.scratch_tag.start[0],
> +                                                                                       &qup->brx.scratch_tag, 2,
> +                                                                                       qup, 0, 0);
> +               } else {
> +                       tx_nents += (blocks * 2);
> +
> +                       while (qup->blk.pos < blocks) {
> +                               tlen = (i == (blocks - 1)) ? rem : 0;
> +                               tags = &qup->start_tag.start[off + tx_len];
> +                               len = qup_i2c_get_tags(tags, qup, msg, 1);
> +
> +                               qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> +                                                                                               tags,
> +                                                                                               &qup->start_tag, len,
> +                                                                                               qup, 0, 0);
> +
> +                               tx_len += len;
> +                               qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> +                                                                                               &msg->buf[QUP_READ_LIMIT * i],
> +                                                                                               NULL, tlen, qup, 1,
> +                                                                                               DMA_TO_DEVICE);
> +                               i++;
> +                               qup->blk.pos = i;
> +                       }
> +                       off += tx_len;
> +
> +                       if (qup->cmsg == (qup->num - 1)) {
> +                               qup->btx.footer_tag.start[0] =
> +                                                                       QUP_BAM_FLUSH_STOP;
> +                               qup->btx.footer_tag.start[1] =
> +                                                                       QUP_BAM_FLUSH_STOP;
> +                               qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> +                                                                                               &qup->btx.footer_tag.start[0],
> +                                                                                               &qup->btx.footer_tag, 2,
> +                                                                                               qup, 0, 0);
> +                               tx_nents += 1;
> +                       }
> +               }
> +               qup->cmsg++;
> +               msg++;
> +       }
> +
> +       txd = dmaengine_prep_slave_sg(qup->btx.dma_tx, qup->btx.sg_tx, tx_nents,
> +                                                                               DMA_MEM_TO_DEV,
> +                                                                               DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
> +       if (!txd) {
> +               dev_err(qup->dev, "failed to get tx desc\n");
> +               ret = -EINVAL;
> +               goto desc_err;
> +       }
> +
> +       if (!rx_nents) {
> +               txd->callback = qup_i2c_bam_cb;
> +               txd->callback_param = qup;
> +       }
> +
> +       cookie_tx = dmaengine_submit(txd);

Check this cookie for error? Same bellow.

> +       dma_async_issue_pending(qup->btx.dma_tx);

Why TX messages are started first?

> +
> +       if (rx_nents) {
> +               rxd = dmaengine_prep_slave_sg(qup->brx.dma_rx, qup->brx.sg_rx,
> +                                                                                       rx_nents, DMA_DEV_TO_MEM,
> +                                                                                       DMA_PREP_INTERRUPT);
> +               if (!rxd) {
> +                       dev_err(qup->dev, "failed to get rx desc\n");
> +                       ret = -EINVAL;
> +
> +                       /* abort TX descriptors */
> +                       dmaengine_terminate_all(qup->btx.dma_tx);
> +                       goto desc_err;
> +               }
> +
> +               rxd->callback = qup_i2c_bam_cb;
> +               rxd->callback_param = qup;
> +               cookie_rx = dmaengine_submit(rxd);
> +               dma_async_issue_pending(qup->brx.dma_rx);
> +       }
> +
> +       if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
> +               dev_err(qup->dev, "normal trans timed out\n");
> +               ret = -ETIMEDOUT;
> +       }

There could be multiple messages for RX and TX queued for transfer, 
and they could be mixed. Using just one completion did't look right. 

> +
> +       if (ret || qup->bus_err || qup->qup_err) {
> +               if (qup->bus_err & QUP_I2C_NACK_FLAG) {
> +                       msg--;
> +                       dev_err(qup->dev, "NACK from %x\n", msg->addr);
> +                       ret = -EIO;
> +
> +                       if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
> +                               dev_err(qup->dev, "change to run state timed out");
> +                               return ret;
> +                       }
> +
> +                       if (rx_nents)
> +                               writel(QUP_BAM_INPUT_EOT,
> +                                                                                       qup->base + QUP_OUT_FIFO_BASE);
> +
> +                       writel(QUP_BAM_FLUSH_STOP,
> +                                                                               qup->base + QUP_OUT_FIFO_BASE);
> +
> +                       qup_i2c_flush(qup);
> +
> +                       /* wait for remaining interrupts to occur */
> +                       if (!wait_for_completion_timeout(&qup->xfer, HZ))
> +                               dev_err(qup->dev, "flush timed out\n");
> +
> +                       qup_i2c_rel_dma(qup);
> +               }
> +       }
> +
> +       dma_unmap_sg(qup->dev, qup->btx.sg_tx, tx_nents, DMA_TO_DEVICE);
> +
> +       if (rx_nents)
> +               dma_unmap_sg(qup->dev, qup->brx.sg_rx, rx_nents,
> +                                                               DMA_FROM_DEVICE);
> +desc_err:
> +       return ret;
> +}
> +
> +static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg)
> +{

Please use consistent naming convention.

> +       struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> +       int ret = 0;
> +
> +       enable_irq(qup->irq);
> +       if (qup_i2c_req_dma(qup))

Why?

> 
> +
>  static int qup_i2c_xfer(struct i2c_adapter *adap,
>                         struct i2c_msg msgs[],
>                         int num)
> @@ -836,7 +1143,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>                                                 int num)
>  {
>         struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> -       int ret, idx;
> +       int ret, idx, len, use_dma  = 0;
> 
>         qup->num = num;
>         qup->cmsg = 0;
> @@ -854,12 +1161,27 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>         writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
>         writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
> 
> -       for (idx = 0; idx < num; idx++) {
> -               if (msgs[idx].len == 0) {
> -                       ret = -EINVAL;
> -                       goto out;
> +       if ((qup->is_dma)) {
> +               /* All i2c_msgs should be transferred using either dma or cpu */
> +               for (idx = 0; idx < num; idx++) {
> +                       if (msgs[idx].len == 0) {
> +                               ret = -EINVAL;
> +                               goto out;
> +                       }
> +
> +                       len = (msgs[idx].len > qup->out_fifo_sz) ||
> +                                                                       (msgs[idx].len > qup->in_fifo_sz);
> +
> +                       if ((!is_vmalloc_addr(msgs[idx].buf)) && len) {

What is wrong with vmalloc addresses?

> +                               use_dma = 1;
> +                               } else {
> +                               use_dma = 0;
> +                               break;
> +                       }
>                 }
> +       }
> 
> +       for (idx = 0; idx < num; idx++) {
>                 if (qup_i2c_poll_state_i2c_master(qup)) {
>                         ret = -EIO;
>                         goto out;
> @@ -867,10 +1189,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
> 
>                 reinit_completion(&qup->xfer);
> 
> -               if (msgs[idx].flags & I2C_M_RD)
> -                       ret = qup_i2c_read(qup, &msgs[idx]);
> -               else
> -                       ret = qup_i2c_write(qup, &msgs[idx]);
> +               len = msgs[idx].len;

Unused?

> +
> +               if (use_dma) {
> +                       ret = qup_bam_xfer(adap, &msgs[idx]);
> +                       idx = num;

Hacky.

> +               } else {
> +                       if (msgs[idx].flags & I2C_M_RD)
> +                               ret = qup_i2c_read(qup, &msgs[idx]);
> +                       else
> +                               ret = qup_i2c_write(qup, &msgs[idx]);
> +               }
> 
>                 if (ret)
>                         break;
> @@ -943,6 +1272,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>         int ret, fs_div, hs_div;
>         int src_clk_freq;
>         u32 clk_freq = 100000;
> +       int blocks;
> 
>         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>         if (!qup)
> @@ -963,8 +1293,60 @@ static int qup_i2c_probe(struct platform_device *pdev)
>                 qup->qup_i2c_write_one = qup_i2c_write_one_v2;
>                 qup->qup_i2c_read_one = qup_i2c_read_one_v2;
>                 qup->use_v2_tags = 1;
> +
> +               if (qup_i2c_req_dma(qup))
> +                       goto nodma;

Just return what request DMA functions return?

Regards,
Ivan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
@ 2015-07-20 14:46       ` Ivan T. Ivanov
  0 siblings, 0 replies; 41+ messages in thread
From: Ivan T. Ivanov @ 2015-07-20 14:46 UTC (permalink / raw)
  To: linux-arm-kernel


Hi Sricharan,

On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> QUP cores can be attached to a BAM module, which acts as a dma engine for the
> QUP core. When DMA with BAM is enabled, the BAM consumer pipe transmitted data
> is written to the output FIFO and the BAM producer pipe received data is read
> from the input FIFO.
> 
> With BAM capabilities, qup-i2c core can transfer more than 256 bytes, without a
> 'stop' which is not possible otherwise.
> 
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 431 +++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 415 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
> index c0757d9..810b021 100644
> --- a/drivers/i2c/busses/i2c-qup.c
> +++ b/drivers/i2c/busses/i2c-qup.c
> @@ -24,6 +24,11 @@
>  #include <linux/of.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/scatterlist.h>
> +#include <linux/atomic.h>
> +#include <linux/dmaengine.h>
> +#include <linux/dmapool.h>

Keep includes sorted alphabetically.

<snip>

> +#define MX_TX_RX_LEN                   SZ_64K
> +#define MX_BLOCKS                      (MX_TX_RX_LEN / QUP_READ_LIMIT)
> +
> +/* Max timeout in ms for 32k bytes */
> +#define TOUT_MAX                       300
> +
>  struct qup_i2c_block {
>         int     count;
>         int     pos;
> @@ -125,6 +143,23 @@ struct qup_i2c_block {
>         int     config_run;
>  };
> 
> +struct qup_i2c_tag {
> +       u8 *start;
> +       dma_addr_t addr;
> +};
> +
> +struct qup_i2c_bam_rx {
> +       struct  qup_i2c_tag scratch_tag;
> +       struct  dma_chan *dma_rx;
> +       struct  scatterlist *sg_rx;
> +};
> +
> +struct qup_i2c_bam_tx {
> +       struct  qup_i2c_tag footer_tag;
> +       struct  dma_chan *dma_tx;
> +       struct  scatterlist *sg_tx;
> +};
> +

The only difference between above 2 structures is name of the fields.
Please, just define one struct qup_i2c_bam and instantiate it twice.

>  struct qup_i2c_dev {
>         struct device*dev;
>         void __iomem*base;
> @@ -154,14 +189,20 @@ struct qup_i2c_dev {
> 
>         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
>                                         struct i2c_msg *msg);
> +       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> +                               struct i2c_msg *msg);
> +
>         /* Current i2c_msg in i2c_msgs */
>         int     cmsg;
>         /* total num of i2c_msgs */
>         int     num;
> 
> -       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> -                               struct i2c_msg *msg);
> -
> +       /* dma parameters */
> +       bool    is_dma;
> +       struct  dma_pool *dpool;
> +       struct  qup_i2c_tag start_tag;
> +       struct  qup_i2c_bam_rx brx;
> +       struct  qup_i2c_bam_tx btx;
>         struct completionxfer;
>  };
> 
> @@ -238,6 +279,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state)
>         return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK);
>  }
> 
> +static void qup_i2c_flush(struct qup_i2c_dev *qup)
> +{
> +       u32 val = readl(qup->base + QUP_STATE);
> +
> +       val |= QUP_I2C_FLUSH;
> +       writel(val, qup->base + QUP_STATE);
> +}
> +

Used in only one place.

<snip>

> 
> +static void qup_i2c_bam_cb(void *data)
> +{
> +       struct qup_i2c_dev *qup = data;
> +
> +       complete(&qup->xfer);
> +}
> +
> +void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct qup_i2c_tag *tg,
> +                                               unsigned int buflen, struct qup_i2c_dev *qup,
> +                                               int map, int dir)
> +{
> +       sg_set_buf(sg, buf, buflen);
> +       dma_map_sg(qup->dev, sg, 1, dir);
> +
> +       if (!map)
> +               sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start);

Changing DMA address that we just mapped?

> +}
> +
> +static void qup_i2c_rel_dma(struct qup_i2c_dev *qup)
> +{
> +       if (qup->btx.dma_tx)
> +               dma_release_channel(qup->btx.dma_tx);
> +       if (qup->brx.dma_rx)
> +               dma_release_channel(qup->brx.dma_rx);
> +       qup->btx.dma_tx = NULL;
> +       qup->brx.dma_rx = NULL;
> +}
> +
> +static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
> +{
> +       if (!qup->btx.dma_tx) {
> +               qup->btx.dma_tx = dma_request_slave_channel(qup->dev, "tx");

Please use dma_request_slave_channel_reason() and let deferred probe work.

> +               if (!qup->btx.dma_tx) {
> +                       dev_err(qup->dev, "\n tx channel not available");
> +                       return -ENODEV;
> +               }
> +       }
> +
> +       if (!qup->brx.dma_rx) {
> +               qup->brx.dma_rx = dma_request_slave_channel(qup->dev, "rx");
> +               if (!qup->brx.dma_rx) {
> +                       dev_err(qup->dev, "\n rx channel not available");
> +                       qup_i2c_rel_dma(qup);
> +                       return -ENODEV;
> +               }
> +       }
> +       return 0;
> +}
> +
> +static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +{

Please use consistent naming convention.

> +       struct dma_async_tx_descriptor *txd, *rxd = NULL;
> +       int ret = 0;
> +       dma_cookie_t cookie_rx, cookie_tx;
> +       u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
> +       u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
> +       u8 *tags;
> +
> +       while (qup->cmsg < qup->num) {
> +               blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
> +               rem = msg->len % QUP_READ_LIMIT;
> +               tx_len = 0, len = 0, i = 0;
> +
> +               qup_i2c_get_blk_data(qup, msg);
> +
> +               if (msg->flags & I2C_M_RD) {
> +                       rx_nents += (blocks * 2) + 1;
> +                       tx_nents += 1;
> +
> +                       while (qup->blk.pos < blocks) {
> +                               /* length set to '0' implies 256 bytes */
> +                               tlen = (i == (blocks - 1)) ? rem : 0;
> +                               tags = &qup->start_tag.start[off + len];
> +                               len += qup_i2c_get_tags(tags, qup, msg, 1);
> +
> +                               /* scratch buf to read the start and len tags */
> +                               qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> +                                                                                               &qup->brx.scratch_tag.start[0],
> +                                                                                               &qup->brx.scratch_tag,
> +                                                                                               2, qup, 0, 0);
> +
> +                               qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> +                                                                                               &msg->buf[QUP_READ_LIMIT * i],
> +                                                                                               NULL, tlen, qup,
> +                                                                                               1, DMA_FROM_DEVICE);
> +                               i++;
> +                               qup->blk.pos = i;
> +                       }
> +                       qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> +                                                                                       &qup->start_tag.start[off],
> +                                                                                       &qup->start_tag, len, qup, 0, 0);
> +                       off += len;
> +                       /* scratch buf to read the BAM EOT and FLUSH tags */
> +                       qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> +                                                                                       &qup->brx.scratch_tag.start[0],
> +                                                                                       &qup->brx.scratch_tag, 2,
> +                                                                                       qup, 0, 0);
> +               } else {
> +                       tx_nents += (blocks * 2);
> +
> +                       while (qup->blk.pos < blocks) {
> +                               tlen = (i == (blocks - 1)) ? rem : 0;
> +                               tags = &qup->start_tag.start[off + tx_len];
> +                               len = qup_i2c_get_tags(tags, qup, msg, 1);
> +
> +                               qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> +                                                                                               tags,
> +                                                                                               &qup->start_tag, len,
> +                                                                                               qup, 0, 0);
> +
> +                               tx_len += len;
> +                               qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> +                                                                                               &msg->buf[QUP_READ_LIMIT * i],
> +                                                                                               NULL, tlen, qup, 1,
> +                                                                                               DMA_TO_DEVICE);
> +                               i++;
> +                               qup->blk.pos = i;
> +                       }
> +                       off += tx_len;
> +
> +                       if (qup->cmsg == (qup->num - 1)) {
> +                               qup->btx.footer_tag.start[0] =
> +                                                                       QUP_BAM_FLUSH_STOP;
> +                               qup->btx.footer_tag.start[1] =
> +                                                                       QUP_BAM_FLUSH_STOP;
> +                               qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> +                                                                                               &qup->btx.footer_tag.start[0],
> +                                                                                               &qup->btx.footer_tag, 2,
> +                                                                                               qup, 0, 0);
> +                               tx_nents += 1;
> +                       }
> +               }
> +               qup->cmsg++;
> +               msg++;
> +       }
> +
> +       txd = dmaengine_prep_slave_sg(qup->btx.dma_tx, qup->btx.sg_tx, tx_nents,
> +                                                                               DMA_MEM_TO_DEV,
> +                                                                               DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
> +       if (!txd) {
> +               dev_err(qup->dev, "failed to get tx desc\n");
> +               ret = -EINVAL;
> +               goto desc_err;
> +       }
> +
> +       if (!rx_nents) {
> +               txd->callback = qup_i2c_bam_cb;
> +               txd->callback_param = qup;
> +       }
> +
> +       cookie_tx = dmaengine_submit(txd);

Check this cookie for error? Same bellow.

> +       dma_async_issue_pending(qup->btx.dma_tx);

Why TX messages are started first?

> +
> +       if (rx_nents) {
> +               rxd = dmaengine_prep_slave_sg(qup->brx.dma_rx, qup->brx.sg_rx,
> +                                                                                       rx_nents, DMA_DEV_TO_MEM,
> +                                                                                       DMA_PREP_INTERRUPT);
> +               if (!rxd) {
> +                       dev_err(qup->dev, "failed to get rx desc\n");
> +                       ret = -EINVAL;
> +
> +                       /* abort TX descriptors */
> +                       dmaengine_terminate_all(qup->btx.dma_tx);
> +                       goto desc_err;
> +               }
> +
> +               rxd->callback = qup_i2c_bam_cb;
> +               rxd->callback_param = qup;
> +               cookie_rx = dmaengine_submit(rxd);
> +               dma_async_issue_pending(qup->brx.dma_rx);
> +       }
> +
> +       if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
> +               dev_err(qup->dev, "normal trans timed out\n");
> +               ret = -ETIMEDOUT;
> +       }

There could be multiple messages for RX and TX queued for transfer, 
and they could be mixed. Using just one completion did't look right. 

> +
> +       if (ret || qup->bus_err || qup->qup_err) {
> +               if (qup->bus_err & QUP_I2C_NACK_FLAG) {
> +                       msg--;
> +                       dev_err(qup->dev, "NACK from %x\n", msg->addr);
> +                       ret = -EIO;
> +
> +                       if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
> +                               dev_err(qup->dev, "change to run state timed out");
> +                               return ret;
> +                       }
> +
> +                       if (rx_nents)
> +                               writel(QUP_BAM_INPUT_EOT,
> +                                                                                       qup->base + QUP_OUT_FIFO_BASE);
> +
> +                       writel(QUP_BAM_FLUSH_STOP,
> +                                                                               qup->base + QUP_OUT_FIFO_BASE);
> +
> +                       qup_i2c_flush(qup);
> +
> +                       /* wait for remaining interrupts to occur */
> +                       if (!wait_for_completion_timeout(&qup->xfer, HZ))
> +                               dev_err(qup->dev, "flush timed out\n");
> +
> +                       qup_i2c_rel_dma(qup);
> +               }
> +       }
> +
> +       dma_unmap_sg(qup->dev, qup->btx.sg_tx, tx_nents, DMA_TO_DEVICE);
> +
> +       if (rx_nents)
> +               dma_unmap_sg(qup->dev, qup->brx.sg_rx, rx_nents,
> +                                                               DMA_FROM_DEVICE);
> +desc_err:
> +       return ret;
> +}
> +
> +static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg)
> +{

Please use consistent naming convention.

> +       struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> +       int ret = 0;
> +
> +       enable_irq(qup->irq);
> +       if (qup_i2c_req_dma(qup))

Why?

> 
> +
>  static int qup_i2c_xfer(struct i2c_adapter *adap,
>                         struct i2c_msg msgs[],
>                         int num)
> @@ -836,7 +1143,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>                                                 int num)
>  {
>         struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> -       int ret, idx;
> +       int ret, idx, len, use_dma  = 0;
> 
>         qup->num = num;
>         qup->cmsg = 0;
> @@ -854,12 +1161,27 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
>         writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
>         writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
> 
> -       for (idx = 0; idx < num; idx++) {
> -               if (msgs[idx].len == 0) {
> -                       ret = -EINVAL;
> -                       goto out;
> +       if ((qup->is_dma)) {
> +               /* All i2c_msgs should be transferred using either dma or cpu */
> +               for (idx = 0; idx < num; idx++) {
> +                       if (msgs[idx].len == 0) {
> +                               ret = -EINVAL;
> +                               goto out;
> +                       }
> +
> +                       len = (msgs[idx].len > qup->out_fifo_sz) ||
> +                                                                       (msgs[idx].len > qup->in_fifo_sz);
> +
> +                       if ((!is_vmalloc_addr(msgs[idx].buf)) && len) {

What is wrong with vmalloc addresses?

> +                               use_dma = 1;
> +                               } else {
> +                               use_dma = 0;
> +                               break;
> +                       }
>                 }
> +       }
> 
> +       for (idx = 0; idx < num; idx++) {
>                 if (qup_i2c_poll_state_i2c_master(qup)) {
>                         ret = -EIO;
>                         goto out;
> @@ -867,10 +1189,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
> 
>                 reinit_completion(&qup->xfer);
> 
> -               if (msgs[idx].flags & I2C_M_RD)
> -                       ret = qup_i2c_read(qup, &msgs[idx]);
> -               else
> -                       ret = qup_i2c_write(qup, &msgs[idx]);
> +               len = msgs[idx].len;

Unused?

> +
> +               if (use_dma) {
> +                       ret = qup_bam_xfer(adap, &msgs[idx]);
> +                       idx = num;

Hacky.

> +               } else {
> +                       if (msgs[idx].flags & I2C_M_RD)
> +                               ret = qup_i2c_read(qup, &msgs[idx]);
> +                       else
> +                               ret = qup_i2c_write(qup, &msgs[idx]);
> +               }
> 
>                 if (ret)
>                         break;
> @@ -943,6 +1272,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>         int ret, fs_div, hs_div;
>         int src_clk_freq;
>         u32 clk_freq = 100000;
> +       int blocks;
> 
>         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>         if (!qup)
> @@ -963,8 +1293,60 @@ static int qup_i2c_probe(struct platform_device *pdev)
>                 qup->qup_i2c_write_one = qup_i2c_write_one_v2;
>                 qup->qup_i2c_read_one = qup_i2c_read_one_v2;
>                 qup->use_v2_tags = 1;
> +
> +               if (qup_i2c_req_dma(qup))
> +                       goto nodma;

Just return what request DMA functions return?

Regards,
Ivan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH V4 2/7] qup: i2c: factor out common code for reuse
  2015-07-20  8:25     ` Ivan T. Ivanov
  (?)
@ 2015-07-21  6:54       ` Sricharan
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21  6:54 UTC (permalink / raw)
  To: 'Ivan T. Ivanov'
  Cc: devicetree, linux-arm-msm, galak, linux-kernel, linux-i2c,
	agross, dmaengine, linux-arm-kernel

Hi Ivan,
  Thnaks for all the reviews.

> -----Original Message-----
> From: linux-arm-msm-owner@vger.kernel.org [mailto:linux-arm-msm-
> owner@vger.kernel.org] On Behalf Of Ivan T. Ivanov
> Sent: Monday, July 20, 2015 1:55 PM
> To: Sricharan R
> Cc: devicetree@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> galak@codeaurora.org; linux-kernel@vger.kernel.org; linux-
> i2c@vger.kernel.org; agross@codeaurora.org; dmaengine@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH V4 2/7] qup: i2c: factor out common code for reuse
> 
> 
> Hi Sricharan,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> >
> 
> >  static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg
> > *msg)  {
> > -       unsigned long left;
> > -       int ret;
> > +       int ret = 0;
> >
> > -       qup->msg = msg;
> > -       qup->pos  = 0;
> > +       /*
> > +               * The QUP block will issue a NACK and STOP on the bus when
> reaching
> > +               * the end of the read, the length of the read is specified as one
> byte
> > +               * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
> > +               */
> > +       if (msg->len > QUP_READ_LIMIT) {
> > +               dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
> > +                       QUP_READ_LIMIT);
> > +               return -EINVAL;
> > +       }
> >
> 
> This should be removed. Please see qup_i2c_quirks.
> 
  Ok get it, will remove this.

Regards,
 Sricharan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH V4 2/7] qup: i2c: factor out common code for reuse
@ 2015-07-21  6:54       ` Sricharan
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21  6:54 UTC (permalink / raw)
  To: 'Ivan T. Ivanov'
  Cc: devicetree, linux-arm-msm, galak, linux-kernel, linux-i2c,
	agross, dmaengine, linux-arm-kernel

Hi Ivan,
  Thnaks for all the reviews.

> -----Original Message-----
> From: linux-arm-msm-owner@vger.kernel.org [mailto:linux-arm-msm-
> owner@vger.kernel.org] On Behalf Of Ivan T. Ivanov
> Sent: Monday, July 20, 2015 1:55 PM
> To: Sricharan R
> Cc: devicetree@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> galak@codeaurora.org; linux-kernel@vger.kernel.org; linux-
> i2c@vger.kernel.org; agross@codeaurora.org; dmaengine@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH V4 2/7] qup: i2c: factor out common code for reuse
> 
> 
> Hi Sricharan,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> >
> 
> >  static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg
> > *msg)  {
> > -       unsigned long left;
> > -       int ret;
> > +       int ret = 0;
> >
> > -       qup->msg = msg;
> > -       qup->pos  = 0;
> > +       /*
> > +               * The QUP block will issue a NACK and STOP on the bus when
> reaching
> > +               * the end of the read, the length of the read is specified as one
> byte
> > +               * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
> > +               */
> > +       if (msg->len > QUP_READ_LIMIT) {
> > +               dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
> > +                       QUP_READ_LIMIT);
> > +               return -EINVAL;
> > +       }
> >
> 
> This should be removed. Please see qup_i2c_quirks.
> 
  Ok get it, will remove this.

Regards,
 Sricharan


^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 2/7] qup: i2c: factor out common code for reuse
@ 2015-07-21  6:54       ` Sricharan
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21  6:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ivan,
  Thnaks for all the reviews.

> -----Original Message-----
> From: linux-arm-msm-owner at vger.kernel.org [mailto:linux-arm-msm-
> owner at vger.kernel.org] On Behalf Of Ivan T. Ivanov
> Sent: Monday, July 20, 2015 1:55 PM
> To: Sricharan R
> Cc: devicetree at vger.kernel.org; linux-arm-msm at vger.kernel.org;
> galak at codeaurora.org; linux-kernel at vger.kernel.org; linux-
> i2c at vger.kernel.org; agross at codeaurora.org; dmaengine at vger.kernel.org;
> linux-arm-kernel at lists.infradead.org
> Subject: Re: [PATCH V4 2/7] qup: i2c: factor out common code for reuse
> 
> 
> Hi Sricharan,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> >
> 
> >  static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg
> > *msg)  {
> > -       unsigned long left;
> > -       int ret;
> > +       int ret = 0;
> >
> > -       qup->msg = msg;
> > -       qup->pos  = 0;
> > +       /*
> > +               * The QUP block will issue a NACK and STOP on the bus when
> reaching
> > +               * the end of the read, the length of the read is specified as one
> byte
> > +               * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
> > +               */
> > +       if (msg->len > QUP_READ_LIMIT) {
> > +               dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
> > +                       QUP_READ_LIMIT);
> > +               return -EINVAL;
> > +       }
> >
> 
> This should be removed. Please see qup_i2c_quirks.
> 
  Ok get it, will remove this.

Regards,
 Sricharan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH V4 3/7] i2c: qup: Add V2 tags support
  2015-07-20  9:44     ` Ivan T. Ivanov
  (?)
@ 2015-07-21  7:11         ` Sricharan
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21  7:11 UTC (permalink / raw)
  To: 'Ivan T. Ivanov'
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, agross-sgV2jX0FEOL9JmXXK+q4OQ,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi Ivan,

> -----Original Message-----
> From: Ivan T. Ivanov [mailto:iivanov-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org]
> Sent: Monday, July 20, 2015 3:14 PM
> To: Sricharan R
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; linux-arm-msm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org;
> galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org; linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; linux-
> i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; agross-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org; dmaengine-u79uwXL29TY76Z2rM5mHXA@public.gmane.org;
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> Subject: Re: [PATCH V4 3/7] i2c: qup: Add V2 tags support
> 
> 
> Hi Sricharan,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> > QUP from version 2.1.1 onwards, supports a new format of i2c command
> > tags. Tag codes instructs the controller to perform a operation like
> > read/write. This new tagging version supports bam dma and transfers of
> > more than 256 bytes without 'stop'
> > in between. Adding the support for the same.
> 
> IIRC, more than 256 bytes in message is supported only in BAM(DMA) mode,
> if this is true, please be more explicit in commit message.

   More than 256 byte read transfers are possible in V2 mode and not possible only
   in V1 mode.  So qup_i2c_quirks should be populated only for V1 mode and V2 mode
   during probe.

> 
> You haven't tried to read more than 256 bytes with this patch, right? See
> qup_i2c_quirks ;-)
     Ya I have tested for 256 bytes transfer in my previous series, not on
     this one. My bad. Should have error'ed out with qup_i2c_quirks in place.
     Anyways will not populate qup_i2c_quirks for v2 mode.

> 
> >
> >
> >  struct qup_i2c_dev {
> >         struct device*dev;
> >         void __iomem*base;
> > @@ -117,6 +138,7 @@ struct qup_i2c_dev {
> >         int     in_blk_sz;
> >
> >         unsigned longone_byte_t;
> > +       struct qup_i2c_blockblk;
> >
> >         struct i2c_msg*msg;
> >         /* Current posion in user message buffer */ @@ -126,6 +148,14
> > @@ struct qup_i2c_dev {
> >         /* QUP core errors */
> >         u32     qup_err;
> >
> > +       int     use_v2_tags;
> > +
> > +       int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> > +                                       struct i2c_msg *msg);
> > +
> > +       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> > +                               struct i2c_msg *msg);
> > +
> 
> Do we really need additional level of indirection?
> 
> We have separate struct i2c_algorithm, then we have common
> qup_i2c_read/write methods and then we have different read/write sub
> functions. I don't think 3-4 lines code reuse deserve increased complexity.

   Infact I was thinking this way as well. But anyways wanted to get reviewed
   and see which was better. Will change this.

> 
> <snip>
> 
> > +static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
> > +                                       struct i2c_msg *msg) {
> 
> This is more like "set_blk_metadata". Second argument could fit line above.
> 
 Ok. Will change name and indentation.

> > +       memset(&qup->blk, 0, sizeof(qup->blk));
> > +
> > +       if (!qup->use_v2_tags) {
> > +               if (!(msg->flags & I2C_M_RD))
> > +                       qup->blk.tx_tag_len = 1;
> > +               return;
> > +       }
> > +
> > +       qup->blk.data_len = msg->len;
> > +       qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) /
> > + QUP_READ_LIMIT;
> > +
> > +       /* 4 bytes for first block and 2 writes for rest */
> > +       qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
> > +
> > +       /* There are 2 tag bytes that are read in to fifo for every block */
> > +       if (msg->flags & I2C_M_RD)
> > +               qup->blk.rx_tag_len = qup->blk.count * 2; }
> > +
> 
> <snip>
> 
> > +static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
> > +                                                       struct i2c_msg
> > +*msg) {
> 
> This is more like "set_tags".

 Ok, will change.
> 
> > +       u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) ==
> I2C_M_RD);
> > +       int len = 0;
> > +       int data_len;
> > +
> > +       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;
> > +       }
> > +
> > +       /* Send _STOP commands for the last block */
> > +       if (qup->blk.pos == (qup->blk.count - 1)) {
> > +               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);
> > +
> > +       /* 0 implies 256 bytes */
> > +       if (data_len == QUP_READ_LIMIT)
> > +               tags[len++] = 0;
> > +       else
> > +               tags[len++] = data_len;
> > +
> > +       return len;
> > +}
> > +

Regards,
  Sricharan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH V4 3/7] i2c: qup: Add V2 tags support
@ 2015-07-21  7:11         ` Sricharan
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21  7:11 UTC (permalink / raw)
  To: 'Ivan T. Ivanov'
  Cc: devicetree, linux-arm-msm, galak, linux-kernel, linux-i2c,
	agross, dmaengine, linux-arm-kernel

Hi Ivan,

> -----Original Message-----
> From: Ivan T. Ivanov [mailto:iivanov@mm-sol.com]
> Sent: Monday, July 20, 2015 3:14 PM
> To: Sricharan R
> Cc: devicetree@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> galak@codeaurora.org; linux-kernel@vger.kernel.org; linux-
> i2c@vger.kernel.org; agross@codeaurora.org; dmaengine@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH V4 3/7] i2c: qup: Add V2 tags support
> 
> 
> Hi Sricharan,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> > QUP from version 2.1.1 onwards, supports a new format of i2c command
> > tags. Tag codes instructs the controller to perform a operation like
> > read/write. This new tagging version supports bam dma and transfers of
> > more than 256 bytes without 'stop'
> > in between. Adding the support for the same.
> 
> IIRC, more than 256 bytes in message is supported only in BAM(DMA) mode,
> if this is true, please be more explicit in commit message.

   More than 256 byte read transfers are possible in V2 mode and not possible only
   in V1 mode.  So qup_i2c_quirks should be populated only for V1 mode and V2 mode
   during probe.

> 
> You haven't tried to read more than 256 bytes with this patch, right? See
> qup_i2c_quirks ;-)
     Ya I have tested for 256 bytes transfer in my previous series, not on
     this one. My bad. Should have error'ed out with qup_i2c_quirks in place.
     Anyways will not populate qup_i2c_quirks for v2 mode.

> 
> >
> >
> >  struct qup_i2c_dev {
> >         struct device*dev;
> >         void __iomem*base;
> > @@ -117,6 +138,7 @@ struct qup_i2c_dev {
> >         int     in_blk_sz;
> >
> >         unsigned longone_byte_t;
> > +       struct qup_i2c_blockblk;
> >
> >         struct i2c_msg*msg;
> >         /* Current posion in user message buffer */ @@ -126,6 +148,14
> > @@ struct qup_i2c_dev {
> >         /* QUP core errors */
> >         u32     qup_err;
> >
> > +       int     use_v2_tags;
> > +
> > +       int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> > +                                       struct i2c_msg *msg);
> > +
> > +       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> > +                               struct i2c_msg *msg);
> > +
> 
> Do we really need additional level of indirection?
> 
> We have separate struct i2c_algorithm, then we have common
> qup_i2c_read/write methods and then we have different read/write sub
> functions. I don't think 3-4 lines code reuse deserve increased complexity.

   Infact I was thinking this way as well. But anyways wanted to get reviewed
   and see which was better. Will change this.

> 
> <snip>
> 
> > +static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
> > +                                       struct i2c_msg *msg) {
> 
> This is more like "set_blk_metadata". Second argument could fit line above.
> 
 Ok. Will change name and indentation.

> > +       memset(&qup->blk, 0, sizeof(qup->blk));
> > +
> > +       if (!qup->use_v2_tags) {
> > +               if (!(msg->flags & I2C_M_RD))
> > +                       qup->blk.tx_tag_len = 1;
> > +               return;
> > +       }
> > +
> > +       qup->blk.data_len = msg->len;
> > +       qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) /
> > + QUP_READ_LIMIT;
> > +
> > +       /* 4 bytes for first block and 2 writes for rest */
> > +       qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
> > +
> > +       /* There are 2 tag bytes that are read in to fifo for every block */
> > +       if (msg->flags & I2C_M_RD)
> > +               qup->blk.rx_tag_len = qup->blk.count * 2; }
> > +
> 
> <snip>
> 
> > +static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
> > +                                                       struct i2c_msg
> > +*msg) {
> 
> This is more like "set_tags".

 Ok, will change.
> 
> > +       u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) ==
> I2C_M_RD);
> > +       int len = 0;
> > +       int data_len;
> > +
> > +       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;
> > +       }
> > +
> > +       /* Send _STOP commands for the last block */
> > +       if (qup->blk.pos == (qup->blk.count - 1)) {
> > +               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);
> > +
> > +       /* 0 implies 256 bytes */
> > +       if (data_len == QUP_READ_LIMIT)
> > +               tags[len++] = 0;
> > +       else
> > +               tags[len++] = data_len;
> > +
> > +       return len;
> > +}
> > +

Regards,
  Sricharan


^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 3/7] i2c: qup: Add V2 tags support
@ 2015-07-21  7:11         ` Sricharan
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21  7:11 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ivan,

> -----Original Message-----
> From: Ivan T. Ivanov [mailto:iivanov at mm-sol.com]
> Sent: Monday, July 20, 2015 3:14 PM
> To: Sricharan R
> Cc: devicetree at vger.kernel.org; linux-arm-msm at vger.kernel.org;
> galak at codeaurora.org; linux-kernel at vger.kernel.org; linux-
> i2c at vger.kernel.org; agross at codeaurora.org; dmaengine at vger.kernel.org;
> linux-arm-kernel at lists.infradead.org
> Subject: Re: [PATCH V4 3/7] i2c: qup: Add V2 tags support
> 
> 
> Hi Sricharan,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> > QUP from version 2.1.1 onwards, supports a new format of i2c command
> > tags. Tag codes instructs the controller to perform a operation like
> > read/write. This new tagging version supports bam dma and transfers of
> > more than 256 bytes without 'stop'
> > in between. Adding the support for the same.
> 
> IIRC, more than 256 bytes in message is supported only in BAM(DMA) mode,
> if this is true, please be more explicit in commit message.

   More than 256 byte read transfers are possible in V2 mode and not possible only
   in V1 mode.  So qup_i2c_quirks should be populated only for V1 mode and V2 mode
   during probe.

> 
> You haven't tried to read more than 256 bytes with this patch, right? See
> qup_i2c_quirks ;-)
     Ya I have tested for 256 bytes transfer in my previous series, not on
     this one. My bad. Should have error'ed out with qup_i2c_quirks in place.
     Anyways will not populate qup_i2c_quirks for v2 mode.

> 
> >
> >
> >  struct qup_i2c_dev {
> >         struct device*dev;
> >         void __iomem*base;
> > @@ -117,6 +138,7 @@ struct qup_i2c_dev {
> >         int     in_blk_sz;
> >
> >         unsigned longone_byte_t;
> > +       struct qup_i2c_blockblk;
> >
> >         struct i2c_msg*msg;
> >         /* Current posion in user message buffer */ @@ -126,6 +148,14
> > @@ struct qup_i2c_dev {
> >         /* QUP core errors */
> >         u32     qup_err;
> >
> > +       int     use_v2_tags;
> > +
> > +       int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> > +                                       struct i2c_msg *msg);
> > +
> > +       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> > +                               struct i2c_msg *msg);
> > +
> 
> Do we really need additional level of indirection?
> 
> We have separate struct i2c_algorithm, then we have common
> qup_i2c_read/write methods and then we have different read/write sub
> functions. I don't think 3-4 lines code reuse deserve increased complexity.

   Infact I was thinking this way as well. But anyways wanted to get reviewed
   and see which was better. Will change this.

> 
> <snip>
> 
> > +static void qup_i2c_get_blk_data(struct qup_i2c_dev *qup,
> > +                                       struct i2c_msg *msg) {
> 
> This is more like "set_blk_metadata". Second argument could fit line above.
> 
 Ok. Will change name and indentation.

> > +       memset(&qup->blk, 0, sizeof(qup->blk));
> > +
> > +       if (!qup->use_v2_tags) {
> > +               if (!(msg->flags & I2C_M_RD))
> > +                       qup->blk.tx_tag_len = 1;
> > +               return;
> > +       }
> > +
> > +       qup->blk.data_len = msg->len;
> > +       qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) /
> > + QUP_READ_LIMIT;
> > +
> > +       /* 4 bytes for first block and 2 writes for rest */
> > +       qup->blk.tx_tag_len = 4 + (qup->blk.count - 1) * 2;
> > +
> > +       /* There are 2 tag bytes that are read in to fifo for every block */
> > +       if (msg->flags & I2C_M_RD)
> > +               qup->blk.rx_tag_len = qup->blk.count * 2; }
> > +
> 
> <snip>
> 
> > +static int qup_i2c_get_tags(u8 *tags, struct qup_i2c_dev *qup,
> > +                                                       struct i2c_msg
> > +*msg) {
> 
> This is more like "set_tags".

 Ok, will change.
> 
> > +       u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) ==
> I2C_M_RD);
> > +       int len = 0;
> > +       int data_len;
> > +
> > +       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;
> > +       }
> > +
> > +       /* Send _STOP commands for the last block */
> > +       if (qup->blk.pos == (qup->blk.count - 1)) {
> > +               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);
> > +
> > +       /* 0 implies 256 bytes */
> > +       if (data_len == QUP_READ_LIMIT)
> > +               tags[len++] = 0;
> > +       else
> > +               tags[len++] = data_len;
> > +
> > +       return len;
> > +}
> > +

Regards,
  Sricharan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
  2015-07-20 11:22         ` Ivan T. Ivanov
  (?)
@ 2015-07-21  8:09           ` Sricharan
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21  8:09 UTC (permalink / raw)
  To: 'Ivan T. Ivanov'
  Cc: devicetree, linux-arm-msm, galak, linux-kernel, linux-i2c,
	agross, dmaengine, linux-arm-kernel

Hi Ivan,

> -----Original Message-----
> From: Ivan T. Ivanov [mailto:iivanov@mm-sol.com]
> Sent: Monday, July 20, 2015 4:53 PM
> To: Sricharan R
> Cc: devicetree@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> galak@codeaurora.org; linux-kernel@vger.kernel.org; linux-
> i2c@vger.kernel.org; agross@codeaurora.org; dmaengine@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs
> without a stop bit
> 
> 
> Hi,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> 
> <snip>
> 
> >  #define ONE_BYTE                       0x1
> > +#define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
> >
> >  struct qup_i2c_block {
> >         int     count;
> > @@ -121,6 +122,7 @@ struct qup_i2c_block {
> >         int     rx_tag_len;
> >         int     data_len;
> >         u8      tags[6];
> > +       int     config_run;
> 
> This is not directly related to "block" control logic, right?
> Could it made part of qup_i2c_dev structure?
> 
   Yes, can move it there.

> >  };
> >
> >  struct qup_i2c_dev {
> > @@ -152,6 +154,10 @@ struct qup_i2c_dev {
> >
> >         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> >                                         struct i2c_msg *msg);
> > +       /* Current i2c_msg in i2c_msgs */
> > +       int     cmsg;
> > +       /* total num of i2c_msgs */
> > +       int     num;
> 
> I think it will be simpler with just "bool is_last" evaluated in main xfer loop.
  
   Hmm ok. Will change it that way. Set it one place and use it other places.
> 
> <snip>
> 
> >
> > @@ -374,6 +383,9 @@ static void qup_i2c_get_blk_data(struct
> qup_i2c_dev *qup,
> >         /* There are 2 tag bytes that are read in to fifo for every block */
> >         if (msg->flags & I2C_M_RD)
> >                 qup->blk.rx_tag_len = qup->blk.count * 2;
> > +
> > +       if (qup->cmsg)
> > +               qup->blk.config_run = QUP_I2C_MX_CONFIG_DURING_RUN;
> 
> This could be moved to qup_i2c_xfer_v2() to avoid repeatedly setting it.
     Ok, correct.

Regards,
 Sricharan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
@ 2015-07-21  8:09           ` Sricharan
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21  8:09 UTC (permalink / raw)
  To: 'Ivan T. Ivanov'
  Cc: devicetree, linux-arm-msm, galak, linux-kernel, linux-i2c,
	agross, dmaengine, linux-arm-kernel

Hi Ivan,

> -----Original Message-----
> From: Ivan T. Ivanov [mailto:iivanov@mm-sol.com]
> Sent: Monday, July 20, 2015 4:53 PM
> To: Sricharan R
> Cc: devicetree@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> galak@codeaurora.org; linux-kernel@vger.kernel.org; linux-
> i2c@vger.kernel.org; agross@codeaurora.org; dmaengine@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs
> without a stop bit
> 
> 
> Hi,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> 
> <snip>
> 
> >  #define ONE_BYTE                       0x1
> > +#define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
> >
> >  struct qup_i2c_block {
> >         int     count;
> > @@ -121,6 +122,7 @@ struct qup_i2c_block {
> >         int     rx_tag_len;
> >         int     data_len;
> >         u8      tags[6];
> > +       int     config_run;
> 
> This is not directly related to "block" control logic, right?
> Could it made part of qup_i2c_dev structure?
> 
   Yes, can move it there.

> >  };
> >
> >  struct qup_i2c_dev {
> > @@ -152,6 +154,10 @@ struct qup_i2c_dev {
> >
> >         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> >                                         struct i2c_msg *msg);
> > +       /* Current i2c_msg in i2c_msgs */
> > +       int     cmsg;
> > +       /* total num of i2c_msgs */
> > +       int     num;
> 
> I think it will be simpler with just "bool is_last" evaluated in main xfer loop.
  
   Hmm ok. Will change it that way. Set it one place and use it other places.
> 
> <snip>
> 
> >
> > @@ -374,6 +383,9 @@ static void qup_i2c_get_blk_data(struct
> qup_i2c_dev *qup,
> >         /* There are 2 tag bytes that are read in to fifo for every block */
> >         if (msg->flags & I2C_M_RD)
> >                 qup->blk.rx_tag_len = qup->blk.count * 2;
> > +
> > +       if (qup->cmsg)
> > +               qup->blk.config_run = QUP_I2C_MX_CONFIG_DURING_RUN;
> 
> This could be moved to qup_i2c_xfer_v2() to avoid repeatedly setting it.
     Ok, correct.

Regards,
 Sricharan


^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit
@ 2015-07-21  8:09           ` Sricharan
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21  8:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ivan,

> -----Original Message-----
> From: Ivan T. Ivanov [mailto:iivanov at mm-sol.com]
> Sent: Monday, July 20, 2015 4:53 PM
> To: Sricharan R
> Cc: devicetree at vger.kernel.org; linux-arm-msm at vger.kernel.org;
> galak at codeaurora.org; linux-kernel at vger.kernel.org; linux-
> i2c at vger.kernel.org; agross at codeaurora.org; dmaengine at vger.kernel.org;
> linux-arm-kernel at lists.infradead.org
> Subject: Re: [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs
> without a stop bit
> 
> 
> Hi,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> 
> <snip>
> 
> >  #define ONE_BYTE                       0x1
> > +#define QUP_I2C_MX_CONFIG_DURING_RUN   BIT(31)
> >
> >  struct qup_i2c_block {
> >         int     count;
> > @@ -121,6 +122,7 @@ struct qup_i2c_block {
> >         int     rx_tag_len;
> >         int     data_len;
> >         u8      tags[6];
> > +       int     config_run;
> 
> This is not directly related to "block" control logic, right?
> Could it made part of qup_i2c_dev structure?
> 
   Yes, can move it there.

> >  };
> >
> >  struct qup_i2c_dev {
> > @@ -152,6 +154,10 @@ struct qup_i2c_dev {
> >
> >         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> >                                         struct i2c_msg *msg);
> > +       /* Current i2c_msg in i2c_msgs */
> > +       int     cmsg;
> > +       /* total num of i2c_msgs */
> > +       int     num;
> 
> I think it will be simpler with just "bool is_last" evaluated in main xfer loop.
  
   Hmm ok. Will change it that way. Set it one place and use it other places.
> 
> <snip>
> 
> >
> > @@ -374,6 +383,9 @@ static void qup_i2c_get_blk_data(struct
> qup_i2c_dev *qup,
> >         /* There are 2 tag bytes that are read in to fifo for every block */
> >         if (msg->flags & I2C_M_RD)
> >                 qup->blk.rx_tag_len = qup->blk.count * 2;
> > +
> > +       if (qup->cmsg)
> > +               qup->blk.config_run = QUP_I2C_MX_CONFIG_DURING_RUN;
> 
> This could be moved to qup_i2c_xfer_v2() to avoid repeatedly setting it.
     Ok, correct.

Regards,
 Sricharan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
  2015-07-20 14:46       ` Ivan T. Ivanov
  (?)
@ 2015-07-21 11:10         ` Sricharan
  -1 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21 11:10 UTC (permalink / raw)
  To: 'Ivan T. Ivanov'
  Cc: devicetree, linux-arm-msm, agross, linux-kernel, linux-i2c,
	galak, dmaengine, linux-arm-kernel

Hi Ivan,

> -----Original Message-----
> From: linux-arm-kernel [mailto:linux-arm-kernel-
> bounces@lists.infradead.org] On Behalf Of Ivan T. Ivanov
> Sent: Monday, July 20, 2015 8:17 PM
> To: Sricharan R
> Cc: devicetree@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> agross@codeaurora.org; linux-kernel@vger.kernel.org; linux-
> i2c@vger.kernel.org; galak@codeaurora.org; dmaengine@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
> 
> 
> Hi Sricharan,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> > QUP cores can be attached to a BAM module, which acts as a dma engine
> > for the QUP core. When DMA with BAM is enabled, the BAM consumer
> pipe
> > transmitted data is written to the output FIFO and the BAM producer
> > pipe received data is read from the input FIFO.
> >
> > With BAM capabilities, qup-i2c core can transfer more than 256 bytes,
> > without a 'stop' which is not possible otherwise.
> >
> > Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> > ---
> >  drivers/i2c/busses/i2c-qup.c | 431
> > +++++++++++++++++++++++++++++++++++++++++--
> >  1 file changed, 415 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/i2c/busses/i2c-qup.c
> > b/drivers/i2c/busses/i2c-qup.c index c0757d9..810b021 100644
> > --- a/drivers/i2c/busses/i2c-qup.c
> > +++ b/drivers/i2c/busses/i2c-qup.c
> > @@ -24,6 +24,11 @@
> >  #include <linux/of.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/pm_runtime.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/scatterlist.h>
> > +#include <linux/atomic.h>
> > +#include <linux/dmaengine.h>
> > +#include <linux/dmapool.h>
> 
> Keep includes sorted alphabetically.
 Ok.

> 
> <snip>
> 
> > +#define MX_TX_RX_LEN                   SZ_64K
> > +#define MX_BLOCKS                      (MX_TX_RX_LEN / QUP_READ_LIMIT)
> > +
> > +/* Max timeout in ms for 32k bytes */
> > +#define TOUT_MAX                       300
> > +
> >  struct qup_i2c_block {
> >         int     count;
> >         int     pos;
> > @@ -125,6 +143,23 @@ struct qup_i2c_block {
> >         int     config_run;
> >  };
> >
> > +struct qup_i2c_tag {
> > +       u8 *start;
> > +       dma_addr_t addr;
> > +};
> > +
> > +struct qup_i2c_bam_rx {
> > +       struct  qup_i2c_tag scratch_tag;
> > +       struct  dma_chan *dma_rx;
> > +       struct  scatterlist *sg_rx;
> > +};
> > +
> > +struct qup_i2c_bam_tx {
> > +       struct  qup_i2c_tag footer_tag;
> > +       struct  dma_chan *dma_tx;
> > +       struct  scatterlist *sg_tx;
> > +};
> > +
> 
> The only difference between above 2 structures is name of the fields.
> Please, just define one struct qup_i2c_bam and instantiate it twice.
 Ok.

> 
> >  struct qup_i2c_dev {
> >         struct device*dev;
> >         void __iomem*base;
> > @@ -154,14 +189,20 @@ struct qup_i2c_dev {
> >
> >         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> >                                         struct i2c_msg *msg);
> > +       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> > +                               struct i2c_msg *msg);
> > +
> >         /* Current i2c_msg in i2c_msgs */
> >         int     cmsg;
> >         /* total num of i2c_msgs */
> >         int     num;
> >
> > -       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> > -                               struct i2c_msg *msg);
> > -
> > +       /* dma parameters */
> > +       bool    is_dma;
> > +       struct  dma_pool *dpool;
> > +       struct  qup_i2c_tag start_tag;
> > +       struct  qup_i2c_bam_rx brx;
> > +       struct  qup_i2c_bam_tx btx;
> >         struct completionxfer;
> >  };
> >
> > @@ -238,6 +279,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev
> *qup, u32 req_state)
> >         return qup_i2c_poll_state_mask(qup, req_state,
> > QUP_STATE_MASK);  }
> >
> > +static void qup_i2c_flush(struct qup_i2c_dev *qup) {
> > +       u32 val = readl(qup->base + QUP_STATE);
> > +
> > +       val |= QUP_I2C_FLUSH;
> > +       writel(val, qup->base + QUP_STATE); }
> > +
> 
> Used in only one place.
        So you mean no need to separate this as function ?

> 
> <snip>
> 
> >
> > +static void qup_i2c_bam_cb(void *data) {
> > +       struct qup_i2c_dev *qup = data;
> > +
> > +       complete(&qup->xfer);
> > +}
> > +
> > +void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct
qup_i2c_tag
> *tg,
> > +                                               unsigned int buflen,
struct qup_i2c_dev *qup,
> > +                                               int map, int dir) {
> > +       sg_set_buf(sg, buf, buflen);
> > +       dma_map_sg(qup->dev, sg, 1, dir);
> > +
> > +       if (!map)
> > +               sg_dma_address(sg) = tg->addr + ((u8 *)buf -
> > + tg->start);
> 
> Changing DMA address that we just mapped?

       The reason was tags that were allocated during probe
       using dma_alloc could also be from highmem. dma_map_sg
       assumes linear kernel addresses for virtual addresses to be mapped.
       So the sg->addr set using sg_set_buf goes wrong for such addresses.
       sg->len is fine for both cases. So setting the addresses explicitly
here. 
 
> 
> > +}
> > +
> > +static void qup_i2c_rel_dma(struct qup_i2c_dev *qup) {
> > +       if (qup->btx.dma_tx)
> > +               dma_release_channel(qup->btx.dma_tx);
> > +       if (qup->brx.dma_rx)
> > +               dma_release_channel(qup->brx.dma_rx);
> > +       qup->btx.dma_tx = NULL;
> > +       qup->brx.dma_rx = NULL;
> > +}
> > +
> > +static int qup_i2c_req_dma(struct qup_i2c_dev *qup) {
> > +       if (!qup->btx.dma_tx) {
> > +               qup->btx.dma_tx = dma_request_slave_channel(qup->dev,
> > +"tx");
> 
> Please use dma_request_slave_channel_reason() and let deferred probe
> work.
 Ok, right. Did this for something else previously. Missed it here. Will
change this.

> 
> > +               if (!qup->btx.dma_tx) {
> > +                       dev_err(qup->dev, "\n tx channel not
available");
> > +                       return -ENODEV;
> > +               }
> > +       }
> > +
> > +       if (!qup->brx.dma_rx) {
> > +               qup->brx.dma_rx = dma_request_slave_channel(qup->dev,
"rx");
> > +               if (!qup->brx.dma_rx) {
> > +                       dev_err(qup->dev, "\n rx channel not
available");
> > +                       qup_i2c_rel_dma(qup);
> > +                       return -ENODEV;
> > +               }
> > +       }
> > +       return 0;
> > +}
> > +
> > +static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> > +{
> 
> Please use consistent naming convention.
 Ok.

> 
> > +       struct dma_async_tx_descriptor *txd, *rxd = NULL;
> > +       int ret = 0;
> > +       dma_cookie_t cookie_rx, cookie_tx;
> > +       u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
> > +       u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
> > +       u8 *tags;
> > +
> > +       while (qup->cmsg < qup->num) {
> > +               blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
> > +               rem = msg->len % QUP_READ_LIMIT;
> > +               tx_len = 0, len = 0, i = 0;
> > +
> > +               qup_i2c_get_blk_data(qup, msg);
> > +
> > +               if (msg->flags & I2C_M_RD) {
> > +                       rx_nents += (blocks * 2) + 1;
> > +                       tx_nents += 1;
> > +
> > +                       while (qup->blk.pos < blocks) {
> > +                               /* length set to '0' implies 256 bytes
*/
> > +                               tlen = (i == (blocks - 1)) ? rem : 0;
> > +                               tags = &qup->start_tag.start[off + len];
> > +                               len += qup_i2c_get_tags(tags, qup,
> > + msg, 1);
> > +
> > +                               /* scratch buf to read the start and len
tags */
> > +
qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> > +
&qup-
> >brx.scratch_tag.start[0],
> > +
&qup-
> >brx.scratch_tag,
> > +
> > + 2, qup, 0, 0);
> > +
> > +
qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> > +
&msg-
> >buf[QUP_READ_LIMIT * i],
> > +
NULL, tlen, qup,
> > +
1,
> DMA_FROM_DEVICE);
> > +                               i++;
> > +                               qup->blk.pos = i;
> > +                       }
> > +                       qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
&qup-
> >start_tag.start[off],
> > +
&qup->start_tag, len, qup,
> 0, 0);
> > +                       off += len;
> > +                       /* scratch buf to read the BAM EOT and FLUSH
tags */
> > +                       qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> > +
&qup-
> >brx.scratch_tag.start[0],
> > +
&qup->brx.scratch_tag, 2,
> > +
qup, 0, 0);
> > +               } else {
> > +                       tx_nents += (blocks * 2);
> > +
> > +                       while (qup->blk.pos < blocks) {
> > +                               tlen = (i == (blocks - 1)) ? rem : 0;
> > +                               tags = &qup->start_tag.start[off +
tx_len];
> > +                               len = qup_i2c_get_tags(tags, qup, msg,
> > + 1);
> > +
> > +
qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
tags,
> > +
&qup->start_tag, len,
> > +
> > + qup, 0, 0);
> > +
> > +                               tx_len += len;
> > +
qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
&msg-
> >buf[QUP_READ_LIMIT * i],
> > +
NULL, tlen, qup, 1,
> > +
DMA_TO_DEVICE);
> > +                               i++;
> > +                               qup->blk.pos = i;
> > +                       }
> > +                       off += tx_len;
> > +
> > +                       if (qup->cmsg == (qup->num - 1)) {
> > +                               qup->btx.footer_tag.start[0] =
> > +
QUP_BAM_FLUSH_STOP;
> > +                               qup->btx.footer_tag.start[1] =
> > +
QUP_BAM_FLUSH_STOP;
> > +
qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
&qup-
> >btx.footer_tag.start[0],
> > +
&qup-
> >btx.footer_tag, 2,
> > +
qup, 0, 0);
> > +                               tx_nents += 1;
> > +                       }
> > +               }
> > +               qup->cmsg++;
> > +               msg++;
> > +       }
> > +
> > +       txd = dmaengine_prep_slave_sg(qup->btx.dma_tx, qup->btx.sg_tx,
> tx_nents,
> > +
DMA_MEM_TO_DEV,
> > +
DMA_PREP_INTERRUPT |
> DMA_PREP_FENCE);
> > +       if (!txd) {
> > +               dev_err(qup->dev, "failed to get tx desc\n");
> > +               ret = -EINVAL;
> > +               goto desc_err;
> > +       }
> > +
> > +       if (!rx_nents) {
> > +               txd->callback = qup_i2c_bam_cb;
> > +               txd->callback_param = qup;
> > +       }
> > +
> > +       cookie_tx = dmaengine_submit(txd);
> 
> Check this cookie for error? Same bellow.
Ok.

> 
> > +       dma_async_issue_pending(qup->btx.dma_tx);
> 
> Why TX messages are started first?
     For rx to start, tx pipe of tags have to start first.
     So tx always have to happen and rx happens only when
     there are rx_nents as below.
    
> 
> > +
> > +       if (rx_nents) {
> > +               rxd = dmaengine_prep_slave_sg(qup->brx.dma_rx, qup-
> >brx.sg_rx,
> > +
rx_nents,
> DMA_DEV_TO_MEM,
> > +
DMA_PREP_INTERRUPT);
> > +               if (!rxd) {
> > +                       dev_err(qup->dev, "failed to get rx desc\n");
> > +                       ret = -EINVAL;
> > +
> > +                       /* abort TX descriptors */
> > +                       dmaengine_terminate_all(qup->btx.dma_tx);
> > +                       goto desc_err;
> > +               }
> > +
> > +               rxd->callback = qup_i2c_bam_cb;
> > +               rxd->callback_param = qup;
> > +               cookie_rx = dmaengine_submit(rxd);
> > +               dma_async_issue_pending(qup->brx.dma_rx);
> > +       }
> > +
> > +       if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
> > +               dev_err(qup->dev, "normal trans timed out\n");
> > +               ret = -ETIMEDOUT;
> > +       }
> 
> There could be multiple messages for RX and TX queued for transfer, and
> they could be mixed. Using just one completion didn't look right.

  Even though there are multiple message mixed, all of them are packed as 
  one tx and rx descriptor finally.  Two things here,

      1)  when only tx pipe is used, we set the txd->callback which gets
fired after
             writing the last desc which has a 'EOT' bit set.

       2) For rx, we set the callback only for rx. Because
            for any RX transfer tx is used for writing tags. So when doing a

            read command, qup signals a completion on tx and rx pipe when it
sees a
            'BAM_INPUT_EOT'  for rx. So rx callback being called for read
implies
            corresponding tx is also done. I have seen this while doing
reads,
            tx and rx bam interrupts fire together. So even when mixed TX
and RX are there
            getting a callback for the last RX data implies a completion of
all.

           Having said above things, one thing missing is if tx is last
message
           then BAM_INPUT_EOT tag should be sent there as well. I did not
have
          a case where tx was the last. But will have to just add that tag
in above
          for tx. But not sure if there are clients to test all
combinations.
> 
> > +
> > +       if (ret || qup->bus_err || qup->qup_err) {
> > +               if (qup->bus_err & QUP_I2C_NACK_FLAG) {
> > +                       msg--;
> > +                       dev_err(qup->dev, "NACK from %x\n", msg->addr);
> > +                       ret = -EIO;
> > +
> > +                       if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
> > +                               dev_err(qup->dev, "change to run state
timed out");
> > +                               return ret;
> > +                       }
> > +
> > +                       if (rx_nents)
> > +                               writel(QUP_BAM_INPUT_EOT,
> > +
> > + qup->base + QUP_OUT_FIFO_BASE);
> > +
> > +                       writel(QUP_BAM_FLUSH_STOP,
> > +
> > + qup->base + QUP_OUT_FIFO_BASE);
> > +
> > +                       qup_i2c_flush(qup);
> > +
> > +                       /* wait for remaining interrupts to occur */
> > +                       if (!wait_for_completion_timeout(&qup->xfer,
HZ))
> > +                               dev_err(qup->dev, "flush timed
> > + out\n");
> > +
> > +                       qup_i2c_rel_dma(qup);
> > +               }
> > +       }
> > +
> > +       dma_unmap_sg(qup->dev, qup->btx.sg_tx, tx_nents,
> > + DMA_TO_DEVICE);
> > +
> > +       if (rx_nents)
> > +               dma_unmap_sg(qup->dev, qup->brx.sg_rx, rx_nents,
> > +
> > +DMA_FROM_DEVICE);
> > +desc_err:
> > +       return ret;
> > +}
> > +
> > +static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg
> > +*msg) {
> 
> Please use consistent naming convention.
 Ok.

> 
> > +       struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> > +       int ret = 0;
> > +
> > +       enable_irq(qup->irq);
> > +       if (qup_i2c_req_dma(qup))
> 
> Why?
    Have to request it again because, when the device 'Nacks out'
    on the previous transfers, then the bam channels used for that transfer
    have to be reset and init to be used again. Release and requesting them
    does this.

> 
> >
> > +
> >  static int qup_i2c_xfer(struct i2c_adapter *adap,
> >                         struct i2c_msg msgs[],
> >                         int num)
> > @@ -836,7 +1143,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter
> *adap,
> >                                                 int num)  {
> >         struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> > -       int ret, idx;
> > +       int ret, idx, len, use_dma  = 0;
> >
> >         qup->num = num;
> >         qup->cmsg = 0;
> > @@ -854,12 +1161,27 @@ static int qup_i2c_xfer_v2(struct i2c_adapter
> *adap,
> >         writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
> >         writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
> >
> > -       for (idx = 0; idx < num; idx++) {
> > -               if (msgs[idx].len == 0) {
> > -                       ret = -EINVAL;
> > -                       goto out;
> > +       if ((qup->is_dma)) {
> > +               /* All i2c_msgs should be transferred using either dma
or cpu */
> > +               for (idx = 0; idx < num; idx++) {
> > +                       if (msgs[idx].len == 0) {
> > +                               ret = -EINVAL;
> > +                               goto out;
> > +                       }
> > +
> > +                       len = (msgs[idx].len > qup->out_fifo_sz) ||
> > +
> > + (msgs[idx].len > qup->in_fifo_sz);
> > +
> > +                       if ((!is_vmalloc_addr(msgs[idx].buf)) && len)
> > + {
> 
> What is wrong with vmalloc addresses?
  When not physically contiguous, then we will have to again split it in
   to smaller sg buffers and then DMA them. This check was done to avoid
that
   extra level and use cpu transfers to keep it simple.

> 
> > +                               use_dma = 1;
> > +                               } else {
> > +                               use_dma = 0;
> > +                               break;
> > +                       }
> >                 }
> > +       }
> >
> > +       for (idx = 0; idx < num; idx++) {
> >                 if (qup_i2c_poll_state_i2c_master(qup)) {
> >                         ret = -EIO;
> >                         goto out;
> > @@ -867,10 +1189,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter
> > *adap,
> >
> >                 reinit_completion(&qup->xfer);
> >
> > -               if (msgs[idx].flags & I2C_M_RD)
> > -                       ret = qup_i2c_read(qup, &msgs[idx]);
> > -               else
> > -                       ret = qup_i2c_write(qup, &msgs[idx]);
> > +               len = msgs[idx].len;
> 
> Unused?
     Oh right. Will remove this above assignment.
> 
> > +
> > +               if (use_dma) {
> > +                       ret = qup_bam_xfer(adap, &msgs[idx]);
> > +                       idx = num;
> 
> Hacky.
       Hmm, because looping is not required for BAM.
       Will change this to look correct.
> 
> > +               } else {
> > +                       if (msgs[idx].flags & I2C_M_RD)
> > +                               ret = qup_i2c_read(qup, &msgs[idx]);
> > +                       else
> > +                               ret = qup_i2c_write(qup, &msgs[idx]);
> > +               }
> >
> >                 if (ret)
> >                         break;
> > @@ -943,6 +1272,7 @@ static int qup_i2c_probe(struct platform_device
> *pdev)
> >         int ret, fs_div, hs_div;
> >         int src_clk_freq;
> >         u32 clk_freq = 100000;
> > +       int blocks;
> >
> >         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
> >         if (!qup)
> > @@ -963,8 +1293,60 @@ static int qup_i2c_probe(struct platform_device
> *pdev)
> >                 qup->qup_i2c_write_one = qup_i2c_write_one_v2;
> >                 qup->qup_i2c_read_one = qup_i2c_read_one_v2;
> >                 qup->use_v2_tags = 1;
> > +
> > +               if (qup_i2c_req_dma(qup))
> > +                       goto nodma;
> 
> Just return what request DMA functions return?
       You mean return when DMA functions returns EPROBE_DEFER and
       continue if it errors out.

Regards,
 Sricharan

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
@ 2015-07-21 11:10         ` Sricharan
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21 11:10 UTC (permalink / raw)
  To: 'Ivan T. Ivanov'
  Cc: devicetree, linux-arm-msm, agross, linux-kernel, linux-i2c,
	galak, dmaengine, linux-arm-kernel

Hi Ivan,

> -----Original Message-----
> From: linux-arm-kernel [mailto:linux-arm-kernel-
> bounces@lists.infradead.org] On Behalf Of Ivan T. Ivanov
> Sent: Monday, July 20, 2015 8:17 PM
> To: Sricharan R
> Cc: devicetree@vger.kernel.org; linux-arm-msm@vger.kernel.org;
> agross@codeaurora.org; linux-kernel@vger.kernel.org; linux-
> i2c@vger.kernel.org; galak@codeaurora.org; dmaengine@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
> 
> 
> Hi Sricharan,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> > QUP cores can be attached to a BAM module, which acts as a dma engine
> > for the QUP core. When DMA with BAM is enabled, the BAM consumer
> pipe
> > transmitted data is written to the output FIFO and the BAM producer
> > pipe received data is read from the input FIFO.
> >
> > With BAM capabilities, qup-i2c core can transfer more than 256 bytes,
> > without a 'stop' which is not possible otherwise.
> >
> > Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> > ---
> >  drivers/i2c/busses/i2c-qup.c | 431
> > +++++++++++++++++++++++++++++++++++++++++--
> >  1 file changed, 415 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/i2c/busses/i2c-qup.c
> > b/drivers/i2c/busses/i2c-qup.c index c0757d9..810b021 100644
> > --- a/drivers/i2c/busses/i2c-qup.c
> > +++ b/drivers/i2c/busses/i2c-qup.c
> > @@ -24,6 +24,11 @@
> >  #include <linux/of.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/pm_runtime.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/scatterlist.h>
> > +#include <linux/atomic.h>
> > +#include <linux/dmaengine.h>
> > +#include <linux/dmapool.h>
> 
> Keep includes sorted alphabetically.
 Ok.

> 
> <snip>
> 
> > +#define MX_TX_RX_LEN                   SZ_64K
> > +#define MX_BLOCKS                      (MX_TX_RX_LEN / QUP_READ_LIMIT)
> > +
> > +/* Max timeout in ms for 32k bytes */
> > +#define TOUT_MAX                       300
> > +
> >  struct qup_i2c_block {
> >         int     count;
> >         int     pos;
> > @@ -125,6 +143,23 @@ struct qup_i2c_block {
> >         int     config_run;
> >  };
> >
> > +struct qup_i2c_tag {
> > +       u8 *start;
> > +       dma_addr_t addr;
> > +};
> > +
> > +struct qup_i2c_bam_rx {
> > +       struct  qup_i2c_tag scratch_tag;
> > +       struct  dma_chan *dma_rx;
> > +       struct  scatterlist *sg_rx;
> > +};
> > +
> > +struct qup_i2c_bam_tx {
> > +       struct  qup_i2c_tag footer_tag;
> > +       struct  dma_chan *dma_tx;
> > +       struct  scatterlist *sg_tx;
> > +};
> > +
> 
> The only difference between above 2 structures is name of the fields.
> Please, just define one struct qup_i2c_bam and instantiate it twice.
 Ok.

> 
> >  struct qup_i2c_dev {
> >         struct device*dev;
> >         void __iomem*base;
> > @@ -154,14 +189,20 @@ struct qup_i2c_dev {
> >
> >         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> >                                         struct i2c_msg *msg);
> > +       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> > +                               struct i2c_msg *msg);
> > +
> >         /* Current i2c_msg in i2c_msgs */
> >         int     cmsg;
> >         /* total num of i2c_msgs */
> >         int     num;
> >
> > -       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> > -                               struct i2c_msg *msg);
> > -
> > +       /* dma parameters */
> > +       bool    is_dma;
> > +       struct  dma_pool *dpool;
> > +       struct  qup_i2c_tag start_tag;
> > +       struct  qup_i2c_bam_rx brx;
> > +       struct  qup_i2c_bam_tx btx;
> >         struct completionxfer;
> >  };
> >
> > @@ -238,6 +279,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev
> *qup, u32 req_state)
> >         return qup_i2c_poll_state_mask(qup, req_state,
> > QUP_STATE_MASK);  }
> >
> > +static void qup_i2c_flush(struct qup_i2c_dev *qup) {
> > +       u32 val = readl(qup->base + QUP_STATE);
> > +
> > +       val |= QUP_I2C_FLUSH;
> > +       writel(val, qup->base + QUP_STATE); }
> > +
> 
> Used in only one place.
        So you mean no need to separate this as function ?

> 
> <snip>
> 
> >
> > +static void qup_i2c_bam_cb(void *data) {
> > +       struct qup_i2c_dev *qup = data;
> > +
> > +       complete(&qup->xfer);
> > +}
> > +
> > +void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct
qup_i2c_tag
> *tg,
> > +                                               unsigned int buflen,
struct qup_i2c_dev *qup,
> > +                                               int map, int dir) {
> > +       sg_set_buf(sg, buf, buflen);
> > +       dma_map_sg(qup->dev, sg, 1, dir);
> > +
> > +       if (!map)
> > +               sg_dma_address(sg) = tg->addr + ((u8 *)buf -
> > + tg->start);
> 
> Changing DMA address that we just mapped?

       The reason was tags that were allocated during probe
       using dma_alloc could also be from highmem. dma_map_sg
       assumes linear kernel addresses for virtual addresses to be mapped.
       So the sg->addr set using sg_set_buf goes wrong for such addresses.
       sg->len is fine for both cases. So setting the addresses explicitly
here. 
 
> 
> > +}
> > +
> > +static void qup_i2c_rel_dma(struct qup_i2c_dev *qup) {
> > +       if (qup->btx.dma_tx)
> > +               dma_release_channel(qup->btx.dma_tx);
> > +       if (qup->brx.dma_rx)
> > +               dma_release_channel(qup->brx.dma_rx);
> > +       qup->btx.dma_tx = NULL;
> > +       qup->brx.dma_rx = NULL;
> > +}
> > +
> > +static int qup_i2c_req_dma(struct qup_i2c_dev *qup) {
> > +       if (!qup->btx.dma_tx) {
> > +               qup->btx.dma_tx = dma_request_slave_channel(qup->dev,
> > +"tx");
> 
> Please use dma_request_slave_channel_reason() and let deferred probe
> work.
 Ok, right. Did this for something else previously. Missed it here. Will
change this.

> 
> > +               if (!qup->btx.dma_tx) {
> > +                       dev_err(qup->dev, "\n tx channel not
available");
> > +                       return -ENODEV;
> > +               }
> > +       }
> > +
> > +       if (!qup->brx.dma_rx) {
> > +               qup->brx.dma_rx = dma_request_slave_channel(qup->dev,
"rx");
> > +               if (!qup->brx.dma_rx) {
> > +                       dev_err(qup->dev, "\n rx channel not
available");
> > +                       qup_i2c_rel_dma(qup);
> > +                       return -ENODEV;
> > +               }
> > +       }
> > +       return 0;
> > +}
> > +
> > +static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> > +{
> 
> Please use consistent naming convention.
 Ok.

> 
> > +       struct dma_async_tx_descriptor *txd, *rxd = NULL;
> > +       int ret = 0;
> > +       dma_cookie_t cookie_rx, cookie_tx;
> > +       u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
> > +       u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
> > +       u8 *tags;
> > +
> > +       while (qup->cmsg < qup->num) {
> > +               blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
> > +               rem = msg->len % QUP_READ_LIMIT;
> > +               tx_len = 0, len = 0, i = 0;
> > +
> > +               qup_i2c_get_blk_data(qup, msg);
> > +
> > +               if (msg->flags & I2C_M_RD) {
> > +                       rx_nents += (blocks * 2) + 1;
> > +                       tx_nents += 1;
> > +
> > +                       while (qup->blk.pos < blocks) {
> > +                               /* length set to '0' implies 256 bytes
*/
> > +                               tlen = (i == (blocks - 1)) ? rem : 0;
> > +                               tags = &qup->start_tag.start[off + len];
> > +                               len += qup_i2c_get_tags(tags, qup,
> > + msg, 1);
> > +
> > +                               /* scratch buf to read the start and len
tags */
> > +
qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> > +
&qup-
> >brx.scratch_tag.start[0],
> > +
&qup-
> >brx.scratch_tag,
> > +
> > + 2, qup, 0, 0);
> > +
> > +
qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> > +
&msg-
> >buf[QUP_READ_LIMIT * i],
> > +
NULL, tlen, qup,
> > +
1,
> DMA_FROM_DEVICE);
> > +                               i++;
> > +                               qup->blk.pos = i;
> > +                       }
> > +                       qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
&qup-
> >start_tag.start[off],
> > +
&qup->start_tag, len, qup,
> 0, 0);
> > +                       off += len;
> > +                       /* scratch buf to read the BAM EOT and FLUSH
tags */
> > +                       qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> > +
&qup-
> >brx.scratch_tag.start[0],
> > +
&qup->brx.scratch_tag, 2,
> > +
qup, 0, 0);
> > +               } else {
> > +                       tx_nents += (blocks * 2);
> > +
> > +                       while (qup->blk.pos < blocks) {
> > +                               tlen = (i == (blocks - 1)) ? rem : 0;
> > +                               tags = &qup->start_tag.start[off +
tx_len];
> > +                               len = qup_i2c_get_tags(tags, qup, msg,
> > + 1);
> > +
> > +
qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
tags,
> > +
&qup->start_tag, len,
> > +
> > + qup, 0, 0);
> > +
> > +                               tx_len += len;
> > +
qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
&msg-
> >buf[QUP_READ_LIMIT * i],
> > +
NULL, tlen, qup, 1,
> > +
DMA_TO_DEVICE);
> > +                               i++;
> > +                               qup->blk.pos = i;
> > +                       }
> > +                       off += tx_len;
> > +
> > +                       if (qup->cmsg == (qup->num - 1)) {
> > +                               qup->btx.footer_tag.start[0] =
> > +
QUP_BAM_FLUSH_STOP;
> > +                               qup->btx.footer_tag.start[1] =
> > +
QUP_BAM_FLUSH_STOP;
> > +
qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
&qup-
> >btx.footer_tag.start[0],
> > +
&qup-
> >btx.footer_tag, 2,
> > +
qup, 0, 0);
> > +                               tx_nents += 1;
> > +                       }
> > +               }
> > +               qup->cmsg++;
> > +               msg++;
> > +       }
> > +
> > +       txd = dmaengine_prep_slave_sg(qup->btx.dma_tx, qup->btx.sg_tx,
> tx_nents,
> > +
DMA_MEM_TO_DEV,
> > +
DMA_PREP_INTERRUPT |
> DMA_PREP_FENCE);
> > +       if (!txd) {
> > +               dev_err(qup->dev, "failed to get tx desc\n");
> > +               ret = -EINVAL;
> > +               goto desc_err;
> > +       }
> > +
> > +       if (!rx_nents) {
> > +               txd->callback = qup_i2c_bam_cb;
> > +               txd->callback_param = qup;
> > +       }
> > +
> > +       cookie_tx = dmaengine_submit(txd);
> 
> Check this cookie for error? Same bellow.
Ok.

> 
> > +       dma_async_issue_pending(qup->btx.dma_tx);
> 
> Why TX messages are started first?
     For rx to start, tx pipe of tags have to start first.
     So tx always have to happen and rx happens only when
     there are rx_nents as below.
    
> 
> > +
> > +       if (rx_nents) {
> > +               rxd = dmaengine_prep_slave_sg(qup->brx.dma_rx, qup-
> >brx.sg_rx,
> > +
rx_nents,
> DMA_DEV_TO_MEM,
> > +
DMA_PREP_INTERRUPT);
> > +               if (!rxd) {
> > +                       dev_err(qup->dev, "failed to get rx desc\n");
> > +                       ret = -EINVAL;
> > +
> > +                       /* abort TX descriptors */
> > +                       dmaengine_terminate_all(qup->btx.dma_tx);
> > +                       goto desc_err;
> > +               }
> > +
> > +               rxd->callback = qup_i2c_bam_cb;
> > +               rxd->callback_param = qup;
> > +               cookie_rx = dmaengine_submit(rxd);
> > +               dma_async_issue_pending(qup->brx.dma_rx);
> > +       }
> > +
> > +       if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
> > +               dev_err(qup->dev, "normal trans timed out\n");
> > +               ret = -ETIMEDOUT;
> > +       }
> 
> There could be multiple messages for RX and TX queued for transfer, and
> they could be mixed. Using just one completion didn't look right.

  Even though there are multiple message mixed, all of them are packed as 
  one tx and rx descriptor finally.  Two things here,

      1)  when only tx pipe is used, we set the txd->callback which gets
fired after
             writing the last desc which has a 'EOT' bit set.

       2) For rx, we set the callback only for rx. Because
            for any RX transfer tx is used for writing tags. So when doing a

            read command, qup signals a completion on tx and rx pipe when it
sees a
            'BAM_INPUT_EOT'  for rx. So rx callback being called for read
implies
            corresponding tx is also done. I have seen this while doing
reads,
            tx and rx bam interrupts fire together. So even when mixed TX
and RX are there
            getting a callback for the last RX data implies a completion of
all.

           Having said above things, one thing missing is if tx is last
message
           then BAM_INPUT_EOT tag should be sent there as well. I did not
have
          a case where tx was the last. But will have to just add that tag
in above
          for tx. But not sure if there are clients to test all
combinations.
> 
> > +
> > +       if (ret || qup->bus_err || qup->qup_err) {
> > +               if (qup->bus_err & QUP_I2C_NACK_FLAG) {
> > +                       msg--;
> > +                       dev_err(qup->dev, "NACK from %x\n", msg->addr);
> > +                       ret = -EIO;
> > +
> > +                       if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
> > +                               dev_err(qup->dev, "change to run state
timed out");
> > +                               return ret;
> > +                       }
> > +
> > +                       if (rx_nents)
> > +                               writel(QUP_BAM_INPUT_EOT,
> > +
> > + qup->base + QUP_OUT_FIFO_BASE);
> > +
> > +                       writel(QUP_BAM_FLUSH_STOP,
> > +
> > + qup->base + QUP_OUT_FIFO_BASE);
> > +
> > +                       qup_i2c_flush(qup);
> > +
> > +                       /* wait for remaining interrupts to occur */
> > +                       if (!wait_for_completion_timeout(&qup->xfer,
HZ))
> > +                               dev_err(qup->dev, "flush timed
> > + out\n");
> > +
> > +                       qup_i2c_rel_dma(qup);
> > +               }
> > +       }
> > +
> > +       dma_unmap_sg(qup->dev, qup->btx.sg_tx, tx_nents,
> > + DMA_TO_DEVICE);
> > +
> > +       if (rx_nents)
> > +               dma_unmap_sg(qup->dev, qup->brx.sg_rx, rx_nents,
> > +
> > +DMA_FROM_DEVICE);
> > +desc_err:
> > +       return ret;
> > +}
> > +
> > +static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg
> > +*msg) {
> 
> Please use consistent naming convention.
 Ok.

> 
> > +       struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> > +       int ret = 0;
> > +
> > +       enable_irq(qup->irq);
> > +       if (qup_i2c_req_dma(qup))
> 
> Why?
    Have to request it again because, when the device 'Nacks out'
    on the previous transfers, then the bam channels used for that transfer
    have to be reset and init to be used again. Release and requesting them
    does this.

> 
> >
> > +
> >  static int qup_i2c_xfer(struct i2c_adapter *adap,
> >                         struct i2c_msg msgs[],
> >                         int num)
> > @@ -836,7 +1143,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter
> *adap,
> >                                                 int num)  {
> >         struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> > -       int ret, idx;
> > +       int ret, idx, len, use_dma  = 0;
> >
> >         qup->num = num;
> >         qup->cmsg = 0;
> > @@ -854,12 +1161,27 @@ static int qup_i2c_xfer_v2(struct i2c_adapter
> *adap,
> >         writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
> >         writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
> >
> > -       for (idx = 0; idx < num; idx++) {
> > -               if (msgs[idx].len == 0) {
> > -                       ret = -EINVAL;
> > -                       goto out;
> > +       if ((qup->is_dma)) {
> > +               /* All i2c_msgs should be transferred using either dma
or cpu */
> > +               for (idx = 0; idx < num; idx++) {
> > +                       if (msgs[idx].len == 0) {
> > +                               ret = -EINVAL;
> > +                               goto out;
> > +                       }
> > +
> > +                       len = (msgs[idx].len > qup->out_fifo_sz) ||
> > +
> > + (msgs[idx].len > qup->in_fifo_sz);
> > +
> > +                       if ((!is_vmalloc_addr(msgs[idx].buf)) && len)
> > + {
> 
> What is wrong with vmalloc addresses?
  When not physically contiguous, then we will have to again split it in
   to smaller sg buffers and then DMA them. This check was done to avoid
that
   extra level and use cpu transfers to keep it simple.

> 
> > +                               use_dma = 1;
> > +                               } else {
> > +                               use_dma = 0;
> > +                               break;
> > +                       }
> >                 }
> > +       }
> >
> > +       for (idx = 0; idx < num; idx++) {
> >                 if (qup_i2c_poll_state_i2c_master(qup)) {
> >                         ret = -EIO;
> >                         goto out;
> > @@ -867,10 +1189,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter
> > *adap,
> >
> >                 reinit_completion(&qup->xfer);
> >
> > -               if (msgs[idx].flags & I2C_M_RD)
> > -                       ret = qup_i2c_read(qup, &msgs[idx]);
> > -               else
> > -                       ret = qup_i2c_write(qup, &msgs[idx]);
> > +               len = msgs[idx].len;
> 
> Unused?
     Oh right. Will remove this above assignment.
> 
> > +
> > +               if (use_dma) {
> > +                       ret = qup_bam_xfer(adap, &msgs[idx]);
> > +                       idx = num;
> 
> Hacky.
       Hmm, because looping is not required for BAM.
       Will change this to look correct.
> 
> > +               } else {
> > +                       if (msgs[idx].flags & I2C_M_RD)
> > +                               ret = qup_i2c_read(qup, &msgs[idx]);
> > +                       else
> > +                               ret = qup_i2c_write(qup, &msgs[idx]);
> > +               }
> >
> >                 if (ret)
> >                         break;
> > @@ -943,6 +1272,7 @@ static int qup_i2c_probe(struct platform_device
> *pdev)
> >         int ret, fs_div, hs_div;
> >         int src_clk_freq;
> >         u32 clk_freq = 100000;
> > +       int blocks;
> >
> >         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
> >         if (!qup)
> > @@ -963,8 +1293,60 @@ static int qup_i2c_probe(struct platform_device
> *pdev)
> >                 qup->qup_i2c_write_one = qup_i2c_write_one_v2;
> >                 qup->qup_i2c_read_one = qup_i2c_read_one_v2;
> >                 qup->use_v2_tags = 1;
> > +
> > +               if (qup_i2c_req_dma(qup))
> > +                       goto nodma;
> 
> Just return what request DMA functions return?
       You mean return when DMA functions returns EPROBE_DEFER and
       continue if it errors out.

Regards,
 Sricharan


^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
@ 2015-07-21 11:10         ` Sricharan
  0 siblings, 0 replies; 41+ messages in thread
From: Sricharan @ 2015-07-21 11:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ivan,

> -----Original Message-----
> From: linux-arm-kernel [mailto:linux-arm-kernel-
> bounces at lists.infradead.org] On Behalf Of Ivan T. Ivanov
> Sent: Monday, July 20, 2015 8:17 PM
> To: Sricharan R
> Cc: devicetree at vger.kernel.org; linux-arm-msm at vger.kernel.org;
> agross at codeaurora.org; linux-kernel at vger.kernel.org; linux-
> i2c at vger.kernel.org; galak at codeaurora.org; dmaengine at vger.kernel.org;
> linux-arm-kernel at lists.infradead.org
> Subject: Re: [PATCH V4 5/7] i2c: qup: Add bam dma capabilities
> 
> 
> Hi Sricharan,
> 
> On Thu, 2015-07-09 at 08:55 +0530, Sricharan R wrote:
> > QUP cores can be attached to a BAM module, which acts as a dma engine
> > for the QUP core. When DMA with BAM is enabled, the BAM consumer
> pipe
> > transmitted data is written to the output FIFO and the BAM producer
> > pipe received data is read from the input FIFO.
> >
> > With BAM capabilities, qup-i2c core can transfer more than 256 bytes,
> > without a 'stop' which is not possible otherwise.
> >
> > Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> > ---
> >  drivers/i2c/busses/i2c-qup.c | 431
> > +++++++++++++++++++++++++++++++++++++++++--
> >  1 file changed, 415 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/i2c/busses/i2c-qup.c
> > b/drivers/i2c/busses/i2c-qup.c index c0757d9..810b021 100644
> > --- a/drivers/i2c/busses/i2c-qup.c
> > +++ b/drivers/i2c/busses/i2c-qup.c
> > @@ -24,6 +24,11 @@
> >  #include <linux/of.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/pm_runtime.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/scatterlist.h>
> > +#include <linux/atomic.h>
> > +#include <linux/dmaengine.h>
> > +#include <linux/dmapool.h>
> 
> Keep includes sorted alphabetically.
 Ok.

> 
> <snip>
> 
> > +#define MX_TX_RX_LEN                   SZ_64K
> > +#define MX_BLOCKS                      (MX_TX_RX_LEN / QUP_READ_LIMIT)
> > +
> > +/* Max timeout in ms for 32k bytes */
> > +#define TOUT_MAX                       300
> > +
> >  struct qup_i2c_block {
> >         int     count;
> >         int     pos;
> > @@ -125,6 +143,23 @@ struct qup_i2c_block {
> >         int     config_run;
> >  };
> >
> > +struct qup_i2c_tag {
> > +       u8 *start;
> > +       dma_addr_t addr;
> > +};
> > +
> > +struct qup_i2c_bam_rx {
> > +       struct  qup_i2c_tag scratch_tag;
> > +       struct  dma_chan *dma_rx;
> > +       struct  scatterlist *sg_rx;
> > +};
> > +
> > +struct qup_i2c_bam_tx {
> > +       struct  qup_i2c_tag footer_tag;
> > +       struct  dma_chan *dma_tx;
> > +       struct  scatterlist *sg_tx;
> > +};
> > +
> 
> The only difference between above 2 structures is name of the fields.
> Please, just define one struct qup_i2c_bam and instantiate it twice.
 Ok.

> 
> >  struct qup_i2c_dev {
> >         struct device*dev;
> >         void __iomem*base;
> > @@ -154,14 +189,20 @@ struct qup_i2c_dev {
> >
> >         int (*qup_i2c_write_one)(struct qup_i2c_dev *qup,
> >                                         struct i2c_msg *msg);
> > +       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> > +                               struct i2c_msg *msg);
> > +
> >         /* Current i2c_msg in i2c_msgs */
> >         int     cmsg;
> >         /* total num of i2c_msgs */
> >         int     num;
> >
> > -       int (*qup_i2c_read_one)(struct qup_i2c_dev *qup,
> > -                               struct i2c_msg *msg);
> > -
> > +       /* dma parameters */
> > +       bool    is_dma;
> > +       struct  dma_pool *dpool;
> > +       struct  qup_i2c_tag start_tag;
> > +       struct  qup_i2c_bam_rx brx;
> > +       struct  qup_i2c_bam_tx btx;
> >         struct completionxfer;
> >  };
> >
> > @@ -238,6 +279,14 @@ static int qup_i2c_poll_state(struct qup_i2c_dev
> *qup, u32 req_state)
> >         return qup_i2c_poll_state_mask(qup, req_state,
> > QUP_STATE_MASK);  }
> >
> > +static void qup_i2c_flush(struct qup_i2c_dev *qup) {
> > +       u32 val = readl(qup->base + QUP_STATE);
> > +
> > +       val |= QUP_I2C_FLUSH;
> > +       writel(val, qup->base + QUP_STATE); }
> > +
> 
> Used in only one place.
        So you mean no need to separate this as function ?

> 
> <snip>
> 
> >
> > +static void qup_i2c_bam_cb(void *data) {
> > +       struct qup_i2c_dev *qup = data;
> > +
> > +       complete(&qup->xfer);
> > +}
> > +
> > +void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct
qup_i2c_tag
> *tg,
> > +                                               unsigned int buflen,
struct qup_i2c_dev *qup,
> > +                                               int map, int dir) {
> > +       sg_set_buf(sg, buf, buflen);
> > +       dma_map_sg(qup->dev, sg, 1, dir);
> > +
> > +       if (!map)
> > +               sg_dma_address(sg) = tg->addr + ((u8 *)buf -
> > + tg->start);
> 
> Changing DMA address that we just mapped?

       The reason was tags that were allocated during probe
       using dma_alloc could also be from highmem. dma_map_sg
       assumes linear kernel addresses for virtual addresses to be mapped.
       So the sg->addr set using sg_set_buf goes wrong for such addresses.
       sg->len is fine for both cases. So setting the addresses explicitly
here. 
 
> 
> > +}
> > +
> > +static void qup_i2c_rel_dma(struct qup_i2c_dev *qup) {
> > +       if (qup->btx.dma_tx)
> > +               dma_release_channel(qup->btx.dma_tx);
> > +       if (qup->brx.dma_rx)
> > +               dma_release_channel(qup->brx.dma_rx);
> > +       qup->btx.dma_tx = NULL;
> > +       qup->brx.dma_rx = NULL;
> > +}
> > +
> > +static int qup_i2c_req_dma(struct qup_i2c_dev *qup) {
> > +       if (!qup->btx.dma_tx) {
> > +               qup->btx.dma_tx = dma_request_slave_channel(qup->dev,
> > +"tx");
> 
> Please use dma_request_slave_channel_reason() and let deferred probe
> work.
 Ok, right. Did this for something else previously. Missed it here. Will
change this.

> 
> > +               if (!qup->btx.dma_tx) {
> > +                       dev_err(qup->dev, "\n tx channel not
available");
> > +                       return -ENODEV;
> > +               }
> > +       }
> > +
> > +       if (!qup->brx.dma_rx) {
> > +               qup->brx.dma_rx = dma_request_slave_channel(qup->dev,
"rx");
> > +               if (!qup->brx.dma_rx) {
> > +                       dev_err(qup->dev, "\n rx channel not
available");
> > +                       qup_i2c_rel_dma(qup);
> > +                       return -ENODEV;
> > +               }
> > +       }
> > +       return 0;
> > +}
> > +
> > +static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> > +{
> 
> Please use consistent naming convention.
 Ok.

> 
> > +       struct dma_async_tx_descriptor *txd, *rxd = NULL;
> > +       int ret = 0;
> > +       dma_cookie_t cookie_rx, cookie_tx;
> > +       u32 rx_nents = 0, tx_nents = 0, len, blocks, rem;
> > +       u32 i, tlen, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
> > +       u8 *tags;
> > +
> > +       while (qup->cmsg < qup->num) {
> > +               blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
> > +               rem = msg->len % QUP_READ_LIMIT;
> > +               tx_len = 0, len = 0, i = 0;
> > +
> > +               qup_i2c_get_blk_data(qup, msg);
> > +
> > +               if (msg->flags & I2C_M_RD) {
> > +                       rx_nents += (blocks * 2) + 1;
> > +                       tx_nents += 1;
> > +
> > +                       while (qup->blk.pos < blocks) {
> > +                               /* length set to '0' implies 256 bytes
*/
> > +                               tlen = (i == (blocks - 1)) ? rem : 0;
> > +                               tags = &qup->start_tag.start[off + len];
> > +                               len += qup_i2c_get_tags(tags, qup,
> > + msg, 1);
> > +
> > +                               /* scratch buf to read the start and len
tags */
> > +
qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> > +
&qup-
> >brx.scratch_tag.start[0],
> > +
&qup-
> >brx.scratch_tag,
> > +
> > + 2, qup, 0, 0);
> > +
> > +
qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> > +
&msg-
> >buf[QUP_READ_LIMIT * i],
> > +
NULL, tlen, qup,
> > +
1,
> DMA_FROM_DEVICE);
> > +                               i++;
> > +                               qup->blk.pos = i;
> > +                       }
> > +                       qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
&qup-
> >start_tag.start[off],
> > +
&qup->start_tag, len, qup,
> 0, 0);
> > +                       off += len;
> > +                       /* scratch buf to read the BAM EOT and FLUSH
tags */
> > +                       qup_sg_set_buf(&qup->brx.sg_rx[rx_buf++],
> > +
&qup-
> >brx.scratch_tag.start[0],
> > +
&qup->brx.scratch_tag, 2,
> > +
qup, 0, 0);
> > +               } else {
> > +                       tx_nents += (blocks * 2);
> > +
> > +                       while (qup->blk.pos < blocks) {
> > +                               tlen = (i == (blocks - 1)) ? rem : 0;
> > +                               tags = &qup->start_tag.start[off +
tx_len];
> > +                               len = qup_i2c_get_tags(tags, qup, msg,
> > + 1);
> > +
> > +
qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
tags,
> > +
&qup->start_tag, len,
> > +
> > + qup, 0, 0);
> > +
> > +                               tx_len += len;
> > +
qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
&msg-
> >buf[QUP_READ_LIMIT * i],
> > +
NULL, tlen, qup, 1,
> > +
DMA_TO_DEVICE);
> > +                               i++;
> > +                               qup->blk.pos = i;
> > +                       }
> > +                       off += tx_len;
> > +
> > +                       if (qup->cmsg == (qup->num - 1)) {
> > +                               qup->btx.footer_tag.start[0] =
> > +
QUP_BAM_FLUSH_STOP;
> > +                               qup->btx.footer_tag.start[1] =
> > +
QUP_BAM_FLUSH_STOP;
> > +
qup_sg_set_buf(&qup->btx.sg_tx[tx_buf++],
> > +
&qup-
> >btx.footer_tag.start[0],
> > +
&qup-
> >btx.footer_tag, 2,
> > +
qup, 0, 0);
> > +                               tx_nents += 1;
> > +                       }
> > +               }
> > +               qup->cmsg++;
> > +               msg++;
> > +       }
> > +
> > +       txd = dmaengine_prep_slave_sg(qup->btx.dma_tx, qup->btx.sg_tx,
> tx_nents,
> > +
DMA_MEM_TO_DEV,
> > +
DMA_PREP_INTERRUPT |
> DMA_PREP_FENCE);
> > +       if (!txd) {
> > +               dev_err(qup->dev, "failed to get tx desc\n");
> > +               ret = -EINVAL;
> > +               goto desc_err;
> > +       }
> > +
> > +       if (!rx_nents) {
> > +               txd->callback = qup_i2c_bam_cb;
> > +               txd->callback_param = qup;
> > +       }
> > +
> > +       cookie_tx = dmaengine_submit(txd);
> 
> Check this cookie for error? Same bellow.
Ok.

> 
> > +       dma_async_issue_pending(qup->btx.dma_tx);
> 
> Why TX messages are started first?
     For rx to start, tx pipe of tags have to start first.
     So tx always have to happen and rx happens only when
     there are rx_nents as below.
    
> 
> > +
> > +       if (rx_nents) {
> > +               rxd = dmaengine_prep_slave_sg(qup->brx.dma_rx, qup-
> >brx.sg_rx,
> > +
rx_nents,
> DMA_DEV_TO_MEM,
> > +
DMA_PREP_INTERRUPT);
> > +               if (!rxd) {
> > +                       dev_err(qup->dev, "failed to get rx desc\n");
> > +                       ret = -EINVAL;
> > +
> > +                       /* abort TX descriptors */
> > +                       dmaengine_terminate_all(qup->btx.dma_tx);
> > +                       goto desc_err;
> > +               }
> > +
> > +               rxd->callback = qup_i2c_bam_cb;
> > +               rxd->callback_param = qup;
> > +               cookie_rx = dmaengine_submit(rxd);
> > +               dma_async_issue_pending(qup->brx.dma_rx);
> > +       }
> > +
> > +       if (!wait_for_completion_timeout(&qup->xfer, TOUT_MAX * HZ)) {
> > +               dev_err(qup->dev, "normal trans timed out\n");
> > +               ret = -ETIMEDOUT;
> > +       }
> 
> There could be multiple messages for RX and TX queued for transfer, and
> they could be mixed. Using just one completion didn't look right.

  Even though there are multiple message mixed, all of them are packed as 
  one tx and rx descriptor finally.  Two things here,

      1)  when only tx pipe is used, we set the txd->callback which gets
fired after
             writing the last desc which has a 'EOT' bit set.

       2) For rx, we set the callback only for rx. Because
            for any RX transfer tx is used for writing tags. So when doing a

            read command, qup signals a completion on tx and rx pipe when it
sees a
            'BAM_INPUT_EOT'  for rx. So rx callback being called for read
implies
            corresponding tx is also done. I have seen this while doing
reads,
            tx and rx bam interrupts fire together. So even when mixed TX
and RX are there
            getting a callback for the last RX data implies a completion of
all.

           Having said above things, one thing missing is if tx is last
message
           then BAM_INPUT_EOT tag should be sent there as well. I did not
have
          a case where tx was the last. But will have to just add that tag
in above
          for tx. But not sure if there are clients to test all
combinations.
> 
> > +
> > +       if (ret || qup->bus_err || qup->qup_err) {
> > +               if (qup->bus_err & QUP_I2C_NACK_FLAG) {
> > +                       msg--;
> > +                       dev_err(qup->dev, "NACK from %x\n", msg->addr);
> > +                       ret = -EIO;
> > +
> > +                       if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
> > +                               dev_err(qup->dev, "change to run state
timed out");
> > +                               return ret;
> > +                       }
> > +
> > +                       if (rx_nents)
> > +                               writel(QUP_BAM_INPUT_EOT,
> > +
> > + qup->base + QUP_OUT_FIFO_BASE);
> > +
> > +                       writel(QUP_BAM_FLUSH_STOP,
> > +
> > + qup->base + QUP_OUT_FIFO_BASE);
> > +
> > +                       qup_i2c_flush(qup);
> > +
> > +                       /* wait for remaining interrupts to occur */
> > +                       if (!wait_for_completion_timeout(&qup->xfer,
HZ))
> > +                               dev_err(qup->dev, "flush timed
> > + out\n");
> > +
> > +                       qup_i2c_rel_dma(qup);
> > +               }
> > +       }
> > +
> > +       dma_unmap_sg(qup->dev, qup->btx.sg_tx, tx_nents,
> > + DMA_TO_DEVICE);
> > +
> > +       if (rx_nents)
> > +               dma_unmap_sg(qup->dev, qup->brx.sg_rx, rx_nents,
> > +
> > +DMA_FROM_DEVICE);
> > +desc_err:
> > +       return ret;
> > +}
> > +
> > +static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg
> > +*msg) {
> 
> Please use consistent naming convention.
 Ok.

> 
> > +       struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> > +       int ret = 0;
> > +
> > +       enable_irq(qup->irq);
> > +       if (qup_i2c_req_dma(qup))
> 
> Why?
    Have to request it again because, when the device 'Nacks out'
    on the previous transfers, then the bam channels used for that transfer
    have to be reset and init to be used again. Release and requesting them
    does this.

> 
> >
> > +
> >  static int qup_i2c_xfer(struct i2c_adapter *adap,
> >                         struct i2c_msg msgs[],
> >                         int num)
> > @@ -836,7 +1143,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter
> *adap,
> >                                                 int num)  {
> >         struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
> > -       int ret, idx;
> > +       int ret, idx, len, use_dma  = 0;
> >
> >         qup->num = num;
> >         qup->cmsg = 0;
> > @@ -854,12 +1161,27 @@ static int qup_i2c_xfer_v2(struct i2c_adapter
> *adap,
> >         writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
> >         writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
> >
> > -       for (idx = 0; idx < num; idx++) {
> > -               if (msgs[idx].len == 0) {
> > -                       ret = -EINVAL;
> > -                       goto out;
> > +       if ((qup->is_dma)) {
> > +               /* All i2c_msgs should be transferred using either dma
or cpu */
> > +               for (idx = 0; idx < num; idx++) {
> > +                       if (msgs[idx].len == 0) {
> > +                               ret = -EINVAL;
> > +                               goto out;
> > +                       }
> > +
> > +                       len = (msgs[idx].len > qup->out_fifo_sz) ||
> > +
> > + (msgs[idx].len > qup->in_fifo_sz);
> > +
> > +                       if ((!is_vmalloc_addr(msgs[idx].buf)) && len)
> > + {
> 
> What is wrong with vmalloc addresses?
  When not physically contiguous, then we will have to again split it in
   to smaller sg buffers and then DMA them. This check was done to avoid
that
   extra level and use cpu transfers to keep it simple.

> 
> > +                               use_dma = 1;
> > +                               } else {
> > +                               use_dma = 0;
> > +                               break;
> > +                       }
> >                 }
> > +       }
> >
> > +       for (idx = 0; idx < num; idx++) {
> >                 if (qup_i2c_poll_state_i2c_master(qup)) {
> >                         ret = -EIO;
> >                         goto out;
> > @@ -867,10 +1189,17 @@ static int qup_i2c_xfer_v2(struct i2c_adapter
> > *adap,
> >
> >                 reinit_completion(&qup->xfer);
> >
> > -               if (msgs[idx].flags & I2C_M_RD)
> > -                       ret = qup_i2c_read(qup, &msgs[idx]);
> > -               else
> > -                       ret = qup_i2c_write(qup, &msgs[idx]);
> > +               len = msgs[idx].len;
> 
> Unused?
     Oh right. Will remove this above assignment.
> 
> > +
> > +               if (use_dma) {
> > +                       ret = qup_bam_xfer(adap, &msgs[idx]);
> > +                       idx = num;
> 
> Hacky.
       Hmm, because looping is not required for BAM.
       Will change this to look correct.
> 
> > +               } else {
> > +                       if (msgs[idx].flags & I2C_M_RD)
> > +                               ret = qup_i2c_read(qup, &msgs[idx]);
> > +                       else
> > +                               ret = qup_i2c_write(qup, &msgs[idx]);
> > +               }
> >
> >                 if (ret)
> >                         break;
> > @@ -943,6 +1272,7 @@ static int qup_i2c_probe(struct platform_device
> *pdev)
> >         int ret, fs_div, hs_div;
> >         int src_clk_freq;
> >         u32 clk_freq = 100000;
> > +       int blocks;
> >
> >         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
> >         if (!qup)
> > @@ -963,8 +1293,60 @@ static int qup_i2c_probe(struct platform_device
> *pdev)
> >                 qup->qup_i2c_write_one = qup_i2c_write_one_v2;
> >                 qup->qup_i2c_read_one = qup_i2c_read_one_v2;
> >                 qup->use_v2_tags = 1;
> > +
> > +               if (qup_i2c_req_dma(qup))
> > +                       goto nodma;
> 
> Just return what request DMA functions return?
       You mean return when DMA functions returns EPROBE_DEFER and
       continue if it errors out.

Regards,
 Sricharan

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2015-07-21 11:10 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-09  3:25 [PATCH V4 0/7] i2c: qup: Add support for v2 tags and bam dma Sricharan R
2015-07-09  3:25 ` Sricharan R
2015-07-09  3:25 ` Sricharan R
2015-07-09  3:25 ` [PATCH V4 2/7] qup: i2c: factor out common code for reuse Sricharan R
2015-07-09  3:25   ` Sricharan R
2015-07-20  8:25   ` Ivan T. Ivanov
2015-07-20  8:25     ` Ivan T. Ivanov
2015-07-21  6:54     ` Sricharan
2015-07-21  6:54       ` Sricharan
2015-07-21  6:54       ` Sricharan
2015-07-09  3:25 ` [PATCH V4 3/7] i2c: qup: Add V2 tags support Sricharan R
2015-07-09  3:25   ` Sricharan R
2015-07-20  9:44   ` Ivan T. Ivanov
2015-07-20  9:44     ` Ivan T. Ivanov
     [not found]     ` <1437385443.6267.5.camel-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org>
2015-07-21  7:11       ` Sricharan
2015-07-21  7:11         ` Sricharan
2015-07-21  7:11         ` Sricharan
     [not found] ` <1436412350-19519-1-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-07-09  3:25   ` [PATCH V4 1/7] i2c: qup: Change qup_wait_writeready function to use for all timeouts Sricharan R
2015-07-09  3:25     ` Sricharan R
2015-07-09  3:25     ` Sricharan R
2015-07-09  3:25   ` [PATCH V4 4/7] i2c: qup: Transfer each i2c_msg in i2c_msgs without a stop bit Sricharan R
2015-07-09  3:25     ` Sricharan R
2015-07-09  3:25     ` Sricharan R
     [not found]     ` <1436412350-19519-5-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-07-20 11:22       ` Ivan T. Ivanov
2015-07-20 11:22         ` Ivan T. Ivanov
2015-07-20 11:22         ` Ivan T. Ivanov
2015-07-21  8:09         ` Sricharan
2015-07-21  8:09           ` Sricharan
2015-07-21  8:09           ` Sricharan
2015-07-09  3:25   ` [PATCH V4 5/7] i2c: qup: Add bam dma capabilities Sricharan R
2015-07-09  3:25     ` Sricharan R
2015-07-09  3:25     ` Sricharan R
2015-07-20 14:46     ` Ivan T. Ivanov
2015-07-20 14:46       ` Ivan T. Ivanov
2015-07-21 11:10       ` Sricharan
2015-07-21 11:10         ` Sricharan
2015-07-21 11:10         ` Sricharan
2015-07-09  3:25 ` [PATCH V4 6/7] dts: msm8974: Add blsp2_bam dma node Sricharan R
2015-07-09  3:25   ` Sricharan R
2015-07-09  3:25 ` [PATCH V4 7/7] dts: msm8974: Add dma channels for blsp2_i2c1 node Sricharan R
2015-07-09  3:25   ` Sricharan R

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.