All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-09 11:45 ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-09 11:45 UTC (permalink / raw)
  To: linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: Marek Vasut, Detlev Zundel, Dong Aisheng, Fabio Estevam,
	Linux ARM kernel, Sascha Hauer, Shawn Guo, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

This patch configures the I2C bus timing registers according
to information passed via DT. Currently, 100kHz and 400kHz
modes are supported.

Signed-off-by: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org>
Cc: Detlev Zundel <dzu-ynQEQJNshbs@public.gmane.org>
CC: Dong Aisheng <b29396-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
CC: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Cc: Linux ARM kernel <linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>
Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
CC: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
CC: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Stefano Babic <sbabic-ynQEQJNshbs@public.gmane.org>
CC: Uwe Kleine-König <u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Cc: Wolfgang Denk <wd-ynQEQJNshbs@public.gmane.org>
Cc: Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 Documentation/devicetree/bindings/i2c/i2c-mxs.txt |    1 +
 arch/arm/boot/dts/imx28.dtsi                      |    2 +
 drivers/i2c/busses/i2c-mxs.c                      |   55 +++++++++++++++++++++
 3 files changed, 58 insertions(+)

V2: Use clock-frequency instead
V3: Document that 24MHz clock are the base for i2c speed settings

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
index 1bfc02d..d2bf750 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
@@ -4,6 +4,7 @@ Required properties:
 - compatible: Should be "fsl,<chip>-i2c"
 - reg: Should contain registers location and length
 - interrupts: Should contain ERROR and DMA interrupts
+- clock-frequency: desired I2C bus clock frequency in Hz.
 
 Examples:
 
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index a89da5a..714e63c 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -398,6 +398,7 @@
 				compatible = "fsl,imx28-i2c";
 				reg = <0x80058000 2000>;
 				interrupts = <111 68>;
+				clock-frequency = <400000>;
 				status = "disabled";
 			};
 
@@ -407,6 +408,7 @@
 				compatible = "fsl,imx28-i2c";
 				reg = <0x8005a000 2000>;
 				interrupts = <110 69>;
+				clock-frequency = <400000>;
 				status = "disabled";
 			};
 
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 04eb441..b7d423e 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -46,6 +46,10 @@
 #define MXS_I2C_CTRL0_DIRECTION			0x00010000
 #define MXS_I2C_CTRL0_XFER_COUNT(v)		((v) & 0x0000FFFF)
 
+#define MXS_I2C_TIMING0		(0x10)
+#define MXS_I2C_TIMING1		(0x20)
+#define MXS_I2C_TIMING2		(0x30)
+
 #define MXS_I2C_CTRL1		(0x40)
 #define MXS_I2C_CTRL1_SET	(0x44)
 #define MXS_I2C_CTRL1_CLR	(0x48)
@@ -97,6 +101,25 @@
 #define MXS_CMD_I2C_READ	(MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
 				 MXS_I2C_CTRL0_MASTER_MODE)
 
+struct mxs_i2c_speed_config {
+	uint32_t	timing0;
+	uint32_t	timing1;
+	uint32_t	timing2;
+};
+
+/* Timing values for the default 24MHz clock supplied into the i2c block. */
+const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
+	.timing0	= 0x00780030,
+	.timing1	= 0x00800030,
+	.timing2	= 0x0015000d,
+};
+
+const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
+	.timing0	= 0x000f0007,
+	.timing1	= 0x001f000f,
+	.timing2	= 0x0015000d,
+};
+
 /**
  * struct mxs_i2c_dev - per device, private MXS-I2C data
  *
@@ -112,11 +135,17 @@ struct mxs_i2c_dev {
 	struct completion cmd_complete;
 	u32 cmd_err;
 	struct i2c_adapter adapter;
+	const struct mxs_i2c_speed_config *speed;
 };
 
 static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
 {
 	stmp_reset_block(i2c->regs);
+
+	writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0);
+	writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1);
+	writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
+
 	writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
 	writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
 			i2c->regs + MXS_I2C_QUEUECTRL_SET);
@@ -319,6 +348,27 @@ static const struct i2c_algorithm mxs_i2c_algo = {
 	.functionality = mxs_i2c_func,
 };
 
+static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
+{
+	uint32_t speed;
+	struct device *dev = i2c->dev;
+	struct device_node *node = dev->of_node;
+
+	if (!node)
+		return -EINVAL;
+
+	i2c->speed = &mxs_i2c_95kHz_config;
+	ret = of_property_read_u32(node, "clock-frequency", &speed);
+	if (ret)
+		dev_warn(dev, "No I2C speed selected, using 100kHz\n");
+	else if (speed == 400000)
+		i2c->speed = &mxs_i2c_400kHz_config;
+	else if (speed != 100000)
+		dev_warn(dev, "Invalid I2C speed selected, using 100kHz\n");
+
+	return 0;
+}
+
 static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -358,6 +408,11 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 		return err;
 
 	i2c->dev = dev;
+
+	err = mxs_i2c_get_ofdata(i2c);
+	if (err)
+		return err;
+
 	platform_set_drvdata(pdev, i2c);
 
 	/* Do reset to enforce correct startup after pinmuxing */
-- 
1.7.10

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-09 11:45 ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-09 11:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patch configures the I2C bus timing registers according
to information passed via DT. Currently, 100kHz and 400kHz
modes are supported.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Detlev Zundel <dzu@denx.de>
CC: Dong Aisheng <b29396@freescale.com>
CC: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Linux ARM kernel <linux-arm-kernel@lists.infradead.org>
Cc: linux-i2c at vger.kernel.org
CC: Sascha Hauer <s.hauer@pengutronix.de>
CC: Shawn Guo <shawn.guo@linaro.org>
Cc: Stefano Babic <sbabic@denx.de>
CC: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
Cc: Wolfgang Denk <wd@denx.de>
Cc: Wolfram Sang <w.sang@pengutronix.de>
---
 Documentation/devicetree/bindings/i2c/i2c-mxs.txt |    1 +
 arch/arm/boot/dts/imx28.dtsi                      |    2 +
 drivers/i2c/busses/i2c-mxs.c                      |   55 +++++++++++++++++++++
 3 files changed, 58 insertions(+)

V2: Use clock-frequency instead
V3: Document that 24MHz clock are the base for i2c speed settings

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
index 1bfc02d..d2bf750 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
@@ -4,6 +4,7 @@ Required properties:
 - compatible: Should be "fsl,<chip>-i2c"
 - reg: Should contain registers location and length
 - interrupts: Should contain ERROR and DMA interrupts
+- clock-frequency: desired I2C bus clock frequency in Hz.
 
 Examples:
 
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index a89da5a..714e63c 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -398,6 +398,7 @@
 				compatible = "fsl,imx28-i2c";
 				reg = <0x80058000 2000>;
 				interrupts = <111 68>;
+				clock-frequency = <400000>;
 				status = "disabled";
 			};
 
@@ -407,6 +408,7 @@
 				compatible = "fsl,imx28-i2c";
 				reg = <0x8005a000 2000>;
 				interrupts = <110 69>;
+				clock-frequency = <400000>;
 				status = "disabled";
 			};
 
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 04eb441..b7d423e 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -46,6 +46,10 @@
 #define MXS_I2C_CTRL0_DIRECTION			0x00010000
 #define MXS_I2C_CTRL0_XFER_COUNT(v)		((v) & 0x0000FFFF)
 
+#define MXS_I2C_TIMING0		(0x10)
+#define MXS_I2C_TIMING1		(0x20)
+#define MXS_I2C_TIMING2		(0x30)
+
 #define MXS_I2C_CTRL1		(0x40)
 #define MXS_I2C_CTRL1_SET	(0x44)
 #define MXS_I2C_CTRL1_CLR	(0x48)
@@ -97,6 +101,25 @@
 #define MXS_CMD_I2C_READ	(MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
 				 MXS_I2C_CTRL0_MASTER_MODE)
 
+struct mxs_i2c_speed_config {
+	uint32_t	timing0;
+	uint32_t	timing1;
+	uint32_t	timing2;
+};
+
+/* Timing values for the default 24MHz clock supplied into the i2c block. */
+const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
+	.timing0	= 0x00780030,
+	.timing1	= 0x00800030,
+	.timing2	= 0x0015000d,
+};
+
+const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
+	.timing0	= 0x000f0007,
+	.timing1	= 0x001f000f,
+	.timing2	= 0x0015000d,
+};
+
 /**
  * struct mxs_i2c_dev - per device, private MXS-I2C data
  *
@@ -112,11 +135,17 @@ struct mxs_i2c_dev {
 	struct completion cmd_complete;
 	u32 cmd_err;
 	struct i2c_adapter adapter;
+	const struct mxs_i2c_speed_config *speed;
 };
 
 static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
 {
 	stmp_reset_block(i2c->regs);
+
+	writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0);
+	writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1);
+	writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
+
 	writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
 	writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
 			i2c->regs + MXS_I2C_QUEUECTRL_SET);
@@ -319,6 +348,27 @@ static const struct i2c_algorithm mxs_i2c_algo = {
 	.functionality = mxs_i2c_func,
 };
 
+static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
+{
+	uint32_t speed;
+	struct device *dev = i2c->dev;
+	struct device_node *node = dev->of_node;
+
+	if (!node)
+		return -EINVAL;
+
+	i2c->speed = &mxs_i2c_95kHz_config;
+	ret = of_property_read_u32(node, "clock-frequency", &speed);
+	if (ret)
+		dev_warn(dev, "No I2C speed selected, using 100kHz\n");
+	else if (speed == 400000)
+		i2c->speed = &mxs_i2c_400kHz_config;
+	else if (speed != 100000)
+		dev_warn(dev, "Invalid I2C speed selected, using 100kHz\n");
+
+	return 0;
+}
+
 static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -358,6 +408,11 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 		return err;
 
 	i2c->dev = dev;
+
+	err = mxs_i2c_get_ofdata(i2c);
+	if (err)
+		return err;
+
 	platform_set_drvdata(pdev, i2c);
 
 	/* Do reset to enforce correct startup after pinmuxing */
-- 
1.7.10

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

* [PATCH 2/2 V2] MXS: Implement DMA support into mxs-i2c
  2012-06-09 11:45 ` Marek Vasut
@ 2012-06-09 11:45     ` Marek Vasut
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-09 11:45 UTC (permalink / raw)
  To: linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: Marek Vasut, Detlev Zundel, Dong Aisheng, Fabio Estevam,
	Linux ARM kernel, Sascha Hauer, Shawn Guo, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

This patch implements DMA support into mxs-i2c. DMA transfers are now enabled
via DT. The DMA operation is enabled by default.

Signed-off-by: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org>
Cc: Detlev Zundel <dzu-ynQEQJNshbs@public.gmane.org>
CC: Dong Aisheng <b29396-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
CC: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Cc: Linux ARM kernel <linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>
Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
CC: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
CC: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Stefano Babic <sbabic-ynQEQJNshbs@public.gmane.org>
CC: Uwe Kleine-König <u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Cc: Wolfgang Denk <wd-ynQEQJNshbs@public.gmane.org>
Cc: Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 Documentation/devicetree/bindings/i2c/i2c-mxs.txt |    4 +
 arch/arm/boot/dts/imx28.dtsi                      |    2 +
 drivers/i2c/busses/i2c-mxs.c                      |  268 +++++++++++++++++++--
 3 files changed, 252 insertions(+), 22 deletions(-)

V2: Improve documentation

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
index d2bf750..9497ee0 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
@@ -5,6 +5,10 @@ Required properties:
 - reg: Should contain registers location and length
 - interrupts: Should contain ERROR and DMA interrupts
 - clock-frequency: desired I2C bus clock frequency in Hz.
+- fsl,i2c-dma-channel: APBX DMA channel for the I2C
+
+Optional properties:
+- fsl,use-pio: Use PIO transfers instead of DMA, useful for debug
 
 Examples:
 
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index 714e63c..cabcce8 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -399,6 +399,7 @@
 				reg = <0x80058000 2000>;
 				interrupts = <111 68>;
 				clock-frequency = <400000>;
+				fsl,i2c-dma-channel = <6>;
 				status = "disabled";
 			};
 
@@ -409,6 +410,7 @@
 				reg = <0x8005a000 2000>;
 				interrupts = <110 69>;
 				clock-frequency = <400000>;
+				fsl,i2c-dma-channel = <7>;
 				status = "disabled";
 			};
 
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index b7d423e..e38be56 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -7,8 +7,6 @@
  *
  * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
  *
- * TODO: add dma-support if platform-support for it is available
- *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -31,6 +29,9 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_i2c.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/fsl/mxs-dma.h>
 
 #define DRIVER_NAME "mxs-i2c"
 
@@ -136,6 +137,16 @@ struct mxs_i2c_dev {
 	u32 cmd_err;
 	struct i2c_adapter adapter;
 	const struct mxs_i2c_speed_config *speed;
+
+	/* DMA support components */
+	bool				dma_mode;
+	int				dma_channel;
+	struct dma_chan         	*dmach;
+	struct mxs_dma_data		dma_data;
+	uint32_t			pio_data[2];
+	uint32_t			addr_data;
+	struct scatterlist		sg_io[2];
+	bool				dma_read;
 };
 
 static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
@@ -147,7 +158,11 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
 	writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
 
 	writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
-	writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+	if (i2c->dma_mode)
+		writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+			i2c->regs + MXS_I2C_QUEUECTRL_CLR);
+	else
+		writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
 			i2c->regs + MXS_I2C_QUEUECTRL_SET);
 }
 
@@ -238,6 +253,151 @@ static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
 	return 0;
 }
 
+static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c)
+{
+	if (i2c->dma_read) {
+		dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+		dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+	} else {
+		dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+	}
+}
+
+static void mxs_i2c_dma_irq_callback(void *param)
+{
+	struct mxs_i2c_dev *i2c = param;
+
+	complete(&i2c->cmd_complete);
+	mxs_i2c_dma_finish(i2c);
+}
+
+static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
+			struct i2c_msg *msg, uint32_t flags)
+{
+	struct dma_async_tx_descriptor *desc;
+	struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
+
+	if (msg->flags & I2C_M_RD) {
+		i2c->dma_read = 1;
+		i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ;
+
+		/*
+		 * SELECT command.
+		 */
+
+		/* Queue the PIO register write transfer. */
+		i2c->pio_data[0] = MXS_CMD_I2C_SELECT;
+		desc = dmaengine_prep_slave_sg(i2c->dmach,
+					(struct scatterlist *)&i2c->pio_data[0],
+					1, DMA_TRANS_NONE, 0);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get PIO reg. write descriptor.\n");
+			goto select_init_pio_fail;
+		}
+
+		/* Queue the DMA data transfer. */
+		sg_init_one(&i2c->sg_io[0], &i2c->addr_data, 1);
+		dma_map_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+		desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1,
+					DMA_MEM_TO_DEV,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get DMA data write descriptor.\n");
+			goto select_init_dma_fail;
+		}
+
+		/*
+		 * READ command.
+		 */
+
+		/* Queue the PIO register write transfer. */
+		i2c->pio_data[1] = flags | MXS_CMD_I2C_READ |
+				MXS_I2C_CTRL0_XFER_COUNT(msg->len);
+		desc = dmaengine_prep_slave_sg(i2c->dmach,
+					(struct scatterlist *)&i2c->pio_data[1],
+					1, DMA_TRANS_NONE, DMA_PREP_INTERRUPT);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get PIO reg. write descriptor.\n");
+			goto select_init_dma_fail;
+		}
+
+		/* Queue the DMA data transfer. */
+		sg_init_one(&i2c->sg_io[1], msg->buf, msg->len);
+		dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+		desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1,
+					DMA_DEV_TO_MEM,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get DMA data write descriptor.\n");
+			goto read_init_dma_fail;
+		}
+	} else {
+		i2c->dma_read = 0;
+		i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE;
+
+		/*
+		 * WRITE command.
+		 */
+
+		/* Queue the PIO register write transfer. */
+		i2c->pio_data[0] = flags | MXS_CMD_I2C_WRITE |
+				MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1);
+		desc = dmaengine_prep_slave_sg(i2c->dmach,
+					(struct scatterlist *)&i2c->pio_data[0],
+					1, DMA_TRANS_NONE, 0);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get PIO reg. write descriptor.\n");
+			goto write_init_pio_fail;
+		}
+
+		/* Queue the DMA data transfer. */
+		sg_init_table(i2c->sg_io, 2);
+		sg_set_buf(&i2c->sg_io[0], &i2c->addr_data, 1);
+		sg_set_buf(&i2c->sg_io[1], msg->buf, msg->len);
+		dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+		desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2,
+					DMA_MEM_TO_DEV,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get DMA data write descriptor.\n");
+			goto write_init_dma_fail;
+		}
+	}
+
+	/*
+	 * The last descriptor must have this callback,
+	 * to finish the DMA transaction.
+	 */
+	desc->callback = mxs_i2c_dma_irq_callback;
+	desc->callback_param = i2c;
+
+	/* Start the transfer. */
+	dmaengine_submit(desc);
+	dma_async_issue_pending(i2c->dmach);
+	return 0;
+
+/* Read failpath. */
+read_init_dma_fail:
+	dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+select_init_dma_fail:
+	dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+select_init_pio_fail:
+	return 1;
+
+
+/* Write failpath. */
+write_init_dma_fail:
+	dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+write_init_pio_fail:
+	return 1;
+}
+
 /*
  * Low level master read/write transaction.
  */
@@ -248,6 +408,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
 	int ret;
 	int flags;
 
+	flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
+
 	dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
 		msg->addr, msg->len, msg->flags, stop);
 
@@ -257,23 +419,29 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
 	init_completion(&i2c->cmd_complete);
 	i2c->cmd_err = 0;
 
-	flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
-
-	if (msg->flags & I2C_M_RD)
-		mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags);
-	else
-		mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len,
-					flags);
+	if (i2c->dma_mode) {
+		ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
+		if (ret)
+			return -EINVAL;
+	} else {
+		if (msg->flags & I2C_M_RD) {
+			mxs_i2c_pioq_setup_read(i2c, msg->addr,
+						msg->len, flags);
+		} else {
+			mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf,
+						msg->len, flags);
+		}
 
-	writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
+		writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
 			i2c->regs + MXS_I2C_QUEUECTRL_SET);
+	}
 
 	ret = wait_for_completion_timeout(&i2c->cmd_complete,
 						msecs_to_jiffies(1000));
 	if (ret == 0)
 		goto timeout;
 
-	if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) {
+	if (!i2c->dma_mode && !i2c->cmd_err && (msg->flags & I2C_M_RD)) {
 		ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len);
 		if (ret)
 			goto timeout;
@@ -291,6 +459,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
 
 timeout:
 	dev_dbg(i2c->dev, "Timeout!\n");
+	mxs_i2c_dma_finish(i2c);
 	mxs_i2c_reset(i2c);
 	return -ETIMEDOUT;
 }
@@ -332,11 +501,13 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
 		/* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */
 		i2c->cmd_err = -EIO;
 
-	is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
-		MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
+	if (!i2c->dma_mode) {
+		is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
+			MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
 
-	if (is_last_cmd || i2c->cmd_err)
-		complete(&i2c->cmd_complete);
+		if (is_last_cmd || i2c->cmd_err)
+			complete(&i2c->cmd_complete);
+	}
 
 	writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
 
@@ -348,15 +519,53 @@ static const struct i2c_algorithm mxs_i2c_algo = {
 	.functionality = mxs_i2c_func,
 };
 
+static bool mxs_i2c_dma_filter(struct dma_chan *chan, void *param)
+{
+	struct mxs_i2c_dev *i2c = param;
+
+	if (!mxs_dma_is_apbx(chan))
+		return false;
+
+	if (chan->chan_id != i2c->dma_channel)
+		return false;
+
+	chan->private = &i2c->dma_data;
+
+	return true;
+}
+
 static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
 {
 	uint32_t speed;
 	struct device *dev = i2c->dev;
 	struct device_node *node = dev->of_node;
+	int ret;
 
 	if (!node)
 		return -EINVAL;
 
+	/*
+	 * The MXS I2C DMA mode is prefered and enabled by default.
+	 * The PIO mode is still supported, but should be used only
+	 * for debuging purposes etc.
+	 */
+	i2c->dma_mode = 1;
+	if (of_find_property(node, "fsl,use-pio", NULL)) {
+		i2c->dma_mode = 0;
+		dev_info(dev, "Using PIO mode for I2C transfers!\n");
+	}
+
+	/*
+	 * TODO: This is a temporary solution and should be changed
+	 * to use generic DMA binding later when the helpers get in.
+	 */
+	ret = of_property_read_u32(node, "fsl,i2c-dma-channel",
+				   &i2c->dma_channel);
+	if (ret) {
+		dev_warn(dev, "Failed to get DMA channel!\n");
+		i2c->dma_mode = 0;
+	}
+
 	i2c->speed = &mxs_i2c_95kHz_config;
 	ret = of_property_read_u32(node, "clock-frequency", &speed);
 	if (ret)
@@ -377,7 +586,8 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 	struct pinctrl *pinctrl;
 	struct resource *res;
 	resource_size_t res_size;
-	int err, irq;
+	int err, irq, dmairq;
+	dma_cap_mask_t mask;
 
 	pinctrl = devm_pinctrl_get_select_default(dev);
 	if (IS_ERR(pinctrl))
@@ -388,7 +598,10 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
+	irq = platform_get_irq(pdev, 0);
+	dmairq = platform_get_irq(pdev, 1);
+
+	if (!res || irq < 0 || dmairq < 0)
 		return -ENOENT;
 
 	res_size = resource_size(res);
@@ -399,10 +612,6 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 	if (!i2c->regs)
 		return -EBUSY;
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
 	err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
 	if (err)
 		return err;
@@ -413,6 +622,18 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 	if (err)
 		return err;
 
+	/* Setup the DMA */
+	if (i2c->dma_mode) {
+		dma_cap_zero(mask);
+		dma_cap_set(DMA_SLAVE, mask);
+		i2c->dma_data.chan_irq = dmairq;
+		i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c);
+		if (!i2c->dmach) {
+			dev_err(dev, "Failed to request dma\n");
+			return -ENODEV;
+		}
+	}
+
 	platform_set_drvdata(pdev, i2c);
 
 	/* Do reset to enforce correct startup after pinmuxing */
@@ -448,6 +669,9 @@ static int __devexit mxs_i2c_remove(struct platform_device *pdev)
 	if (ret)
 		return -EBUSY;
 
+	if (i2c->dmach)
+		dma_release_channel(i2c->dmach);
+
 	writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
 
 	platform_set_drvdata(pdev, NULL);
-- 
1.7.10

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

* [PATCH 2/2 V2] MXS: Implement DMA support into mxs-i2c
@ 2012-06-09 11:45     ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-09 11:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patch implements DMA support into mxs-i2c. DMA transfers are now enabled
via DT. The DMA operation is enabled by default.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Detlev Zundel <dzu@denx.de>
CC: Dong Aisheng <b29396@freescale.com>
CC: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Linux ARM kernel <linux-arm-kernel@lists.infradead.org>
Cc: linux-i2c at vger.kernel.org
CC: Sascha Hauer <s.hauer@pengutronix.de>
CC: Shawn Guo <shawn.guo@linaro.org>
Cc: Stefano Babic <sbabic@denx.de>
CC: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
Cc: Wolfgang Denk <wd@denx.de>
Cc: Wolfram Sang <w.sang@pengutronix.de>
---
 Documentation/devicetree/bindings/i2c/i2c-mxs.txt |    4 +
 arch/arm/boot/dts/imx28.dtsi                      |    2 +
 drivers/i2c/busses/i2c-mxs.c                      |  268 +++++++++++++++++++--
 3 files changed, 252 insertions(+), 22 deletions(-)

V2: Improve documentation

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
index d2bf750..9497ee0 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
@@ -5,6 +5,10 @@ Required properties:
 - reg: Should contain registers location and length
 - interrupts: Should contain ERROR and DMA interrupts
 - clock-frequency: desired I2C bus clock frequency in Hz.
+- fsl,i2c-dma-channel: APBX DMA channel for the I2C
+
+Optional properties:
+- fsl,use-pio: Use PIO transfers instead of DMA, useful for debug
 
 Examples:
 
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index 714e63c..cabcce8 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -399,6 +399,7 @@
 				reg = <0x80058000 2000>;
 				interrupts = <111 68>;
 				clock-frequency = <400000>;
+				fsl,i2c-dma-channel = <6>;
 				status = "disabled";
 			};
 
@@ -409,6 +410,7 @@
 				reg = <0x8005a000 2000>;
 				interrupts = <110 69>;
 				clock-frequency = <400000>;
+				fsl,i2c-dma-channel = <7>;
 				status = "disabled";
 			};
 
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index b7d423e..e38be56 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -7,8 +7,6 @@
  *
  * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
  *
- * TODO: add dma-support if platform-support for it is available
- *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -31,6 +29,9 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_i2c.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/fsl/mxs-dma.h>
 
 #define DRIVER_NAME "mxs-i2c"
 
@@ -136,6 +137,16 @@ struct mxs_i2c_dev {
 	u32 cmd_err;
 	struct i2c_adapter adapter;
 	const struct mxs_i2c_speed_config *speed;
+
+	/* DMA support components */
+	bool				dma_mode;
+	int				dma_channel;
+	struct dma_chan         	*dmach;
+	struct mxs_dma_data		dma_data;
+	uint32_t			pio_data[2];
+	uint32_t			addr_data;
+	struct scatterlist		sg_io[2];
+	bool				dma_read;
 };
 
 static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
@@ -147,7 +158,11 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
 	writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
 
 	writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
-	writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+	if (i2c->dma_mode)
+		writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+			i2c->regs + MXS_I2C_QUEUECTRL_CLR);
+	else
+		writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
 			i2c->regs + MXS_I2C_QUEUECTRL_SET);
 }
 
@@ -238,6 +253,151 @@ static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
 	return 0;
 }
 
+static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c)
+{
+	if (i2c->dma_read) {
+		dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+		dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+	} else {
+		dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+	}
+}
+
+static void mxs_i2c_dma_irq_callback(void *param)
+{
+	struct mxs_i2c_dev *i2c = param;
+
+	complete(&i2c->cmd_complete);
+	mxs_i2c_dma_finish(i2c);
+}
+
+static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
+			struct i2c_msg *msg, uint32_t flags)
+{
+	struct dma_async_tx_descriptor *desc;
+	struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
+
+	if (msg->flags & I2C_M_RD) {
+		i2c->dma_read = 1;
+		i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ;
+
+		/*
+		 * SELECT command.
+		 */
+
+		/* Queue the PIO register write transfer. */
+		i2c->pio_data[0] = MXS_CMD_I2C_SELECT;
+		desc = dmaengine_prep_slave_sg(i2c->dmach,
+					(struct scatterlist *)&i2c->pio_data[0],
+					1, DMA_TRANS_NONE, 0);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get PIO reg. write descriptor.\n");
+			goto select_init_pio_fail;
+		}
+
+		/* Queue the DMA data transfer. */
+		sg_init_one(&i2c->sg_io[0], &i2c->addr_data, 1);
+		dma_map_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+		desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1,
+					DMA_MEM_TO_DEV,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get DMA data write descriptor.\n");
+			goto select_init_dma_fail;
+		}
+
+		/*
+		 * READ command.
+		 */
+
+		/* Queue the PIO register write transfer. */
+		i2c->pio_data[1] = flags | MXS_CMD_I2C_READ |
+				MXS_I2C_CTRL0_XFER_COUNT(msg->len);
+		desc = dmaengine_prep_slave_sg(i2c->dmach,
+					(struct scatterlist *)&i2c->pio_data[1],
+					1, DMA_TRANS_NONE, DMA_PREP_INTERRUPT);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get PIO reg. write descriptor.\n");
+			goto select_init_dma_fail;
+		}
+
+		/* Queue the DMA data transfer. */
+		sg_init_one(&i2c->sg_io[1], msg->buf, msg->len);
+		dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+		desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1,
+					DMA_DEV_TO_MEM,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get DMA data write descriptor.\n");
+			goto read_init_dma_fail;
+		}
+	} else {
+		i2c->dma_read = 0;
+		i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE;
+
+		/*
+		 * WRITE command.
+		 */
+
+		/* Queue the PIO register write transfer. */
+		i2c->pio_data[0] = flags | MXS_CMD_I2C_WRITE |
+				MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1);
+		desc = dmaengine_prep_slave_sg(i2c->dmach,
+					(struct scatterlist *)&i2c->pio_data[0],
+					1, DMA_TRANS_NONE, 0);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get PIO reg. write descriptor.\n");
+			goto write_init_pio_fail;
+		}
+
+		/* Queue the DMA data transfer. */
+		sg_init_table(i2c->sg_io, 2);
+		sg_set_buf(&i2c->sg_io[0], &i2c->addr_data, 1);
+		sg_set_buf(&i2c->sg_io[1], msg->buf, msg->len);
+		dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+		desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2,
+					DMA_MEM_TO_DEV,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (!desc) {
+			dev_err(i2c->dev,
+				"Failed to get DMA data write descriptor.\n");
+			goto write_init_dma_fail;
+		}
+	}
+
+	/*
+	 * The last descriptor must have this callback,
+	 * to finish the DMA transaction.
+	 */
+	desc->callback = mxs_i2c_dma_irq_callback;
+	desc->callback_param = i2c;
+
+	/* Start the transfer. */
+	dmaengine_submit(desc);
+	dma_async_issue_pending(i2c->dmach);
+	return 0;
+
+/* Read failpath. */
+read_init_dma_fail:
+	dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE);
+select_init_dma_fail:
+	dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
+select_init_pio_fail:
+	return 1;
+
+
+/* Write failpath. */
+write_init_dma_fail:
+	dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
+write_init_pio_fail:
+	return 1;
+}
+
 /*
  * Low level master read/write transaction.
  */
@@ -248,6 +408,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
 	int ret;
 	int flags;
 
+	flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
+
 	dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
 		msg->addr, msg->len, msg->flags, stop);
 
@@ -257,23 +419,29 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
 	init_completion(&i2c->cmd_complete);
 	i2c->cmd_err = 0;
 
-	flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
-
-	if (msg->flags & I2C_M_RD)
-		mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags);
-	else
-		mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len,
-					flags);
+	if (i2c->dma_mode) {
+		ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
+		if (ret)
+			return -EINVAL;
+	} else {
+		if (msg->flags & I2C_M_RD) {
+			mxs_i2c_pioq_setup_read(i2c, msg->addr,
+						msg->len, flags);
+		} else {
+			mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf,
+						msg->len, flags);
+		}
 
-	writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
+		writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
 			i2c->regs + MXS_I2C_QUEUECTRL_SET);
+	}
 
 	ret = wait_for_completion_timeout(&i2c->cmd_complete,
 						msecs_to_jiffies(1000));
 	if (ret == 0)
 		goto timeout;
 
-	if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) {
+	if (!i2c->dma_mode && !i2c->cmd_err && (msg->flags & I2C_M_RD)) {
 		ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len);
 		if (ret)
 			goto timeout;
@@ -291,6 +459,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
 
 timeout:
 	dev_dbg(i2c->dev, "Timeout!\n");
+	mxs_i2c_dma_finish(i2c);
 	mxs_i2c_reset(i2c);
 	return -ETIMEDOUT;
 }
@@ -332,11 +501,13 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
 		/* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */
 		i2c->cmd_err = -EIO;
 
-	is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
-		MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
+	if (!i2c->dma_mode) {
+		is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
+			MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
 
-	if (is_last_cmd || i2c->cmd_err)
-		complete(&i2c->cmd_complete);
+		if (is_last_cmd || i2c->cmd_err)
+			complete(&i2c->cmd_complete);
+	}
 
 	writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
 
@@ -348,15 +519,53 @@ static const struct i2c_algorithm mxs_i2c_algo = {
 	.functionality = mxs_i2c_func,
 };
 
+static bool mxs_i2c_dma_filter(struct dma_chan *chan, void *param)
+{
+	struct mxs_i2c_dev *i2c = param;
+
+	if (!mxs_dma_is_apbx(chan))
+		return false;
+
+	if (chan->chan_id != i2c->dma_channel)
+		return false;
+
+	chan->private = &i2c->dma_data;
+
+	return true;
+}
+
 static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
 {
 	uint32_t speed;
 	struct device *dev = i2c->dev;
 	struct device_node *node = dev->of_node;
+	int ret;
 
 	if (!node)
 		return -EINVAL;
 
+	/*
+	 * The MXS I2C DMA mode is prefered and enabled by default.
+	 * The PIO mode is still supported, but should be used only
+	 * for debuging purposes etc.
+	 */
+	i2c->dma_mode = 1;
+	if (of_find_property(node, "fsl,use-pio", NULL)) {
+		i2c->dma_mode = 0;
+		dev_info(dev, "Using PIO mode for I2C transfers!\n");
+	}
+
+	/*
+	 * TODO: This is a temporary solution and should be changed
+	 * to use generic DMA binding later when the helpers get in.
+	 */
+	ret = of_property_read_u32(node, "fsl,i2c-dma-channel",
+				   &i2c->dma_channel);
+	if (ret) {
+		dev_warn(dev, "Failed to get DMA channel!\n");
+		i2c->dma_mode = 0;
+	}
+
 	i2c->speed = &mxs_i2c_95kHz_config;
 	ret = of_property_read_u32(node, "clock-frequency", &speed);
 	if (ret)
@@ -377,7 +586,8 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 	struct pinctrl *pinctrl;
 	struct resource *res;
 	resource_size_t res_size;
-	int err, irq;
+	int err, irq, dmairq;
+	dma_cap_mask_t mask;
 
 	pinctrl = devm_pinctrl_get_select_default(dev);
 	if (IS_ERR(pinctrl))
@@ -388,7 +598,10 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
+	irq = platform_get_irq(pdev, 0);
+	dmairq = platform_get_irq(pdev, 1);
+
+	if (!res || irq < 0 || dmairq < 0)
 		return -ENOENT;
 
 	res_size = resource_size(res);
@@ -399,10 +612,6 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 	if (!i2c->regs)
 		return -EBUSY;
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
 	err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
 	if (err)
 		return err;
@@ -413,6 +622,18 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 	if (err)
 		return err;
 
+	/* Setup the DMA */
+	if (i2c->dma_mode) {
+		dma_cap_zero(mask);
+		dma_cap_set(DMA_SLAVE, mask);
+		i2c->dma_data.chan_irq = dmairq;
+		i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c);
+		if (!i2c->dmach) {
+			dev_err(dev, "Failed to request dma\n");
+			return -ENODEV;
+		}
+	}
+
 	platform_set_drvdata(pdev, i2c);
 
 	/* Do reset to enforce correct startup after pinmuxing */
@@ -448,6 +669,9 @@ static int __devexit mxs_i2c_remove(struct platform_device *pdev)
 	if (ret)
 		return -EBUSY;
 
+	if (i2c->dmach)
+		dma_release_channel(i2c->dmach);
+
 	writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
 
 	platform_set_drvdata(pdev, NULL);
-- 
1.7.10

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-09 11:45 ` Marek Vasut
@ 2012-06-10 11:53     ` Marek Vasut
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-10 11:53 UTC (permalink / raw)
  To: linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: Detlev Zundel, Dong Aisheng, Fabio Estevam, Linux ARM kernel,
	Sascha Hauer, Shawn Guo, Stefano Babic, Uwe Kleine-König,
	Wolfgang Denk, Wolfram Sang

Dear Marek Vasut,

> This patch configures the I2C bus timing registers according
> to information passed via DT. Currently, 100kHz and 400kHz
> modes are supported.

[...]

> +struct mxs_i2c_speed_config {
> +	uint32_t	timing0;
> +	uint32_t	timing1;
> +	uint32_t	timing2;
> +};
> +
> +/* Timing values for the default 24MHz clock supplied into the i2c block.

Thinking about these further -- does anyone have any idea how these numbers were 
derived? And possibly even formula for that?

And maybe we should somehow make sure the source runs on 24MHz (how?).

> */ +const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
> +	.timing0	= 0x00780030,
> +	.timing1	= 0x00800030,
> +	.timing2	= 0x0015000d,
> +};
> +
> +const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
> +	.timing0	= 0x000f0007,
> +	.timing1	= 0x001f000f,
> +	.timing2	= 0x0015000d,
> +};

[...]

Best regards,
Marek Vasut

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-10 11:53     ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-10 11:53 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Marek Vasut,

> This patch configures the I2C bus timing registers according
> to information passed via DT. Currently, 100kHz and 400kHz
> modes are supported.

[...]

> +struct mxs_i2c_speed_config {
> +	uint32_t	timing0;
> +	uint32_t	timing1;
> +	uint32_t	timing2;
> +};
> +
> +/* Timing values for the default 24MHz clock supplied into the i2c block.

Thinking about these further -- does anyone have any idea how these numbers were 
derived? And possibly even formula for that?

And maybe we should somehow make sure the source runs on 24MHz (how?).

> */ +const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
> +	.timing0	= 0x00780030,
> +	.timing1	= 0x00800030,
> +	.timing2	= 0x0015000d,
> +};
> +
> +const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
> +	.timing0	= 0x000f0007,
> +	.timing1	= 0x001f000f,
> +	.timing2	= 0x0015000d,
> +};

[...]

Best regards,
Marek Vasut

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-09 11:45 ` Marek Vasut
@ 2012-06-11  6:39     ` Shawn Guo
  -1 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2012-06-11  6:39 UTC (permalink / raw)
  To: Marek Vasut
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

On Sat, Jun 09, 2012 at 01:45:50PM +0200, Marek Vasut wrote:
> This patch configures the I2C bus timing registers according
> to information passed via DT. Currently, 100kHz and 400kHz
> modes are supported.
> 
> Signed-off-by: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org>

I gave it a test on imx28-evk board with audio playback.  It seems
the patch makes the first time playback non-functional, but the later
playback is still working.

> +static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
> +{
> +	uint32_t speed;
> +	struct device *dev = i2c->dev;
> +	struct device_node *node = dev->of_node;
> +
> +	if (!node)
> +		return -EINVAL;
> +
> +	i2c->speed = &mxs_i2c_95kHz_config;
> +	ret = of_property_read_u32(node, "clock-frequency", &speed);

"ret" is undeclared.

> +	if (ret)
> +		dev_warn(dev, "No I2C speed selected, using 100kHz\n");
> +	else if (speed == 400000)
> +		i2c->speed = &mxs_i2c_400kHz_config;
> +	else if (speed != 100000)
> +		dev_warn(dev, "Invalid I2C speed selected, using 100kHz\n");
> +
> +	return 0;
> +}
> +

-- 
Regards,
Shawn

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-11  6:39     ` Shawn Guo
  0 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2012-06-11  6:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jun 09, 2012 at 01:45:50PM +0200, Marek Vasut wrote:
> This patch configures the I2C bus timing registers according
> to information passed via DT. Currently, 100kHz and 400kHz
> modes are supported.
> 
> Signed-off-by: Marek Vasut <marex@denx.de>

I gave it a test on imx28-evk board with audio playback.  It seems
the patch makes the first time playback non-functional, but the later
playback is still working.

> +static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
> +{
> +	uint32_t speed;
> +	struct device *dev = i2c->dev;
> +	struct device_node *node = dev->of_node;
> +
> +	if (!node)
> +		return -EINVAL;
> +
> +	i2c->speed = &mxs_i2c_95kHz_config;
> +	ret = of_property_read_u32(node, "clock-frequency", &speed);

"ret" is undeclared.

> +	if (ret)
> +		dev_warn(dev, "No I2C speed selected, using 100kHz\n");
> +	else if (speed == 400000)
> +		i2c->speed = &mxs_i2c_400kHz_config;
> +	else if (speed != 100000)
> +		dev_warn(dev, "Invalid I2C speed selected, using 100kHz\n");
> +
> +	return 0;
> +}
> +

-- 
Regards,
Shawn

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-10 11:53     ` Marek Vasut
@ 2012-06-11  7:30         ` Shawn Guo
  -1 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2012-06-11  7:30 UTC (permalink / raw)
  To: Marek Vasut
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

On Sun, Jun 10, 2012 at 01:53:05PM +0200, Marek Vasut wrote:
> > +struct mxs_i2c_speed_config {
> > +	uint32_t	timing0;
> > +	uint32_t	timing1;
> > +	uint32_t	timing2;
> > +};
> > +
> > +/* Timing values for the default 24MHz clock supplied into the i2c block.
> 
> Thinking about these further -- does anyone have any idea how these numbers were 
> derived? And possibly even formula for that?
> 
> And maybe we should somehow make sure the source runs on 24MHz (how?).
> 
There is nothing about I2C clock mentioned in CLKCTRL chapter.  I just
contacted design team and was told that I2C clock sources from APBX
(xbus) clock and always runs at the same frequency there.

-- 
Regards,
Shawn

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-11  7:30         ` Shawn Guo
  0 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2012-06-11  7:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jun 10, 2012 at 01:53:05PM +0200, Marek Vasut wrote:
> > +struct mxs_i2c_speed_config {
> > +	uint32_t	timing0;
> > +	uint32_t	timing1;
> > +	uint32_t	timing2;
> > +};
> > +
> > +/* Timing values for the default 24MHz clock supplied into the i2c block.
> 
> Thinking about these further -- does anyone have any idea how these numbers were 
> derived? And possibly even formula for that?
> 
> And maybe we should somehow make sure the source runs on 24MHz (how?).
> 
There is nothing about I2C clock mentioned in CLKCTRL chapter.  I just
contacted design team and was told that I2C clock sources from APBX
(xbus) clock and always runs at the same frequency there.

-- 
Regards,
Shawn

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-11  7:30         ` Shawn Guo
@ 2012-06-11 10:53             ` Marek Vasut
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-11 10:53 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

Dear Shawn Guo,

> On Sun, Jun 10, 2012 at 01:53:05PM +0200, Marek Vasut wrote:
> > > +struct mxs_i2c_speed_config {
> > > +	uint32_t	timing0;
> > > +	uint32_t	timing1;
> > > +	uint32_t	timing2;
> > > +};
> > > +
> > > +/* Timing values for the default 24MHz clock supplied into the i2c
> > > block.
> > 
> > Thinking about these further -- does anyone have any idea how these
> > numbers were derived? And possibly even formula for that?
> > 
> > And maybe we should somehow make sure the source runs on 24MHz (how?).
> 
> There is nothing about I2C clock mentioned in CLKCTRL chapter.  I just
> contacted design team and was told that I2C clock sources from APBX
> (xbus) clock and always runs at the same frequency there.

Ok, then can you please try asking them how to exactly compute the values in 
timing0-timing2 registers? So we don't have to hardcode them like it's done now?

Best regards,
Marek Vasut

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-11 10:53             ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-11 10:53 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Shawn Guo,

> On Sun, Jun 10, 2012 at 01:53:05PM +0200, Marek Vasut wrote:
> > > +struct mxs_i2c_speed_config {
> > > +	uint32_t	timing0;
> > > +	uint32_t	timing1;
> > > +	uint32_t	timing2;
> > > +};
> > > +
> > > +/* Timing values for the default 24MHz clock supplied into the i2c
> > > block.
> > 
> > Thinking about these further -- does anyone have any idea how these
> > numbers were derived? And possibly even formula for that?
> > 
> > And maybe we should somehow make sure the source runs on 24MHz (how?).
> 
> There is nothing about I2C clock mentioned in CLKCTRL chapter.  I just
> contacted design team and was told that I2C clock sources from APBX
> (xbus) clock and always runs at the same frequency there.

Ok, then can you please try asking them how to exactly compute the values in 
timing0-timing2 registers? So we don't have to hardcode them like it's done now?

Best regards,
Marek Vasut

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-11  6:39     ` Shawn Guo
@ 2012-06-11 10:54         ` Marek Vasut
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-11 10:54 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

Dear Shawn Guo,

> On Sat, Jun 09, 2012 at 01:45:50PM +0200, Marek Vasut wrote:
> > This patch configures the I2C bus timing registers according
> > to information passed via DT. Currently, 100kHz and 400kHz
> > modes are supported.
> > 
> > Signed-off-by: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org>
> 
> I gave it a test on imx28-evk board with audio playback.  It seems
> the patch makes the first time playback non-functional, but the later
> playback is still working.

Any hints what can be the source of this issue? I tested it with i2c eeprom, saw 
no issues in there. I'll poke into it later.

> > +static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
> > +{
> > +	uint32_t speed;
> > +	struct device *dev = i2c->dev;
> > +	struct device_node *node = dev->of_node;
> > +
> > +	if (!node)
> > +		return -EINVAL;
> > +
> > +	i2c->speed = &mxs_i2c_95kHz_config;
> > +	ret = of_property_read_u32(node, "clock-frequency", &speed);
> 
> "ret" is undeclared.
> 
> > +	if (ret)
> > +		dev_warn(dev, "No I2C speed selected, using 100kHz\n");
> > +	else if (speed == 400000)
> > +		i2c->speed = &mxs_i2c_400kHz_config;
> > +	else if (speed != 100000)
> > +		dev_warn(dev, "Invalid I2C speed selected, using 100kHz\n");
> > +
> > +	return 0;
> > +}
> > +

Best regards,
Marek Vasut

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-11 10:54         ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-11 10:54 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Shawn Guo,

> On Sat, Jun 09, 2012 at 01:45:50PM +0200, Marek Vasut wrote:
> > This patch configures the I2C bus timing registers according
> > to information passed via DT. Currently, 100kHz and 400kHz
> > modes are supported.
> > 
> > Signed-off-by: Marek Vasut <marex@denx.de>
> 
> I gave it a test on imx28-evk board with audio playback.  It seems
> the patch makes the first time playback non-functional, but the later
> playback is still working.

Any hints what can be the source of this issue? I tested it with i2c eeprom, saw 
no issues in there. I'll poke into it later.

> > +static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
> > +{
> > +	uint32_t speed;
> > +	struct device *dev = i2c->dev;
> > +	struct device_node *node = dev->of_node;
> > +
> > +	if (!node)
> > +		return -EINVAL;
> > +
> > +	i2c->speed = &mxs_i2c_95kHz_config;
> > +	ret = of_property_read_u32(node, "clock-frequency", &speed);
> 
> "ret" is undeclared.
> 
> > +	if (ret)
> > +		dev_warn(dev, "No I2C speed selected, using 100kHz\n");
> > +	else if (speed == 400000)
> > +		i2c->speed = &mxs_i2c_400kHz_config;
> > +	else if (speed != 100000)
> > +		dev_warn(dev, "Invalid I2C speed selected, using 100kHz\n");
> > +
> > +	return 0;
> > +}
> > +

Best regards,
Marek Vasut

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-11 10:53             ` Marek Vasut
@ 2012-06-11 14:42                 ` Shawn Guo
  -1 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2012-06-11 14:42 UTC (permalink / raw)
  To: Marek Vasut
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

On Mon, Jun 11, 2012 at 12:53:17PM +0200, Marek Vasut wrote:
> Ok, then can you please try asking them how to exactly compute the values in 
> timing0-timing2 registers? So we don't have to hardcode them like it's done now?
> 
It's determined I2C clock waveform you want to get.  See i.MX28 RM
"Figure 27-2. I2C Data and Clock Timing" and "Figure 27-3. I2C Data
and Clock Timing Generation".

For example, if you run 12MHz APBX clock, and set HIGH_COUNT to 60,
the I2C clock will have 60 cycle x (1/12MHz) = 5us time for its high
period.

-- 
Regards,
Shawn

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-11 14:42                 ` Shawn Guo
  0 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2012-06-11 14:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 11, 2012 at 12:53:17PM +0200, Marek Vasut wrote:
> Ok, then can you please try asking them how to exactly compute the values in 
> timing0-timing2 registers? So we don't have to hardcode them like it's done now?
> 
It's determined I2C clock waveform you want to get.  See i.MX28 RM
"Figure 27-2. I2C Data and Clock Timing" and "Figure 27-3. I2C Data
and Clock Timing Generation".

For example, if you run 12MHz APBX clock, and set HIGH_COUNT to 60,
the I2C clock will have 60 cycle x (1/12MHz) = 5us time for its high
period.

-- 
Regards,
Shawn

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-11 14:42                 ` Shawn Guo
@ 2012-06-23 18:19                     ` Marek Vasut
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-23 18:19 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

Dear Shawn Guo,

> On Mon, Jun 11, 2012 at 12:53:17PM +0200, Marek Vasut wrote:
> > Ok, then can you please try asking them how to exactly compute the values
> > in timing0-timing2 registers? So we don't have to hardcode them like
> > it's done now?
> 
> It's determined I2C clock waveform you want to get.  See i.MX28 RM
> "Figure 27-2. I2C Data and Clock Timing" and "Figure 27-3. I2C Data
> and Clock Timing Generation".
> 
> For example, if you run 12MHz APBX clock, and set HIGH_COUNT to 60,
> the I2C clock will have 60 cycle x (1/12MHz) = 5us time for its high
> period.

Ok, I think I see the equation. But what still doesn't make sense is how you got 
to the value of 48 (RCV_COUNT at 95kHz). And how you got 120 for HIGH_COUNT and 
128 for LOW_COUNT?

Were these values based on some measurements, making them the best possible 
values? Won't computation of slightly different values affect reliability of 
this driver?

Best regards,
Marek Vasut

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-23 18:19                     ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-23 18:19 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Shawn Guo,

> On Mon, Jun 11, 2012 at 12:53:17PM +0200, Marek Vasut wrote:
> > Ok, then can you please try asking them how to exactly compute the values
> > in timing0-timing2 registers? So we don't have to hardcode them like
> > it's done now?
> 
> It's determined I2C clock waveform you want to get.  See i.MX28 RM
> "Figure 27-2. I2C Data and Clock Timing" and "Figure 27-3. I2C Data
> and Clock Timing Generation".
> 
> For example, if you run 12MHz APBX clock, and set HIGH_COUNT to 60,
> the I2C clock will have 60 cycle x (1/12MHz) = 5us time for its high
> period.

Ok, I think I see the equation. But what still doesn't make sense is how you got 
to the value of 48 (RCV_COUNT at 95kHz). And how you got 120 for HIGH_COUNT and 
128 for LOW_COUNT?

Were these values based on some measurements, making them the best possible 
values? Won't computation of slightly different values affect reliability of 
this driver?

Best regards,
Marek Vasut

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-09 11:45 ` Marek Vasut
@ 2012-06-23 18:47     ` Marek Vasut
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-23 18:47 UTC (permalink / raw)
  To: linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: Detlev Zundel, Dong Aisheng, Fabio Estevam, Linux ARM kernel,
	Sascha Hauer, Shawn Guo, Stefano Babic, Uwe Kleine-König,
	Wolfgang Denk, Wolfram Sang

Dear Shawn Guo,

> This patch configures the I2C bus timing registers according
> to information passed via DT. Currently, 100kHz and 400kHz
> modes are supported.
[...]

Is there any reason why this can not be merged other than the timing registers 
goo (which I believe shall stay as in the datasheet until we figure out if it's 
even reasonable to add some computation there).

Best regards,
Marek Vasut

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-23 18:47     ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-23 18:47 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Shawn Guo,

> This patch configures the I2C bus timing registers according
> to information passed via DT. Currently, 100kHz and 400kHz
> modes are supported.
[...]

Is there any reason why this can not be merged other than the timing registers 
goo (which I believe shall stay as in the datasheet until we figure out if it's 
even reasonable to add some computation there).

Best regards,
Marek Vasut

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-23 18:47     ` Marek Vasut
@ 2012-06-25 15:43         ` Shawn Guo
  -1 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2012-06-25 15:43 UTC (permalink / raw)
  To: Marek Vasut
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

On Sat, Jun 23, 2012 at 08:47:32PM +0200, Marek Vasut wrote:
> Dear Shawn Guo,
> 
> > This patch configures the I2C bus timing registers according
> > to information passed via DT. Currently, 100kHz and 400kHz
> > modes are supported.
> [...]
> 
> Is there any reason why this can not be merged other than the timing registers 
> goo (which I believe shall stay as in the datasheet until we figure out if it's 
> even reasonable to add some computation there).
> 
I assume this is a question for Wolfram.  But I guess part of the reason
is there is still one comment from me staying unresolved.

-- 
Regards,
Shawn

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-25 15:43         ` Shawn Guo
  0 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2012-06-25 15:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jun 23, 2012 at 08:47:32PM +0200, Marek Vasut wrote:
> Dear Shawn Guo,
> 
> > This patch configures the I2C bus timing registers according
> > to information passed via DT. Currently, 100kHz and 400kHz
> > modes are supported.
> [...]
> 
> Is there any reason why this can not be merged other than the timing registers 
> goo (which I believe shall stay as in the datasheet until we figure out if it's 
> even reasonable to add some computation there).
> 
I assume this is a question for Wolfram.  But I guess part of the reason
is there is still one comment from me staying unresolved.

-- 
Regards,
Shawn

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-25 15:43         ` Shawn Guo
@ 2012-06-25 16:02             ` Marek Vasut
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-25 16:02 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

Dear Shawn Guo,

> On Sat, Jun 23, 2012 at 08:47:32PM +0200, Marek Vasut wrote:
> > Dear Shawn Guo,
> > 
> > > This patch configures the I2C bus timing registers according
> > > to information passed via DT. Currently, 100kHz and 400kHz
> > > modes are supported.
> > 
> > [...]
> > 
> > Is there any reason why this can not be merged other than the timing
> > registers goo (which I believe shall stay as in the datasheet until we
> > figure out if it's even reasonable to add some computation there).
> 
> I assume this is a question for Wolfram.  But I guess part of the reason
> is there is still one comment from me staying unresolved.

Ah, you mean about the audio? I'll poke into it tonight.

Best regards,
Marek Vasut

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-25 16:02             ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-25 16:02 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Shawn Guo,

> On Sat, Jun 23, 2012 at 08:47:32PM +0200, Marek Vasut wrote:
> > Dear Shawn Guo,
> > 
> > > This patch configures the I2C bus timing registers according
> > > to information passed via DT. Currently, 100kHz and 400kHz
> > > modes are supported.
> > 
> > [...]
> > 
> > Is there any reason why this can not be merged other than the timing
> > registers goo (which I believe shall stay as in the datasheet until we
> > figure out if it's even reasonable to add some computation there).
> 
> I assume this is a question for Wolfram.  But I guess part of the reason
> is there is still one comment from me staying unresolved.

Ah, you mean about the audio? I'll poke into it tonight.

Best regards,
Marek Vasut

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-25 15:43         ` Shawn Guo
@ 2012-06-27  1:15             ` Marek Vasut
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-27  1:15 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

Dear Shawn Guo,

> On Sat, Jun 23, 2012 at 08:47:32PM +0200, Marek Vasut wrote:
> > Dear Shawn Guo,
> > 
> > > This patch configures the I2C bus timing registers according
> > > to information passed via DT. Currently, 100kHz and 400kHz
> > > modes are supported.
> > 
> > [...]
> > 
> > Is there any reason why this can not be merged other than the timing
> > registers goo (which I believe shall stay as in the datasheet until we
> > figure out if it's even reasonable to add some computation there).
> 
> I assume this is a question for Wolfram.  But I guess part of the reason
> is there is still one comment from me staying unresolved.

Shawn, I just re-tested the i2c with mpg123 playing "MPEG 1.0 layer III, VBR, 
44100 Hz joint-stereo" and it worked on a first try ... can you retest please?

Best regards,
Marek Vasut

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-27  1:15             ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-27  1:15 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Shawn Guo,

> On Sat, Jun 23, 2012 at 08:47:32PM +0200, Marek Vasut wrote:
> > Dear Shawn Guo,
> > 
> > > This patch configures the I2C bus timing registers according
> > > to information passed via DT. Currently, 100kHz and 400kHz
> > > modes are supported.
> > 
> > [...]
> > 
> > Is there any reason why this can not be merged other than the timing
> > registers goo (which I believe shall stay as in the datasheet until we
> > figure out if it's even reasonable to add some computation there).
> 
> I assume this is a question for Wolfram.  But I guess part of the reason
> is there is still one comment from me staying unresolved.

Shawn, I just re-tested the i2c with mpg123 playing "MPEG 1.0 layer III, VBR, 
44100 Hz joint-stereo" and it worked on a first try ... can you retest please?

Best regards,
Marek Vasut

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-11 10:54         ` Marek Vasut
@ 2012-06-27  1:30             ` Marek Vasut
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-27  1:30 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

Dear Shawn Guo,

> > On Sat, Jun 09, 2012 at 01:45:50PM +0200, Marek Vasut wrote:
> > > This patch configures the I2C bus timing registers according
> > > to information passed via DT. Currently, 100kHz and 400kHz
> > > modes are supported.
> > > 
> > > Signed-off-by: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org>
> > 
> > I gave it a test on imx28-evk board with audio playback.  It seems
> > the patch makes the first time playback non-functional, but the later
> > playback is still working.
> 
> Any hints what can be the source of this issue? I tested it with i2c
> eeprom, saw no issues in there. I'll poke into it later.

Ok, I managed to replicate it just now. Scrap my previous email.

Still, any idea what can cause this?

Best regards,
Marek Vasut

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-27  1:30             ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-27  1:30 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Shawn Guo,

> > On Sat, Jun 09, 2012 at 01:45:50PM +0200, Marek Vasut wrote:
> > > This patch configures the I2C bus timing registers according
> > > to information passed via DT. Currently, 100kHz and 400kHz
> > > modes are supported.
> > > 
> > > Signed-off-by: Marek Vasut <marex@denx.de>
> > 
> > I gave it a test on imx28-evk board with audio playback.  It seems
> > the patch makes the first time playback non-functional, but the later
> > playback is still working.
> 
> Any hints what can be the source of this issue? I tested it with i2c
> eeprom, saw no issues in there. I'll poke into it later.

Ok, I managed to replicate it just now. Scrap my previous email.

Still, any idea what can cause this?

Best regards,
Marek Vasut

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-27  1:30             ` Marek Vasut
@ 2012-06-27  2:13                 ` Shawn Guo
  -1 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2012-06-27  2:13 UTC (permalink / raw)
  To: Marek Vasut
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

On Wed, Jun 27, 2012 at 03:30:31AM +0200, Marek Vasut wrote:
> Ok, I managed to replicate it just now. Scrap my previous email.
> 
> Still, any idea what can cause this?
> 
I just spent some time on it.  It looks like a document issue (dammit).

The HW_I2C_TIMING2 EXAMPLE tells the value is 0x0015000d which is the
one you looked at and used.  But the register field figure tells it's
0x00300030, which seems the real case.

The mxs_i2c_reset at probe changes the value to 0x0015000d which causes
the first time playback nonfunctional, but the mxs_i2c_reset call in
mxs_i2c_xfer_msg happens to reset the value back to 0x00300030, and
then second time playback starts working.

The changes below get everything work fine, both 100k and 400k.  So
with the changes in, you can add:

Tested-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

Regards,
Shawn

--8<---

diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index e38be56..c2467e9 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -112,13 +112,13 @@ struct mxs_i2c_speed_config {
 const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
        .timing0        = 0x00780030,
        .timing1        = 0x00800030,
-       .timing2        = 0x0015000d,
+       .timing2        = 0x00300030,
 };

 const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
        .timing0        = 0x000f0007,
        .timing1        = 0x001f000f,
-       .timing2        = 0x0015000d,
+       .timing2        = 0x00300030,
 };

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-27  2:13                 ` Shawn Guo
  0 siblings, 0 replies; 36+ messages in thread
From: Shawn Guo @ 2012-06-27  2:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 27, 2012 at 03:30:31AM +0200, Marek Vasut wrote:
> Ok, I managed to replicate it just now. Scrap my previous email.
> 
> Still, any idea what can cause this?
> 
I just spent some time on it.  It looks like a document issue (dammit).

The HW_I2C_TIMING2 EXAMPLE tells the value is 0x0015000d which is the
one you looked at and used.  But the register field figure tells it's
0x00300030, which seems the real case.

The mxs_i2c_reset at probe changes the value to 0x0015000d which causes
the first time playback nonfunctional, but the mxs_i2c_reset call in
mxs_i2c_xfer_msg happens to reset the value back to 0x00300030, and
then second time playback starts working.

The changes below get everything work fine, both 100k and 400k.  So
with the changes in, you can add:

Tested-by: Shawn Guo <shawn.guo@linaro.org>

Regards,
Shawn

--8<---

diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index e38be56..c2467e9 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -112,13 +112,13 @@ struct mxs_i2c_speed_config {
 const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
        .timing0        = 0x00780030,
        .timing1        = 0x00800030,
-       .timing2        = 0x0015000d,
+       .timing2        = 0x00300030,
 };

 const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
        .timing0        = 0x000f0007,
        .timing1        = 0x001f000f,
-       .timing2        = 0x0015000d,
+       .timing2        = 0x00300030,
 };

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-06-27  2:13                 ` Shawn Guo
@ 2012-06-27  2:34                     ` Marek Vasut
  -1 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-27  2:34 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

Dear Shawn Guo,

> On Wed, Jun 27, 2012 at 03:30:31AM +0200, Marek Vasut wrote:
> > Ok, I managed to replicate it just now. Scrap my previous email.
> > 
> > Still, any idea what can cause this?
> 
> I just spent some time on it.  It looks like a document issue (dammit).
> 
> The HW_I2C_TIMING2 EXAMPLE tells the value is 0x0015000d which is the
> one you looked at and used.  But the register field figure tells it's
> 0x00300030, which seems the real case.
> 
> The mxs_i2c_reset at probe changes the value to 0x0015000d which causes
> the first time playback nonfunctional, but the mxs_i2c_reset call in
> mxs_i2c_xfer_msg happens to reset the value back to 0x00300030, and
> then second time playback starts working.
> 
> The changes below get everything work fine, both 100k and 400k.  So
> with the changes in, you can add:

Ok, can you push the FSL guys to roll out updated document?

Do you consider it reasonable to add some calculations of these timing values or 
were they somehow fine-tuned with a scope/deep HW knowledge as the best working 
values and we should stick to those?

> Tested-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> 
> Regards,
> Shawn
> 
> --8<---
> 
> diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
> index e38be56..c2467e9 100644
> --- a/drivers/i2c/busses/i2c-mxs.c
> +++ b/drivers/i2c/busses/i2c-mxs.c
> @@ -112,13 +112,13 @@ struct mxs_i2c_speed_config {
>  const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
>         .timing0        = 0x00780030,
>         .timing1        = 0x00800030,
> -       .timing2        = 0x0015000d,
> +       .timing2        = 0x00300030,
>  };
> 
>  const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
>         .timing0        = 0x000f0007,
>         .timing1        = 0x001f000f,
> -       .timing2        = 0x0015000d,
> +       .timing2        = 0x00300030,
>  };

Best regards,
Marek Vasut

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-06-27  2:34                     ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-06-27  2:34 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Shawn Guo,

> On Wed, Jun 27, 2012 at 03:30:31AM +0200, Marek Vasut wrote:
> > Ok, I managed to replicate it just now. Scrap my previous email.
> > 
> > Still, any idea what can cause this?
> 
> I just spent some time on it.  It looks like a document issue (dammit).
> 
> The HW_I2C_TIMING2 EXAMPLE tells the value is 0x0015000d which is the
> one you looked at and used.  But the register field figure tells it's
> 0x00300030, which seems the real case.
> 
> The mxs_i2c_reset at probe changes the value to 0x0015000d which causes
> the first time playback nonfunctional, but the mxs_i2c_reset call in
> mxs_i2c_xfer_msg happens to reset the value back to 0x00300030, and
> then second time playback starts working.
> 
> The changes below get everything work fine, both 100k and 400k.  So
> with the changes in, you can add:

Ok, can you push the FSL guys to roll out updated document?

Do you consider it reasonable to add some calculations of these timing values or 
were they somehow fine-tuned with a scope/deep HW knowledge as the best working 
values and we should stick to those?

> Tested-by: Shawn Guo <shawn.guo@linaro.org>
> 
> Regards,
> Shawn
> 
> --8<---
> 
> diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
> index e38be56..c2467e9 100644
> --- a/drivers/i2c/busses/i2c-mxs.c
> +++ b/drivers/i2c/busses/i2c-mxs.c
> @@ -112,13 +112,13 @@ struct mxs_i2c_speed_config {
>  const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
>         .timing0        = 0x00780030,
>         .timing1        = 0x00800030,
> -       .timing2        = 0x0015000d,
> +       .timing2        = 0x00300030,
>  };
> 
>  const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
>         .timing0        = 0x000f0007,
>         .timing1        = 0x001f000f,
> -       .timing2        = 0x0015000d,
> +       .timing2        = 0x00300030,
>  };

Best regards,
Marek Vasut

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

* Re: [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
  2012-07-09 16:22 ` Marek Vasut
@ 2012-07-13  8:07     ` Wolfram Sang
  -1 siblings, 0 replies; 36+ messages in thread
From: Wolfram Sang @ 2012-07-13  8:07 UTC (permalink / raw)
  To: Marek Vasut
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Detlev Zundel, Dong Aisheng,
	Fabio Estevam, Linux ARM kernel, Sascha Hauer, Shawn Guo,
	Stefano Babic, Uwe Kleine-König, Wolfgang Denk

[-- Attachment #1: Type: text/plain, Size: 645 bytes --]

On Mon, Jul 09, 2012 at 06:22:53PM +0200, Marek Vasut wrote:
> This patch configures the I2C bus timing registers according
> to information passed via DT. Currently, 100kHz and 400kHz
> modes are supported.
> 
> The TIMING2 register value is wrong in the documentation for
> i.MX28! This was found and fixed by:
>   Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> 
> Signed-off-by: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org>

Applied to next, thanks.

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-07-13  8:07     ` Wolfram Sang
  0 siblings, 0 replies; 36+ messages in thread
From: Wolfram Sang @ 2012-07-13  8:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 09, 2012 at 06:22:53PM +0200, Marek Vasut wrote:
> This patch configures the I2C bus timing registers according
> to information passed via DT. Currently, 100kHz and 400kHz
> modes are supported.
> 
> The TIMING2 register value is wrong in the documentation for
> i.MX28! This was found and fixed by:
>   Shawn Guo <shawn.guo@linaro.org>
> 
> Signed-off-by: Marek Vasut <marex@denx.de>

Applied to next, thanks.

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120713/87880d65/attachment.sig>

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-07-09 16:22 ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-07-09 16:22 UTC (permalink / raw)
  To: linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: Marek Vasut, Detlev Zundel, Dong Aisheng, Fabio Estevam,
	Linux ARM kernel, Sascha Hauer, Shawn Guo, Stefano Babic,
	Uwe Kleine-König, Wolfgang Denk, Wolfram Sang

This patch configures the I2C bus timing registers according
to information passed via DT. Currently, 100kHz and 400kHz
modes are supported.

The TIMING2 register value is wrong in the documentation for
i.MX28! This was found and fixed by:
  Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

Signed-off-by: Marek Vasut <marex-ynQEQJNshbs@public.gmane.org>
Cc: Detlev Zundel <dzu-ynQEQJNshbs@public.gmane.org>
CC: Dong Aisheng <b29396-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
CC: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Cc: Linux ARM kernel <linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>
Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
CC: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
CC: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Stefano Babic <sbabic-ynQEQJNshbs@public.gmane.org>
CC: Uwe Kleine-König <u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Cc: Wolfgang Denk <wd-ynQEQJNshbs@public.gmane.org>
Cc: Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 Documentation/devicetree/bindings/i2c/i2c-mxs.txt |    3 +
 arch/arm/boot/dts/imx28.dtsi                      |    2 +
 drivers/i2c/busses/i2c-mxs.c                      |   66 +++++++++++++++++++++
 3 files changed, 71 insertions(+)

V2: Fixed static const struct mxs_i2c_speed_config
V3: Use 100kHz by default
    Document support only for 100kHz and 400kHz
    Document why the bus is configured to 95kHz instead of 100kHz
    Replace "Invalid speed ..." message with "Unsupported speed ..." message

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
index 1bfc02d..30ac3a0 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
@@ -4,6 +4,8 @@ Required properties:
 - compatible: Should be "fsl,<chip>-i2c"
 - reg: Should contain registers location and length
 - interrupts: Should contain ERROR and DMA interrupts
+- clock-frequency: Desired I2C bus clock frequency in Hz.
+                   Only 100000Hz and 400000Hz modes are supported.
 
 Examples:
 
@@ -13,4 +15,5 @@ i2c0: i2c@80058000 {
 	compatible = "fsl,imx28-i2c";
 	reg = <0x80058000 2000>;
 	interrupts = <111 68>;
+	clock-frequency = <100000>;
 };
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index adb5ffc..e2e9a2b 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -586,6 +586,7 @@
 				compatible = "fsl,imx28-i2c";
 				reg = <0x80058000 2000>;
 				interrupts = <111 68>;
+				clock-frequency = <100000>;
 				status = "disabled";
 			};
 
@@ -595,6 +596,7 @@
 				compatible = "fsl,imx28-i2c";
 				reg = <0x8005a000 2000>;
 				interrupts = <110 69>;
+				clock-frequency = <100000>;
 				status = "disabled";
 			};
 
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 04eb441..877b169 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -46,6 +46,10 @@
 #define MXS_I2C_CTRL0_DIRECTION			0x00010000
 #define MXS_I2C_CTRL0_XFER_COUNT(v)		((v) & 0x0000FFFF)
 
+#define MXS_I2C_TIMING0		(0x10)
+#define MXS_I2C_TIMING1		(0x20)
+#define MXS_I2C_TIMING2		(0x30)
+
 #define MXS_I2C_CTRL1		(0x40)
 #define MXS_I2C_CTRL1_SET	(0x44)
 #define MXS_I2C_CTRL1_CLR	(0x48)
@@ -97,6 +101,35 @@
 #define MXS_CMD_I2C_READ	(MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
 				 MXS_I2C_CTRL0_MASTER_MODE)
 
+struct mxs_i2c_speed_config {
+	uint32_t	timing0;
+	uint32_t	timing1;
+	uint32_t	timing2;
+};
+
+/*
+ * Timing values for the default 24MHz clock supplied into the i2c block.
+ *
+ * The bus can operate at 95kHz or at 400kHz with the following timing
+ * register configurations. The 100kHz mode isn't present because it's
+ * values are not stated in the i.MX233/i.MX28 datasheet. The 95kHz mode
+ * shall be close enough replacement. Therefore when the bus is configured
+ * for 100kHz operation, 95kHz timing settings are actually loaded.
+ *
+ * For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4].
+ */
+static const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
+	.timing0	= 0x00780030,
+	.timing1	= 0x00800030,
+	.timing2	= 0x00300030,
+};
+
+static const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
+	.timing0	= 0x000f0007,
+	.timing1	= 0x001f000f,
+	.timing2	= 0x00300030,
+};
+
 /**
  * struct mxs_i2c_dev - per device, private MXS-I2C data
  *
@@ -112,11 +145,17 @@ struct mxs_i2c_dev {
 	struct completion cmd_complete;
 	u32 cmd_err;
 	struct i2c_adapter adapter;
+	const struct mxs_i2c_speed_config *speed;
 };
 
 static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
 {
 	stmp_reset_block(i2c->regs);
+
+	writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0);
+	writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1);
+	writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
+
 	writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
 	writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
 			i2c->regs + MXS_I2C_QUEUECTRL_SET);
@@ -319,6 +358,28 @@ static const struct i2c_algorithm mxs_i2c_algo = {
 	.functionality = mxs_i2c_func,
 };
 
+static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
+{
+	uint32_t speed;
+	struct device *dev = i2c->dev;
+	struct device_node *node = dev->of_node;
+	int ret;
+
+	if (!node)
+		return -EINVAL;
+
+	i2c->speed = &mxs_i2c_95kHz_config;
+	ret = of_property_read_u32(node, "clock-frequency", &speed);
+	if (ret)
+		dev_warn(dev, "No I2C speed selected, using 100kHz\n");
+	else if (speed == 400000)
+		i2c->speed = &mxs_i2c_400kHz_config;
+	else if (speed != 100000)
+		dev_warn(dev, "Unsupported I2C speed selected, using 100kHz\n");
+
+	return 0;
+}
+
 static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -358,6 +419,11 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 		return err;
 
 	i2c->dev = dev;
+
+	err = mxs_i2c_get_ofdata(i2c);
+	if (err)
+		return err;
+
 	platform_set_drvdata(pdev, i2c);
 
 	/* Do reset to enforce correct startup after pinmuxing */
-- 
1.7.10.4

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

* [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c
@ 2012-07-09 16:22 ` Marek Vasut
  0 siblings, 0 replies; 36+ messages in thread
From: Marek Vasut @ 2012-07-09 16:22 UTC (permalink / raw)
  To: linux-arm-kernel

This patch configures the I2C bus timing registers according
to information passed via DT. Currently, 100kHz and 400kHz
modes are supported.

The TIMING2 register value is wrong in the documentation for
i.MX28! This was found and fixed by:
  Shawn Guo <shawn.guo@linaro.org>

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Detlev Zundel <dzu@denx.de>
CC: Dong Aisheng <b29396@freescale.com>
CC: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Linux ARM kernel <linux-arm-kernel@lists.infradead.org>
Cc: linux-i2c at vger.kernel.org
CC: Sascha Hauer <s.hauer@pengutronix.de>
CC: Shawn Guo <shawn.guo@linaro.org>
Cc: Stefano Babic <sbabic@denx.de>
CC: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
Cc: Wolfgang Denk <wd@denx.de>
Cc: Wolfram Sang <w.sang@pengutronix.de>
---
 Documentation/devicetree/bindings/i2c/i2c-mxs.txt |    3 +
 arch/arm/boot/dts/imx28.dtsi                      |    2 +
 drivers/i2c/busses/i2c-mxs.c                      |   66 +++++++++++++++++++++
 3 files changed, 71 insertions(+)

V2: Fixed static const struct mxs_i2c_speed_config
V3: Use 100kHz by default
    Document support only for 100kHz and 400kHz
    Document why the bus is configured to 95kHz instead of 100kHz
    Replace "Invalid speed ..." message with "Unsupported speed ..." message

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
index 1bfc02d..30ac3a0 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt
@@ -4,6 +4,8 @@ Required properties:
 - compatible: Should be "fsl,<chip>-i2c"
 - reg: Should contain registers location and length
 - interrupts: Should contain ERROR and DMA interrupts
+- clock-frequency: Desired I2C bus clock frequency in Hz.
+                   Only 100000Hz and 400000Hz modes are supported.
 
 Examples:
 
@@ -13,4 +15,5 @@ i2c0: i2c at 80058000 {
 	compatible = "fsl,imx28-i2c";
 	reg = <0x80058000 2000>;
 	interrupts = <111 68>;
+	clock-frequency = <100000>;
 };
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index adb5ffc..e2e9a2b 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -586,6 +586,7 @@
 				compatible = "fsl,imx28-i2c";
 				reg = <0x80058000 2000>;
 				interrupts = <111 68>;
+				clock-frequency = <100000>;
 				status = "disabled";
 			};
 
@@ -595,6 +596,7 @@
 				compatible = "fsl,imx28-i2c";
 				reg = <0x8005a000 2000>;
 				interrupts = <110 69>;
+				clock-frequency = <100000>;
 				status = "disabled";
 			};
 
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 04eb441..877b169 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -46,6 +46,10 @@
 #define MXS_I2C_CTRL0_DIRECTION			0x00010000
 #define MXS_I2C_CTRL0_XFER_COUNT(v)		((v) & 0x0000FFFF)
 
+#define MXS_I2C_TIMING0		(0x10)
+#define MXS_I2C_TIMING1		(0x20)
+#define MXS_I2C_TIMING2		(0x30)
+
 #define MXS_I2C_CTRL1		(0x40)
 #define MXS_I2C_CTRL1_SET	(0x44)
 #define MXS_I2C_CTRL1_CLR	(0x48)
@@ -97,6 +101,35 @@
 #define MXS_CMD_I2C_READ	(MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
 				 MXS_I2C_CTRL0_MASTER_MODE)
 
+struct mxs_i2c_speed_config {
+	uint32_t	timing0;
+	uint32_t	timing1;
+	uint32_t	timing2;
+};
+
+/*
+ * Timing values for the default 24MHz clock supplied into the i2c block.
+ *
+ * The bus can operate at 95kHz or at 400kHz with the following timing
+ * register configurations. The 100kHz mode isn't present because it's
+ * values are not stated in the i.MX233/i.MX28 datasheet. The 95kHz mode
+ * shall be close enough replacement. Therefore when the bus is configured
+ * for 100kHz operation, 95kHz timing settings are actually loaded.
+ *
+ * For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4].
+ */
+static const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = {
+	.timing0	= 0x00780030,
+	.timing1	= 0x00800030,
+	.timing2	= 0x00300030,
+};
+
+static const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = {
+	.timing0	= 0x000f0007,
+	.timing1	= 0x001f000f,
+	.timing2	= 0x00300030,
+};
+
 /**
  * struct mxs_i2c_dev - per device, private MXS-I2C data
  *
@@ -112,11 +145,17 @@ struct mxs_i2c_dev {
 	struct completion cmd_complete;
 	u32 cmd_err;
 	struct i2c_adapter adapter;
+	const struct mxs_i2c_speed_config *speed;
 };
 
 static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
 {
 	stmp_reset_block(i2c->regs);
+
+	writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0);
+	writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1);
+	writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);
+
 	writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
 	writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
 			i2c->regs + MXS_I2C_QUEUECTRL_SET);
@@ -319,6 +358,28 @@ static const struct i2c_algorithm mxs_i2c_algo = {
 	.functionality = mxs_i2c_func,
 };
 
+static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
+{
+	uint32_t speed;
+	struct device *dev = i2c->dev;
+	struct device_node *node = dev->of_node;
+	int ret;
+
+	if (!node)
+		return -EINVAL;
+
+	i2c->speed = &mxs_i2c_95kHz_config;
+	ret = of_property_read_u32(node, "clock-frequency", &speed);
+	if (ret)
+		dev_warn(dev, "No I2C speed selected, using 100kHz\n");
+	else if (speed == 400000)
+		i2c->speed = &mxs_i2c_400kHz_config;
+	else if (speed != 100000)
+		dev_warn(dev, "Unsupported I2C speed selected, using 100kHz\n");
+
+	return 0;
+}
+
 static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -358,6 +419,11 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 		return err;
 
 	i2c->dev = dev;
+
+	err = mxs_i2c_get_ofdata(i2c);
+	if (err)
+		return err;
+
 	platform_set_drvdata(pdev, i2c);
 
 	/* Do reset to enforce correct startup after pinmuxing */
-- 
1.7.10.4

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

end of thread, other threads:[~2012-07-13  8:07 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-09 11:45 [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c Marek Vasut
2012-06-09 11:45 ` Marek Vasut
     [not found] ` <1339242351-8797-1-git-send-email-marex-ynQEQJNshbs@public.gmane.org>
2012-06-09 11:45   ` [PATCH 2/2 V2] MXS: Implement DMA support into mxs-i2c Marek Vasut
2012-06-09 11:45     ` Marek Vasut
2012-06-10 11:53   ` [PATCH 1/2 V3] MXS: Set I2C timing registers for mxs-i2c Marek Vasut
2012-06-10 11:53     ` Marek Vasut
     [not found]     ` <201206101353.06018.marex-ynQEQJNshbs@public.gmane.org>
2012-06-11  7:30       ` Shawn Guo
2012-06-11  7:30         ` Shawn Guo
     [not found]         ` <20120611073036.GG2552-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
2012-06-11 10:53           ` Marek Vasut
2012-06-11 10:53             ` Marek Vasut
     [not found]             ` <201206111253.17314.marex-ynQEQJNshbs@public.gmane.org>
2012-06-11 14:42               ` Shawn Guo
2012-06-11 14:42                 ` Shawn Guo
     [not found]                 ` <20120611144237.GI2552-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
2012-06-23 18:19                   ` Marek Vasut
2012-06-23 18:19                     ` Marek Vasut
2012-06-11  6:39   ` Shawn Guo
2012-06-11  6:39     ` Shawn Guo
     [not found]     ` <20120611063903.GD2552-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
2012-06-11 10:54       ` Marek Vasut
2012-06-11 10:54         ` Marek Vasut
     [not found]         ` <201206111254.21766.marex-ynQEQJNshbs@public.gmane.org>
2012-06-27  1:30           ` Marek Vasut
2012-06-27  1:30             ` Marek Vasut
     [not found]             ` <201206270330.31669.marex-ynQEQJNshbs@public.gmane.org>
2012-06-27  2:13               ` Shawn Guo
2012-06-27  2:13                 ` Shawn Guo
     [not found]                 ` <20120627021336.GA9787-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
2012-06-27  2:34                   ` Marek Vasut
2012-06-27  2:34                     ` Marek Vasut
2012-06-23 18:47   ` Marek Vasut
2012-06-23 18:47     ` Marek Vasut
     [not found]     ` <201206232047.33228.marex-ynQEQJNshbs@public.gmane.org>
2012-06-25 15:43       ` Shawn Guo
2012-06-25 15:43         ` Shawn Guo
     [not found]         ` <20120625154354.GC2342-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
2012-06-25 16:02           ` Marek Vasut
2012-06-25 16:02             ` Marek Vasut
2012-06-27  1:15           ` Marek Vasut
2012-06-27  1:15             ` Marek Vasut
2012-07-09 16:22 Marek Vasut
2012-07-09 16:22 ` Marek Vasut
     [not found] ` <1341850974-11977-1-git-send-email-marex-ynQEQJNshbs@public.gmane.org>
2012-07-13  8:07   ` Wolfram Sang
2012-07-13  8:07     ` Wolfram Sang

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.