All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] i2c: qup: Add support for v2 tags and bam dma
@ 2015-03-13 17:49 ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	dmaengine-u79uwXL29TY76Z2rM5mHXA, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: sricharan-sgV2jX0FEOL9JmXXK+q4OQ, agross-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.

This series depends on the below bam dma bug fix
 https://lkml.org/lkml/2015/2/20/47

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

Andy Gross (1):
  i2c: qup: Add V2 tags support

Sricharan R (5):
  i2c: qup: Change qup_wait_writeready function to use for all timeouts
  i2c: qup: Add bam dma capabilities
  i2c: qup: Transfer every i2c_msg in i2c_msgs without stop
  dts: msm8974: Add blsp2_bam dma node
  dts: msm8974: Add dma channels for blsp2_i2c1 node

 arch/arm/boot/dts/qcom-msm8974.dtsi |  12 +
 drivers/i2c/busses/i2c-qup.c        | 783 +++++++++++++++++++++++++++++++++---
 2 files changed, 741 insertions(+), 54 deletions(-)

-- 
1.8.2.1

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

* [PATCH 0/6] i2c: qup: Add support for v2 tags and bam dma
@ 2015-03-13 17:49 ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel
  Cc: sricharan, agross

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.

This series depends on the below bam dma bug fix
 https://lkml.org/lkml/2015/2/20/47

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

Andy Gross (1):
  i2c: qup: Add V2 tags support

Sricharan R (5):
  i2c: qup: Change qup_wait_writeready function to use for all timeouts
  i2c: qup: Add bam dma capabilities
  i2c: qup: Transfer every i2c_msg in i2c_msgs without stop
  dts: msm8974: Add blsp2_bam dma node
  dts: msm8974: Add dma channels for blsp2_i2c1 node

 arch/arm/boot/dts/qcom-msm8974.dtsi |  12 +
 drivers/i2c/busses/i2c-qup.c        | 783 +++++++++++++++++++++++++++++++++---
 2 files changed, 741 insertions(+), 54 deletions(-)

-- 
1.8.2.1


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

* [PATCH 0/6] i2c: qup: Add support for v2 tags and bam dma
@ 2015-03-13 17:49 ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 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.

This series depends on the below bam dma bug fix
 https://lkml.org/lkml/2015/2/20/47

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

Andy Gross (1):
  i2c: qup: Add V2 tags support

Sricharan R (5):
  i2c: qup: Change qup_wait_writeready function to use for all timeouts
  i2c: qup: Add bam dma capabilities
  i2c: qup: Transfer every i2c_msg in i2c_msgs without stop
  dts: msm8974: Add blsp2_bam dma node
  dts: msm8974: Add dma channels for blsp2_i2c1 node

 arch/arm/boot/dts/qcom-msm8974.dtsi |  12 +
 drivers/i2c/busses/i2c-qup.c        | 783 +++++++++++++++++++++++++++++++++---
 2 files changed, 741 insertions(+), 54 deletions(-)

-- 
1.8.2.1

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

* [PATCH 1/6] i2c: qup: Change qup_wait_writeready function to use for all timeouts
  2015-03-13 17:49 ` Sricharan R
@ 2015-03-13 17:49   ` Sricharan R
  -1 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel
  Cc: sricharan, agross

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 | 30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 4dad23b..49c6cba 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -221,26 +221,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);
 	}
 }
 
@@ -347,7 +363,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, 0, 1);
 
 err:
 	disable_irq(qup->irq);
-- 
1.8.2.1

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

* [PATCH 1/6] i2c: qup: Change qup_wait_writeready function to use for all timeouts
@ 2015-03-13 17:49   ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 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 | 30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 4dad23b..49c6cba 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -221,26 +221,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);
 	}
 }
 
@@ -347,7 +363,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, 0, 1);
 
 err:
 	disable_irq(qup->irq);
-- 
1.8.2.1

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

* [PATCH 2/6] i2c: qup: Add V2 tags support
  2015-03-13 17:49 ` Sricharan R
  (?)
@ 2015-03-13 17:49     ` Sricharan R
  -1 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	dmaengine-u79uwXL29TY76Z2rM5mHXA, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: sricharan-sgV2jX0FEOL9JmXXK+q4OQ, agross-sgV2jX0FEOL9JmXXK+q4OQ

From: Andy Gross <agross-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

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-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
 drivers/i2c/busses/i2c-qup.c | 342 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 305 insertions(+), 37 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 49c6cba..e4e223f 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/slab.h>
 
 /* QUP Registers */
 #define QUP_CONFIG		0x000
@@ -42,6 +43,7 @@
 #define QUP_IN_FIFO_BASE	0x218
 #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
@@ -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)
 
@@ -80,17 +84,31 @@
 
 #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)
 #define QUP_INPUT_BLOCK_SIZE(x)	(((x) >> 5) & 0x03)
 #define QUP_INPUT_FIFO_SIZE(x)	(((x) >> 7) & 0x07)
 
-/* QUP tags */
+/* QUP V1 tags */
 #define QUP_TAG_START		(1 << 8)
 #define QUP_TAG_DATA		(2 << 8)
 #define QUP_TAG_STOP		(3 << 8)
 #define QUP_TAG_REC		(4 << 8)
 
+/* QUP v2 tags */
+#define QUP_TAG_V2_HS                  0xff
+#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
+
+/* frequency definitions for high speed and max speed */
+#define I2C_QUP_CLK_FAST_FREQ          1000000
+#define I2C_QUP_CLK_MAX_FREQ           3400000
+
 /* Status, Error flags */
 #define I2C_STATUS_WR_BUFFER_FULL	BIT(0)
 #define I2C_STATUS_BUS_ACTIVE		BIT(8)
@@ -99,6 +117,11 @@
 
 #define QUP_READ_LIMIT			256
 
+struct qup_i2c_config {
+	int tag_ver;
+	int max_freq;
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -112,9 +135,20 @@ struct qup_i2c_dev {
 	int			in_fifo_sz;
 	int			out_blk_sz;
 	int			in_blk_sz;
-
+	int			blocks;
+	u8			*block_tag_len;
+	int			*block_data_len;
+	int			block_pos;
 	unsigned long		one_byte_t;
 
+	int			is_hs;
+	bool			use_v2_tags;
+
+	int			tx_tag_len;
+	int			rx_tag_len;
+	u8			*tags;
+	int			tags_pos;
+
 	struct i2c_msg		*msg;
 	/* Current posion in user message buffer */
 	int			pos;
@@ -262,8 +296,13 @@ 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;
+	/* Total Number of entries to shift out, including the tags */
+	int total;
+
+	if (qup->use_v2_tags)
+		total = msg->len + qup->tx_tag_len;
+	else
+		total = msg->len + 1; /* plus start tag */
 
 	if (total < qup->out_fifo_sz) {
 		/* FIFO mode */
@@ -277,7 +316,7 @@ 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 void qup_i2c_issue_write_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	u32 addr = msg->addr << 1;
 	u32 qup_tag;
@@ -318,6 +357,136 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	}
 }
 
+static void qup_i2c_create_tag_v2(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, prev_len = 0;
+	int blocks = 0;
+	int rem;
+	int block_len = 0;
+	int data_len;
+
+	qup->block_pos = 0;
+	qup->pos = 0;
+	qup->blocks = (msg->len + QUP_READ_LIMIT - 1) / (QUP_READ_LIMIT);
+	rem = msg->len % QUP_READ_LIMIT;
+
+	/* 2 tag bytes for each block + 2 extra bytes for first block */
+	qup->tags = kzalloc((qup->blocks << 1) + 2, GFP_KERNEL);
+	qup->block_tag_len = kzalloc(qup->blocks, GFP_KERNEL);
+	qup->block_data_len = kzalloc(sizeof(int) * qup->blocks, GFP_KERNEL);
+
+	while (blocks < qup->blocks) {
+		/* 0 is used to specify a READ_LIMIT of 256 bytes */
+		data_len = (blocks < (qup->blocks - 1)) ? 0 : rem;
+
+		/* Send START and ADDR bytes only for the first block */
+		if (!blocks) {
+			qup->tags[len++] = QUP_TAG_V2_START;
+
+			if (qup->is_hs) {
+				qup->tags[len++] = QUP_TAG_V2_HS;
+				qup->tags[len++] = QUP_TAG_V2_START;
+			}
+
+			qup->tags[len++] = addr & 0xff;
+			if (msg->flags & I2C_M_TEN)
+				qup->tags[len++] = addr >> 8;
+		}
+
+		/* Send _STOP commands for the last block */
+		if (blocks == (qup->blocks - 1)) {
+			if (msg->flags & I2C_M_RD)
+				qup->tags[len++] = QUP_TAG_V2_DATARD_STOP;
+			else
+				qup->tags[len++] = QUP_TAG_V2_DATAWR_STOP;
+		} else {
+			if (msg->flags & I2C_M_RD)
+				qup->tags[len++] = QUP_TAG_V2_DATARD;
+			else
+				qup->tags[len++] = QUP_TAG_V2_DATAWR;
+		}
+
+		qup->tags[len++] = data_len;
+		block_len = len - prev_len;
+		prev_len = len;
+		qup->block_tag_len[blocks] = block_len;
+
+		if (!data_len)
+			qup->block_data_len[blocks] = QUP_READ_LIMIT;
+		else
+			qup->block_data_len[blocks] = data_len;
+
+		qup->tags_pos = 0;
+		blocks++;
+	}
+
+	qup->tx_tag_len = len;
+
+	if (msg->flags & I2C_M_RD)
+		qup->rx_tag_len = (qup->blocks << 1);
+	else
+		qup->rx_tag_len = 0;
+}
+
+static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
+			     u8 *buf, int last)
+{
+	static u32 val, idx;
+	u32  t, rem, pos = 0;
+
+	rem = len - pos + idx;
+
+	while (rem) {
+		if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, 0, 4)) {
+			dev_err(qup->dev, "timeout for fifo out full");
+			break;
+		}
+
+		t = (rem >= 4) ? 4 : rem;
+
+		while (idx < t)
+			val |= buf[pos++] << (idx++ << 3);
+
+		if (t == 4) {
+			writel(val, qup->base + QUP_OUT_FIFO_BASE);
+			idx = val = 0;
+		}
+
+		rem = len - pos;
+	}
+
+	if (last) {
+		writel(val, qup->base + QUP_OUT_FIFO_BASE);
+		idx = val = 0;
+	}
+
+	return 0;
+}
+
+static void qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	u32 data_len, tag_len, rem;
+
+	tag_len = qup->block_tag_len[qup->block_pos];
+	data_len = qup->block_data_len[qup->block_pos];
+
+	qup_i2c_xfer_data(qup, tag_len, qup->tags, 0);
+
+	if (!(msg->flags & I2C_M_RD))
+		rem = qup_i2c_xfer_data(qup, data_len, msg->buf, 1);
+}
+
+static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg
+				*msg)
+{
+	if (qup->use_v2_tags)
+		qup_i2c_issue_xfer_v2(qup, msg);
+	else
+		qup_i2c_issue_write_v1(qup, msg);
+}
+
 static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	unsigned long left;
@@ -326,6 +495,11 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	qup->msg = msg;
 	qup->pos = 0;
 
+	if (qup->use_v2_tags)
+		qup_i2c_create_tag_v2(qup, msg);
+	else
+		qup->blocks = 0;
+
 	enable_irq(qup->irq);
 
 	qup_i2c_set_write_mode(qup, msg);
@@ -360,7 +534,8 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 			ret = -EIO;
 			goto err;
 		}
-	} while (qup->pos < msg->len);
+		qup->block_pos++;
+	} while (qup->block_pos < qup->blocks);
 
 	/* Wait for the outstanding data in the fifo to drain */
 	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, 0, 1);
@@ -374,6 +549,11 @@ err:
 
 static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 {
+	if (qup->use_v2_tags) {
+		len += qup->rx_tag_len;
+		writel(qup->tx_tag_len, qup->base + QUP_MX_WRITE_CNT);
+	}
+
 	if (len < qup->in_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
@@ -386,7 +566,8 @@ static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 	}
 }
 
-static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static void qup_i2c_issue_read_v1(struct qup_i2c_dev *qup, struct
+				  i2c_msg *msg)
 {
 	u32 addr, len, val;
 
@@ -395,24 +576,33 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	/* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
 	len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
 
-	val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
+	val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START |
+			addr;
 	writel(val, qup->base + QUP_OUT_FIFO_BASE);
 }
 
+static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg
+			       *msg)
+{
+	if (qup->use_v2_tags)
+		qup_i2c_issue_xfer_v2(qup, msg);
+	else
+		qup_i2c_issue_read_v1(qup, msg);
+}
 
-static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static void qup_i2c_read_fifo_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
-	u32 opflags;
 	u32 val = 0;
 	int idx;
+	int len = msg->len + qup->rx_tag_len;
 
-	for (idx = 0; qup->pos < msg->len; idx++) {
+	for (idx = 0; qup->pos < len; idx++) {
 		if ((idx & 1) == 0) {
 			/* Check that FIFO have data */
-			opflags = readl(qup->base + QUP_OPERATIONAL);
-			if (!(opflags & QUP_IN_NOT_EMPTY))
+			if (qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY, 1, 4)) {
+				dev_err(qup->dev, "timeout for fifo not empty");
 				break;
-
+			}
 			/* Reading 2 words at time */
 			val = readl(qup->base + QUP_IN_FIFO_BASE);
 
@@ -423,11 +613,48 @@ static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	}
 }
 
+static void qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, struct
+				 i2c_msg *msg)
+{
+	u32 val;
+	int idx;
+	int pos = 0;
+	int total = qup->block_data_len[qup->block_pos] + 2;
+
+	while (pos < total) {
+		/* Check that FIFO have data */
+		if (qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY, 1, 4)) {
+			dev_err(qup->dev, "timeout for fifo not empty");
+			break;
+		}
+		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)
+				return;
+
+			msg->buf[qup->pos++] = val & 0xff;
+		}
+	}
+}
+
+static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg
+			      *msg)
+{
+	if (qup->use_v2_tags)
+		qup_i2c_read_fifo_v2(qup, msg);
+	else
+		qup_i2c_read_fifo_v1(qup, msg);
+}
+
 static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	unsigned long left;
 	int ret;
-
 	/*
 	 * 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
@@ -441,6 +668,10 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	qup->msg = msg;
 	qup->pos  = 0;
+	if (qup->use_v2_tags)
+		qup_i2c_create_tag_v2(qup, msg);
+	else
+		qup->blocks = 0;
 
 	enable_irq(qup->irq);
 
@@ -452,17 +683,17 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
-	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
-	if (ret)
-		goto err;
+	do {
+		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+		if (ret)
+			goto err;
 
-	qup_i2c_issue_read(qup, msg);
+		qup_i2c_issue_read(qup, msg);
 
-	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-	if (ret)
-		goto err;
+		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);
@@ -478,7 +709,8 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		}
 
 		qup_i2c_read_fifo(qup, msg);
-	} while (qup->pos < msg->len);
+		qup->block_pos++;
+	} while (qup->block_pos < qup->blocks);
 
 err:
 	disable_irq(qup->irq);
@@ -504,7 +736,12 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 		goto out;
 
 	/* Configure QUP as I2C mini core */
-	writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
+	if (qup->use_v2_tags) {
+		writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
+		writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
+	} else {
+		writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
+	}
 
 	for (idx = 0; idx < num; idx++) {
 		if (msgs[idx].len == 0) {
@@ -517,6 +754,8 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 			goto out;
 		}
 
+		reinit_completion(&qup->xfer);
+
 		if (msgs[idx].flags & I2C_M_RD)
 			ret = qup_i2c_read_one(qup, &msgs[idx]);
 		else
@@ -534,6 +773,12 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 		ret = num;
 out:
 
+	if (qup->use_v2_tags) {
+		kfree(qup->tags);
+		kfree(qup->block_tag_len);
+		kfree(qup->block_data_len);
+	}
+
 	pm_runtime_mark_last_busy(qup->dev);
 	pm_runtime_put_autosuspend(qup->dev);
 
@@ -556,6 +801,19 @@ static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
 	clk_prepare_enable(qup->pclk);
 }
 
+static const struct qup_i2c_config configs[] = {
+	{ 0, 400000, },
+	{ 1, 3400000, },
+};
+
+static const struct of_device_id qup_i2c_dt_match[] = {
+	{ .compatible = "qcom,i2c-qup-v1.1.1", .data = &configs[0] },
+	{ .compatible = "qcom,i2c-qup-v2.1.1", .data = &configs[1] },
+	{ .compatible = "qcom,i2c-qup-v2.2.1", .data = &configs[1] },
+	{}
+};
+MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
+
 static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
 {
 	u32 config;
@@ -579,6 +837,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	int ret, fs_div, hs_div;
 	int src_clk_freq;
 	u32 clk_freq = 100000;
+	const struct qup_i2c_config *config;
+	const struct of_device_id *of_id;
 
 	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
 	if (!qup)
@@ -590,8 +850,15 @@ static int qup_i2c_probe(struct platform_device *pdev)
 
 	of_property_read_u32(node, "clock-frequency", &clk_freq);
 
-	/* We support frequencies up to FAST Mode (400KHz) */
-	if (!clk_freq || clk_freq > 400000) {
+	of_id = of_match_node(qup_i2c_dt_match, node);
+	if (!of_id)
+		return -EINVAL;
+
+	config = of_id->data;
+	qup->use_v2_tags = !!config->tag_ver;
+
+	/* We support frequencies up to HIGH SPEED Mode (3400KHz) */
+	if (!clk_freq || clk_freq > config->max_freq) {
 		dev_err(qup->dev, "clock frequency not supported %d\n",
 			clk_freq);
 		return -EINVAL;
@@ -669,8 +936,17 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
 
 	src_clk_freq = clk_get_rate(qup->clk);
-	fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
-	hs_div = 3;
+	if (clk_freq > I2C_QUP_CLK_FAST_FREQ) {
+		fs_div = I2C_QUP_CLK_FAST_FREQ;
+		hs_div = (src_clk_freq / clk_freq) / 3;
+
+		qup->is_hs = 1;
+	} else {
+		fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
+		hs_div = 3;
+	}
+
+	hs_div = min_t(int, hs_div, 0x7);
 	qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff);
 
 	/*
@@ -767,14 +1043,6 @@ static const struct dev_pm_ops qup_i2c_qup_pm_ops = {
 		NULL)
 };
 
-static const struct of_device_id qup_i2c_dt_match[] = {
-	{ .compatible = "qcom,i2c-qup-v1.1.1" },
-	{ .compatible = "qcom,i2c-qup-v2.1.1" },
-	{ .compatible = "qcom,i2c-qup-v2.2.1" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
-
 static struct platform_driver qup_i2c_driver = {
 	.probe  = qup_i2c_probe,
 	.remove = qup_i2c_remove,
-- 
1.8.2.1

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

* [PATCH 2/6] i2c: qup: Add V2 tags support
@ 2015-03-13 17:49     ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel
  Cc: sricharan, agross

From: Andy Gross <agross@codeaurora.org>

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 | 342 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 305 insertions(+), 37 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 49c6cba..e4e223f 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/slab.h>
 
 /* QUP Registers */
 #define QUP_CONFIG		0x000
@@ -42,6 +43,7 @@
 #define QUP_IN_FIFO_BASE	0x218
 #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
@@ -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)
 
@@ -80,17 +84,31 @@
 
 #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)
 #define QUP_INPUT_BLOCK_SIZE(x)	(((x) >> 5) & 0x03)
 #define QUP_INPUT_FIFO_SIZE(x)	(((x) >> 7) & 0x07)
 
-/* QUP tags */
+/* QUP V1 tags */
 #define QUP_TAG_START		(1 << 8)
 #define QUP_TAG_DATA		(2 << 8)
 #define QUP_TAG_STOP		(3 << 8)
 #define QUP_TAG_REC		(4 << 8)
 
+/* QUP v2 tags */
+#define QUP_TAG_V2_HS                  0xff
+#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
+
+/* frequency definitions for high speed and max speed */
+#define I2C_QUP_CLK_FAST_FREQ          1000000
+#define I2C_QUP_CLK_MAX_FREQ           3400000
+
 /* Status, Error flags */
 #define I2C_STATUS_WR_BUFFER_FULL	BIT(0)
 #define I2C_STATUS_BUS_ACTIVE		BIT(8)
@@ -99,6 +117,11 @@
 
 #define QUP_READ_LIMIT			256
 
+struct qup_i2c_config {
+	int tag_ver;
+	int max_freq;
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -112,9 +135,20 @@ struct qup_i2c_dev {
 	int			in_fifo_sz;
 	int			out_blk_sz;
 	int			in_blk_sz;
-
+	int			blocks;
+	u8			*block_tag_len;
+	int			*block_data_len;
+	int			block_pos;
 	unsigned long		one_byte_t;
 
+	int			is_hs;
+	bool			use_v2_tags;
+
+	int			tx_tag_len;
+	int			rx_tag_len;
+	u8			*tags;
+	int			tags_pos;
+
 	struct i2c_msg		*msg;
 	/* Current posion in user message buffer */
 	int			pos;
@@ -262,8 +296,13 @@ 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;
+	/* Total Number of entries to shift out, including the tags */
+	int total;
+
+	if (qup->use_v2_tags)
+		total = msg->len + qup->tx_tag_len;
+	else
+		total = msg->len + 1; /* plus start tag */
 
 	if (total < qup->out_fifo_sz) {
 		/* FIFO mode */
@@ -277,7 +316,7 @@ 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 void qup_i2c_issue_write_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	u32 addr = msg->addr << 1;
 	u32 qup_tag;
@@ -318,6 +357,136 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	}
 }
 
+static void qup_i2c_create_tag_v2(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, prev_len = 0;
+	int blocks = 0;
+	int rem;
+	int block_len = 0;
+	int data_len;
+
+	qup->block_pos = 0;
+	qup->pos = 0;
+	qup->blocks = (msg->len + QUP_READ_LIMIT - 1) / (QUP_READ_LIMIT);
+	rem = msg->len % QUP_READ_LIMIT;
+
+	/* 2 tag bytes for each block + 2 extra bytes for first block */
+	qup->tags = kzalloc((qup->blocks << 1) + 2, GFP_KERNEL);
+	qup->block_tag_len = kzalloc(qup->blocks, GFP_KERNEL);
+	qup->block_data_len = kzalloc(sizeof(int) * qup->blocks, GFP_KERNEL);
+
+	while (blocks < qup->blocks) {
+		/* 0 is used to specify a READ_LIMIT of 256 bytes */
+		data_len = (blocks < (qup->blocks - 1)) ? 0 : rem;
+
+		/* Send START and ADDR bytes only for the first block */
+		if (!blocks) {
+			qup->tags[len++] = QUP_TAG_V2_START;
+
+			if (qup->is_hs) {
+				qup->tags[len++] = QUP_TAG_V2_HS;
+				qup->tags[len++] = QUP_TAG_V2_START;
+			}
+
+			qup->tags[len++] = addr & 0xff;
+			if (msg->flags & I2C_M_TEN)
+				qup->tags[len++] = addr >> 8;
+		}
+
+		/* Send _STOP commands for the last block */
+		if (blocks == (qup->blocks - 1)) {
+			if (msg->flags & I2C_M_RD)
+				qup->tags[len++] = QUP_TAG_V2_DATARD_STOP;
+			else
+				qup->tags[len++] = QUP_TAG_V2_DATAWR_STOP;
+		} else {
+			if (msg->flags & I2C_M_RD)
+				qup->tags[len++] = QUP_TAG_V2_DATARD;
+			else
+				qup->tags[len++] = QUP_TAG_V2_DATAWR;
+		}
+
+		qup->tags[len++] = data_len;
+		block_len = len - prev_len;
+		prev_len = len;
+		qup->block_tag_len[blocks] = block_len;
+
+		if (!data_len)
+			qup->block_data_len[blocks] = QUP_READ_LIMIT;
+		else
+			qup->block_data_len[blocks] = data_len;
+
+		qup->tags_pos = 0;
+		blocks++;
+	}
+
+	qup->tx_tag_len = len;
+
+	if (msg->flags & I2C_M_RD)
+		qup->rx_tag_len = (qup->blocks << 1);
+	else
+		qup->rx_tag_len = 0;
+}
+
+static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
+			     u8 *buf, int last)
+{
+	static u32 val, idx;
+	u32  t, rem, pos = 0;
+
+	rem = len - pos + idx;
+
+	while (rem) {
+		if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, 0, 4)) {
+			dev_err(qup->dev, "timeout for fifo out full");
+			break;
+		}
+
+		t = (rem >= 4) ? 4 : rem;
+
+		while (idx < t)
+			val |= buf[pos++] << (idx++ << 3);
+
+		if (t == 4) {
+			writel(val, qup->base + QUP_OUT_FIFO_BASE);
+			idx = val = 0;
+		}
+
+		rem = len - pos;
+	}
+
+	if (last) {
+		writel(val, qup->base + QUP_OUT_FIFO_BASE);
+		idx = val = 0;
+	}
+
+	return 0;
+}
+
+static void qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	u32 data_len, tag_len, rem;
+
+	tag_len = qup->block_tag_len[qup->block_pos];
+	data_len = qup->block_data_len[qup->block_pos];
+
+	qup_i2c_xfer_data(qup, tag_len, qup->tags, 0);
+
+	if (!(msg->flags & I2C_M_RD))
+		rem = qup_i2c_xfer_data(qup, data_len, msg->buf, 1);
+}
+
+static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg
+				*msg)
+{
+	if (qup->use_v2_tags)
+		qup_i2c_issue_xfer_v2(qup, msg);
+	else
+		qup_i2c_issue_write_v1(qup, msg);
+}
+
 static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	unsigned long left;
@@ -326,6 +495,11 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	qup->msg = msg;
 	qup->pos = 0;
 
+	if (qup->use_v2_tags)
+		qup_i2c_create_tag_v2(qup, msg);
+	else
+		qup->blocks = 0;
+
 	enable_irq(qup->irq);
 
 	qup_i2c_set_write_mode(qup, msg);
@@ -360,7 +534,8 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 			ret = -EIO;
 			goto err;
 		}
-	} while (qup->pos < msg->len);
+		qup->block_pos++;
+	} while (qup->block_pos < qup->blocks);
 
 	/* Wait for the outstanding data in the fifo to drain */
 	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, 0, 1);
@@ -374,6 +549,11 @@ err:
 
 static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 {
+	if (qup->use_v2_tags) {
+		len += qup->rx_tag_len;
+		writel(qup->tx_tag_len, qup->base + QUP_MX_WRITE_CNT);
+	}
+
 	if (len < qup->in_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
@@ -386,7 +566,8 @@ static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 	}
 }
 
-static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static void qup_i2c_issue_read_v1(struct qup_i2c_dev *qup, struct
+				  i2c_msg *msg)
 {
 	u32 addr, len, val;
 
@@ -395,24 +576,33 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	/* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
 	len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
 
-	val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
+	val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START |
+			addr;
 	writel(val, qup->base + QUP_OUT_FIFO_BASE);
 }
 
+static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg
+			       *msg)
+{
+	if (qup->use_v2_tags)
+		qup_i2c_issue_xfer_v2(qup, msg);
+	else
+		qup_i2c_issue_read_v1(qup, msg);
+}
 
-static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static void qup_i2c_read_fifo_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
-	u32 opflags;
 	u32 val = 0;
 	int idx;
+	int len = msg->len + qup->rx_tag_len;
 
-	for (idx = 0; qup->pos < msg->len; idx++) {
+	for (idx = 0; qup->pos < len; idx++) {
 		if ((idx & 1) == 0) {
 			/* Check that FIFO have data */
-			opflags = readl(qup->base + QUP_OPERATIONAL);
-			if (!(opflags & QUP_IN_NOT_EMPTY))
+			if (qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY, 1, 4)) {
+				dev_err(qup->dev, "timeout for fifo not empty");
 				break;
-
+			}
 			/* Reading 2 words at time */
 			val = readl(qup->base + QUP_IN_FIFO_BASE);
 
@@ -423,11 +613,48 @@ static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	}
 }
 
+static void qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, struct
+				 i2c_msg *msg)
+{
+	u32 val;
+	int idx;
+	int pos = 0;
+	int total = qup->block_data_len[qup->block_pos] + 2;
+
+	while (pos < total) {
+		/* Check that FIFO have data */
+		if (qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY, 1, 4)) {
+			dev_err(qup->dev, "timeout for fifo not empty");
+			break;
+		}
+		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)
+				return;
+
+			msg->buf[qup->pos++] = val & 0xff;
+		}
+	}
+}
+
+static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg
+			      *msg)
+{
+	if (qup->use_v2_tags)
+		qup_i2c_read_fifo_v2(qup, msg);
+	else
+		qup_i2c_read_fifo_v1(qup, msg);
+}
+
 static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	unsigned long left;
 	int ret;
-
 	/*
 	 * 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
@@ -441,6 +668,10 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	qup->msg = msg;
 	qup->pos  = 0;
+	if (qup->use_v2_tags)
+		qup_i2c_create_tag_v2(qup, msg);
+	else
+		qup->blocks = 0;
 
 	enable_irq(qup->irq);
 
@@ -452,17 +683,17 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
-	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
-	if (ret)
-		goto err;
+	do {
+		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+		if (ret)
+			goto err;
 
-	qup_i2c_issue_read(qup, msg);
+		qup_i2c_issue_read(qup, msg);
 
-	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-	if (ret)
-		goto err;
+		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);
@@ -478,7 +709,8 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		}
 
 		qup_i2c_read_fifo(qup, msg);
-	} while (qup->pos < msg->len);
+		qup->block_pos++;
+	} while (qup->block_pos < qup->blocks);
 
 err:
 	disable_irq(qup->irq);
@@ -504,7 +736,12 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 		goto out;
 
 	/* Configure QUP as I2C mini core */
-	writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
+	if (qup->use_v2_tags) {
+		writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
+		writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
+	} else {
+		writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
+	}
 
 	for (idx = 0; idx < num; idx++) {
 		if (msgs[idx].len == 0) {
@@ -517,6 +754,8 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 			goto out;
 		}
 
+		reinit_completion(&qup->xfer);
+
 		if (msgs[idx].flags & I2C_M_RD)
 			ret = qup_i2c_read_one(qup, &msgs[idx]);
 		else
@@ -534,6 +773,12 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 		ret = num;
 out:
 
+	if (qup->use_v2_tags) {
+		kfree(qup->tags);
+		kfree(qup->block_tag_len);
+		kfree(qup->block_data_len);
+	}
+
 	pm_runtime_mark_last_busy(qup->dev);
 	pm_runtime_put_autosuspend(qup->dev);
 
@@ -556,6 +801,19 @@ static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
 	clk_prepare_enable(qup->pclk);
 }
 
+static const struct qup_i2c_config configs[] = {
+	{ 0, 400000, },
+	{ 1, 3400000, },
+};
+
+static const struct of_device_id qup_i2c_dt_match[] = {
+	{ .compatible = "qcom,i2c-qup-v1.1.1", .data = &configs[0] },
+	{ .compatible = "qcom,i2c-qup-v2.1.1", .data = &configs[1] },
+	{ .compatible = "qcom,i2c-qup-v2.2.1", .data = &configs[1] },
+	{}
+};
+MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
+
 static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
 {
 	u32 config;
@@ -579,6 +837,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	int ret, fs_div, hs_div;
 	int src_clk_freq;
 	u32 clk_freq = 100000;
+	const struct qup_i2c_config *config;
+	const struct of_device_id *of_id;
 
 	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
 	if (!qup)
@@ -590,8 +850,15 @@ static int qup_i2c_probe(struct platform_device *pdev)
 
 	of_property_read_u32(node, "clock-frequency", &clk_freq);
 
-	/* We support frequencies up to FAST Mode (400KHz) */
-	if (!clk_freq || clk_freq > 400000) {
+	of_id = of_match_node(qup_i2c_dt_match, node);
+	if (!of_id)
+		return -EINVAL;
+
+	config = of_id->data;
+	qup->use_v2_tags = !!config->tag_ver;
+
+	/* We support frequencies up to HIGH SPEED Mode (3400KHz) */
+	if (!clk_freq || clk_freq > config->max_freq) {
 		dev_err(qup->dev, "clock frequency not supported %d\n",
 			clk_freq);
 		return -EINVAL;
@@ -669,8 +936,17 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
 
 	src_clk_freq = clk_get_rate(qup->clk);
-	fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
-	hs_div = 3;
+	if (clk_freq > I2C_QUP_CLK_FAST_FREQ) {
+		fs_div = I2C_QUP_CLK_FAST_FREQ;
+		hs_div = (src_clk_freq / clk_freq) / 3;
+
+		qup->is_hs = 1;
+	} else {
+		fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
+		hs_div = 3;
+	}
+
+	hs_div = min_t(int, hs_div, 0x7);
 	qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff);
 
 	/*
@@ -767,14 +1043,6 @@ static const struct dev_pm_ops qup_i2c_qup_pm_ops = {
 		NULL)
 };
 
-static const struct of_device_id qup_i2c_dt_match[] = {
-	{ .compatible = "qcom,i2c-qup-v1.1.1" },
-	{ .compatible = "qcom,i2c-qup-v2.1.1" },
-	{ .compatible = "qcom,i2c-qup-v2.2.1" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
-
 static struct platform_driver qup_i2c_driver = {
 	.probe  = qup_i2c_probe,
 	.remove = qup_i2c_remove,
-- 
1.8.2.1


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

* [PATCH 2/6] i2c: qup: Add V2 tags support
@ 2015-03-13 17:49     ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Andy Gross <agross@codeaurora.org>

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 | 342 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 305 insertions(+), 37 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 49c6cba..e4e223f 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/slab.h>
 
 /* QUP Registers */
 #define QUP_CONFIG		0x000
@@ -42,6 +43,7 @@
 #define QUP_IN_FIFO_BASE	0x218
 #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
@@ -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)
 
@@ -80,17 +84,31 @@
 
 #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)
 #define QUP_INPUT_BLOCK_SIZE(x)	(((x) >> 5) & 0x03)
 #define QUP_INPUT_FIFO_SIZE(x)	(((x) >> 7) & 0x07)
 
-/* QUP tags */
+/* QUP V1 tags */
 #define QUP_TAG_START		(1 << 8)
 #define QUP_TAG_DATA		(2 << 8)
 #define QUP_TAG_STOP		(3 << 8)
 #define QUP_TAG_REC		(4 << 8)
 
+/* QUP v2 tags */
+#define QUP_TAG_V2_HS                  0xff
+#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
+
+/* frequency definitions for high speed and max speed */
+#define I2C_QUP_CLK_FAST_FREQ          1000000
+#define I2C_QUP_CLK_MAX_FREQ           3400000
+
 /* Status, Error flags */
 #define I2C_STATUS_WR_BUFFER_FULL	BIT(0)
 #define I2C_STATUS_BUS_ACTIVE		BIT(8)
@@ -99,6 +117,11 @@
 
 #define QUP_READ_LIMIT			256
 
+struct qup_i2c_config {
+	int tag_ver;
+	int max_freq;
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -112,9 +135,20 @@ struct qup_i2c_dev {
 	int			in_fifo_sz;
 	int			out_blk_sz;
 	int			in_blk_sz;
-
+	int			blocks;
+	u8			*block_tag_len;
+	int			*block_data_len;
+	int			block_pos;
 	unsigned long		one_byte_t;
 
+	int			is_hs;
+	bool			use_v2_tags;
+
+	int			tx_tag_len;
+	int			rx_tag_len;
+	u8			*tags;
+	int			tags_pos;
+
 	struct i2c_msg		*msg;
 	/* Current posion in user message buffer */
 	int			pos;
@@ -262,8 +296,13 @@ 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;
+	/* Total Number of entries to shift out, including the tags */
+	int total;
+
+	if (qup->use_v2_tags)
+		total = msg->len + qup->tx_tag_len;
+	else
+		total = msg->len + 1; /* plus start tag */
 
 	if (total < qup->out_fifo_sz) {
 		/* FIFO mode */
@@ -277,7 +316,7 @@ 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 void qup_i2c_issue_write_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	u32 addr = msg->addr << 1;
 	u32 qup_tag;
@@ -318,6 +357,136 @@ static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	}
 }
 
+static void qup_i2c_create_tag_v2(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, prev_len = 0;
+	int blocks = 0;
+	int rem;
+	int block_len = 0;
+	int data_len;
+
+	qup->block_pos = 0;
+	qup->pos = 0;
+	qup->blocks = (msg->len + QUP_READ_LIMIT - 1) / (QUP_READ_LIMIT);
+	rem = msg->len % QUP_READ_LIMIT;
+
+	/* 2 tag bytes for each block + 2 extra bytes for first block */
+	qup->tags = kzalloc((qup->blocks << 1) + 2, GFP_KERNEL);
+	qup->block_tag_len = kzalloc(qup->blocks, GFP_KERNEL);
+	qup->block_data_len = kzalloc(sizeof(int) * qup->blocks, GFP_KERNEL);
+
+	while (blocks < qup->blocks) {
+		/* 0 is used to specify a READ_LIMIT of 256 bytes */
+		data_len = (blocks < (qup->blocks - 1)) ? 0 : rem;
+
+		/* Send START and ADDR bytes only for the first block */
+		if (!blocks) {
+			qup->tags[len++] = QUP_TAG_V2_START;
+
+			if (qup->is_hs) {
+				qup->tags[len++] = QUP_TAG_V2_HS;
+				qup->tags[len++] = QUP_TAG_V2_START;
+			}
+
+			qup->tags[len++] = addr & 0xff;
+			if (msg->flags & I2C_M_TEN)
+				qup->tags[len++] = addr >> 8;
+		}
+
+		/* Send _STOP commands for the last block */
+		if (blocks == (qup->blocks - 1)) {
+			if (msg->flags & I2C_M_RD)
+				qup->tags[len++] = QUP_TAG_V2_DATARD_STOP;
+			else
+				qup->tags[len++] = QUP_TAG_V2_DATAWR_STOP;
+		} else {
+			if (msg->flags & I2C_M_RD)
+				qup->tags[len++] = QUP_TAG_V2_DATARD;
+			else
+				qup->tags[len++] = QUP_TAG_V2_DATAWR;
+		}
+
+		qup->tags[len++] = data_len;
+		block_len = len - prev_len;
+		prev_len = len;
+		qup->block_tag_len[blocks] = block_len;
+
+		if (!data_len)
+			qup->block_data_len[blocks] = QUP_READ_LIMIT;
+		else
+			qup->block_data_len[blocks] = data_len;
+
+		qup->tags_pos = 0;
+		blocks++;
+	}
+
+	qup->tx_tag_len = len;
+
+	if (msg->flags & I2C_M_RD)
+		qup->rx_tag_len = (qup->blocks << 1);
+	else
+		qup->rx_tag_len = 0;
+}
+
+static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
+			     u8 *buf, int last)
+{
+	static u32 val, idx;
+	u32  t, rem, pos = 0;
+
+	rem = len - pos + idx;
+
+	while (rem) {
+		if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, 0, 4)) {
+			dev_err(qup->dev, "timeout for fifo out full");
+			break;
+		}
+
+		t = (rem >= 4) ? 4 : rem;
+
+		while (idx < t)
+			val |= buf[pos++] << (idx++ << 3);
+
+		if (t == 4) {
+			writel(val, qup->base + QUP_OUT_FIFO_BASE);
+			idx = val = 0;
+		}
+
+		rem = len - pos;
+	}
+
+	if (last) {
+		writel(val, qup->base + QUP_OUT_FIFO_BASE);
+		idx = val = 0;
+	}
+
+	return 0;
+}
+
+static void qup_i2c_issue_xfer_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+	u32 data_len, tag_len, rem;
+
+	tag_len = qup->block_tag_len[qup->block_pos];
+	data_len = qup->block_data_len[qup->block_pos];
+
+	qup_i2c_xfer_data(qup, tag_len, qup->tags, 0);
+
+	if (!(msg->flags & I2C_M_RD))
+		rem = qup_i2c_xfer_data(qup, data_len, msg->buf, 1);
+}
+
+static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg
+				*msg)
+{
+	if (qup->use_v2_tags)
+		qup_i2c_issue_xfer_v2(qup, msg);
+	else
+		qup_i2c_issue_write_v1(qup, msg);
+}
+
 static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	unsigned long left;
@@ -326,6 +495,11 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	qup->msg = msg;
 	qup->pos = 0;
 
+	if (qup->use_v2_tags)
+		qup_i2c_create_tag_v2(qup, msg);
+	else
+		qup->blocks = 0;
+
 	enable_irq(qup->irq);
 
 	qup_i2c_set_write_mode(qup, msg);
@@ -360,7 +534,8 @@ static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 			ret = -EIO;
 			goto err;
 		}
-	} while (qup->pos < msg->len);
+		qup->block_pos++;
+	} while (qup->block_pos < qup->blocks);
 
 	/* Wait for the outstanding data in the fifo to drain */
 	ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, 0, 1);
@@ -374,6 +549,11 @@ err:
 
 static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 {
+	if (qup->use_v2_tags) {
+		len += qup->rx_tag_len;
+		writel(qup->tx_tag_len, qup->base + QUP_MX_WRITE_CNT);
+	}
+
 	if (len < qup->in_fifo_sz) {
 		/* FIFO mode */
 		writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
@@ -386,7 +566,8 @@ static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
 	}
 }
 
-static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static void qup_i2c_issue_read_v1(struct qup_i2c_dev *qup, struct
+				  i2c_msg *msg)
 {
 	u32 addr, len, val;
 
@@ -395,24 +576,33 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	/* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
 	len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
 
-	val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
+	val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START |
+			addr;
 	writel(val, qup->base + QUP_OUT_FIFO_BASE);
 }
 
+static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg
+			       *msg)
+{
+	if (qup->use_v2_tags)
+		qup_i2c_issue_xfer_v2(qup, msg);
+	else
+		qup_i2c_issue_read_v1(qup, msg);
+}
 
-static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static void qup_i2c_read_fifo_v1(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
-	u32 opflags;
 	u32 val = 0;
 	int idx;
+	int len = msg->len + qup->rx_tag_len;
 
-	for (idx = 0; qup->pos < msg->len; idx++) {
+	for (idx = 0; qup->pos < len; idx++) {
 		if ((idx & 1) == 0) {
 			/* Check that FIFO have data */
-			opflags = readl(qup->base + QUP_OPERATIONAL);
-			if (!(opflags & QUP_IN_NOT_EMPTY))
+			if (qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY, 1, 4)) {
+				dev_err(qup->dev, "timeout for fifo not empty");
 				break;
-
+			}
 			/* Reading 2 words at time */
 			val = readl(qup->base + QUP_IN_FIFO_BASE);
 
@@ -423,11 +613,48 @@ static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	}
 }
 
+static void qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, struct
+				 i2c_msg *msg)
+{
+	u32 val;
+	int idx;
+	int pos = 0;
+	int total = qup->block_data_len[qup->block_pos] + 2;
+
+	while (pos < total) {
+		/* Check that FIFO have data */
+		if (qup_i2c_wait_ready(qup, QUP_IN_NOT_EMPTY, 1, 4)) {
+			dev_err(qup->dev, "timeout for fifo not empty");
+			break;
+		}
+		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)
+				return;
+
+			msg->buf[qup->pos++] = val & 0xff;
+		}
+	}
+}
+
+static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg
+			      *msg)
+{
+	if (qup->use_v2_tags)
+		qup_i2c_read_fifo_v2(qup, msg);
+	else
+		qup_i2c_read_fifo_v1(qup, msg);
+}
+
 static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 {
 	unsigned long left;
 	int ret;
-
 	/*
 	 * 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
@@ -441,6 +668,10 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	qup->msg = msg;
 	qup->pos  = 0;
+	if (qup->use_v2_tags)
+		qup_i2c_create_tag_v2(qup, msg);
+	else
+		qup->blocks = 0;
 
 	enable_irq(qup->irq);
 
@@ -452,17 +683,17 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
-	ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
-	if (ret)
-		goto err;
+	do {
+		ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+		if (ret)
+			goto err;
 
-	qup_i2c_issue_read(qup, msg);
+		qup_i2c_issue_read(qup, msg);
 
-	ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
-	if (ret)
-		goto err;
+		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);
@@ -478,7 +709,8 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		}
 
 		qup_i2c_read_fifo(qup, msg);
-	} while (qup->pos < msg->len);
+		qup->block_pos++;
+	} while (qup->block_pos < qup->blocks);
 
 err:
 	disable_irq(qup->irq);
@@ -504,7 +736,12 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 		goto out;
 
 	/* Configure QUP as I2C mini core */
-	writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
+	if (qup->use_v2_tags) {
+		writel(I2C_MINI_CORE | I2C_N_VAL_V2, qup->base + QUP_CONFIG);
+		writel(QUP_V2_TAGS_EN, qup->base + QUP_I2C_MASTER_GEN);
+	} else {
+		writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
+	}
 
 	for (idx = 0; idx < num; idx++) {
 		if (msgs[idx].len == 0) {
@@ -517,6 +754,8 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 			goto out;
 		}
 
+		reinit_completion(&qup->xfer);
+
 		if (msgs[idx].flags & I2C_M_RD)
 			ret = qup_i2c_read_one(qup, &msgs[idx]);
 		else
@@ -534,6 +773,12 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 		ret = num;
 out:
 
+	if (qup->use_v2_tags) {
+		kfree(qup->tags);
+		kfree(qup->block_tag_len);
+		kfree(qup->block_data_len);
+	}
+
 	pm_runtime_mark_last_busy(qup->dev);
 	pm_runtime_put_autosuspend(qup->dev);
 
@@ -556,6 +801,19 @@ static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
 	clk_prepare_enable(qup->pclk);
 }
 
+static const struct qup_i2c_config configs[] = {
+	{ 0, 400000, },
+	{ 1, 3400000, },
+};
+
+static const struct of_device_id qup_i2c_dt_match[] = {
+	{ .compatible = "qcom,i2c-qup-v1.1.1", .data = &configs[0] },
+	{ .compatible = "qcom,i2c-qup-v2.1.1", .data = &configs[1] },
+	{ .compatible = "qcom,i2c-qup-v2.2.1", .data = &configs[1] },
+	{}
+};
+MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
+
 static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
 {
 	u32 config;
@@ -579,6 +837,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	int ret, fs_div, hs_div;
 	int src_clk_freq;
 	u32 clk_freq = 100000;
+	const struct qup_i2c_config *config;
+	const struct of_device_id *of_id;
 
 	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
 	if (!qup)
@@ -590,8 +850,15 @@ static int qup_i2c_probe(struct platform_device *pdev)
 
 	of_property_read_u32(node, "clock-frequency", &clk_freq);
 
-	/* We support frequencies up to FAST Mode (400KHz) */
-	if (!clk_freq || clk_freq > 400000) {
+	of_id = of_match_node(qup_i2c_dt_match, node);
+	if (!of_id)
+		return -EINVAL;
+
+	config = of_id->data;
+	qup->use_v2_tags = !!config->tag_ver;
+
+	/* We support frequencies up to HIGH SPEED Mode (3400KHz) */
+	if (!clk_freq || clk_freq > config->max_freq) {
 		dev_err(qup->dev, "clock frequency not supported %d\n",
 			clk_freq);
 		return -EINVAL;
@@ -669,8 +936,17 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
 
 	src_clk_freq = clk_get_rate(qup->clk);
-	fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
-	hs_div = 3;
+	if (clk_freq > I2C_QUP_CLK_FAST_FREQ) {
+		fs_div = I2C_QUP_CLK_FAST_FREQ;
+		hs_div = (src_clk_freq / clk_freq) / 3;
+
+		qup->is_hs = 1;
+	} else {
+		fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
+		hs_div = 3;
+	}
+
+	hs_div = min_t(int, hs_div, 0x7);
 	qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff);
 
 	/*
@@ -767,14 +1043,6 @@ static const struct dev_pm_ops qup_i2c_qup_pm_ops = {
 		NULL)
 };
 
-static const struct of_device_id qup_i2c_dt_match[] = {
-	{ .compatible = "qcom,i2c-qup-v1.1.1" },
-	{ .compatible = "qcom,i2c-qup-v2.1.1" },
-	{ .compatible = "qcom,i2c-qup-v2.2.1" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
-
 static struct platform_driver qup_i2c_driver = {
 	.probe  = qup_i2c_probe,
 	.remove = qup_i2c_remove,
-- 
1.8.2.1

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

* [PATCH 3/6] i2c: qup: Add bam dma capabilities
  2015-03-13 17:49 ` Sricharan R
  (?)
@ 2015-03-13 17:49     ` Sricharan R
  -1 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	dmaengine-u79uwXL29TY76Z2rM5mHXA, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: sricharan-sgV2jX0FEOL9JmXXK+q4OQ, agross-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 | 365 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 359 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index e4e223f..11ea6af 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -25,6 +25,11 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.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
@@ -34,6 +39,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
@@ -44,6 +50,7 @@
 #define QUP_I2C_CLK_CTL		0x400
 #define QUP_I2C_STATUS		0x404
 #define QUP_I2C_MASTER_GEN	0x408
+#define QUP_I2C_MASTER_CONFIG	0x408
 
 /* QUP States and reset values */
 #define QUP_RESET_STATE		0
@@ -53,6 +60,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 +86,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)
 
@@ -105,6 +116,10 @@
 #define QUP_TAG_V2_DATARD              0x85
 #define QUP_TAG_V2_DATARD_STOP         0x87
 
+/* QUP BAM v2 tags */
+#define QUP_BAM_INPUT_EOT		0x93
+#define QUP_BAM_FLUSH_STOP		0x96
+
 /* frequency definitions for high speed and max speed */
 #define I2C_QUP_CLK_FAST_FREQ          1000000
 #define I2C_QUP_CLK_MAX_FREQ           3400000
@@ -116,12 +131,21 @@
 #define QUP_STATUS_ERROR_FLAGS		0x7c
 
 #define QUP_READ_LIMIT			256
+#define MX_TX_RX_LEN			SZ_64K
+#define MX_BLOCKS			(MX_TX_RX_LEN / QUP_READ_LIMIT)
+
+#define TOUT_MAX			300 /* Max timeout for 32k tx/tx */
 
 struct qup_i2c_config {
 	int tag_ver;
 	int max_freq;
 };
 
+struct tag {
+	u8 *start;
+	dma_addr_t addr;
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -157,9 +181,35 @@ struct qup_i2c_dev {
 	/* QUP core errors */
 	u32			qup_err;
 
+	/* dma parameters */
+	bool			is_dma;
+	struct			dma_pool *dpool;
+	struct			tag start_tag;
+	struct			tag scratch_tag;
+	struct			tag footer_tag;
+	struct			dma_chan *dma_tx;
+	struct			dma_chan *dma_rx;
+	struct			scatterlist *sg_tx;
+	struct			scatterlist *sg_rx;
+	dma_addr_t		sg_tx_phys;
+	dma_addr_t		sg_rx_phys;
+
 	struct completion	xfer;
 };
 
+struct i2c_bam_xfer {
+	struct qup_i2c_dev *qup;
+	u32 start_len;
+
+	u32 rx_nents;
+	u32 tx_nents;
+
+	struct dma_async_tx_descriptor *tx_desc;
+	dma_cookie_t tx_cookie;
+	struct dma_async_tx_descriptor *rx_desc;
+	dma_cookie_t rx_cookie;
+};
+
 static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
 {
 	struct qup_i2c_dev *qup = dev;
@@ -233,6 +283,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);
@@ -719,12 +777,244 @@ err:
 	return ret;
 }
 
+static void bam_i2c_callback(void *data)
+{
+	struct qup_i2c_dev *qup = data;
+
+	complete(&qup->xfer);
+}
+
+static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last,
+			int blen)
+{
+	u8 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
+	u8 op;
+	int len = 0;
+
+	/* always issue stop for each read block */
+	if (last) {
+		if (msg->flags & I2C_M_RD)
+			op = QUP_TAG_V2_DATARD_STOP;
+		else
+			op = QUP_TAG_V2_DATAWR_STOP;
+	} else {
+		if (msg->flags & I2C_M_RD)
+			op = QUP_TAG_V2_DATARD;
+		else
+			op = QUP_TAG_V2_DATAWR;
+	}
+
+	if (msg->flags & I2C_M_TEN) {
+		len += 5;
+		tag[0] = QUP_TAG_V2_START;
+		tag[1] = addr;
+		tag[2] = op;
+		tag[3] = blen;
+
+		if (msg->flags & I2C_M_RD && last) {
+			len += 2;
+			tag[4] = QUP_BAM_INPUT_EOT;
+			tag[5] = QUP_BAM_FLUSH_STOP;
+		}
+	} else {
+		if (first) {
+			tag[len++] = QUP_TAG_V2_START;
+			tag[len++] = addr;
+		}
+
+		tag[len++] = op;
+		tag[len++] = blen;
+
+		if (msg->flags & I2C_M_RD & last) {
+			tag[len++] = QUP_BAM_INPUT_EOT;
+			tag[len++] = QUP_BAM_FLUSH_STOP;
+		}
+	}
+
+	return len;
+}
+
+void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct tag *tg,
+		    unsigned int buflen, struct qup_i2c_dev *qup,
+		    int map, int dir)
+{
+	sg_set_buf(sg, buf, buflen);
+
+	if (map)
+		sg->dma_address = dma_map_single(qup->dev, buf, buflen, dir);
+	else
+		sg_dma_address(sg) = tg->addr + ((u8 *) buf - tg->start);
+}
+
+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 = 0;
+	/* QUP I2C read/write limit for single command is 256bytes max*/
+	int blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
+	int rem = msg->len % QUP_READ_LIMIT;
+	int tlen, i = 0, tx_len = 0;
+
+	if (msg->flags & I2C_M_RD) {
+		tx_nents = 1;
+		rx_nents = (blocks << 1) + 1;
+		sg_init_table(qup->sg_rx, rx_nents);
+
+		while (i < blocks) {
+			/* transfer length set to '0' implies 256 bytes */
+			tlen = (i == (blocks - 1)) ? rem : 0;
+			len += get_start_tag(&qup->start_tag.start[len],
+					      msg, !i, (i == (blocks-1)),
+					      tlen);
+
+			qup_sg_set_buf(&qup->sg_rx[i << 1],
+				       &qup->scratch_tag.start[0],
+				       &qup->scratch_tag,
+				       2, qup, 0, 0);
+
+			qup_sg_set_buf(&qup->sg_rx[(i << 1) + 1],
+				       &msg->buf[QUP_READ_LIMIT * i],
+				       NULL, tlen, qup, 1,
+				       DMA_FROM_DEVICE);
+
+			i++;
+		}
+
+		sg_init_one(qup->sg_tx, &qup->start_tag.start[0], len);
+		qup_sg_set_buf(qup->sg_tx, &qup->start_tag.start[0],
+			       &qup->start_tag, len, qup, 0, 0);
+		qup_sg_set_buf(&qup->sg_rx[i << 1],
+			       &qup->scratch_tag.start[1],
+			       &qup->scratch_tag, 2,
+			       qup, 0, 0);
+	} else {
+		qup->footer_tag.start[0] = QUP_BAM_FLUSH_STOP;
+		qup->footer_tag.start[1] = QUP_BAM_FLUSH_STOP;
+
+		tx_nents = (blocks << 1) + 1;
+		sg_init_table(qup->sg_tx, tx_nents);
+
+		while (i < blocks) {
+			tlen = (i == (blocks - 1)) ? rem : 0;
+			len = get_start_tag(&qup->start_tag.start[tx_len],
+					    msg, !i, (i == (blocks-1)), tlen);
+
+			qup_sg_set_buf(&qup->sg_tx[i << 1],
+				       &qup->start_tag.start[tx_len],
+				       &qup->start_tag,
+				       len, qup, 0, 0);
+
+			tx_len += len;
+			qup_sg_set_buf(&qup->sg_tx[(i << 1) + 1],
+				       &msg->buf[QUP_READ_LIMIT * i], NULL,
+				       tlen, qup, 1, DMA_TO_DEVICE);
+			i++;
+		}
+		qup_sg_set_buf(&qup->sg_tx[i << 1], &qup->footer_tag.start[0],
+			       &qup->footer_tag, 2,
+			       qup, 0, 0);
+	}
+
+	txd = dmaengine_prep_slave_sg(qup->dma_tx, qup->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 = bam_i2c_callback;
+		txd->callback_param = qup;
+	}
+
+	cookie_tx = dmaengine_submit(txd);
+	dma_async_issue_pending(qup->dma_tx);
+
+	if (rx_nents) {
+		rxd = dmaengine_prep_slave_sg(qup->dma_rx, qup->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->dma_tx);
+			goto desc_err;
+		}
+
+		rxd->callback = bam_i2c_callback;
+		rxd->callback_param = qup;
+		cookie_rx = dmaengine_submit(rxd);
+		dma_async_issue_pending(qup->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)
+			dev_err(qup->dev, "NACK from %x\n", msg->addr);
+		ret = -EIO;
+		qup_i2c_flush(qup);
+		qup_i2c_change_state(qup, QUP_RUN_STATE);
+
+		/* wait for remaining interrupts to occur */
+		if (!wait_for_completion_timeout(&qup->xfer, HZ))
+			dev_err(qup->dev, "flush timed out\n");
+	}
+
+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);
+
+	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)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
-	int ret, idx;
+	int ret, idx, len;
 
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
@@ -756,10 +1046,17 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 
 		reinit_completion(&qup->xfer);
 
-		if (msgs[idx].flags & I2C_M_RD)
-			ret = qup_i2c_read_one(qup, &msgs[idx]);
-		else
-			ret = qup_i2c_write_one(qup, &msgs[idx]);
+		len = (&msgs[idx])->len;
+
+		if ((qup->is_dma) && (!is_vmalloc_addr((&msgs[idx])->buf)) &&
+						(len > qup->out_fifo_sz)) {
+			ret = qup_bam_xfer(adap, &msgs[idx]);
+		} else {
+			if (msgs[idx].flags & I2C_M_RD)
+				ret = qup_i2c_read_one(qup, &msgs[idx]);
+			else
+				ret = qup_i2c_write_one(qup, &msgs[idx]);
+		}
 
 		if (ret)
 			break;
@@ -790,7 +1087,7 @@ static u32 qup_i2c_func(struct i2c_adapter *adap)
 	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
 }
 
-static const struct i2c_algorithm qup_i2c_algo = {
+static struct i2c_algorithm qup_i2c_algo = {
 	.master_xfer	= qup_i2c_xfer,
 	.functionality	= qup_i2c_func,
 };
@@ -839,6 +1136,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	u32 clk_freq = 100000;
 	const struct qup_i2c_config *config;
 	const struct of_device_id *of_id;
+	int blocks;
 
 	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
 	if (!qup)
@@ -875,6 +1173,53 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		return qup->irq;
 	}
 
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v2.1.1") ||
+		of_device_is_compatible(pdev->dev.of_node,
+			"qcom,i2c-qup-v2.2.1")) {
+		qup->dma_rx = dma_request_slave_channel(&pdev->dev, "bam-rx");
+
+		if (!qup->dma_rx)
+			return -EPROBE_DEFER;
+
+		qup->dma_tx = dma_request_slave_channel(&pdev->dev, "bam-tx");
+		if (!qup->dma_tx)
+			return -EPROBE_DEFER;
+
+		qup->is_dma = 1;
+
+		blocks = (MX_BLOCKS << 1) + 1;
+		qup->sg_tx = devm_kzalloc(&pdev->dev,
+					  sizeof(*qup->sg_tx) * blocks,
+					  GFP_KERNEL);
+		if (!qup->sg_tx)
+			return -ENOMEM;
+
+		qup->sg_rx = devm_kzalloc(&pdev->dev,
+					  sizeof(*qup->sg_tx) * blocks,
+					  GFP_KERNEL);
+		if (!qup->sg_rx)
+			return -ENOMEM;
+
+		size = sizeof(struct tag) * (blocks + 3);
+		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)
+			return -ENOMEM;
+
+		qup->scratch_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
+							&qup->scratch_tag.addr);
+		if (!qup->scratch_tag.start)
+			return -ENOMEM;
+
+		qup->footer_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
+						       &qup->footer_tag.addr);
+		if (!qup->footer_tag.start)
+			return -ENOMEM;
+	}
+
 	qup->clk = devm_clk_get(qup->dev, "core");
 	if (IS_ERR(qup->clk)) {
 		dev_err(qup->dev, "Could not get core clock\n");
@@ -989,6 +1334,14 @@ static int qup_i2c_remove(struct platform_device *pdev)
 {
 	struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
 
+	dma_pool_free(qup->dpool, qup->start_tag.start,
+		      qup->start_tag.addr);
+	dma_pool_free(qup->dpool, qup->scratch_tag.start,
+		      qup->scratch_tag.addr);
+	dma_pool_free(qup->dpool, qup->footer_tag.start,
+		      qup->footer_tag.addr);
+	dma_pool_destroy(qup->dpool);
+
 	disable_irq(qup->irq);
 	qup_i2c_disable_clocks(qup);
 	i2c_del_adapter(&qup->adap);
-- 
1.8.2.1

--
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] 43+ messages in thread

* [PATCH 3/6] i2c: qup: Add bam dma capabilities
@ 2015-03-13 17:49     ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel
  Cc: sricharan, agross

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 | 365 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 359 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index e4e223f..11ea6af 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -25,6 +25,11 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.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
@@ -34,6 +39,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
@@ -44,6 +50,7 @@
 #define QUP_I2C_CLK_CTL		0x400
 #define QUP_I2C_STATUS		0x404
 #define QUP_I2C_MASTER_GEN	0x408
+#define QUP_I2C_MASTER_CONFIG	0x408
 
 /* QUP States and reset values */
 #define QUP_RESET_STATE		0
@@ -53,6 +60,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 +86,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)
 
@@ -105,6 +116,10 @@
 #define QUP_TAG_V2_DATARD              0x85
 #define QUP_TAG_V2_DATARD_STOP         0x87
 
+/* QUP BAM v2 tags */
+#define QUP_BAM_INPUT_EOT		0x93
+#define QUP_BAM_FLUSH_STOP		0x96
+
 /* frequency definitions for high speed and max speed */
 #define I2C_QUP_CLK_FAST_FREQ          1000000
 #define I2C_QUP_CLK_MAX_FREQ           3400000
@@ -116,12 +131,21 @@
 #define QUP_STATUS_ERROR_FLAGS		0x7c
 
 #define QUP_READ_LIMIT			256
+#define MX_TX_RX_LEN			SZ_64K
+#define MX_BLOCKS			(MX_TX_RX_LEN / QUP_READ_LIMIT)
+
+#define TOUT_MAX			300 /* Max timeout for 32k tx/tx */
 
 struct qup_i2c_config {
 	int tag_ver;
 	int max_freq;
 };
 
+struct tag {
+	u8 *start;
+	dma_addr_t addr;
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -157,9 +181,35 @@ struct qup_i2c_dev {
 	/* QUP core errors */
 	u32			qup_err;
 
+	/* dma parameters */
+	bool			is_dma;
+	struct			dma_pool *dpool;
+	struct			tag start_tag;
+	struct			tag scratch_tag;
+	struct			tag footer_tag;
+	struct			dma_chan *dma_tx;
+	struct			dma_chan *dma_rx;
+	struct			scatterlist *sg_tx;
+	struct			scatterlist *sg_rx;
+	dma_addr_t		sg_tx_phys;
+	dma_addr_t		sg_rx_phys;
+
 	struct completion	xfer;
 };
 
+struct i2c_bam_xfer {
+	struct qup_i2c_dev *qup;
+	u32 start_len;
+
+	u32 rx_nents;
+	u32 tx_nents;
+
+	struct dma_async_tx_descriptor *tx_desc;
+	dma_cookie_t tx_cookie;
+	struct dma_async_tx_descriptor *rx_desc;
+	dma_cookie_t rx_cookie;
+};
+
 static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
 {
 	struct qup_i2c_dev *qup = dev;
@@ -233,6 +283,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);
@@ -719,12 +777,244 @@ err:
 	return ret;
 }
 
+static void bam_i2c_callback(void *data)
+{
+	struct qup_i2c_dev *qup = data;
+
+	complete(&qup->xfer);
+}
+
+static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last,
+			int blen)
+{
+	u8 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
+	u8 op;
+	int len = 0;
+
+	/* always issue stop for each read block */
+	if (last) {
+		if (msg->flags & I2C_M_RD)
+			op = QUP_TAG_V2_DATARD_STOP;
+		else
+			op = QUP_TAG_V2_DATAWR_STOP;
+	} else {
+		if (msg->flags & I2C_M_RD)
+			op = QUP_TAG_V2_DATARD;
+		else
+			op = QUP_TAG_V2_DATAWR;
+	}
+
+	if (msg->flags & I2C_M_TEN) {
+		len += 5;
+		tag[0] = QUP_TAG_V2_START;
+		tag[1] = addr;
+		tag[2] = op;
+		tag[3] = blen;
+
+		if (msg->flags & I2C_M_RD && last) {
+			len += 2;
+			tag[4] = QUP_BAM_INPUT_EOT;
+			tag[5] = QUP_BAM_FLUSH_STOP;
+		}
+	} else {
+		if (first) {
+			tag[len++] = QUP_TAG_V2_START;
+			tag[len++] = addr;
+		}
+
+		tag[len++] = op;
+		tag[len++] = blen;
+
+		if (msg->flags & I2C_M_RD & last) {
+			tag[len++] = QUP_BAM_INPUT_EOT;
+			tag[len++] = QUP_BAM_FLUSH_STOP;
+		}
+	}
+
+	return len;
+}
+
+void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct tag *tg,
+		    unsigned int buflen, struct qup_i2c_dev *qup,
+		    int map, int dir)
+{
+	sg_set_buf(sg, buf, buflen);
+
+	if (map)
+		sg->dma_address = dma_map_single(qup->dev, buf, buflen, dir);
+	else
+		sg_dma_address(sg) = tg->addr + ((u8 *) buf - tg->start);
+}
+
+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 = 0;
+	/* QUP I2C read/write limit for single command is 256bytes max*/
+	int blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
+	int rem = msg->len % QUP_READ_LIMIT;
+	int tlen, i = 0, tx_len = 0;
+
+	if (msg->flags & I2C_M_RD) {
+		tx_nents = 1;
+		rx_nents = (blocks << 1) + 1;
+		sg_init_table(qup->sg_rx, rx_nents);
+
+		while (i < blocks) {
+			/* transfer length set to '0' implies 256 bytes */
+			tlen = (i == (blocks - 1)) ? rem : 0;
+			len += get_start_tag(&qup->start_tag.start[len],
+					      msg, !i, (i == (blocks-1)),
+					      tlen);
+
+			qup_sg_set_buf(&qup->sg_rx[i << 1],
+				       &qup->scratch_tag.start[0],
+				       &qup->scratch_tag,
+				       2, qup, 0, 0);
+
+			qup_sg_set_buf(&qup->sg_rx[(i << 1) + 1],
+				       &msg->buf[QUP_READ_LIMIT * i],
+				       NULL, tlen, qup, 1,
+				       DMA_FROM_DEVICE);
+
+			i++;
+		}
+
+		sg_init_one(qup->sg_tx, &qup->start_tag.start[0], len);
+		qup_sg_set_buf(qup->sg_tx, &qup->start_tag.start[0],
+			       &qup->start_tag, len, qup, 0, 0);
+		qup_sg_set_buf(&qup->sg_rx[i << 1],
+			       &qup->scratch_tag.start[1],
+			       &qup->scratch_tag, 2,
+			       qup, 0, 0);
+	} else {
+		qup->footer_tag.start[0] = QUP_BAM_FLUSH_STOP;
+		qup->footer_tag.start[1] = QUP_BAM_FLUSH_STOP;
+
+		tx_nents = (blocks << 1) + 1;
+		sg_init_table(qup->sg_tx, tx_nents);
+
+		while (i < blocks) {
+			tlen = (i == (blocks - 1)) ? rem : 0;
+			len = get_start_tag(&qup->start_tag.start[tx_len],
+					    msg, !i, (i == (blocks-1)), tlen);
+
+			qup_sg_set_buf(&qup->sg_tx[i << 1],
+				       &qup->start_tag.start[tx_len],
+				       &qup->start_tag,
+				       len, qup, 0, 0);
+
+			tx_len += len;
+			qup_sg_set_buf(&qup->sg_tx[(i << 1) + 1],
+				       &msg->buf[QUP_READ_LIMIT * i], NULL,
+				       tlen, qup, 1, DMA_TO_DEVICE);
+			i++;
+		}
+		qup_sg_set_buf(&qup->sg_tx[i << 1], &qup->footer_tag.start[0],
+			       &qup->footer_tag, 2,
+			       qup, 0, 0);
+	}
+
+	txd = dmaengine_prep_slave_sg(qup->dma_tx, qup->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 = bam_i2c_callback;
+		txd->callback_param = qup;
+	}
+
+	cookie_tx = dmaengine_submit(txd);
+	dma_async_issue_pending(qup->dma_tx);
+
+	if (rx_nents) {
+		rxd = dmaengine_prep_slave_sg(qup->dma_rx, qup->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->dma_tx);
+			goto desc_err;
+		}
+
+		rxd->callback = bam_i2c_callback;
+		rxd->callback_param = qup;
+		cookie_rx = dmaengine_submit(rxd);
+		dma_async_issue_pending(qup->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)
+			dev_err(qup->dev, "NACK from %x\n", msg->addr);
+		ret = -EIO;
+		qup_i2c_flush(qup);
+		qup_i2c_change_state(qup, QUP_RUN_STATE);
+
+		/* wait for remaining interrupts to occur */
+		if (!wait_for_completion_timeout(&qup->xfer, HZ))
+			dev_err(qup->dev, "flush timed out\n");
+	}
+
+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);
+
+	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)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
-	int ret, idx;
+	int ret, idx, len;
 
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
@@ -756,10 +1046,17 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 
 		reinit_completion(&qup->xfer);
 
-		if (msgs[idx].flags & I2C_M_RD)
-			ret = qup_i2c_read_one(qup, &msgs[idx]);
-		else
-			ret = qup_i2c_write_one(qup, &msgs[idx]);
+		len = (&msgs[idx])->len;
+
+		if ((qup->is_dma) && (!is_vmalloc_addr((&msgs[idx])->buf)) &&
+						(len > qup->out_fifo_sz)) {
+			ret = qup_bam_xfer(adap, &msgs[idx]);
+		} else {
+			if (msgs[idx].flags & I2C_M_RD)
+				ret = qup_i2c_read_one(qup, &msgs[idx]);
+			else
+				ret = qup_i2c_write_one(qup, &msgs[idx]);
+		}
 
 		if (ret)
 			break;
@@ -790,7 +1087,7 @@ static u32 qup_i2c_func(struct i2c_adapter *adap)
 	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
 }
 
-static const struct i2c_algorithm qup_i2c_algo = {
+static struct i2c_algorithm qup_i2c_algo = {
 	.master_xfer	= qup_i2c_xfer,
 	.functionality	= qup_i2c_func,
 };
@@ -839,6 +1136,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	u32 clk_freq = 100000;
 	const struct qup_i2c_config *config;
 	const struct of_device_id *of_id;
+	int blocks;
 
 	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
 	if (!qup)
@@ -875,6 +1173,53 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		return qup->irq;
 	}
 
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v2.1.1") ||
+		of_device_is_compatible(pdev->dev.of_node,
+			"qcom,i2c-qup-v2.2.1")) {
+		qup->dma_rx = dma_request_slave_channel(&pdev->dev, "bam-rx");
+
+		if (!qup->dma_rx)
+			return -EPROBE_DEFER;
+
+		qup->dma_tx = dma_request_slave_channel(&pdev->dev, "bam-tx");
+		if (!qup->dma_tx)
+			return -EPROBE_DEFER;
+
+		qup->is_dma = 1;
+
+		blocks = (MX_BLOCKS << 1) + 1;
+		qup->sg_tx = devm_kzalloc(&pdev->dev,
+					  sizeof(*qup->sg_tx) * blocks,
+					  GFP_KERNEL);
+		if (!qup->sg_tx)
+			return -ENOMEM;
+
+		qup->sg_rx = devm_kzalloc(&pdev->dev,
+					  sizeof(*qup->sg_tx) * blocks,
+					  GFP_KERNEL);
+		if (!qup->sg_rx)
+			return -ENOMEM;
+
+		size = sizeof(struct tag) * (blocks + 3);
+		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)
+			return -ENOMEM;
+
+		qup->scratch_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
+							&qup->scratch_tag.addr);
+		if (!qup->scratch_tag.start)
+			return -ENOMEM;
+
+		qup->footer_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
+						       &qup->footer_tag.addr);
+		if (!qup->footer_tag.start)
+			return -ENOMEM;
+	}
+
 	qup->clk = devm_clk_get(qup->dev, "core");
 	if (IS_ERR(qup->clk)) {
 		dev_err(qup->dev, "Could not get core clock\n");
@@ -989,6 +1334,14 @@ static int qup_i2c_remove(struct platform_device *pdev)
 {
 	struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
 
+	dma_pool_free(qup->dpool, qup->start_tag.start,
+		      qup->start_tag.addr);
+	dma_pool_free(qup->dpool, qup->scratch_tag.start,
+		      qup->scratch_tag.addr);
+	dma_pool_free(qup->dpool, qup->footer_tag.start,
+		      qup->footer_tag.addr);
+	dma_pool_destroy(qup->dpool);
+
 	disable_irq(qup->irq);
 	qup_i2c_disable_clocks(qup);
 	i2c_del_adapter(&qup->adap);
-- 
1.8.2.1


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

* [PATCH 3/6] i2c: qup: Add bam dma capabilities
@ 2015-03-13 17:49     ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 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 | 365 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 359 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index e4e223f..11ea6af 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -25,6 +25,11 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.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
@@ -34,6 +39,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
@@ -44,6 +50,7 @@
 #define QUP_I2C_CLK_CTL		0x400
 #define QUP_I2C_STATUS		0x404
 #define QUP_I2C_MASTER_GEN	0x408
+#define QUP_I2C_MASTER_CONFIG	0x408
 
 /* QUP States and reset values */
 #define QUP_RESET_STATE		0
@@ -53,6 +60,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 +86,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)
 
@@ -105,6 +116,10 @@
 #define QUP_TAG_V2_DATARD              0x85
 #define QUP_TAG_V2_DATARD_STOP         0x87
 
+/* QUP BAM v2 tags */
+#define QUP_BAM_INPUT_EOT		0x93
+#define QUP_BAM_FLUSH_STOP		0x96
+
 /* frequency definitions for high speed and max speed */
 #define I2C_QUP_CLK_FAST_FREQ          1000000
 #define I2C_QUP_CLK_MAX_FREQ           3400000
@@ -116,12 +131,21 @@
 #define QUP_STATUS_ERROR_FLAGS		0x7c
 
 #define QUP_READ_LIMIT			256
+#define MX_TX_RX_LEN			SZ_64K
+#define MX_BLOCKS			(MX_TX_RX_LEN / QUP_READ_LIMIT)
+
+#define TOUT_MAX			300 /* Max timeout for 32k tx/tx */
 
 struct qup_i2c_config {
 	int tag_ver;
 	int max_freq;
 };
 
+struct tag {
+	u8 *start;
+	dma_addr_t addr;
+};
+
 struct qup_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
@@ -157,9 +181,35 @@ struct qup_i2c_dev {
 	/* QUP core errors */
 	u32			qup_err;
 
+	/* dma parameters */
+	bool			is_dma;
+	struct			dma_pool *dpool;
+	struct			tag start_tag;
+	struct			tag scratch_tag;
+	struct			tag footer_tag;
+	struct			dma_chan *dma_tx;
+	struct			dma_chan *dma_rx;
+	struct			scatterlist *sg_tx;
+	struct			scatterlist *sg_rx;
+	dma_addr_t		sg_tx_phys;
+	dma_addr_t		sg_rx_phys;
+
 	struct completion	xfer;
 };
 
+struct i2c_bam_xfer {
+	struct qup_i2c_dev *qup;
+	u32 start_len;
+
+	u32 rx_nents;
+	u32 tx_nents;
+
+	struct dma_async_tx_descriptor *tx_desc;
+	dma_cookie_t tx_cookie;
+	struct dma_async_tx_descriptor *rx_desc;
+	dma_cookie_t rx_cookie;
+};
+
 static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
 {
 	struct qup_i2c_dev *qup = dev;
@@ -233,6 +283,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);
@@ -719,12 +777,244 @@ err:
 	return ret;
 }
 
+static void bam_i2c_callback(void *data)
+{
+	struct qup_i2c_dev *qup = data;
+
+	complete(&qup->xfer);
+}
+
+static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last,
+			int blen)
+{
+	u8 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
+	u8 op;
+	int len = 0;
+
+	/* always issue stop for each read block */
+	if (last) {
+		if (msg->flags & I2C_M_RD)
+			op = QUP_TAG_V2_DATARD_STOP;
+		else
+			op = QUP_TAG_V2_DATAWR_STOP;
+	} else {
+		if (msg->flags & I2C_M_RD)
+			op = QUP_TAG_V2_DATARD;
+		else
+			op = QUP_TAG_V2_DATAWR;
+	}
+
+	if (msg->flags & I2C_M_TEN) {
+		len += 5;
+		tag[0] = QUP_TAG_V2_START;
+		tag[1] = addr;
+		tag[2] = op;
+		tag[3] = blen;
+
+		if (msg->flags & I2C_M_RD && last) {
+			len += 2;
+			tag[4] = QUP_BAM_INPUT_EOT;
+			tag[5] = QUP_BAM_FLUSH_STOP;
+		}
+	} else {
+		if (first) {
+			tag[len++] = QUP_TAG_V2_START;
+			tag[len++] = addr;
+		}
+
+		tag[len++] = op;
+		tag[len++] = blen;
+
+		if (msg->flags & I2C_M_RD & last) {
+			tag[len++] = QUP_BAM_INPUT_EOT;
+			tag[len++] = QUP_BAM_FLUSH_STOP;
+		}
+	}
+
+	return len;
+}
+
+void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct tag *tg,
+		    unsigned int buflen, struct qup_i2c_dev *qup,
+		    int map, int dir)
+{
+	sg_set_buf(sg, buf, buflen);
+
+	if (map)
+		sg->dma_address = dma_map_single(qup->dev, buf, buflen, dir);
+	else
+		sg_dma_address(sg) = tg->addr + ((u8 *) buf - tg->start);
+}
+
+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 = 0;
+	/* QUP I2C read/write limit for single command is 256bytes max*/
+	int blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
+	int rem = msg->len % QUP_READ_LIMIT;
+	int tlen, i = 0, tx_len = 0;
+
+	if (msg->flags & I2C_M_RD) {
+		tx_nents = 1;
+		rx_nents = (blocks << 1) + 1;
+		sg_init_table(qup->sg_rx, rx_nents);
+
+		while (i < blocks) {
+			/* transfer length set to '0' implies 256 bytes */
+			tlen = (i == (blocks - 1)) ? rem : 0;
+			len += get_start_tag(&qup->start_tag.start[len],
+					      msg, !i, (i == (blocks-1)),
+					      tlen);
+
+			qup_sg_set_buf(&qup->sg_rx[i << 1],
+				       &qup->scratch_tag.start[0],
+				       &qup->scratch_tag,
+				       2, qup, 0, 0);
+
+			qup_sg_set_buf(&qup->sg_rx[(i << 1) + 1],
+				       &msg->buf[QUP_READ_LIMIT * i],
+				       NULL, tlen, qup, 1,
+				       DMA_FROM_DEVICE);
+
+			i++;
+		}
+
+		sg_init_one(qup->sg_tx, &qup->start_tag.start[0], len);
+		qup_sg_set_buf(qup->sg_tx, &qup->start_tag.start[0],
+			       &qup->start_tag, len, qup, 0, 0);
+		qup_sg_set_buf(&qup->sg_rx[i << 1],
+			       &qup->scratch_tag.start[1],
+			       &qup->scratch_tag, 2,
+			       qup, 0, 0);
+	} else {
+		qup->footer_tag.start[0] = QUP_BAM_FLUSH_STOP;
+		qup->footer_tag.start[1] = QUP_BAM_FLUSH_STOP;
+
+		tx_nents = (blocks << 1) + 1;
+		sg_init_table(qup->sg_tx, tx_nents);
+
+		while (i < blocks) {
+			tlen = (i == (blocks - 1)) ? rem : 0;
+			len = get_start_tag(&qup->start_tag.start[tx_len],
+					    msg, !i, (i == (blocks-1)), tlen);
+
+			qup_sg_set_buf(&qup->sg_tx[i << 1],
+				       &qup->start_tag.start[tx_len],
+				       &qup->start_tag,
+				       len, qup, 0, 0);
+
+			tx_len += len;
+			qup_sg_set_buf(&qup->sg_tx[(i << 1) + 1],
+				       &msg->buf[QUP_READ_LIMIT * i], NULL,
+				       tlen, qup, 1, DMA_TO_DEVICE);
+			i++;
+		}
+		qup_sg_set_buf(&qup->sg_tx[i << 1], &qup->footer_tag.start[0],
+			       &qup->footer_tag, 2,
+			       qup, 0, 0);
+	}
+
+	txd = dmaengine_prep_slave_sg(qup->dma_tx, qup->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 = bam_i2c_callback;
+		txd->callback_param = qup;
+	}
+
+	cookie_tx = dmaengine_submit(txd);
+	dma_async_issue_pending(qup->dma_tx);
+
+	if (rx_nents) {
+		rxd = dmaengine_prep_slave_sg(qup->dma_rx, qup->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->dma_tx);
+			goto desc_err;
+		}
+
+		rxd->callback = bam_i2c_callback;
+		rxd->callback_param = qup;
+		cookie_rx = dmaengine_submit(rxd);
+		dma_async_issue_pending(qup->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)
+			dev_err(qup->dev, "NACK from %x\n", msg->addr);
+		ret = -EIO;
+		qup_i2c_flush(qup);
+		qup_i2c_change_state(qup, QUP_RUN_STATE);
+
+		/* wait for remaining interrupts to occur */
+		if (!wait_for_completion_timeout(&qup->xfer, HZ))
+			dev_err(qup->dev, "flush timed out\n");
+	}
+
+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);
+
+	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)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
-	int ret, idx;
+	int ret, idx, len;
 
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
@@ -756,10 +1046,17 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 
 		reinit_completion(&qup->xfer);
 
-		if (msgs[idx].flags & I2C_M_RD)
-			ret = qup_i2c_read_one(qup, &msgs[idx]);
-		else
-			ret = qup_i2c_write_one(qup, &msgs[idx]);
+		len = (&msgs[idx])->len;
+
+		if ((qup->is_dma) && (!is_vmalloc_addr((&msgs[idx])->buf)) &&
+						(len > qup->out_fifo_sz)) {
+			ret = qup_bam_xfer(adap, &msgs[idx]);
+		} else {
+			if (msgs[idx].flags & I2C_M_RD)
+				ret = qup_i2c_read_one(qup, &msgs[idx]);
+			else
+				ret = qup_i2c_write_one(qup, &msgs[idx]);
+		}
 
 		if (ret)
 			break;
@@ -790,7 +1087,7 @@ static u32 qup_i2c_func(struct i2c_adapter *adap)
 	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
 }
 
-static const struct i2c_algorithm qup_i2c_algo = {
+static struct i2c_algorithm qup_i2c_algo = {
 	.master_xfer	= qup_i2c_xfer,
 	.functionality	= qup_i2c_func,
 };
@@ -839,6 +1136,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 	u32 clk_freq = 100000;
 	const struct qup_i2c_config *config;
 	const struct of_device_id *of_id;
+	int blocks;
 
 	qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
 	if (!qup)
@@ -875,6 +1173,53 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		return qup->irq;
 	}
 
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v2.1.1") ||
+		of_device_is_compatible(pdev->dev.of_node,
+			"qcom,i2c-qup-v2.2.1")) {
+		qup->dma_rx = dma_request_slave_channel(&pdev->dev, "bam-rx");
+
+		if (!qup->dma_rx)
+			return -EPROBE_DEFER;
+
+		qup->dma_tx = dma_request_slave_channel(&pdev->dev, "bam-tx");
+		if (!qup->dma_tx)
+			return -EPROBE_DEFER;
+
+		qup->is_dma = 1;
+
+		blocks = (MX_BLOCKS << 1) + 1;
+		qup->sg_tx = devm_kzalloc(&pdev->dev,
+					  sizeof(*qup->sg_tx) * blocks,
+					  GFP_KERNEL);
+		if (!qup->sg_tx)
+			return -ENOMEM;
+
+		qup->sg_rx = devm_kzalloc(&pdev->dev,
+					  sizeof(*qup->sg_tx) * blocks,
+					  GFP_KERNEL);
+		if (!qup->sg_rx)
+			return -ENOMEM;
+
+		size = sizeof(struct tag) * (blocks + 3);
+		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)
+			return -ENOMEM;
+
+		qup->scratch_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
+							&qup->scratch_tag.addr);
+		if (!qup->scratch_tag.start)
+			return -ENOMEM;
+
+		qup->footer_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
+						       &qup->footer_tag.addr);
+		if (!qup->footer_tag.start)
+			return -ENOMEM;
+	}
+
 	qup->clk = devm_clk_get(qup->dev, "core");
 	if (IS_ERR(qup->clk)) {
 		dev_err(qup->dev, "Could not get core clock\n");
@@ -989,6 +1334,14 @@ static int qup_i2c_remove(struct platform_device *pdev)
 {
 	struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
 
+	dma_pool_free(qup->dpool, qup->start_tag.start,
+		      qup->start_tag.addr);
+	dma_pool_free(qup->dpool, qup->scratch_tag.start,
+		      qup->scratch_tag.addr);
+	dma_pool_free(qup->dpool, qup->footer_tag.start,
+		      qup->footer_tag.addr);
+	dma_pool_destroy(qup->dpool);
+
 	disable_irq(qup->irq);
 	qup_i2c_disable_clocks(qup);
 	i2c_del_adapter(&qup->adap);
-- 
1.8.2.1

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

* [PATCH 4/6] i2c: qup: Transfer every i2c_msg in i2c_msgs without stop
  2015-03-13 17:49 ` Sricharan R
@ 2015-03-13 17:49   ` Sricharan R
  -1 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel
  Cc: sricharan, agross

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.

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

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 11ea6af..90a2b5e 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -846,75 +846,91 @@ void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct tag *tg,
 		sg_dma_address(sg) = tg->addr + ((u8 *) buf - tg->start);
 }
 
-static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, int num)
 {
 	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 = 0;
-	/* QUP I2C read/write limit for single command is 256bytes max*/
-	int blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
-	int rem = msg->len % QUP_READ_LIMIT;
-	int tlen, i = 0, tx_len = 0;
-
-	if (msg->flags & I2C_M_RD) {
-		tx_nents = 1;
-		rx_nents = (blocks << 1) + 1;
-		sg_init_table(qup->sg_rx, rx_nents);
-
-		while (i < blocks) {
-			/* transfer length set to '0' implies 256 bytes */
-			tlen = (i == (blocks - 1)) ? rem : 0;
-			len += get_start_tag(&qup->start_tag.start[len],
-					      msg, !i, (i == (blocks-1)),
-					      tlen);
-
-			qup_sg_set_buf(&qup->sg_rx[i << 1],
-				       &qup->scratch_tag.start[0],
-				       &qup->scratch_tag,
-				       2, qup, 0, 0);
-
-			qup_sg_set_buf(&qup->sg_rx[(i << 1) + 1],
-				       &msg->buf[QUP_READ_LIMIT * i],
-				       NULL, tlen, qup, 1,
-				       DMA_FROM_DEVICE);
-
-			i++;
-		}
-
-		sg_init_one(qup->sg_tx, &qup->start_tag.start[0], len);
-		qup_sg_set_buf(qup->sg_tx, &qup->start_tag.start[0],
-			       &qup->start_tag, len, qup, 0, 0);
-		qup_sg_set_buf(&qup->sg_rx[i << 1],
-			       &qup->scratch_tag.start[1],
-			       &qup->scratch_tag, 2,
-			       qup, 0, 0);
-	} else {
-		qup->footer_tag.start[0] = QUP_BAM_FLUSH_STOP;
-		qup->footer_tag.start[1] = QUP_BAM_FLUSH_STOP;
-
-		tx_nents = (blocks << 1) + 1;
-		sg_init_table(qup->sg_tx, tx_nents);
-
-		while (i < blocks) {
-			tlen = (i == (blocks - 1)) ? rem : 0;
-			len = get_start_tag(&qup->start_tag.start[tx_len],
-					    msg, !i, (i == (blocks-1)), tlen);
-
-			qup_sg_set_buf(&qup->sg_tx[i << 1],
-				       &qup->start_tag.start[tx_len],
-				       &qup->start_tag,
-				       len, qup, 0, 0);
-
-			tx_len += len;
-			qup_sg_set_buf(&qup->sg_tx[(i << 1) + 1],
-				       &msg->buf[QUP_READ_LIMIT * i], NULL,
-				       tlen, qup, 1, DMA_TO_DEVICE);
-			i++;
+	u32 rx_nents = 0, tx_nents = 0, len, blocks, rem, last;
+	u32 cur_rx_nents, cur_tx_nents;
+	u32 tlen, i, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
+
+	while (num) {
+		blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
+		rem = msg->len % QUP_READ_LIMIT;
+		i = 0, tx_len = 0, len = 0;
+
+		if (msg->flags & I2C_M_RD) {
+			cur_tx_nents = 1;
+			cur_rx_nents = (blocks << 1) + 1;
+			rx_nents += cur_rx_nents;
+			tx_nents += cur_tx_nents;
+
+			while (i < blocks) {
+				/* transfer length set to '0' implies 256
+				   bytes */
+				tlen = (i == (blocks - 1)) ? rem : 0;
+				last = (i == (blocks-1)) && !(num-1);
+				len += get_start_tag(&qup->start_tag.start[off +
+									   len],
+						     msg, !i, last, tlen);
+
+				qup_sg_set_buf(&qup->sg_rx[rx_buf++],
+					   &qup->scratch_tag.start[0],
+					   &qup->scratch_tag,
+					   2, qup, 0, 0);
+
+				qup_sg_set_buf(&qup->sg_rx[rx_buf++],
+					   &msg->buf[QUP_READ_LIMIT * i],
+					   NULL, tlen, qup,
+					   1, DMA_FROM_DEVICE);
+				i++;
+			}
+			qup_sg_set_buf(&qup->sg_tx[tx_buf++],
+				   &qup->start_tag.start[off],
+				   &qup->start_tag, len, qup, 0, 0);
+			off += len;
+			qup_sg_set_buf(&qup->sg_rx[rx_buf++],
+				   &qup->scratch_tag.start[1],
+				   &qup->scratch_tag, 2,
+				   qup, 0, 0);
+		} else {
+			cur_tx_nents = (blocks << 1);
+			tx_nents += cur_tx_nents;
+
+			while (i < blocks) {
+				tlen = (i == (blocks - 1)) ? rem : 0;
+				last = (i == (blocks-1)) && !(num-1);
+				len = get_start_tag(&qup->start_tag.start[off +
+									tx_len],
+						    msg, !i, last, tlen);
+
+				qup_sg_set_buf(&qup->sg_tx[tx_buf++],
+					       &qup->start_tag.start[off +
+								     tx_len],
+					       &qup->start_tag, len,
+					       qup, 0, 0);
+
+				tx_len += len;
+				qup_sg_set_buf(&qup->sg_tx[tx_buf++],
+					   &msg->buf[QUP_READ_LIMIT * i], NULL,
+					   tlen, qup, 1, DMA_TO_DEVICE);
+				i++;
+			}
+			off += tx_len;
+
+			if (!(num-1)) {
+				qup->footer_tag.start[0] = QUP_BAM_FLUSH_STOP;
+				qup->footer_tag.start[1] = QUP_BAM_FLUSH_STOP;
+				qup_sg_set_buf(&qup->sg_tx[tx_buf++],
+					       &qup->footer_tag.start[0],
+					       &qup->footer_tag, 2,
+					       qup, 0, 0);
+				tx_nents += 1;
+			}
 		}
-		qup_sg_set_buf(&qup->sg_tx[i << 1], &qup->footer_tag.start[0],
-			       &qup->footer_tag, 2,
-			       qup, 0, 0);
+		msg++;
+		num--;
 	}
 
 	txd = dmaengine_prep_slave_sg(qup->dma_tx, qup->sg_tx, tx_nents,
@@ -965,6 +981,9 @@ static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		qup_i2c_flush(qup);
 		qup_i2c_change_state(qup, QUP_RUN_STATE);
 
+		writel(QUP_BAM_INPUT_EOT, qup->base + QUP_OUT_FIFO_BASE);
+		writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
+
 		/* wait for remaining interrupts to occur */
 		if (!wait_for_completion_timeout(&qup->xfer, HZ))
 			dev_err(qup->dev, "flush timed out\n");
@@ -974,7 +993,7 @@ desc_err:
 	return ret;
 }
 
-static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg)
+static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
 	int ret = 0;
@@ -1001,7 +1020,7 @@ static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg)
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
 	qup->msg = msg;
-	ret = bam_do_xfer(qup, qup->msg);
+	ret = bam_do_xfer(qup, qup->msg, num);
 out:
 	disable_irq(qup->irq);
 
@@ -1014,7 +1033,7 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 			int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
-	int ret, idx, len;
+	int ret, idx, use_dma = 0, len = 0;
 
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
@@ -1033,12 +1052,28 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 		writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
 	}
 
-	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;
+			}
+
+			if (!len)
+				len = ((&msgs[idx])->len) > qup->out_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;
@@ -1046,11 +1081,9 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 
 		reinit_completion(&qup->xfer);
 
-		len = (&msgs[idx])->len;
-
-		if ((qup->is_dma) && (!is_vmalloc_addr((&msgs[idx])->buf)) &&
-						(len > qup->out_fifo_sz)) {
-			ret = qup_bam_xfer(adap, &msgs[idx]);
+		if (use_dma) {
+			ret = qup_bam_xfer(adap, &msgs[idx], num);
+			idx = num;
 		} else {
 			if (msgs[idx].flags & I2C_M_RD)
 				ret = qup_i2c_read_one(qup, &msgs[idx]);
@@ -1191,15 +1224,20 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		qup->sg_tx = devm_kzalloc(&pdev->dev,
 					  sizeof(*qup->sg_tx) * blocks,
 					  GFP_KERNEL);
+
 		if (!qup->sg_tx)
 			return -ENOMEM;
 
+		sg_init_table(qup->sg_tx, blocks);
+
 		qup->sg_rx = devm_kzalloc(&pdev->dev,
-					  sizeof(*qup->sg_tx) * blocks,
+					  sizeof(*qup->sg_rx) * blocks,
 					  GFP_KERNEL);
 		if (!qup->sg_rx)
 			return -ENOMEM;
 
+		sg_init_table(qup->sg_rx, blocks);
+
 		size = sizeof(struct tag) * (blocks + 3);
 		qup->dpool = dma_pool_create("qup_i2c-dma-pool", &pdev->dev,
 					 size, 4, 0);
-- 
1.8.2.1

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

* [PATCH 4/6] i2c: qup: Transfer every i2c_msg in i2c_msgs without stop
@ 2015-03-13 17:49   ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 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.

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

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 11ea6af..90a2b5e 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -846,75 +846,91 @@ void qup_sg_set_buf(struct scatterlist *sg, void *buf, struct tag *tg,
 		sg_dma_address(sg) = tg->addr + ((u8 *) buf - tg->start);
 }
 
-static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, int num)
 {
 	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 = 0;
-	/* QUP I2C read/write limit for single command is 256bytes max*/
-	int blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
-	int rem = msg->len % QUP_READ_LIMIT;
-	int tlen, i = 0, tx_len = 0;
-
-	if (msg->flags & I2C_M_RD) {
-		tx_nents = 1;
-		rx_nents = (blocks << 1) + 1;
-		sg_init_table(qup->sg_rx, rx_nents);
-
-		while (i < blocks) {
-			/* transfer length set to '0' implies 256 bytes */
-			tlen = (i == (blocks - 1)) ? rem : 0;
-			len += get_start_tag(&qup->start_tag.start[len],
-					      msg, !i, (i == (blocks-1)),
-					      tlen);
-
-			qup_sg_set_buf(&qup->sg_rx[i << 1],
-				       &qup->scratch_tag.start[0],
-				       &qup->scratch_tag,
-				       2, qup, 0, 0);
-
-			qup_sg_set_buf(&qup->sg_rx[(i << 1) + 1],
-				       &msg->buf[QUP_READ_LIMIT * i],
-				       NULL, tlen, qup, 1,
-				       DMA_FROM_DEVICE);
-
-			i++;
-		}
-
-		sg_init_one(qup->sg_tx, &qup->start_tag.start[0], len);
-		qup_sg_set_buf(qup->sg_tx, &qup->start_tag.start[0],
-			       &qup->start_tag, len, qup, 0, 0);
-		qup_sg_set_buf(&qup->sg_rx[i << 1],
-			       &qup->scratch_tag.start[1],
-			       &qup->scratch_tag, 2,
-			       qup, 0, 0);
-	} else {
-		qup->footer_tag.start[0] = QUP_BAM_FLUSH_STOP;
-		qup->footer_tag.start[1] = QUP_BAM_FLUSH_STOP;
-
-		tx_nents = (blocks << 1) + 1;
-		sg_init_table(qup->sg_tx, tx_nents);
-
-		while (i < blocks) {
-			tlen = (i == (blocks - 1)) ? rem : 0;
-			len = get_start_tag(&qup->start_tag.start[tx_len],
-					    msg, !i, (i == (blocks-1)), tlen);
-
-			qup_sg_set_buf(&qup->sg_tx[i << 1],
-				       &qup->start_tag.start[tx_len],
-				       &qup->start_tag,
-				       len, qup, 0, 0);
-
-			tx_len += len;
-			qup_sg_set_buf(&qup->sg_tx[(i << 1) + 1],
-				       &msg->buf[QUP_READ_LIMIT * i], NULL,
-				       tlen, qup, 1, DMA_TO_DEVICE);
-			i++;
+	u32 rx_nents = 0, tx_nents = 0, len, blocks, rem, last;
+	u32 cur_rx_nents, cur_tx_nents;
+	u32 tlen, i, tx_len, tx_buf = 0, rx_buf = 0, off = 0;
+
+	while (num) {
+		blocks = (msg->len + QUP_READ_LIMIT) / QUP_READ_LIMIT;
+		rem = msg->len % QUP_READ_LIMIT;
+		i = 0, tx_len = 0, len = 0;
+
+		if (msg->flags & I2C_M_RD) {
+			cur_tx_nents = 1;
+			cur_rx_nents = (blocks << 1) + 1;
+			rx_nents += cur_rx_nents;
+			tx_nents += cur_tx_nents;
+
+			while (i < blocks) {
+				/* transfer length set to '0' implies 256
+				   bytes */
+				tlen = (i == (blocks - 1)) ? rem : 0;
+				last = (i == (blocks-1)) && !(num-1);
+				len += get_start_tag(&qup->start_tag.start[off +
+									   len],
+						     msg, !i, last, tlen);
+
+				qup_sg_set_buf(&qup->sg_rx[rx_buf++],
+					   &qup->scratch_tag.start[0],
+					   &qup->scratch_tag,
+					   2, qup, 0, 0);
+
+				qup_sg_set_buf(&qup->sg_rx[rx_buf++],
+					   &msg->buf[QUP_READ_LIMIT * i],
+					   NULL, tlen, qup,
+					   1, DMA_FROM_DEVICE);
+				i++;
+			}
+			qup_sg_set_buf(&qup->sg_tx[tx_buf++],
+				   &qup->start_tag.start[off],
+				   &qup->start_tag, len, qup, 0, 0);
+			off += len;
+			qup_sg_set_buf(&qup->sg_rx[rx_buf++],
+				   &qup->scratch_tag.start[1],
+				   &qup->scratch_tag, 2,
+				   qup, 0, 0);
+		} else {
+			cur_tx_nents = (blocks << 1);
+			tx_nents += cur_tx_nents;
+
+			while (i < blocks) {
+				tlen = (i == (blocks - 1)) ? rem : 0;
+				last = (i == (blocks-1)) && !(num-1);
+				len = get_start_tag(&qup->start_tag.start[off +
+									tx_len],
+						    msg, !i, last, tlen);
+
+				qup_sg_set_buf(&qup->sg_tx[tx_buf++],
+					       &qup->start_tag.start[off +
+								     tx_len],
+					       &qup->start_tag, len,
+					       qup, 0, 0);
+
+				tx_len += len;
+				qup_sg_set_buf(&qup->sg_tx[tx_buf++],
+					   &msg->buf[QUP_READ_LIMIT * i], NULL,
+					   tlen, qup, 1, DMA_TO_DEVICE);
+				i++;
+			}
+			off += tx_len;
+
+			if (!(num-1)) {
+				qup->footer_tag.start[0] = QUP_BAM_FLUSH_STOP;
+				qup->footer_tag.start[1] = QUP_BAM_FLUSH_STOP;
+				qup_sg_set_buf(&qup->sg_tx[tx_buf++],
+					       &qup->footer_tag.start[0],
+					       &qup->footer_tag, 2,
+					       qup, 0, 0);
+				tx_nents += 1;
+			}
 		}
-		qup_sg_set_buf(&qup->sg_tx[i << 1], &qup->footer_tag.start[0],
-			       &qup->footer_tag, 2,
-			       qup, 0, 0);
+		msg++;
+		num--;
 	}
 
 	txd = dmaengine_prep_slave_sg(qup->dma_tx, qup->sg_tx, tx_nents,
@@ -965,6 +981,9 @@ static int bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 		qup_i2c_flush(qup);
 		qup_i2c_change_state(qup, QUP_RUN_STATE);
 
+		writel(QUP_BAM_INPUT_EOT, qup->base + QUP_OUT_FIFO_BASE);
+		writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
+
 		/* wait for remaining interrupts to occur */
 		if (!wait_for_completion_timeout(&qup->xfer, HZ))
 			dev_err(qup->dev, "flush timed out\n");
@@ -974,7 +993,7 @@ desc_err:
 	return ret;
 }
 
-static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg)
+static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
 	int ret = 0;
@@ -1001,7 +1020,7 @@ static int qup_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg)
 	writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
 
 	qup->msg = msg;
-	ret = bam_do_xfer(qup, qup->msg);
+	ret = bam_do_xfer(qup, qup->msg, num);
 out:
 	disable_irq(qup->irq);
 
@@ -1014,7 +1033,7 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 			int num)
 {
 	struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
-	int ret, idx, len;
+	int ret, idx, use_dma = 0, len = 0;
 
 	ret = pm_runtime_get_sync(qup->dev);
 	if (ret < 0)
@@ -1033,12 +1052,28 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 		writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
 	}
 
-	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;
+			}
+
+			if (!len)
+				len = ((&msgs[idx])->len) > qup->out_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;
@@ -1046,11 +1081,9 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
 
 		reinit_completion(&qup->xfer);
 
-		len = (&msgs[idx])->len;
-
-		if ((qup->is_dma) && (!is_vmalloc_addr((&msgs[idx])->buf)) &&
-						(len > qup->out_fifo_sz)) {
-			ret = qup_bam_xfer(adap, &msgs[idx]);
+		if (use_dma) {
+			ret = qup_bam_xfer(adap, &msgs[idx], num);
+			idx = num;
 		} else {
 			if (msgs[idx].flags & I2C_M_RD)
 				ret = qup_i2c_read_one(qup, &msgs[idx]);
@@ -1191,15 +1224,20 @@ static int qup_i2c_probe(struct platform_device *pdev)
 		qup->sg_tx = devm_kzalloc(&pdev->dev,
 					  sizeof(*qup->sg_tx) * blocks,
 					  GFP_KERNEL);
+
 		if (!qup->sg_tx)
 			return -ENOMEM;
 
+		sg_init_table(qup->sg_tx, blocks);
+
 		qup->sg_rx = devm_kzalloc(&pdev->dev,
-					  sizeof(*qup->sg_tx) * blocks,
+					  sizeof(*qup->sg_rx) * blocks,
 					  GFP_KERNEL);
 		if (!qup->sg_rx)
 			return -ENOMEM;
 
+		sg_init_table(qup->sg_rx, blocks);
+
 		size = sizeof(struct tag) * (blocks + 3);
 		qup->dpool = dma_pool_create("qup_i2c-dma-pool", &pdev->dev,
 					 size, 4, 0);
-- 
1.8.2.1

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

* [PATCH 5/6] dts: msm8974: Add blsp2_bam dma node
  2015-03-13 17:49 ` Sricharan R
@ 2015-03-13 17:49   ` Sricharan R
  -1 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel
  Cc: sricharan, agross

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

diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index e265ec1..3f648ae 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -247,5 +247,15 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 		};
+
+		blsp2_dma: dma@f9944000 {
+			compatible = "qcom,bam-v1.4.0";
+			reg = <0xf9944000 0x19000>;
+			interrupts = <0 239 0>;
+			clocks = <&gcc GCC_BLSP2_AHB_CLK>;
+			clock-names = "bam_clk";
+			#dma-cells = <1>;
+			qcom,ee = <0>;
+		};
 	};
 };
-- 
1.8.2.1

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

* [PATCH 5/6] dts: msm8974: Add blsp2_bam dma node
@ 2015-03-13 17:49   ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: linux-arm-kernel

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

diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index e265ec1..3f648ae 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -247,5 +247,15 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 		};
+
+		blsp2_dma: dma at f9944000 {
+			compatible = "qcom,bam-v1.4.0";
+			reg = <0xf9944000 0x19000>;
+			interrupts = <0 239 0>;
+			clocks = <&gcc GCC_BLSP2_AHB_CLK>;
+			clock-names = "bam_clk";
+			#dma-cells = <1>;
+			qcom,ee = <0>;
+		};
 	};
 };
-- 
1.8.2.1

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

* [PATCH 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
  2015-03-13 17:49 ` Sricharan R
@ 2015-03-13 17:49   ` Sricharan R
  -1 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 UTC (permalink / raw)
  To: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel
  Cc: sricharan, agross

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 3f648ae..1ec7ec5 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -246,6 +246,8 @@
 			clock-names = "core", "iface";
 			#address-cells = <1>;
 			#size-cells = <0>;
+			dmas = <&blsp2_dma 20>, <&blsp2_dma 21>;
+			dma-names = "bam-tx", "bam-rx";
 		};
 
 		blsp2_dma: dma@f9944000 {
-- 
1.8.2.1

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

* [PATCH 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
@ 2015-03-13 17:49   ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-13 17:49 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 3f648ae..1ec7ec5 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -246,6 +246,8 @@
 			clock-names = "core", "iface";
 			#address-cells = <1>;
 			#size-cells = <0>;
+			dmas = <&blsp2_dma 20>, <&blsp2_dma 21>;
+			dma-names = "bam-tx", "bam-rx";
 		};
 
 		blsp2_dma: dma at f9944000 {
-- 
1.8.2.1

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

* Re: [PATCH 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
  2015-03-13 17:49   ` Sricharan R
@ 2015-03-13 19:54     ` Andy Gross
  -1 siblings, 0 replies; 43+ messages in thread
From: Andy Gross @ 2015-03-13 19:54 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel

On Fri, Mar 13, 2015 at 11:19:52PM +0530, Sricharan R wrote:
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---

Reviewed-by: Andy Gross <agross@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 3f648ae..1ec7ec5 100644
> --- a/arch/arm/boot/dts/qcom-msm8974.dtsi
> +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
> @@ -246,6 +246,8 @@
>  			clock-names = "core", "iface";
>  			#address-cells = <1>;
>  			#size-cells = <0>;
> +			dmas = <&blsp2_dma 20>, <&blsp2_dma 21>;
> +			dma-names = "bam-tx", "bam-rx";

more of a nit, but the bam- is unnecessary.  it's just rx/tx.
>  		};
>  
>  		blsp2_dma: dma@f9944000 {
> -- 
> 1.8.2.1
> 

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* [PATCH 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
@ 2015-03-13 19:54     ` Andy Gross
  0 siblings, 0 replies; 43+ messages in thread
From: Andy Gross @ 2015-03-13 19:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 13, 2015 at 11:19:52PM +0530, Sricharan R wrote:
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---

Reviewed-by: Andy Gross <agross@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 3f648ae..1ec7ec5 100644
> --- a/arch/arm/boot/dts/qcom-msm8974.dtsi
> +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
> @@ -246,6 +246,8 @@
>  			clock-names = "core", "iface";
>  			#address-cells = <1>;
>  			#size-cells = <0>;
> +			dmas = <&blsp2_dma 20>, <&blsp2_dma 21>;
> +			dma-names = "bam-tx", "bam-rx";

more of a nit, but the bam- is unnecessary.  it's just rx/tx.
>  		};
>  
>  		blsp2_dma: dma at f9944000 {
> -- 
> 1.8.2.1
> 

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
  2015-03-13 19:54     ` Andy Gross
  (?)
@ 2015-03-16  9:55         ` sricharan
  -1 siblings, 0 replies; 43+ messages in thread
From: sricharan-sgV2jX0FEOL9JmXXK+q4OQ @ 2015-03-16  9:55 UTC (permalink / raw)
  To: Andy Gross
  Cc: Sricharan R, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi,

> On Fri, Mar 13, 2015 at 11:19:52PM +0530, Sricharan R wrote:
>> Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>> ---
>
> Reviewed-by: Andy Gross <agross-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.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 3f648ae..1ec7ec5 100644
>> --- a/arch/arm/boot/dts/qcom-msm8974.dtsi
>> +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
>> @@ -246,6 +246,8 @@
>>  			clock-names = "core", "iface";
>>  			#address-cells = <1>;
>>  			#size-cells = <0>;
>> +			dmas = <&blsp2_dma 20>, <&blsp2_dma 21>;
>> +			dma-names = "bam-tx", "bam-rx";
>
> more of a nit, but the bam- is unnecessary.  it's just rx/tx.

  Ok, will change it.

Regards,
 Sricharan

--
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] 43+ messages in thread

* Re: [PATCH 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
@ 2015-03-16  9:55         ` sricharan
  0 siblings, 0 replies; 43+ messages in thread
From: sricharan @ 2015-03-16  9:55 UTC (permalink / raw)
  To: Andy Gross
  Cc: Sricharan R, devicetree, linux-arm-msm, linux-kernel, linux-i2c,
	galak, dmaengine, linux-arm-kernel

Hi,

> On Fri, Mar 13, 2015 at 11:19:52PM +0530, Sricharan R wrote:
>> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
>> ---
>
> Reviewed-by: Andy Gross <agross@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 3f648ae..1ec7ec5 100644
>> --- a/arch/arm/boot/dts/qcom-msm8974.dtsi
>> +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
>> @@ -246,6 +246,8 @@
>>  			clock-names = "core", "iface";
>>  			#address-cells = <1>;
>>  			#size-cells = <0>;
>> +			dmas = <&blsp2_dma 20>, <&blsp2_dma 21>;
>> +			dma-names = "bam-tx", "bam-rx";
>
> more of a nit, but the bam- is unnecessary.  it's just rx/tx.

  Ok, will change it.

Regards,
 Sricharan


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

* [PATCH 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node
@ 2015-03-16  9:55         ` sricharan
  0 siblings, 0 replies; 43+ messages in thread
From: sricharan at codeaurora.org @ 2015-03-16  9:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

> On Fri, Mar 13, 2015 at 11:19:52PM +0530, Sricharan R wrote:
>> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
>> ---
>
> Reviewed-by: Andy Gross <agross@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 3f648ae..1ec7ec5 100644
>> --- a/arch/arm/boot/dts/qcom-msm8974.dtsi
>> +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
>> @@ -246,6 +246,8 @@
>>  			clock-names = "core", "iface";
>>  			#address-cells = <1>;
>>  			#size-cells = <0>;
>> +			dmas = <&blsp2_dma 20>, <&blsp2_dma 21>;
>> +			dma-names = "bam-tx", "bam-rx";
>
> more of a nit, but the bam- is unnecessary.  it's just rx/tx.

  Ok, will change it.

Regards,
 Sricharan

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

* Re: [PATCH 5/6] dts: msm8974: Add blsp2_bam dma node
  2015-03-13 17:49   ` Sricharan R
@ 2015-03-17 12:48     ` Stanimir Varbanov
  -1 siblings, 0 replies; 43+ messages in thread
From: Stanimir Varbanov @ 2015-03-17 12:48 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel, agross

On 03/13/2015 07:49 PM, Sricharan R wrote:
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
>  arch/arm/boot/dts/qcom-msm8974.dtsi | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
> index e265ec1..3f648ae 100644
> --- a/arch/arm/boot/dts/qcom-msm8974.dtsi
> +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
> @@ -247,5 +247,15 @@
>  			#address-cells = <1>;
>  			#size-cells = <0>;
>  		};
> +
> +		blsp2_dma: dma@f9944000 {
> +			compatible = "qcom,bam-v1.4.0";
> +			reg = <0xf9944000 0x19000>;
> +			interrupts = <0 239 0>;

for completeness this should be:

interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;

-- 
regards,
Stan

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

* [PATCH 5/6] dts: msm8974: Add blsp2_bam dma node
@ 2015-03-17 12:48     ` Stanimir Varbanov
  0 siblings, 0 replies; 43+ messages in thread
From: Stanimir Varbanov @ 2015-03-17 12:48 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/13/2015 07:49 PM, Sricharan R wrote:
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
>  arch/arm/boot/dts/qcom-msm8974.dtsi | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
> index e265ec1..3f648ae 100644
> --- a/arch/arm/boot/dts/qcom-msm8974.dtsi
> +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
> @@ -247,5 +247,15 @@
>  			#address-cells = <1>;
>  			#size-cells = <0>;
>  		};
> +
> +		blsp2_dma: dma at f9944000 {
> +			compatible = "qcom,bam-v1.4.0";
> +			reg = <0xf9944000 0x19000>;
> +			interrupts = <0 239 0>;

for completeness this should be:

interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;

-- 
regards,
Stan

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

* Re: [PATCH 5/6] dts: msm8974: Add blsp2_bam dma node
  2015-03-17 12:48     ` Stanimir Varbanov
  (?)
@ 2015-03-17 13:10         ` sricharan
  -1 siblings, 0 replies; 43+ messages in thread
From: sricharan-sgV2jX0FEOL9JmXXK+q4OQ @ 2015-03-17 13:10 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Sricharan R, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	agross-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi,

> On 03/13/2015 07:49 PM, Sricharan R wrote:
>> Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>> ---
>>  arch/arm/boot/dts/qcom-msm8974.dtsi | 10 ++++++++++
>>  1 file changed, 10 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi
>> b/arch/arm/boot/dts/qcom-msm8974.dtsi
>> index e265ec1..3f648ae 100644
>> --- a/arch/arm/boot/dts/qcom-msm8974.dtsi
>> +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
>> @@ -247,5 +247,15 @@
>>  			#address-cells = <1>;
>>  			#size-cells = <0>;
>>  		};
>> +
>> +		blsp2_dma: dma@f9944000 {
>> +			compatible = "qcom,bam-v1.4.0";
>> +			reg = <0xf9944000 0x19000>;
>> +			interrupts = <0 239 0>;
>
> for completeness this should be:
>
> interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
>
Ok, will fix. Thanks

-- 
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	[flat|nested] 43+ messages in thread

* Re: [PATCH 5/6] dts: msm8974: Add blsp2_bam dma node
@ 2015-03-17 13:10         ` sricharan
  0 siblings, 0 replies; 43+ messages in thread
From: sricharan @ 2015-03-17 13:10 UTC (permalink / raw)
  To: Stanimir Varbanov
  Cc: Sricharan R, devicetree, linux-arm-msm, agross, linux-kernel,
	linux-i2c, galak, dmaengine, linux-arm-kernel

Hi,

> On 03/13/2015 07:49 PM, Sricharan R wrote:
>> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
>> ---
>>  arch/arm/boot/dts/qcom-msm8974.dtsi | 10 ++++++++++
>>  1 file changed, 10 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi
>> b/arch/arm/boot/dts/qcom-msm8974.dtsi
>> index e265ec1..3f648ae 100644
>> --- a/arch/arm/boot/dts/qcom-msm8974.dtsi
>> +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
>> @@ -247,5 +247,15 @@
>>  			#address-cells = <1>;
>>  			#size-cells = <0>;
>>  		};
>> +
>> +		blsp2_dma: dma@f9944000 {
>> +			compatible = "qcom,bam-v1.4.0";
>> +			reg = <0xf9944000 0x19000>;
>> +			interrupts = <0 239 0>;
>
> for completeness this should be:
>
> interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
>
Ok, will fix. Thanks

-- 
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] 43+ messages in thread

* [PATCH 5/6] dts: msm8974: Add blsp2_bam dma node
@ 2015-03-17 13:10         ` sricharan
  0 siblings, 0 replies; 43+ messages in thread
From: sricharan at codeaurora.org @ 2015-03-17 13:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

> On 03/13/2015 07:49 PM, Sricharan R wrote:
>> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
>> ---
>>  arch/arm/boot/dts/qcom-msm8974.dtsi | 10 ++++++++++
>>  1 file changed, 10 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi
>> b/arch/arm/boot/dts/qcom-msm8974.dtsi
>> index e265ec1..3f648ae 100644
>> --- a/arch/arm/boot/dts/qcom-msm8974.dtsi
>> +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
>> @@ -247,5 +247,15 @@
>>  			#address-cells = <1>;
>>  			#size-cells = <0>;
>>  		};
>> +
>> +		blsp2_dma: dma at f9944000 {
>> +			compatible = "qcom,bam-v1.4.0";
>> +			reg = <0xf9944000 0x19000>;
>> +			interrupts = <0 239 0>;
>
> for completeness this should be:
>
> interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
>
Ok, will fix. Thanks

-- 
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] 43+ messages in thread

* Re: [PATCH 2/6] i2c: qup: Add V2 tags support
  2015-03-13 17:49     ` Sricharan R
  (?)
@ 2015-03-25 12:24         ` Ivan T. Ivanov
  -1 siblings, 0 replies; 43+ messages in thread
From: Ivan T. Ivanov @ 2015-03-25 12:24 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	dmaengine-u79uwXL29TY76Z2rM5mHXA, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	agross-sgV2jX0FEOL9JmXXK+q4OQ


Hi Sricharan,

On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:
> From: Andy Gross <agross-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> 
> 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-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
>  drivers/i2c/busses/i2c-qup.c | 342 ++++++++++++++++++++++++++++++++++++++-----
> 

<snip>

> +#define I2C_QUP_CLK_MAX_FREQ           3400000

unused?

> +
>  /* Status, Error flags */
>  #define I2C_STATUS_WR_BUFFER_FULL      BIT(0)
>  #define I2C_STATUS_BUS_ACTIVE          BIT(8)
> @@ -99,6 +117,11 @@
> 
>  #define QUP_READ_LIMIT                 256
> 
> +struct qup_i2c_config {
> +       int tag_ver;
> +       int max_freq;
> +};
> +

Do you really need this one. It is referenced only during probe, 
but information contained in is already available by other means.


>  struct qup_i2c_dev {
>         struct device*dev;
>         void __iomem*base;
> @@ -112,9 +135,20 @@ struct qup_i2c_dev {
>         int     in_fifo_sz;
>         int     out_blk_sz;
>         int     in_blk_sz;
> -
> +       int     blocks;
> +       u8      *block_tag_len;
> +       int     *block_data_len;

Maybe these could be organized in struct?

<snip>

> 
> +static void qup_i2c_create_tag_v2(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, prev_len = 0;
> +       int blocks = 0;
> +       int rem;
> +       int block_len = 0;
> +       int data_len;
> +
> +       qup->block_pos = 0;
> +       qup->pos = 0;
> +       qup->blocks = (msg->len + QUP_READ_LIMIT - 1) / (QUP_READ_LIMIT);

Braces around QUP_READ_LIMIT are not needed.

> +       rem = msg->len % QUP_READ_LIMIT;
> +
> +       /* 2 tag bytes for each block + 2 extra bytes for first block */
> +       qup->tags = kzalloc((qup->blocks << 1) + 2, GFP_KERNEL);

Don't play tricks with shifts, just use multiplication.

> +       qup->block_tag_len = kzalloc(qup->blocks, GFP_KERNEL);
> +       qup->block_data_len = kzalloc(sizeof(int) * qup->blocks, GFP_KERNEL);

Better use sizeof(*qup->block_data_len).

> +
> +       while (blocks < qup->blocks) {
> +               /* 0 is used to specify a READ_LIMIT of 256 bytes */
> +               data_len = (blocks < (qup->blocks - 1)) ? 0 : rem;
> +
> +               /* Send START and ADDR bytes only for the first block */
> +               if (!blocks) {
> +                       qup->tags[len++] = QUP_TAG_V2_START;
> +
> +                       if (qup->is_hs) {
> +                               qup->tags[len++] = QUP_TAG_V2_HS;
> +                               qup->tags[len++] = QUP_TAG_V2_START;

Is this second QUP_TAG_V2_START intentional?

> +                       }
> +
> +                       qup->tags[len++] = addr & 0xff;
> +                       if (msg->flags & I2C_M_TEN)
> +                               qup->tags[len++] = addr >> 8;
> +               }
> +
> +               /* Send _STOP commands for the last block */
> +               if (blocks == (qup->blocks - 1)) {
> +                       if (msg->flags & I2C_M_RD)
> +                               qup->tags[len++] = QUP_TAG_V2_DATARD_STOP;
> +                       else
> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR_STOP;
> +               } else {
> +                       if (msg->flags & I2C_M_RD)
> +                               qup->tags[len++] = QUP_TAG_V2_DATARD;
> +                       else
> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR;
> +               }
> +
> +               qup->tags[len++] = data_len;
> +               block_len = len - prev_len;
> +               prev_len = len;
> +               qup->block_tag_len[blocks] = block_len;
> +
> +               if (!data_len)
> +                       qup->block_data_len[blocks] = QUP_READ_LIMIT;
> +               else
> +                       qup->block_data_len[blocks] = data_len;
> +
> +               qup->tags_pos = 0;
> +               blocks++;
> +       }
> +
> +       qup->tx_tag_len = len;
> +
> +       if (msg->flags & I2C_M_RD)
> +               qup->rx_tag_len = (qup->blocks << 1);

here again.

> +       else
> +               qup->rx_tag_len = 0;
> +}
> +
> +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
> +                                                               u8 *buf, int last)
> +{

I think that xfer is too vague in this case, prefer write or send.

> +       static u32 val, idx;

static? please fix.

> +       u32  t, rem, pos = 0;
> +
> +       rem = len - pos + idx;
> +
> +       while (rem) {
> +               if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, 0, 4)) {
> +                       dev_err(qup->dev, "timeout for fifo out full");
> +                       break;
> +               }
> +
> +               t = (rem >= 4) ? 4 : rem;
> +
> +               while (idx < t)
> +                       val |= buf[pos++] << (idx++ << 3);

here again, multiplication or shift?

> +
> +               if (t == 4) {
> +                       writel(val, qup->base + QUP_OUT_FIFO_BASE);
> +                       idx = val = 0;
> +               }
> +
> +               rem = len - pos;
> +       }
> +

What will happen if they are less than 4 bytes to send?

> +       if (last) {
> +               writel(val, qup->base + QUP_OUT_FIFO_BASE);
> +               idx = val = 0;
> +       }
> +
> +       return 0;
> +}
> +
> 

<snip>

> 
> -static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +static void qup_i2c_issue_read_v1(struct qup_i2c_dev *qup, struct
> +                                               i2c_msg *msg)

Please, move struct on the same line as i2c_msg.

>  {
>         u32 addr, len, val;
> 
> @@ -395,24 +576,33 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>         /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
>         len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
> 
> -       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
> +       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START |
> +                       addr;

Unrelated change?

>         writel(val, qup->base + QUP_OUT_FIFO_BASE);
>  }
> 
> 

<snip>

> 
> +static void qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, struct
> +                                       i2c_msg *msg)
> +{
> +       u32 val;
> +       int idx;
> +       int pos = 0;

> +       int total = qup->block_data_len[qup->block_pos] + 2;

Could we  have at least comment what is this +2?

<snip>

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

Bad indent? 

<snip>


> +static const struct qup_i2c_config configs[] = {
> +       { 0, 400000, },
> +       { 1, 3400000, },
> +};
> +
> +static const struct of_device_id qup_i2c_dt_match[] = {
> +       { .compatible = "qcom,i2c-qup-v1.1.1", .data = &configs[0] },
> +       { .compatible = "qcom,i2c-qup-v2.1.1", .data = &configs[1] },
> +       { .compatible = "qcom,i2c-qup-v2.2.1", .data = &configs[1] },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
> +
>  static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
>  {
>         u32 config;
> @@ -579,6 +837,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
>         int ret, fs_div, hs_div;
>         int src_clk_freq;
>         u32 clk_freq = 100000;
> +       const struct qup_i2c_config *config;
> +       const struct of_device_id *of_id;
> 
>         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>         if (!qup)
> @@ -590,8 +850,15 @@ static int qup_i2c_probe(struct platform_device *pdev)
> 
>         of_property_read_u32(node, "clock-frequency", &clk_freq);
> 
> -       /* We support frequencies up to FAST Mode (400KHz) */
> -       if (!clk_freq || clk_freq > 400000) {
> +       of_id = of_match_node(qup_i2c_dt_match, node);
> +       if (!of_id)
> +               return -EINVAL;

this could not happen.

> +
> +       config = of_id->data;
> +       qup->use_v2_tags = !!config->tag_ver;
> +
> +       /* We support frequencies up to HIGH SPEED Mode (3400KHz) */
> +       if (!clk_freq || clk_freq > config->max_freq) {

Looks like if controller is v > 1 it supports I2C_QUP_CLK_MAX_FREQ.
I don't see need for struct qup_i2c_config.

Regards,
Ivan

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

* Re: [PATCH 2/6] i2c: qup: Add V2 tags support
@ 2015-03-25 12:24         ` Ivan T. Ivanov
  0 siblings, 0 replies; 43+ messages in thread
From: Ivan T. Ivanov @ 2015-03-25 12:24 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel, agross


Hi Sricharan,

On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:
> From: Andy Gross <agross@codeaurora.org>
> 
> 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 | 342 ++++++++++++++++++++++++++++++++++++++-----
> 

<snip>

> +#define I2C_QUP_CLK_MAX_FREQ           3400000

unused?

> +
>  /* Status, Error flags */
>  #define I2C_STATUS_WR_BUFFER_FULL      BIT(0)
>  #define I2C_STATUS_BUS_ACTIVE          BIT(8)
> @@ -99,6 +117,11 @@
> 
>  #define QUP_READ_LIMIT                 256
> 
> +struct qup_i2c_config {
> +       int tag_ver;
> +       int max_freq;
> +};
> +

Do you really need this one. It is referenced only during probe, 
but information contained in is already available by other means.


>  struct qup_i2c_dev {
>         struct device*dev;
>         void __iomem*base;
> @@ -112,9 +135,20 @@ struct qup_i2c_dev {
>         int     in_fifo_sz;
>         int     out_blk_sz;
>         int     in_blk_sz;
> -
> +       int     blocks;
> +       u8      *block_tag_len;
> +       int     *block_data_len;

Maybe these could be organized in struct?

<snip>

> 
> +static void qup_i2c_create_tag_v2(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, prev_len = 0;
> +       int blocks = 0;
> +       int rem;
> +       int block_len = 0;
> +       int data_len;
> +
> +       qup->block_pos = 0;
> +       qup->pos = 0;
> +       qup->blocks = (msg->len + QUP_READ_LIMIT - 1) / (QUP_READ_LIMIT);

Braces around QUP_READ_LIMIT are not needed.

> +       rem = msg->len % QUP_READ_LIMIT;
> +
> +       /* 2 tag bytes for each block + 2 extra bytes for first block */
> +       qup->tags = kzalloc((qup->blocks << 1) + 2, GFP_KERNEL);

Don't play tricks with shifts, just use multiplication.

> +       qup->block_tag_len = kzalloc(qup->blocks, GFP_KERNEL);
> +       qup->block_data_len = kzalloc(sizeof(int) * qup->blocks, GFP_KERNEL);

Better use sizeof(*qup->block_data_len).

> +
> +       while (blocks < qup->blocks) {
> +               /* 0 is used to specify a READ_LIMIT of 256 bytes */
> +               data_len = (blocks < (qup->blocks - 1)) ? 0 : rem;
> +
> +               /* Send START and ADDR bytes only for the first block */
> +               if (!blocks) {
> +                       qup->tags[len++] = QUP_TAG_V2_START;
> +
> +                       if (qup->is_hs) {
> +                               qup->tags[len++] = QUP_TAG_V2_HS;
> +                               qup->tags[len++] = QUP_TAG_V2_START;

Is this second QUP_TAG_V2_START intentional?

> +                       }
> +
> +                       qup->tags[len++] = addr & 0xff;
> +                       if (msg->flags & I2C_M_TEN)
> +                               qup->tags[len++] = addr >> 8;
> +               }
> +
> +               /* Send _STOP commands for the last block */
> +               if (blocks == (qup->blocks - 1)) {
> +                       if (msg->flags & I2C_M_RD)
> +                               qup->tags[len++] = QUP_TAG_V2_DATARD_STOP;
> +                       else
> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR_STOP;
> +               } else {
> +                       if (msg->flags & I2C_M_RD)
> +                               qup->tags[len++] = QUP_TAG_V2_DATARD;
> +                       else
> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR;
> +               }
> +
> +               qup->tags[len++] = data_len;
> +               block_len = len - prev_len;
> +               prev_len = len;
> +               qup->block_tag_len[blocks] = block_len;
> +
> +               if (!data_len)
> +                       qup->block_data_len[blocks] = QUP_READ_LIMIT;
> +               else
> +                       qup->block_data_len[blocks] = data_len;
> +
> +               qup->tags_pos = 0;
> +               blocks++;
> +       }
> +
> +       qup->tx_tag_len = len;
> +
> +       if (msg->flags & I2C_M_RD)
> +               qup->rx_tag_len = (qup->blocks << 1);

here again.

> +       else
> +               qup->rx_tag_len = 0;
> +}
> +
> +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
> +                                                               u8 *buf, int last)
> +{

I think that xfer is too vague in this case, prefer write or send.

> +       static u32 val, idx;

static? please fix.

> +       u32  t, rem, pos = 0;
> +
> +       rem = len - pos + idx;
> +
> +       while (rem) {
> +               if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, 0, 4)) {
> +                       dev_err(qup->dev, "timeout for fifo out full");
> +                       break;
> +               }
> +
> +               t = (rem >= 4) ? 4 : rem;
> +
> +               while (idx < t)
> +                       val |= buf[pos++] << (idx++ << 3);

here again, multiplication or shift?

> +
> +               if (t == 4) {
> +                       writel(val, qup->base + QUP_OUT_FIFO_BASE);
> +                       idx = val = 0;
> +               }
> +
> +               rem = len - pos;
> +       }
> +

What will happen if they are less than 4 bytes to send?

> +       if (last) {
> +               writel(val, qup->base + QUP_OUT_FIFO_BASE);
> +               idx = val = 0;
> +       }
> +
> +       return 0;
> +}
> +
> 

<snip>

> 
> -static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +static void qup_i2c_issue_read_v1(struct qup_i2c_dev *qup, struct
> +                                               i2c_msg *msg)

Please, move struct on the same line as i2c_msg.

>  {
>         u32 addr, len, val;
> 
> @@ -395,24 +576,33 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>         /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
>         len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
> 
> -       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
> +       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START |
> +                       addr;

Unrelated change?

>         writel(val, qup->base + QUP_OUT_FIFO_BASE);
>  }
> 
> 

<snip>

> 
> +static void qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, struct
> +                                       i2c_msg *msg)
> +{
> +       u32 val;
> +       int idx;
> +       int pos = 0;

> +       int total = qup->block_data_len[qup->block_pos] + 2;

Could we  have at least comment what is this +2?

<snip>

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

Bad indent? 

<snip>


> +static const struct qup_i2c_config configs[] = {
> +       { 0, 400000, },
> +       { 1, 3400000, },
> +};
> +
> +static const struct of_device_id qup_i2c_dt_match[] = {
> +       { .compatible = "qcom,i2c-qup-v1.1.1", .data = &configs[0] },
> +       { .compatible = "qcom,i2c-qup-v2.1.1", .data = &configs[1] },
> +       { .compatible = "qcom,i2c-qup-v2.2.1", .data = &configs[1] },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
> +
>  static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
>  {
>         u32 config;
> @@ -579,6 +837,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
>         int ret, fs_div, hs_div;
>         int src_clk_freq;
>         u32 clk_freq = 100000;
> +       const struct qup_i2c_config *config;
> +       const struct of_device_id *of_id;
> 
>         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>         if (!qup)
> @@ -590,8 +850,15 @@ static int qup_i2c_probe(struct platform_device *pdev)
> 
>         of_property_read_u32(node, "clock-frequency", &clk_freq);
> 
> -       /* We support frequencies up to FAST Mode (400KHz) */
> -       if (!clk_freq || clk_freq > 400000) {
> +       of_id = of_match_node(qup_i2c_dt_match, node);
> +       if (!of_id)
> +               return -EINVAL;

this could not happen.

> +
> +       config = of_id->data;
> +       qup->use_v2_tags = !!config->tag_ver;
> +
> +       /* We support frequencies up to HIGH SPEED Mode (3400KHz) */
> +       if (!clk_freq || clk_freq > config->max_freq) {

Looks like if controller is v > 1 it supports I2C_QUP_CLK_MAX_FREQ.
I don't see need for struct qup_i2c_config.

Regards,
Ivan

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

* [PATCH 2/6] i2c: qup: Add V2 tags support
@ 2015-03-25 12:24         ` Ivan T. Ivanov
  0 siblings, 0 replies; 43+ messages in thread
From: Ivan T. Ivanov @ 2015-03-25 12:24 UTC (permalink / raw)
  To: linux-arm-kernel


Hi Sricharan,

On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:
> From: Andy Gross <agross@codeaurora.org>
> 
> 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 | 342 ++++++++++++++++++++++++++++++++++++++-----
> 

<snip>

> +#define I2C_QUP_CLK_MAX_FREQ           3400000

unused?

> +
>  /* Status, Error flags */
>  #define I2C_STATUS_WR_BUFFER_FULL      BIT(0)
>  #define I2C_STATUS_BUS_ACTIVE          BIT(8)
> @@ -99,6 +117,11 @@
> 
>  #define QUP_READ_LIMIT                 256
> 
> +struct qup_i2c_config {
> +       int tag_ver;
> +       int max_freq;
> +};
> +

Do you really need this one. It is referenced only during probe, 
but information contained in is already available by other means.


>  struct qup_i2c_dev {
>         struct device*dev;
>         void __iomem*base;
> @@ -112,9 +135,20 @@ struct qup_i2c_dev {
>         int     in_fifo_sz;
>         int     out_blk_sz;
>         int     in_blk_sz;
> -
> +       int     blocks;
> +       u8      *block_tag_len;
> +       int     *block_data_len;

Maybe these could be organized in struct?

<snip>

> 
> +static void qup_i2c_create_tag_v2(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, prev_len = 0;
> +       int blocks = 0;
> +       int rem;
> +       int block_len = 0;
> +       int data_len;
> +
> +       qup->block_pos = 0;
> +       qup->pos = 0;
> +       qup->blocks = (msg->len + QUP_READ_LIMIT - 1) / (QUP_READ_LIMIT);

Braces around QUP_READ_LIMIT are not needed.

> +       rem = msg->len % QUP_READ_LIMIT;
> +
> +       /* 2 tag bytes for each block + 2 extra bytes for first block */
> +       qup->tags = kzalloc((qup->blocks << 1) + 2, GFP_KERNEL);

Don't play tricks with shifts, just use multiplication.

> +       qup->block_tag_len = kzalloc(qup->blocks, GFP_KERNEL);
> +       qup->block_data_len = kzalloc(sizeof(int) * qup->blocks, GFP_KERNEL);

Better use sizeof(*qup->block_data_len).

> +
> +       while (blocks < qup->blocks) {
> +               /* 0 is used to specify a READ_LIMIT of 256 bytes */
> +               data_len = (blocks < (qup->blocks - 1)) ? 0 : rem;
> +
> +               /* Send START and ADDR bytes only for the first block */
> +               if (!blocks) {
> +                       qup->tags[len++] = QUP_TAG_V2_START;
> +
> +                       if (qup->is_hs) {
> +                               qup->tags[len++] = QUP_TAG_V2_HS;
> +                               qup->tags[len++] = QUP_TAG_V2_START;

Is this second QUP_TAG_V2_START intentional?

> +                       }
> +
> +                       qup->tags[len++] = addr & 0xff;
> +                       if (msg->flags & I2C_M_TEN)
> +                               qup->tags[len++] = addr >> 8;
> +               }
> +
> +               /* Send _STOP commands for the last block */
> +               if (blocks == (qup->blocks - 1)) {
> +                       if (msg->flags & I2C_M_RD)
> +                               qup->tags[len++] = QUP_TAG_V2_DATARD_STOP;
> +                       else
> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR_STOP;
> +               } else {
> +                       if (msg->flags & I2C_M_RD)
> +                               qup->tags[len++] = QUP_TAG_V2_DATARD;
> +                       else
> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR;
> +               }
> +
> +               qup->tags[len++] = data_len;
> +               block_len = len - prev_len;
> +               prev_len = len;
> +               qup->block_tag_len[blocks] = block_len;
> +
> +               if (!data_len)
> +                       qup->block_data_len[blocks] = QUP_READ_LIMIT;
> +               else
> +                       qup->block_data_len[blocks] = data_len;
> +
> +               qup->tags_pos = 0;
> +               blocks++;
> +       }
> +
> +       qup->tx_tag_len = len;
> +
> +       if (msg->flags & I2C_M_RD)
> +               qup->rx_tag_len = (qup->blocks << 1);

here again.

> +       else
> +               qup->rx_tag_len = 0;
> +}
> +
> +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
> +                                                               u8 *buf, int last)
> +{

I think that xfer is too vague in this case, prefer write or send.

> +       static u32 val, idx;

static? please fix.

> +       u32  t, rem, pos = 0;
> +
> +       rem = len - pos + idx;
> +
> +       while (rem) {
> +               if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, 0, 4)) {
> +                       dev_err(qup->dev, "timeout for fifo out full");
> +                       break;
> +               }
> +
> +               t = (rem >= 4) ? 4 : rem;
> +
> +               while (idx < t)
> +                       val |= buf[pos++] << (idx++ << 3);

here again, multiplication or shift?

> +
> +               if (t == 4) {
> +                       writel(val, qup->base + QUP_OUT_FIFO_BASE);
> +                       idx = val = 0;
> +               }
> +
> +               rem = len - pos;
> +       }
> +

What will happen if they are less than 4 bytes to send?

> +       if (last) {
> +               writel(val, qup->base + QUP_OUT_FIFO_BASE);
> +               idx = val = 0;
> +       }
> +
> +       return 0;
> +}
> +
> 

<snip>

> 
> -static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
> +static void qup_i2c_issue_read_v1(struct qup_i2c_dev *qup, struct
> +                                               i2c_msg *msg)

Please, move struct on the same line as i2c_msg.

>  {
>         u32 addr, len, val;
> 
> @@ -395,24 +576,33 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>         /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
>         len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
> 
> -       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
> +       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START |
> +                       addr;

Unrelated change?

>         writel(val, qup->base + QUP_OUT_FIFO_BASE);
>  }
> 
> 

<snip>

> 
> +static void qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, struct
> +                                       i2c_msg *msg)
> +{
> +       u32 val;
> +       int idx;
> +       int pos = 0;

> +       int total = qup->block_data_len[qup->block_pos] + 2;

Could we  have at least comment what is this +2?

<snip>

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

Bad indent? 

<snip>


> +static const struct qup_i2c_config configs[] = {
> +       { 0, 400000, },
> +       { 1, 3400000, },
> +};
> +
> +static const struct of_device_id qup_i2c_dt_match[] = {
> +       { .compatible = "qcom,i2c-qup-v1.1.1", .data = &configs[0] },
> +       { .compatible = "qcom,i2c-qup-v2.1.1", .data = &configs[1] },
> +       { .compatible = "qcom,i2c-qup-v2.2.1", .data = &configs[1] },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
> +
>  static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
>  {
>         u32 config;
> @@ -579,6 +837,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
>         int ret, fs_div, hs_div;
>         int src_clk_freq;
>         u32 clk_freq = 100000;
> +       const struct qup_i2c_config *config;
> +       const struct of_device_id *of_id;
> 
>         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>         if (!qup)
> @@ -590,8 +850,15 @@ static int qup_i2c_probe(struct platform_device *pdev)
> 
>         of_property_read_u32(node, "clock-frequency", &clk_freq);
> 
> -       /* We support frequencies up to FAST Mode (400KHz) */
> -       if (!clk_freq || clk_freq > 400000) {
> +       of_id = of_match_node(qup_i2c_dt_match, node);
> +       if (!of_id)
> +               return -EINVAL;

this could not happen.

> +
> +       config = of_id->data;
> +       qup->use_v2_tags = !!config->tag_ver;
> +
> +       /* We support frequencies up to HIGH SPEED Mode (3400KHz) */
> +       if (!clk_freq || clk_freq > config->max_freq) {

Looks like if controller is v > 1 it supports I2C_QUP_CLK_MAX_FREQ.
I don't see need for struct qup_i2c_config.

Regards,
Ivan

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

* Re: [PATCH 3/6] i2c: qup: Add bam dma capabilities
  2015-03-13 17:49     ` Sricharan R
  (?)
@ 2015-03-25 13:10         ` Ivan T. Ivanov
  -1 siblings, 0 replies; 43+ messages in thread
From: Ivan T. Ivanov @ 2015-03-25 13:10 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	dmaengine-u79uwXL29TY76Z2rM5mHXA, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	agross-sgV2jX0FEOL9JmXXK+q4OQ


Hi Sricharan,

On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:


>  #define QUP_I2C_MASTER_GEN     0x408
> +#define QUP_I2C_MASTER_CONFIG  0x408
> 

Unused.

>  #define QUP_READ_LIMIT                 256
> +#define MX_TX_RX_LEN                   SZ_64K
> +#define MX_BLOCKS                      (MX_TX_RX_LEN / QUP_READ_LIMIT)
> +
> +#define TOUT_MAX                       300 /* Max timeout for 32k tx/tx */
> 

seconds, muliseconds?

>  struct qup_i2c_config {
>         int tag_ver;
>         int max_freq;
>  };
> 
> +struct tag {

Please use consistent naming convention.

> +       u8 *start;
> +       dma_addr_t addr;
> +};
> +
>  struct qup_i2c_dev {
>         struct device*dev;
>         void __iomem*base;
> @@ -157,9 +181,35 @@ struct qup_i2c_dev {
>         /* QUP core errors */
>         u32     qup_err;
> 
> +       /* dma parameters */
> +       bool    is_dma;
> +       struct  dma_pool *dpool;
> +       struct  tag start_tag;
> +       struct  tag scratch_tag;
> +       struct  tag footer_tag;
> +       struct  dma_chan *dma_tx;
> +       struct  dma_chan *dma_rx;
> +       struct  scatterlist *sg_tx;
> +       struct  scatterlist *sg_rx;
> +       dma_addr_tsg_tx_phys;
> +       dma_addr_tsg_rx_phys;

Maybe these could be organized in structure per direction.

> +
>         struct completionxfer;
>  };
> 
> +struct i2c_bam_xfer {

Unused.

> +       struct qup_i2c_dev *qup;
> +       u32 start_len;
> +
> +       u32 rx_nents;
> +       u32 tx_nents;
> +
> +       struct dma_async_tx_descriptor *tx_desc;
> +       dma_cookie_t tx_cookie;
> +       struct dma_async_tx_descriptor *rx_desc;
> +       dma_cookie_t rx_cookie;

structure per direction.

> +};
> +
> 

> +static void bam_i2c_callback(void *data)
> +{

Please use consistent naming, here and bellow.

> +       struct qup_i2c_dev *qup = data;
> +
> +       complete(&qup->xfer);
> +}
> +
> +static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last,
> +                       int blen)
> +{
> +       u8 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
> +       u8 op;
> +       int len = 0;
> +
> +       /* always issue stop for each read block */
> +       if (last) {
> +               if (msg->flags & I2C_M_RD)
> +                       op = QUP_TAG_V2_DATARD_STOP;
> +               else
> +                       op = QUP_TAG_V2_DATAWR_STOP;
> +       } else {
> +               if (msg->flags & I2C_M_RD)
> +                       op = QUP_TAG_V2_DATARD;
> +               else
> +                       op = QUP_TAG_V2_DATAWR;
> +       }
> +
> +       if (msg->flags & I2C_M_TEN) {
> +               len += 5;
> +               tag[0] = QUP_TAG_V2_START;
> +               tag[1] = addr;
> +               tag[2] = op;
> +               tag[3] = blen;
> +
> +               if (msg->flags & I2C_M_RD && last) {
> +                       len += 2;
> +                       tag[4] = QUP_BAM_INPUT_EOT;
> +                       tag[5] = QUP_BAM_FLUSH_STOP;
> +               }
> +       } else {
> +               if (first) {
> +                       tag[len++] = QUP_TAG_V2_START;
> +                       tag[len++] = addr;
> +               }
> +
> +               tag[len++] = op;
> +               tag[len++] = blen;
> +
> +               if (msg->flags & I2C_M_RD & last) {
> +                       tag[len++] = QUP_BAM_INPUT_EOT;
> +                       tag[len++] = QUP_BAM_FLUSH_STOP;
> +               }
> +       }
> +
> +       return len;
> +}

Maybe could be split to 2 functions?

> -static const struct i2c_algorithm qup_i2c_algo = {
> +static struct i2c_algorithm qup_i2c_algo = {

Why?

>         .master_xfer= qup_i2c_xfer,
>         .functionality= qup_i2c_func,
>  };
> @@ -839,6 +1136,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>         u32 clk_freq = 100000;
>         const struct qup_i2c_config *config;
>         const struct of_device_id *of_id;
> +       int blocks;
> 
>         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>         if (!qup)
> @@ -875,6 +1173,53 @@ static int qup_i2c_probe(struct platform_device *pdev)
>                 return qup->irq;
>         }
> 
> +       if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v2.1.1") ||
> +               of_device_is_compatible(pdev->dev.of_node,
> +                       "qcom,i2c-qup-v2.2.1")) {

Logic will be simpler if you check just for version 1 of the controller.

> +               qup->dma_rx = dma_request_slave_channel(&pdev->dev, "bam-rx");
> +

Please use dma_request_slave_channel_reason.

As Andy noted, please use just "rx", "tx"

> +               if (!qup->dma_rx)
> +                       return -EPROBE_DEFER;

Don't mask other errors, here and bellow. DMA support should be optional.

>                 dev_err(qup->dev, "Could not get core clock\n");
> @@ -989,6 +1334,14 @@ static int qup_i2c_remove(struct platform_device *pdev)
>  {
>         struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
> 
> +       dma_pool_free(qup->dpool, qup->start_tag.start,
> +                                                               qup->start_tag.addr);
> +       dma_pool_free(qup->dpool, qup->scratch_tag.start,
> +                                                               qup->scratch_tag.addr);
> +       dma_pool_free(qup->dpool, qup->footer_tag.start,
> +                                                               qup->footer_tag.addr);
> +       dma_pool_destroy(qup->dpool);

Only if is_dma, right?

DMA mapping code omitted from review. I don't understand it well enough, sorry.

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] 43+ messages in thread

* Re: [PATCH 3/6] i2c: qup: Add bam dma capabilities
@ 2015-03-25 13:10         ` Ivan T. Ivanov
  0 siblings, 0 replies; 43+ messages in thread
From: Ivan T. Ivanov @ 2015-03-25 13:10 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree, linux-arm-msm, linux-arm-kernel, dmaengine, galak,
	linux-i2c, linux-kernel, agross


Hi Sricharan,

On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:


>  #define QUP_I2C_MASTER_GEN     0x408
> +#define QUP_I2C_MASTER_CONFIG  0x408
> 

Unused.

>  #define QUP_READ_LIMIT                 256
> +#define MX_TX_RX_LEN                   SZ_64K
> +#define MX_BLOCKS                      (MX_TX_RX_LEN / QUP_READ_LIMIT)
> +
> +#define TOUT_MAX                       300 /* Max timeout for 32k tx/tx */
> 

seconds, muliseconds?

>  struct qup_i2c_config {
>         int tag_ver;
>         int max_freq;
>  };
> 
> +struct tag {

Please use consistent naming convention.

> +       u8 *start;
> +       dma_addr_t addr;
> +};
> +
>  struct qup_i2c_dev {
>         struct device*dev;
>         void __iomem*base;
> @@ -157,9 +181,35 @@ struct qup_i2c_dev {
>         /* QUP core errors */
>         u32     qup_err;
> 
> +       /* dma parameters */
> +       bool    is_dma;
> +       struct  dma_pool *dpool;
> +       struct  tag start_tag;
> +       struct  tag scratch_tag;
> +       struct  tag footer_tag;
> +       struct  dma_chan *dma_tx;
> +       struct  dma_chan *dma_rx;
> +       struct  scatterlist *sg_tx;
> +       struct  scatterlist *sg_rx;
> +       dma_addr_tsg_tx_phys;
> +       dma_addr_tsg_rx_phys;

Maybe these could be organized in structure per direction.

> +
>         struct completionxfer;
>  };
> 
> +struct i2c_bam_xfer {

Unused.

> +       struct qup_i2c_dev *qup;
> +       u32 start_len;
> +
> +       u32 rx_nents;
> +       u32 tx_nents;
> +
> +       struct dma_async_tx_descriptor *tx_desc;
> +       dma_cookie_t tx_cookie;
> +       struct dma_async_tx_descriptor *rx_desc;
> +       dma_cookie_t rx_cookie;

structure per direction.

> +};
> +
> 

> +static void bam_i2c_callback(void *data)
> +{

Please use consistent naming, here and bellow.

> +       struct qup_i2c_dev *qup = data;
> +
> +       complete(&qup->xfer);
> +}
> +
> +static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last,
> +                       int blen)
> +{
> +       u8 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
> +       u8 op;
> +       int len = 0;
> +
> +       /* always issue stop for each read block */
> +       if (last) {
> +               if (msg->flags & I2C_M_RD)
> +                       op = QUP_TAG_V2_DATARD_STOP;
> +               else
> +                       op = QUP_TAG_V2_DATAWR_STOP;
> +       } else {
> +               if (msg->flags & I2C_M_RD)
> +                       op = QUP_TAG_V2_DATARD;
> +               else
> +                       op = QUP_TAG_V2_DATAWR;
> +       }
> +
> +       if (msg->flags & I2C_M_TEN) {
> +               len += 5;
> +               tag[0] = QUP_TAG_V2_START;
> +               tag[1] = addr;
> +               tag[2] = op;
> +               tag[3] = blen;
> +
> +               if (msg->flags & I2C_M_RD && last) {
> +                       len += 2;
> +                       tag[4] = QUP_BAM_INPUT_EOT;
> +                       tag[5] = QUP_BAM_FLUSH_STOP;
> +               }
> +       } else {
> +               if (first) {
> +                       tag[len++] = QUP_TAG_V2_START;
> +                       tag[len++] = addr;
> +               }
> +
> +               tag[len++] = op;
> +               tag[len++] = blen;
> +
> +               if (msg->flags & I2C_M_RD & last) {
> +                       tag[len++] = QUP_BAM_INPUT_EOT;
> +                       tag[len++] = QUP_BAM_FLUSH_STOP;
> +               }
> +       }
> +
> +       return len;
> +}

Maybe could be split to 2 functions?

> -static const struct i2c_algorithm qup_i2c_algo = {
> +static struct i2c_algorithm qup_i2c_algo = {

Why?

>         .master_xfer= qup_i2c_xfer,
>         .functionality= qup_i2c_func,
>  };
> @@ -839,6 +1136,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>         u32 clk_freq = 100000;
>         const struct qup_i2c_config *config;
>         const struct of_device_id *of_id;
> +       int blocks;
> 
>         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>         if (!qup)
> @@ -875,6 +1173,53 @@ static int qup_i2c_probe(struct platform_device *pdev)
>                 return qup->irq;
>         }
> 
> +       if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v2.1.1") ||
> +               of_device_is_compatible(pdev->dev.of_node,
> +                       "qcom,i2c-qup-v2.2.1")) {

Logic will be simpler if you check just for version 1 of the controller.

> +               qup->dma_rx = dma_request_slave_channel(&pdev->dev, "bam-rx");
> +

Please use dma_request_slave_channel_reason.

As Andy noted, please use just "rx", "tx"

> +               if (!qup->dma_rx)
> +                       return -EPROBE_DEFER;

Don't mask other errors, here and bellow. DMA support should be optional.

>                 dev_err(qup->dev, "Could not get core clock\n");
> @@ -989,6 +1334,14 @@ static int qup_i2c_remove(struct platform_device *pdev)
>  {
>         struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
> 
> +       dma_pool_free(qup->dpool, qup->start_tag.start,
> +                                                               qup->start_tag.addr);
> +       dma_pool_free(qup->dpool, qup->scratch_tag.start,
> +                                                               qup->scratch_tag.addr);
> +       dma_pool_free(qup->dpool, qup->footer_tag.start,
> +                                                               qup->footer_tag.addr);
> +       dma_pool_destroy(qup->dpool);

Only if is_dma, right?

DMA mapping code omitted from review. I don't understand it well enough, sorry.

Regards,
Ivan


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

* [PATCH 3/6] i2c: qup: Add bam dma capabilities
@ 2015-03-25 13:10         ` Ivan T. Ivanov
  0 siblings, 0 replies; 43+ messages in thread
From: Ivan T. Ivanov @ 2015-03-25 13:10 UTC (permalink / raw)
  To: linux-arm-kernel


Hi Sricharan,

On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:


>  #define QUP_I2C_MASTER_GEN     0x408
> +#define QUP_I2C_MASTER_CONFIG  0x408
> 

Unused.

>  #define QUP_READ_LIMIT                 256
> +#define MX_TX_RX_LEN                   SZ_64K
> +#define MX_BLOCKS                      (MX_TX_RX_LEN / QUP_READ_LIMIT)
> +
> +#define TOUT_MAX                       300 /* Max timeout for 32k tx/tx */
> 

seconds, muliseconds?

>  struct qup_i2c_config {
>         int tag_ver;
>         int max_freq;
>  };
> 
> +struct tag {

Please use consistent naming convention.

> +       u8 *start;
> +       dma_addr_t addr;
> +};
> +
>  struct qup_i2c_dev {
>         struct device*dev;
>         void __iomem*base;
> @@ -157,9 +181,35 @@ struct qup_i2c_dev {
>         /* QUP core errors */
>         u32     qup_err;
> 
> +       /* dma parameters */
> +       bool    is_dma;
> +       struct  dma_pool *dpool;
> +       struct  tag start_tag;
> +       struct  tag scratch_tag;
> +       struct  tag footer_tag;
> +       struct  dma_chan *dma_tx;
> +       struct  dma_chan *dma_rx;
> +       struct  scatterlist *sg_tx;
> +       struct  scatterlist *sg_rx;
> +       dma_addr_tsg_tx_phys;
> +       dma_addr_tsg_rx_phys;

Maybe these could be organized in structure per direction.

> +
>         struct completionxfer;
>  };
> 
> +struct i2c_bam_xfer {

Unused.

> +       struct qup_i2c_dev *qup;
> +       u32 start_len;
> +
> +       u32 rx_nents;
> +       u32 tx_nents;
> +
> +       struct dma_async_tx_descriptor *tx_desc;
> +       dma_cookie_t tx_cookie;
> +       struct dma_async_tx_descriptor *rx_desc;
> +       dma_cookie_t rx_cookie;

structure per direction.

> +};
> +
> 

> +static void bam_i2c_callback(void *data)
> +{

Please use consistent naming, here and bellow.

> +       struct qup_i2c_dev *qup = data;
> +
> +       complete(&qup->xfer);
> +}
> +
> +static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last,
> +                       int blen)
> +{
> +       u8 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
> +       u8 op;
> +       int len = 0;
> +
> +       /* always issue stop for each read block */
> +       if (last) {
> +               if (msg->flags & I2C_M_RD)
> +                       op = QUP_TAG_V2_DATARD_STOP;
> +               else
> +                       op = QUP_TAG_V2_DATAWR_STOP;
> +       } else {
> +               if (msg->flags & I2C_M_RD)
> +                       op = QUP_TAG_V2_DATARD;
> +               else
> +                       op = QUP_TAG_V2_DATAWR;
> +       }
> +
> +       if (msg->flags & I2C_M_TEN) {
> +               len += 5;
> +               tag[0] = QUP_TAG_V2_START;
> +               tag[1] = addr;
> +               tag[2] = op;
> +               tag[3] = blen;
> +
> +               if (msg->flags & I2C_M_RD && last) {
> +                       len += 2;
> +                       tag[4] = QUP_BAM_INPUT_EOT;
> +                       tag[5] = QUP_BAM_FLUSH_STOP;
> +               }
> +       } else {
> +               if (first) {
> +                       tag[len++] = QUP_TAG_V2_START;
> +                       tag[len++] = addr;
> +               }
> +
> +               tag[len++] = op;
> +               tag[len++] = blen;
> +
> +               if (msg->flags & I2C_M_RD & last) {
> +                       tag[len++] = QUP_BAM_INPUT_EOT;
> +                       tag[len++] = QUP_BAM_FLUSH_STOP;
> +               }
> +       }
> +
> +       return len;
> +}

Maybe could be split to 2 functions?

> -static const struct i2c_algorithm qup_i2c_algo = {
> +static struct i2c_algorithm qup_i2c_algo = {

Why?

>         .master_xfer= qup_i2c_xfer,
>         .functionality= qup_i2c_func,
>  };
> @@ -839,6 +1136,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>         u32 clk_freq = 100000;
>         const struct qup_i2c_config *config;
>         const struct of_device_id *of_id;
> +       int blocks;
> 
>         qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>         if (!qup)
> @@ -875,6 +1173,53 @@ static int qup_i2c_probe(struct platform_device *pdev)
>                 return qup->irq;
>         }
> 
> +       if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v2.1.1") ||
> +               of_device_is_compatible(pdev->dev.of_node,
> +                       "qcom,i2c-qup-v2.2.1")) {

Logic will be simpler if you check just for version 1 of the controller.

> +               qup->dma_rx = dma_request_slave_channel(&pdev->dev, "bam-rx");
> +

Please use dma_request_slave_channel_reason.

As Andy noted, please use just "rx", "tx"

> +               if (!qup->dma_rx)
> +                       return -EPROBE_DEFER;

Don't mask other errors, here and bellow. DMA support should be optional.

>                 dev_err(qup->dev, "Could not get core clock\n");
> @@ -989,6 +1334,14 @@ static int qup_i2c_remove(struct platform_device *pdev)
>  {
>         struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
> 
> +       dma_pool_free(qup->dpool, qup->start_tag.start,
> +                                                               qup->start_tag.addr);
> +       dma_pool_free(qup->dpool, qup->scratch_tag.start,
> +                                                               qup->scratch_tag.addr);
> +       dma_pool_free(qup->dpool, qup->footer_tag.start,
> +                                                               qup->footer_tag.addr);
> +       dma_pool_destroy(qup->dpool);

Only if is_dma, right?

DMA mapping code omitted from review. I don't understand it well enough, sorry.

Regards,
Ivan

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

* Re: [PATCH 2/6] i2c: qup: Add V2 tags support
  2015-03-25 12:24         ` Ivan T. Ivanov
  (?)
@ 2015-03-26  5:44             ` Sricharan R
  -1 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-26  5:44 UTC (permalink / raw)
  To: Ivan T. Ivanov
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	agross-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi Ivan,

On 03/25/2015 05:54 PM, Ivan T. Ivanov wrote:
>
> Hi Sricharan,
>
> On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:
>> From: Andy Gross <agross-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>>
>> 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-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>> Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>> ---
>>   drivers/i2c/busses/i2c-qup.c | 342 ++++++++++++++++++++++++++++++++++++++-----
>>
>
> <snip>
>
>> +#define I2C_QUP_CLK_MAX_FREQ           3400000
>
> unused?
>
Ok, will remove this.

>> +
>>   /* Status, Error flags */
>>   #define I2C_STATUS_WR_BUFFER_FULL      BIT(0)
>>   #define I2C_STATUS_BUS_ACTIVE          BIT(8)
>> @@ -99,6 +117,11 @@
>>
>>   #define QUP_READ_LIMIT                 256
>>
>> +struct qup_i2c_config {
>> +       int tag_ver;
>> +       int max_freq;
>> +};
>> +
>
> Do you really need this one. It is referenced only during probe,
> but information contained in is already available by other means.
>
Ok, agree that this can be removed and the information can be fixed
for V1 version and same for the rest of the other versions. That would
need to use compatible check though.
>
>>   struct qup_i2c_dev {
>>          struct device*dev;
>>          void __iomem*base;
>> @@ -112,9 +135,20 @@ struct qup_i2c_dev {
>>          int     in_fifo_sz;
>>          int     out_blk_sz;
>>          int     in_blk_sz;
>> -
>> +       int     blocks;
>> +       u8      *block_tag_len;
>> +       int     *block_data_len;
>
> Maybe these could be organized in struct?
>
ok, will group it.
> <snip>
>
>>
>> +static void qup_i2c_create_tag_v2(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, prev_len = 0;
>> +       int blocks = 0;
>> +       int rem;
>> +       int block_len = 0;
>> +       int data_len;
>> +
>> +       qup->block_pos = 0;
>> +       qup->pos = 0;
>> +       qup->blocks = (msg->len + QUP_READ_LIMIT - 1) / (QUP_READ_LIMIT);
>
> Braces around QUP_READ_LIMIT are not needed.
>
ok.
>> +       rem = msg->len % QUP_READ_LIMIT;
>> +
>> +       /* 2 tag bytes for each block + 2 extra bytes for first block */
>> +       qup->tags = kzalloc((qup->blocks << 1) + 2, GFP_KERNEL);
>
> Don't play tricks with shifts, just use multiplication.
>
why ?
>> +       qup->block_tag_len = kzalloc(qup->blocks, GFP_KERNEL);
>> +       qup->block_data_len = kzalloc(sizeof(int) * qup->blocks, GFP_KERNEL);
>
> Better use sizeof(*qup->block_data_len).
>
ok.
>> +
>> +       while (blocks < qup->blocks) {
>> +               /* 0 is used to specify a READ_LIMIT of 256 bytes */
>> +               data_len = (blocks < (qup->blocks - 1)) ? 0 : rem;
>> +
>> +               /* Send START and ADDR bytes only for the first block */
>> +               if (!blocks) {
>> +                       qup->tags[len++] = QUP_TAG_V2_START;
>> +
>> +                       if (qup->is_hs) {
>> +                               qup->tags[len++] = QUP_TAG_V2_HS;
>> +                               qup->tags[len++] = QUP_TAG_V2_START;
>
> Is this second QUP_TAG_V2_START intentional?
>
  Yes, for HS mode 2 start tags are required.
>> +                       }
>> +
>> +                       qup->tags[len++] = addr & 0xff;
>> +                       if (msg->flags & I2C_M_TEN)
>> +                               qup->tags[len++] = addr >> 8;
>> +               }
>> +
>> +               /* Send _STOP commands for the last block */
>> +               if (blocks == (qup->blocks - 1)) {
>> +                       if (msg->flags & I2C_M_RD)
>> +                               qup->tags[len++] = QUP_TAG_V2_DATARD_STOP;
>> +                       else
>> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR_STOP;
>> +               } else {
>> +                       if (msg->flags & I2C_M_RD)
>> +                               qup->tags[len++] = QUP_TAG_V2_DATARD;
>> +                       else
>> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR;
>> +               }
>> +
>> +               qup->tags[len++] = data_len;
>> +               block_len = len - prev_len;
>> +               prev_len = len;
>> +               qup->block_tag_len[blocks] = block_len;
>> +
>> +               if (!data_len)
>> +                       qup->block_data_len[blocks] = QUP_READ_LIMIT;
>> +               else
>> +                       qup->block_data_len[blocks] = data_len;
>> +
>> +               qup->tags_pos = 0;
>> +               blocks++;
>> +       }
>> +
>> +       qup->tx_tag_len = len;
>> +
>> +       if (msg->flags & I2C_M_RD)
>> +               qup->rx_tag_len = (qup->blocks << 1);
>
> here again.
>
hmm, why not shift ?
>> +       else
>> +               qup->rx_tag_len = 0;
>> +}
>> +
>> +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
>> +                                                               u8 *buf, int last)
>> +{
>
> I think that xfer is too vague in this case, prefer write or send.
>
ok. Will change it to send.
>> +       static u32 val, idx;
>
> static? please fix.
  That was intentional. Using to pack tag and data in to one word across
  two calls. So preserving val, idx across calls.
>
>> +       u32  t, rem, pos = 0;
>> +
>> +       rem = len - pos + idx;
>> +
>> +       while (rem) {
>> +               if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, 0, 4)) {
>> +                       dev_err(qup->dev, "timeout for fifo out full");
>> +                       break;
>> +               }
>> +
>> +               t = (rem >= 4) ? 4 : rem;
>> +
>> +               while (idx < t)
>> +                       val |= buf[pos++] << (idx++ << 3);
>
> here again, multiplication or shift?
>
  I felt shifts should be readable. No ?
>> +
>> +               if (t == 4) {
>> +                       writel(val, qup->base + QUP_OUT_FIFO_BASE);
>> +                       idx = val = 0;
>> +               }
>> +
>> +               rem = len - pos;
>> +       }
>> +
>
> What will happen if they are less than 4 bytes to send?
>
It gets written over in the next call and gets written here itself if it 
is the last block of data.
>> +       if (last) {
>> +               writel(val, qup->base + QUP_OUT_FIFO_BASE);
>> +               idx = val = 0;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>>
>
> <snip>
>
>>
>> -static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>> +static void qup_i2c_issue_read_v1(struct qup_i2c_dev *qup, struct
>> +                                               i2c_msg *msg)
>
> Please, move struct on the same line as i2c_msg.
>
ok.

>>   {
>>          u32 addr, len, val;
>>
>> @@ -395,24 +576,33 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>>          /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
>>          len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
>>
>> -       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
>> +       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START |
>> +                       addr;
>
> Unrelated change?
  hmm. Must have come for adjusting 80 chars. Will remove this here.
>
>>          writel(val, qup->base + QUP_OUT_FIFO_BASE);
>>   }
>>
>>
>
> <snip>
>
>>
>> +static void qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, struct
>> +                                       i2c_msg *msg)
>> +{
>> +       u32 val;
>> +       int idx;
>> +       int pos = 0;
>
>> +       int total = qup->block_data_len[qup->block_pos] + 2;
>
> Could we  have at least comment what is this +2?
>
  Ok. The +2 is for the read tags that are extra bytes read for each
  block. Will add comment for that.

> <snip>
>
>> +
>> +static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg
>> +                                                                       *msg)
>
> Bad indent?
>
  ok. Will fix it.
> <snip>
>
>
>> +static const struct qup_i2c_config configs[] = {
>> +       { 0, 400000, },
>> +       { 1, 3400000, },
>> +};
>> +
>> +static const struct of_device_id qup_i2c_dt_match[] = {
>> +       { .compatible = "qcom,i2c-qup-v1.1.1", .data = &configs[0] },
>> +       { .compatible = "qcom,i2c-qup-v2.1.1", .data = &configs[1] },
>> +       { .compatible = "qcom,i2c-qup-v2.2.1", .data = &configs[1] },
>> +       {}
>> +};
>> +MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
>> +
>>   static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
>>   {
>>          u32 config;
>> @@ -579,6 +837,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
>>          int ret, fs_div, hs_div;
>>          int src_clk_freq;
>>          u32 clk_freq = 100000;
>> +       const struct qup_i2c_config *config;
>> +       const struct of_device_id *of_id;
>>
>>          qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>>          if (!qup)
>> @@ -590,8 +850,15 @@ static int qup_i2c_probe(struct platform_device *pdev)
>>
>>          of_property_read_u32(node, "clock-frequency", &clk_freq);
>>
>> -       /* We support frequencies up to FAST Mode (400KHz) */
>> -       if (!clk_freq || clk_freq > 400000) {
>> +       of_id = of_match_node(qup_i2c_dt_match, node);
>> +       if (!of_id)
>> +               return -EINVAL;
>
> this could not happen.
>
  Correct. Will remove it.
>> +
>> +       config = of_id->data;
>> +       qup->use_v2_tags = !!config->tag_ver;
>> +
>> +       /* We support frequencies up to HIGH SPEED Mode (3400KHz) */
>> +       if (!clk_freq || clk_freq > config->max_freq) {
>
> Looks like if controller is v > 1 it supports I2C_QUP_CLK_MAX_FREQ.
> I don't see need for struct qup_i2c_config.
>
Ok, this can removed if compatible check is used to differentiate 
between V1 and rest of the versions.

Regards,
  Sricharan


-- 
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] 43+ messages in thread

* Re: [PATCH 2/6] i2c: qup: Add V2 tags support
@ 2015-03-26  5:44             ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-26  5:44 UTC (permalink / raw)
  To: Ivan T. Ivanov
  Cc: devicetree, linux-arm-msm, agross, linux-kernel, linux-i2c,
	galak, dmaengine, linux-arm-kernel

Hi Ivan,

On 03/25/2015 05:54 PM, Ivan T. Ivanov wrote:
>
> Hi Sricharan,
>
> On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:
>> From: Andy Gross <agross@codeaurora.org>
>>
>> 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 | 342 ++++++++++++++++++++++++++++++++++++++-----
>>
>
> <snip>
>
>> +#define I2C_QUP_CLK_MAX_FREQ           3400000
>
> unused?
>
Ok, will remove this.

>> +
>>   /* Status, Error flags */
>>   #define I2C_STATUS_WR_BUFFER_FULL      BIT(0)
>>   #define I2C_STATUS_BUS_ACTIVE          BIT(8)
>> @@ -99,6 +117,11 @@
>>
>>   #define QUP_READ_LIMIT                 256
>>
>> +struct qup_i2c_config {
>> +       int tag_ver;
>> +       int max_freq;
>> +};
>> +
>
> Do you really need this one. It is referenced only during probe,
> but information contained in is already available by other means.
>
Ok, agree that this can be removed and the information can be fixed
for V1 version and same for the rest of the other versions. That would
need to use compatible check though.
>
>>   struct qup_i2c_dev {
>>          struct device*dev;
>>          void __iomem*base;
>> @@ -112,9 +135,20 @@ struct qup_i2c_dev {
>>          int     in_fifo_sz;
>>          int     out_blk_sz;
>>          int     in_blk_sz;
>> -
>> +       int     blocks;
>> +       u8      *block_tag_len;
>> +       int     *block_data_len;
>
> Maybe these could be organized in struct?
>
ok, will group it.
> <snip>
>
>>
>> +static void qup_i2c_create_tag_v2(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, prev_len = 0;
>> +       int blocks = 0;
>> +       int rem;
>> +       int block_len = 0;
>> +       int data_len;
>> +
>> +       qup->block_pos = 0;
>> +       qup->pos = 0;
>> +       qup->blocks = (msg->len + QUP_READ_LIMIT - 1) / (QUP_READ_LIMIT);
>
> Braces around QUP_READ_LIMIT are not needed.
>
ok.
>> +       rem = msg->len % QUP_READ_LIMIT;
>> +
>> +       /* 2 tag bytes for each block + 2 extra bytes for first block */
>> +       qup->tags = kzalloc((qup->blocks << 1) + 2, GFP_KERNEL);
>
> Don't play tricks with shifts, just use multiplication.
>
why ?
>> +       qup->block_tag_len = kzalloc(qup->blocks, GFP_KERNEL);
>> +       qup->block_data_len = kzalloc(sizeof(int) * qup->blocks, GFP_KERNEL);
>
> Better use sizeof(*qup->block_data_len).
>
ok.
>> +
>> +       while (blocks < qup->blocks) {
>> +               /* 0 is used to specify a READ_LIMIT of 256 bytes */
>> +               data_len = (blocks < (qup->blocks - 1)) ? 0 : rem;
>> +
>> +               /* Send START and ADDR bytes only for the first block */
>> +               if (!blocks) {
>> +                       qup->tags[len++] = QUP_TAG_V2_START;
>> +
>> +                       if (qup->is_hs) {
>> +                               qup->tags[len++] = QUP_TAG_V2_HS;
>> +                               qup->tags[len++] = QUP_TAG_V2_START;
>
> Is this second QUP_TAG_V2_START intentional?
>
  Yes, for HS mode 2 start tags are required.
>> +                       }
>> +
>> +                       qup->tags[len++] = addr & 0xff;
>> +                       if (msg->flags & I2C_M_TEN)
>> +                               qup->tags[len++] = addr >> 8;
>> +               }
>> +
>> +               /* Send _STOP commands for the last block */
>> +               if (blocks == (qup->blocks - 1)) {
>> +                       if (msg->flags & I2C_M_RD)
>> +                               qup->tags[len++] = QUP_TAG_V2_DATARD_STOP;
>> +                       else
>> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR_STOP;
>> +               } else {
>> +                       if (msg->flags & I2C_M_RD)
>> +                               qup->tags[len++] = QUP_TAG_V2_DATARD;
>> +                       else
>> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR;
>> +               }
>> +
>> +               qup->tags[len++] = data_len;
>> +               block_len = len - prev_len;
>> +               prev_len = len;
>> +               qup->block_tag_len[blocks] = block_len;
>> +
>> +               if (!data_len)
>> +                       qup->block_data_len[blocks] = QUP_READ_LIMIT;
>> +               else
>> +                       qup->block_data_len[blocks] = data_len;
>> +
>> +               qup->tags_pos = 0;
>> +               blocks++;
>> +       }
>> +
>> +       qup->tx_tag_len = len;
>> +
>> +       if (msg->flags & I2C_M_RD)
>> +               qup->rx_tag_len = (qup->blocks << 1);
>
> here again.
>
hmm, why not shift ?
>> +       else
>> +               qup->rx_tag_len = 0;
>> +}
>> +
>> +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
>> +                                                               u8 *buf, int last)
>> +{
>
> I think that xfer is too vague in this case, prefer write or send.
>
ok. Will change it to send.
>> +       static u32 val, idx;
>
> static? please fix.
  That was intentional. Using to pack tag and data in to one word across
  two calls. So preserving val, idx across calls.
>
>> +       u32  t, rem, pos = 0;
>> +
>> +       rem = len - pos + idx;
>> +
>> +       while (rem) {
>> +               if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, 0, 4)) {
>> +                       dev_err(qup->dev, "timeout for fifo out full");
>> +                       break;
>> +               }
>> +
>> +               t = (rem >= 4) ? 4 : rem;
>> +
>> +               while (idx < t)
>> +                       val |= buf[pos++] << (idx++ << 3);
>
> here again, multiplication or shift?
>
  I felt shifts should be readable. No ?
>> +
>> +               if (t == 4) {
>> +                       writel(val, qup->base + QUP_OUT_FIFO_BASE);
>> +                       idx = val = 0;
>> +               }
>> +
>> +               rem = len - pos;
>> +       }
>> +
>
> What will happen if they are less than 4 bytes to send?
>
It gets written over in the next call and gets written here itself if it 
is the last block of data.
>> +       if (last) {
>> +               writel(val, qup->base + QUP_OUT_FIFO_BASE);
>> +               idx = val = 0;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>>
>
> <snip>
>
>>
>> -static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>> +static void qup_i2c_issue_read_v1(struct qup_i2c_dev *qup, struct
>> +                                               i2c_msg *msg)
>
> Please, move struct on the same line as i2c_msg.
>
ok.

>>   {
>>          u32 addr, len, val;
>>
>> @@ -395,24 +576,33 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>>          /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
>>          len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
>>
>> -       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
>> +       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START |
>> +                       addr;
>
> Unrelated change?
  hmm. Must have come for adjusting 80 chars. Will remove this here.
>
>>          writel(val, qup->base + QUP_OUT_FIFO_BASE);
>>   }
>>
>>
>
> <snip>
>
>>
>> +static void qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, struct
>> +                                       i2c_msg *msg)
>> +{
>> +       u32 val;
>> +       int idx;
>> +       int pos = 0;
>
>> +       int total = qup->block_data_len[qup->block_pos] + 2;
>
> Could we  have at least comment what is this +2?
>
  Ok. The +2 is for the read tags that are extra bytes read for each
  block. Will add comment for that.

> <snip>
>
>> +
>> +static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg
>> +                                                                       *msg)
>
> Bad indent?
>
  ok. Will fix it.
> <snip>
>
>
>> +static const struct qup_i2c_config configs[] = {
>> +       { 0, 400000, },
>> +       { 1, 3400000, },
>> +};
>> +
>> +static const struct of_device_id qup_i2c_dt_match[] = {
>> +       { .compatible = "qcom,i2c-qup-v1.1.1", .data = &configs[0] },
>> +       { .compatible = "qcom,i2c-qup-v2.1.1", .data = &configs[1] },
>> +       { .compatible = "qcom,i2c-qup-v2.2.1", .data = &configs[1] },
>> +       {}
>> +};
>> +MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
>> +
>>   static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
>>   {
>>          u32 config;
>> @@ -579,6 +837,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
>>          int ret, fs_div, hs_div;
>>          int src_clk_freq;
>>          u32 clk_freq = 100000;
>> +       const struct qup_i2c_config *config;
>> +       const struct of_device_id *of_id;
>>
>>          qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>>          if (!qup)
>> @@ -590,8 +850,15 @@ static int qup_i2c_probe(struct platform_device *pdev)
>>
>>          of_property_read_u32(node, "clock-frequency", &clk_freq);
>>
>> -       /* We support frequencies up to FAST Mode (400KHz) */
>> -       if (!clk_freq || clk_freq > 400000) {
>> +       of_id = of_match_node(qup_i2c_dt_match, node);
>> +       if (!of_id)
>> +               return -EINVAL;
>
> this could not happen.
>
  Correct. Will remove it.
>> +
>> +       config = of_id->data;
>> +       qup->use_v2_tags = !!config->tag_ver;
>> +
>> +       /* We support frequencies up to HIGH SPEED Mode (3400KHz) */
>> +       if (!clk_freq || clk_freq > config->max_freq) {
>
> Looks like if controller is v > 1 it supports I2C_QUP_CLK_MAX_FREQ.
> I don't see need for struct qup_i2c_config.
>
Ok, this can removed if compatible check is used to differentiate 
between V1 and rest of the versions.

Regards,
  Sricharan


-- 
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] 43+ messages in thread

* [PATCH 2/6] i2c: qup: Add V2 tags support
@ 2015-03-26  5:44             ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-26  5:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ivan,

On 03/25/2015 05:54 PM, Ivan T. Ivanov wrote:
>
> Hi Sricharan,
>
> On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:
>> From: Andy Gross <agross@codeaurora.org>
>>
>> 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 | 342 ++++++++++++++++++++++++++++++++++++++-----
>>
>
> <snip>
>
>> +#define I2C_QUP_CLK_MAX_FREQ           3400000
>
> unused?
>
Ok, will remove this.

>> +
>>   /* Status, Error flags */
>>   #define I2C_STATUS_WR_BUFFER_FULL      BIT(0)
>>   #define I2C_STATUS_BUS_ACTIVE          BIT(8)
>> @@ -99,6 +117,11 @@
>>
>>   #define QUP_READ_LIMIT                 256
>>
>> +struct qup_i2c_config {
>> +       int tag_ver;
>> +       int max_freq;
>> +};
>> +
>
> Do you really need this one. It is referenced only during probe,
> but information contained in is already available by other means.
>
Ok, agree that this can be removed and the information can be fixed
for V1 version and same for the rest of the other versions. That would
need to use compatible check though.
>
>>   struct qup_i2c_dev {
>>          struct device*dev;
>>          void __iomem*base;
>> @@ -112,9 +135,20 @@ struct qup_i2c_dev {
>>          int     in_fifo_sz;
>>          int     out_blk_sz;
>>          int     in_blk_sz;
>> -
>> +       int     blocks;
>> +       u8      *block_tag_len;
>> +       int     *block_data_len;
>
> Maybe these could be organized in struct?
>
ok, will group it.
> <snip>
>
>>
>> +static void qup_i2c_create_tag_v2(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, prev_len = 0;
>> +       int blocks = 0;
>> +       int rem;
>> +       int block_len = 0;
>> +       int data_len;
>> +
>> +       qup->block_pos = 0;
>> +       qup->pos = 0;
>> +       qup->blocks = (msg->len + QUP_READ_LIMIT - 1) / (QUP_READ_LIMIT);
>
> Braces around QUP_READ_LIMIT are not needed.
>
ok.
>> +       rem = msg->len % QUP_READ_LIMIT;
>> +
>> +       /* 2 tag bytes for each block + 2 extra bytes for first block */
>> +       qup->tags = kzalloc((qup->blocks << 1) + 2, GFP_KERNEL);
>
> Don't play tricks with shifts, just use multiplication.
>
why ?
>> +       qup->block_tag_len = kzalloc(qup->blocks, GFP_KERNEL);
>> +       qup->block_data_len = kzalloc(sizeof(int) * qup->blocks, GFP_KERNEL);
>
> Better use sizeof(*qup->block_data_len).
>
ok.
>> +
>> +       while (blocks < qup->blocks) {
>> +               /* 0 is used to specify a READ_LIMIT of 256 bytes */
>> +               data_len = (blocks < (qup->blocks - 1)) ? 0 : rem;
>> +
>> +               /* Send START and ADDR bytes only for the first block */
>> +               if (!blocks) {
>> +                       qup->tags[len++] = QUP_TAG_V2_START;
>> +
>> +                       if (qup->is_hs) {
>> +                               qup->tags[len++] = QUP_TAG_V2_HS;
>> +                               qup->tags[len++] = QUP_TAG_V2_START;
>
> Is this second QUP_TAG_V2_START intentional?
>
  Yes, for HS mode 2 start tags are required.
>> +                       }
>> +
>> +                       qup->tags[len++] = addr & 0xff;
>> +                       if (msg->flags & I2C_M_TEN)
>> +                               qup->tags[len++] = addr >> 8;
>> +               }
>> +
>> +               /* Send _STOP commands for the last block */
>> +               if (blocks == (qup->blocks - 1)) {
>> +                       if (msg->flags & I2C_M_RD)
>> +                               qup->tags[len++] = QUP_TAG_V2_DATARD_STOP;
>> +                       else
>> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR_STOP;
>> +               } else {
>> +                       if (msg->flags & I2C_M_RD)
>> +                               qup->tags[len++] = QUP_TAG_V2_DATARD;
>> +                       else
>> +                               qup->tags[len++] = QUP_TAG_V2_DATAWR;
>> +               }
>> +
>> +               qup->tags[len++] = data_len;
>> +               block_len = len - prev_len;
>> +               prev_len = len;
>> +               qup->block_tag_len[blocks] = block_len;
>> +
>> +               if (!data_len)
>> +                       qup->block_data_len[blocks] = QUP_READ_LIMIT;
>> +               else
>> +                       qup->block_data_len[blocks] = data_len;
>> +
>> +               qup->tags_pos = 0;
>> +               blocks++;
>> +       }
>> +
>> +       qup->tx_tag_len = len;
>> +
>> +       if (msg->flags & I2C_M_RD)
>> +               qup->rx_tag_len = (qup->blocks << 1);
>
> here again.
>
hmm, why not shift ?
>> +       else
>> +               qup->rx_tag_len = 0;
>> +}
>> +
>> +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
>> +                                                               u8 *buf, int last)
>> +{
>
> I think that xfer is too vague in this case, prefer write or send.
>
ok. Will change it to send.
>> +       static u32 val, idx;
>
> static? please fix.
  That was intentional. Using to pack tag and data in to one word across
  two calls. So preserving val, idx across calls.
>
>> +       u32  t, rem, pos = 0;
>> +
>> +       rem = len - pos + idx;
>> +
>> +       while (rem) {
>> +               if (qup_i2c_wait_ready(qup, QUP_OUT_FULL, 0, 4)) {
>> +                       dev_err(qup->dev, "timeout for fifo out full");
>> +                       break;
>> +               }
>> +
>> +               t = (rem >= 4) ? 4 : rem;
>> +
>> +               while (idx < t)
>> +                       val |= buf[pos++] << (idx++ << 3);
>
> here again, multiplication or shift?
>
  I felt shifts should be readable. No ?
>> +
>> +               if (t == 4) {
>> +                       writel(val, qup->base + QUP_OUT_FIFO_BASE);
>> +                       idx = val = 0;
>> +               }
>> +
>> +               rem = len - pos;
>> +       }
>> +
>
> What will happen if they are less than 4 bytes to send?
>
It gets written over in the next call and gets written here itself if it 
is the last block of data.
>> +       if (last) {
>> +               writel(val, qup->base + QUP_OUT_FIFO_BASE);
>> +               idx = val = 0;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>>
>
> <snip>
>
>>
>> -static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>> +static void qup_i2c_issue_read_v1(struct qup_i2c_dev *qup, struct
>> +                                               i2c_msg *msg)
>
> Please, move struct on the same line as i2c_msg.
>
ok.

>>   {
>>          u32 addr, len, val;
>>
>> @@ -395,24 +576,33 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
>>          /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
>>          len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
>>
>> -       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
>> +       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START |
>> +                       addr;
>
> Unrelated change?
  hmm. Must have come for adjusting 80 chars. Will remove this here.
>
>>          writel(val, qup->base + QUP_OUT_FIFO_BASE);
>>   }
>>
>>
>
> <snip>
>
>>
>> +static void qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, struct
>> +                                       i2c_msg *msg)
>> +{
>> +       u32 val;
>> +       int idx;
>> +       int pos = 0;
>
>> +       int total = qup->block_data_len[qup->block_pos] + 2;
>
> Could we  have at least comment what is this +2?
>
  Ok. The +2 is for the read tags that are extra bytes read for each
  block. Will add comment for that.

> <snip>
>
>> +
>> +static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg
>> +                                                                       *msg)
>
> Bad indent?
>
  ok. Will fix it.
> <snip>
>
>
>> +static const struct qup_i2c_config configs[] = {
>> +       { 0, 400000, },
>> +       { 1, 3400000, },
>> +};
>> +
>> +static const struct of_device_id qup_i2c_dt_match[] = {
>> +       { .compatible = "qcom,i2c-qup-v1.1.1", .data = &configs[0] },
>> +       { .compatible = "qcom,i2c-qup-v2.1.1", .data = &configs[1] },
>> +       { .compatible = "qcom,i2c-qup-v2.2.1", .data = &configs[1] },
>> +       {}
>> +};
>> +MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
>> +
>>   static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
>>   {
>>          u32 config;
>> @@ -579,6 +837,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
>>          int ret, fs_div, hs_div;
>>          int src_clk_freq;
>>          u32 clk_freq = 100000;
>> +       const struct qup_i2c_config *config;
>> +       const struct of_device_id *of_id;
>>
>>          qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>>          if (!qup)
>> @@ -590,8 +850,15 @@ static int qup_i2c_probe(struct platform_device *pdev)
>>
>>          of_property_read_u32(node, "clock-frequency", &clk_freq);
>>
>> -       /* We support frequencies up to FAST Mode (400KHz) */
>> -       if (!clk_freq || clk_freq > 400000) {
>> +       of_id = of_match_node(qup_i2c_dt_match, node);
>> +       if (!of_id)
>> +               return -EINVAL;
>
> this could not happen.
>
  Correct. Will remove it.
>> +
>> +       config = of_id->data;
>> +       qup->use_v2_tags = !!config->tag_ver;
>> +
>> +       /* We support frequencies up to HIGH SPEED Mode (3400KHz) */
>> +       if (!clk_freq || clk_freq > config->max_freq) {
>
> Looks like if controller is v > 1 it supports I2C_QUP_CLK_MAX_FREQ.
> I don't see need for struct qup_i2c_config.
>
Ok, this can removed if compatible check is used to differentiate 
between V1 and rest of the versions.

Regards,
  Sricharan


-- 
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] 43+ messages in thread

* Re: [PATCH 3/6] i2c: qup: Add bam dma capabilities
  2015-03-25 13:10         ` Ivan T. Ivanov
@ 2015-03-26  6:08           ` Sricharan R
  -1 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-26  6:08 UTC (permalink / raw)
  To: Ivan T. Ivanov
  Cc: devicetree, linux-arm-msm, agross, linux-kernel, linux-i2c,
	galak, dmaengine, linux-arm-kernel

Hi Ivan,

On 03/25/2015 06:40 PM, Ivan T. Ivanov wrote:
>
> Hi Sricharan,
>
> On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:
>
>
>>   #define QUP_I2C_MASTER_GEN     0x408
>> +#define QUP_I2C_MASTER_CONFIG  0x408
>>
>
> Unused.
>
Ok, will remove it
>>   #define QUP_READ_LIMIT                 256
>> +#define MX_TX_RX_LEN                   SZ_64K
>> +#define MX_BLOCKS                      (MX_TX_RX_LEN / QUP_READ_LIMIT)
>> +
>> +#define TOUT_MAX                       300 /* Max timeout for 32k tx/tx */
>>
>
> seconds, muliseconds?
>
  Ok. Will add milliseconds.
>>   struct qup_i2c_config {
>>          int tag_ver;
>>          int max_freq;
>>   };
>>
>> +struct tag {
>
> Please use consistent naming convention.
>
ok.
>> +       u8 *start;
>> +       dma_addr_t addr;
>> +};
>> +
>>   struct qup_i2c_dev {
>>          struct device*dev;
>>          void __iomem*base;
>> @@ -157,9 +181,35 @@ struct qup_i2c_dev {
>>          /* QUP core errors */
>>          u32     qup_err;
>>
>> +       /* dma parameters */
>> +       bool    is_dma;
>> +       struct  dma_pool *dpool;
>> +       struct  tag start_tag;
>> +       struct  tag scratch_tag;
>> +       struct  tag footer_tag;
>> +       struct  dma_chan *dma_tx;
>> +       struct  dma_chan *dma_rx;
>> +       struct  scatterlist *sg_tx;
>> +       struct  scatterlist *sg_rx;
>> +       dma_addr_tsg_tx_phys;
>> +       dma_addr_tsg_rx_phys;
>
> Maybe these could be organized in structure per direction.
>
ok, will group it.
>> +
>>          struct completionxfer;
>>   };
>>
>> +struct i2c_bam_xfer {
>
> Unused.
>
  Right. Will remove the whole thing. Thanks.
>> +       struct qup_i2c_dev *qup;
>> +       u32 start_len;
>> +
>> +       u32 rx_nents;
>> +       u32 tx_nents;
>> +
>> +       struct dma_async_tx_descriptor *tx_desc;
>> +       dma_cookie_t tx_cookie;
>> +       struct dma_async_tx_descriptor *rx_desc;
>> +       dma_cookie_t rx_cookie;
>
> structure per direction.
>
>> +};
>> +
>>
  Infact should be removed.
>
>> +static void bam_i2c_callback(void *data)
>> +{
>
> Please use consistent naming, here and bellow.
>
ok, will change.
>> +       struct qup_i2c_dev *qup = data;
>> +
>> +       complete(&qup->xfer);
>> +}
>> +
>> +static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last,
>> +                       int blen)
>> +{
>> +       u8 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
>> +       u8 op;
>> +       int len = 0;
>> +
>> +       /* always issue stop for each read block */
>> +       if (last) {
>> +               if (msg->flags & I2C_M_RD)
>> +                       op = QUP_TAG_V2_DATARD_STOP;
>> +               else
>> +                       op = QUP_TAG_V2_DATAWR_STOP;
>> +       } else {
>> +               if (msg->flags & I2C_M_RD)
>> +                       op = QUP_TAG_V2_DATARD;
>> +               else
>> +                       op = QUP_TAG_V2_DATAWR;
>> +       }
>> +
>> +       if (msg->flags & I2C_M_TEN) {
>> +               len += 5;
>> +               tag[0] = QUP_TAG_V2_START;
>> +               tag[1] = addr;
>> +               tag[2] = op;
>> +               tag[3] = blen;
>> +
>> +               if (msg->flags & I2C_M_RD && last) {
>> +                       len += 2;
>> +                       tag[4] = QUP_BAM_INPUT_EOT;
>> +                       tag[5] = QUP_BAM_FLUSH_STOP;
>> +               }
>> +       } else {
>> +               if (first) {
>> +                       tag[len++] = QUP_TAG_V2_START;
>> +                       tag[len++] = addr;
>> +               }
>> +
>> +               tag[len++] = op;
>> +               tag[len++] = blen;
>> +
>> +               if (msg->flags & I2C_M_RD & last) {
>> +                       tag[len++] = QUP_BAM_INPUT_EOT;
>> +                       tag[len++] = QUP_BAM_FLUSH_STOP;
>> +               }
>> +       }
>> +
>> +       return len;
>> +}
>
> Maybe could be split to 2 functions?
>
hmm, ok will split couple of small ones.
>> -static const struct i2c_algorithm qup_i2c_algo = {
>> +static struct i2c_algorithm qup_i2c_algo = {
>
> Why?
>
  oops. Should not have been changed. Will fix.
>>          .master_xfer= qup_i2c_xfer,
>>          .functionality= qup_i2c_func,
>>   };
>> @@ -839,6 +1136,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>>          u32 clk_freq = 100000;
>>          const struct qup_i2c_config *config;
>>          const struct of_device_id *of_id;
>> +       int blocks;
>>
>>          qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>>          if (!qup)
>> @@ -875,6 +1173,53 @@ static int qup_i2c_probe(struct platform_device *pdev)
>>                  return qup->irq;
>>          }
>>
>> +       if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v2.1.1") ||
>> +               of_device_is_compatible(pdev->dev.of_node,
>> +                       "qcom,i2c-qup-v2.2.1")) {
>
> Logic will be simpler if you check just for version 1 of the controller.
  yes. Will fix it.
>
>> +               qup->dma_rx = dma_request_slave_channel(&pdev->dev, "bam-rx");
>> +
>
> Please use dma_request_slave_channel_reason.
>
> As Andy noted, please use just "rx", "tx"
>
ok. will change it.
>> +               if (!qup->dma_rx)
>> +                       return -EPROBE_DEFER;
>
> Don't mask other errors, here and bellow. DMA support should be optional.
>
  Ok, will fix here.
>>                  dev_err(qup->dev, "Could not get core clock\n");
>> @@ -989,6 +1334,14 @@ static int qup_i2c_remove(struct platform_device *pdev)
>>   {
>>          struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
>>
>> +       dma_pool_free(qup->dpool, qup->start_tag.start,
>> +                                                               qup->start_tag.addr);
>> +       dma_pool_free(qup->dpool, qup->scratch_tag.start,
>> +                                                               qup->scratch_tag.addr);
>> +       dma_pool_free(qup->dpool, qup->footer_tag.start,
>> +                                                               qup->footer_tag.addr);
>> +       dma_pool_destroy(qup->dpool);
>
> Only if is_dma, right?
>
Right. Will add the check.
> DMA mapping code omitted from review. I don't understand it well enough, sorry.
>
   Ok, thanks for reviewing the rest.

Regards,
  Sricharan

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] 43+ messages in thread

* [PATCH 3/6] i2c: qup: Add bam dma capabilities
@ 2015-03-26  6:08           ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-26  6:08 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ivan,

On 03/25/2015 06:40 PM, Ivan T. Ivanov wrote:
>
> Hi Sricharan,
>
> On Fri, 2015-03-13 at 23:19 +0530, Sricharan R wrote:
>
>
>>   #define QUP_I2C_MASTER_GEN     0x408
>> +#define QUP_I2C_MASTER_CONFIG  0x408
>>
>
> Unused.
>
Ok, will remove it
>>   #define QUP_READ_LIMIT                 256
>> +#define MX_TX_RX_LEN                   SZ_64K
>> +#define MX_BLOCKS                      (MX_TX_RX_LEN / QUP_READ_LIMIT)
>> +
>> +#define TOUT_MAX                       300 /* Max timeout for 32k tx/tx */
>>
>
> seconds, muliseconds?
>
  Ok. Will add milliseconds.
>>   struct qup_i2c_config {
>>          int tag_ver;
>>          int max_freq;
>>   };
>>
>> +struct tag {
>
> Please use consistent naming convention.
>
ok.
>> +       u8 *start;
>> +       dma_addr_t addr;
>> +};
>> +
>>   struct qup_i2c_dev {
>>          struct device*dev;
>>          void __iomem*base;
>> @@ -157,9 +181,35 @@ struct qup_i2c_dev {
>>          /* QUP core errors */
>>          u32     qup_err;
>>
>> +       /* dma parameters */
>> +       bool    is_dma;
>> +       struct  dma_pool *dpool;
>> +       struct  tag start_tag;
>> +       struct  tag scratch_tag;
>> +       struct  tag footer_tag;
>> +       struct  dma_chan *dma_tx;
>> +       struct  dma_chan *dma_rx;
>> +       struct  scatterlist *sg_tx;
>> +       struct  scatterlist *sg_rx;
>> +       dma_addr_tsg_tx_phys;
>> +       dma_addr_tsg_rx_phys;
>
> Maybe these could be organized in structure per direction.
>
ok, will group it.
>> +
>>          struct completionxfer;
>>   };
>>
>> +struct i2c_bam_xfer {
>
> Unused.
>
  Right. Will remove the whole thing. Thanks.
>> +       struct qup_i2c_dev *qup;
>> +       u32 start_len;
>> +
>> +       u32 rx_nents;
>> +       u32 tx_nents;
>> +
>> +       struct dma_async_tx_descriptor *tx_desc;
>> +       dma_cookie_t tx_cookie;
>> +       struct dma_async_tx_descriptor *rx_desc;
>> +       dma_cookie_t rx_cookie;
>
> structure per direction.
>
>> +};
>> +
>>
  Infact should be removed.
>
>> +static void bam_i2c_callback(void *data)
>> +{
>
> Please use consistent naming, here and bellow.
>
ok, will change.
>> +       struct qup_i2c_dev *qup = data;
>> +
>> +       complete(&qup->xfer);
>> +}
>> +
>> +static int get_start_tag(u8 *tag, struct i2c_msg *msg, int first, int last,
>> +                       int blen)
>> +{
>> +       u8 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
>> +       u8 op;
>> +       int len = 0;
>> +
>> +       /* always issue stop for each read block */
>> +       if (last) {
>> +               if (msg->flags & I2C_M_RD)
>> +                       op = QUP_TAG_V2_DATARD_STOP;
>> +               else
>> +                       op = QUP_TAG_V2_DATAWR_STOP;
>> +       } else {
>> +               if (msg->flags & I2C_M_RD)
>> +                       op = QUP_TAG_V2_DATARD;
>> +               else
>> +                       op = QUP_TAG_V2_DATAWR;
>> +       }
>> +
>> +       if (msg->flags & I2C_M_TEN) {
>> +               len += 5;
>> +               tag[0] = QUP_TAG_V2_START;
>> +               tag[1] = addr;
>> +               tag[2] = op;
>> +               tag[3] = blen;
>> +
>> +               if (msg->flags & I2C_M_RD && last) {
>> +                       len += 2;
>> +                       tag[4] = QUP_BAM_INPUT_EOT;
>> +                       tag[5] = QUP_BAM_FLUSH_STOP;
>> +               }
>> +       } else {
>> +               if (first) {
>> +                       tag[len++] = QUP_TAG_V2_START;
>> +                       tag[len++] = addr;
>> +               }
>> +
>> +               tag[len++] = op;
>> +               tag[len++] = blen;
>> +
>> +               if (msg->flags & I2C_M_RD & last) {
>> +                       tag[len++] = QUP_BAM_INPUT_EOT;
>> +                       tag[len++] = QUP_BAM_FLUSH_STOP;
>> +               }
>> +       }
>> +
>> +       return len;
>> +}
>
> Maybe could be split to 2 functions?
>
hmm, ok will split couple of small ones.
>> -static const struct i2c_algorithm qup_i2c_algo = {
>> +static struct i2c_algorithm qup_i2c_algo = {
>
> Why?
>
  oops. Should not have been changed. Will fix.
>>          .master_xfer= qup_i2c_xfer,
>>          .functionality= qup_i2c_func,
>>   };
>> @@ -839,6 +1136,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
>>          u32 clk_freq = 100000;
>>          const struct qup_i2c_config *config;
>>          const struct of_device_id *of_id;
>> +       int blocks;
>>
>>          qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
>>          if (!qup)
>> @@ -875,6 +1173,53 @@ static int qup_i2c_probe(struct platform_device *pdev)
>>                  return qup->irq;
>>          }
>>
>> +       if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v2.1.1") ||
>> +               of_device_is_compatible(pdev->dev.of_node,
>> +                       "qcom,i2c-qup-v2.2.1")) {
>
> Logic will be simpler if you check just for version 1 of the controller.
  yes. Will fix it.
>
>> +               qup->dma_rx = dma_request_slave_channel(&pdev->dev, "bam-rx");
>> +
>
> Please use dma_request_slave_channel_reason.
>
> As Andy noted, please use just "rx", "tx"
>
ok. will change it.
>> +               if (!qup->dma_rx)
>> +                       return -EPROBE_DEFER;
>
> Don't mask other errors, here and bellow. DMA support should be optional.
>
  Ok, will fix here.
>>                  dev_err(qup->dev, "Could not get core clock\n");
>> @@ -989,6 +1334,14 @@ static int qup_i2c_remove(struct platform_device *pdev)
>>   {
>>          struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
>>
>> +       dma_pool_free(qup->dpool, qup->start_tag.start,
>> +                                                               qup->start_tag.addr);
>> +       dma_pool_free(qup->dpool, qup->scratch_tag.start,
>> +                                                               qup->scratch_tag.addr);
>> +       dma_pool_free(qup->dpool, qup->footer_tag.start,
>> +                                                               qup->footer_tag.addr);
>> +       dma_pool_destroy(qup->dpool);
>
> Only if is_dma, right?
>
Right. Will add the check.
> DMA mapping code omitted from review. I don't understand it well enough, sorry.
>
   Ok, thanks for reviewing the rest.

Regards,
  Sricharan

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] 43+ messages in thread

* Re: [PATCH 2/6] i2c: qup: Add V2 tags support
  2015-03-26  5:44             ` Sricharan R
  (?)
@ 2015-03-26  7:31                 ` Ivan T. Ivanov
  -1 siblings, 0 replies; 43+ messages in thread
From: Ivan T. Ivanov @ 2015-03-26  7:31 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	agross-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	dmaengine-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi Sricharan,

On Thu, 2015-03-26 at 11:14 +0530, Sricharan R wrote:
> 
> > > +       if (msg->flags & I2C_M_RD)
> > > +               qup->rx_tag_len = (qup->blocks << 1);
> > 
> > here again.
> > 
> hmm, why not shift ?

Because it makes reading code harder and because compiler
 is smart enough to choose appropriate instruction for
underling CPU architecture.

> > > +       else
> > > +               qup->rx_tag_len = 0;
> > > +}
> > > +
> > > +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
> > > +                                                               u8 *buf, int last)
> > > +{
> > 
> > I think that xfer is too vague in this case, prefer write or send.
> > 
> ok. Will change it to send.
> > > +       static u32 val, idx;
> > 
> > static? please fix.
>   That was intentional. Using to pack tag and data in to one word across
>   two calls. So preserving val, idx across calls.

Sorry this is no go! Reorganize the code, please.

Regards,
Ivan

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

* Re: [PATCH 2/6] i2c: qup: Add V2 tags support
@ 2015-03-26  7:31                 ` Ivan T. Ivanov
  0 siblings, 0 replies; 43+ messages in thread
From: Ivan T. Ivanov @ 2015-03-26  7:31 UTC (permalink / raw)
  To: Sricharan R
  Cc: devicetree, linux-arm-msm, agross, linux-kernel, linux-i2c,
	galak, dmaengine, linux-arm-kernel

Hi Sricharan,

On Thu, 2015-03-26 at 11:14 +0530, Sricharan R wrote:
> 
> > > +       if (msg->flags & I2C_M_RD)
> > > +               qup->rx_tag_len = (qup->blocks << 1);
> > 
> > here again.
> > 
> hmm, why not shift ?

Because it makes reading code harder and because compiler
 is smart enough to choose appropriate instruction for
underling CPU architecture.

> > > +       else
> > > +               qup->rx_tag_len = 0;
> > > +}
> > > +
> > > +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
> > > +                                                               u8 *buf, int last)
> > > +{
> > 
> > I think that xfer is too vague in this case, prefer write or send.
> > 
> ok. Will change it to send.
> > > +       static u32 val, idx;
> > 
> > static? please fix.
>   That was intentional. Using to pack tag and data in to one word across
>   two calls. So preserving val, idx across calls.

Sorry this is no go! Reorganize the code, please.

Regards,
Ivan

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

* [PATCH 2/6] i2c: qup: Add V2 tags support
@ 2015-03-26  7:31                 ` Ivan T. Ivanov
  0 siblings, 0 replies; 43+ messages in thread
From: Ivan T. Ivanov @ 2015-03-26  7:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Sricharan,

On Thu, 2015-03-26 at 11:14 +0530, Sricharan R wrote:
> 
> > > +       if (msg->flags & I2C_M_RD)
> > > +               qup->rx_tag_len = (qup->blocks << 1);
> > 
> > here again.
> > 
> hmm, why not shift ?

Because it makes reading code harder and because compiler
 is smart enough to choose appropriate instruction for
underling CPU architecture.

> > > +       else
> > > +               qup->rx_tag_len = 0;
> > > +}
> > > +
> > > +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
> > > +                                                               u8 *buf, int last)
> > > +{
> > 
> > I think that xfer is too vague in this case, prefer write or send.
> > 
> ok. Will change it to send.
> > > +       static u32 val, idx;
> > 
> > static? please fix.
>   That was intentional. Using to pack tag and data in to one word across
>   two calls. So preserving val, idx across calls.

Sorry this is no go! Reorganize the code, please.

Regards,
Ivan

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

* Re: [PATCH 2/6] i2c: qup: Add V2 tags support
  2015-03-26  7:31                 ` Ivan T. Ivanov
@ 2015-03-26  8:36                   ` Sricharan R
  -1 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-26  8:36 UTC (permalink / raw)
  To: Ivan T. Ivanov
  Cc: devicetree, linux-arm-msm, agross, linux-kernel, linux-i2c,
	galak, dmaengine, linux-arm-kernel


Hi Ivan,

On 03/26/2015 01:01 PM, Ivan T. Ivanov wrote:
> Hi Sricharan,
>
> On Thu, 2015-03-26 at 11:14 +0530, Sricharan R wrote:
>>
>>>> +       if (msg->flags & I2C_M_RD)
>>>> +               qup->rx_tag_len = (qup->blocks << 1);
>>>
>>> here again.
>>>
>> hmm, why not shift ?
>
> Because it makes reading code harder and because compiler
>   is smart enough to choose appropriate instruction for
> underling CPU architecture.
>
ok.
>>>> +       else
>>>> +               qup->rx_tag_len = 0;
>>>> +}
>>>> +
>>>> +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
>>>> +                                                               u8 *buf, int last)
>>>> +{
>>>
>>> I think that xfer is too vague in this case, prefer write or send.
>>>
>> ok. Will change it to send.
>>>> +       static u32 val, idx;
>>>
>>> static? please fix.
>>    That was intentional. Using to pack tag and data in to one word across
>>    two calls. So preserving val, idx across calls.
>
> Sorry this is no go! Reorganize the code, please.
>
Ok, will change this function.

Regards,
  Sricharan
-- 
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] 43+ messages in thread

* [PATCH 2/6] i2c: qup: Add V2 tags support
@ 2015-03-26  8:36                   ` Sricharan R
  0 siblings, 0 replies; 43+ messages in thread
From: Sricharan R @ 2015-03-26  8:36 UTC (permalink / raw)
  To: linux-arm-kernel


Hi Ivan,

On 03/26/2015 01:01 PM, Ivan T. Ivanov wrote:
> Hi Sricharan,
>
> On Thu, 2015-03-26 at 11:14 +0530, Sricharan R wrote:
>>
>>>> +       if (msg->flags & I2C_M_RD)
>>>> +               qup->rx_tag_len = (qup->blocks << 1);
>>>
>>> here again.
>>>
>> hmm, why not shift ?
>
> Because it makes reading code harder and because compiler
>   is smart enough to choose appropriate instruction for
> underling CPU architecture.
>
ok.
>>>> +       else
>>>> +               qup->rx_tag_len = 0;
>>>> +}
>>>> +
>>>> +static u32 qup_i2c_xfer_data(struct qup_i2c_dev *qup, int len,
>>>> +                                                               u8 *buf, int last)
>>>> +{
>>>
>>> I think that xfer is too vague in this case, prefer write or send.
>>>
>> ok. Will change it to send.
>>>> +       static u32 val, idx;
>>>
>>> static? please fix.
>>    That was intentional. Using to pack tag and data in to one word across
>>    two calls. So preserving val, idx across calls.
>
> Sorry this is no go! Reorganize the code, please.
>
Ok, will change this function.

Regards,
  Sricharan
-- 
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] 43+ messages in thread

end of thread, other threads:[~2015-03-26  8:36 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-13 17:49 [PATCH 0/6] i2c: qup: Add support for v2 tags and bam dma Sricharan R
2015-03-13 17:49 ` Sricharan R
2015-03-13 17:49 ` Sricharan R
2015-03-13 17:49 ` [PATCH 1/6] i2c: qup: Change qup_wait_writeready function to use for all timeouts Sricharan R
2015-03-13 17:49   ` Sricharan R
     [not found] ` <1426268992-19298-1-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-03-13 17:49   ` [PATCH 2/6] i2c: qup: Add V2 tags support Sricharan R
2015-03-13 17:49     ` Sricharan R
2015-03-13 17:49     ` Sricharan R
     [not found]     ` <1426268992-19298-3-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-03-25 12:24       ` Ivan T. Ivanov
2015-03-25 12:24         ` Ivan T. Ivanov
2015-03-25 12:24         ` Ivan T. Ivanov
     [not found]         ` <1427286263.25053.18.camel-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org>
2015-03-26  5:44           ` Sricharan R
2015-03-26  5:44             ` Sricharan R
2015-03-26  5:44             ` Sricharan R
     [not found]             ` <55139CD4.5040100-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-03-26  7:31               ` Ivan T. Ivanov
2015-03-26  7:31                 ` Ivan T. Ivanov
2015-03-26  7:31                 ` Ivan T. Ivanov
2015-03-26  8:36                 ` Sricharan R
2015-03-26  8:36                   ` Sricharan R
2015-03-13 17:49   ` [PATCH 3/6] i2c: qup: Add bam dma capabilities Sricharan R
2015-03-13 17:49     ` Sricharan R
2015-03-13 17:49     ` Sricharan R
     [not found]     ` <1426268992-19298-4-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-03-25 13:10       ` Ivan T. Ivanov
2015-03-25 13:10         ` Ivan T. Ivanov
2015-03-25 13:10         ` Ivan T. Ivanov
2015-03-26  6:08         ` Sricharan R
2015-03-26  6:08           ` Sricharan R
2015-03-13 17:49 ` [PATCH 4/6] i2c: qup: Transfer every i2c_msg in i2c_msgs without stop Sricharan R
2015-03-13 17:49   ` Sricharan R
2015-03-13 17:49 ` [PATCH 5/6] dts: msm8974: Add blsp2_bam dma node Sricharan R
2015-03-13 17:49   ` Sricharan R
2015-03-17 12:48   ` Stanimir Varbanov
2015-03-17 12:48     ` Stanimir Varbanov
     [not found]     ` <550822A7.1010209-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org>
2015-03-17 13:10       ` sricharan-sgV2jX0FEOL9JmXXK+q4OQ
2015-03-17 13:10         ` sricharan at codeaurora.org
2015-03-17 13:10         ` sricharan
2015-03-13 17:49 ` [PATCH 6/6] dts: msm8974: Add dma channels for blsp2_i2c1 node Sricharan R
2015-03-13 17:49   ` Sricharan R
2015-03-13 19:54   ` Andy Gross
2015-03-13 19:54     ` Andy Gross
     [not found]     ` <20150313195425.GA16977-zC7DfRvBq/JWk0Htik3J/w@public.gmane.org>
2015-03-16  9:55       ` sricharan-sgV2jX0FEOL9JmXXK+q4OQ
2015-03-16  9:55         ` sricharan at codeaurora.org
2015-03-16  9:55         ` sricharan

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.