All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/4] Clock fix and MXC I2C rework series
@ 2011-09-15  0:09 Marek Vasut
  2011-09-15  0:09 ` [U-Boot] [PATCH 1/4] MX5: Modify the PLL decoding algorithm Marek Vasut
                   ` (3 more replies)
  0 siblings, 4 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-15  0:09 UTC (permalink / raw)
  To: u-boot

First three patches in this series fix problems with clock decoding on MX5, the
remaining patch reworks the MXC I2C driver.

This is tested on:
* MX51 EfikaSB
* MX51 EfikaMX
* MX53 QSB

Marek Vasut (4):
  MX5: Modify the PLL decoding algorithm
  MX5: Add AHB clock reporting and fix IPG clock reporting
  MX5: Clean up the output of "clocks" command
  I2C: mxc_i2c rework

 arch/arm/cpu/armv7/mx5/clock.c           |  125 +++++++--
 arch/arm/include/asm/arch-mx5/imx-regs.h |    3 +
 drivers/i2c/mxc_i2c.c                    |  423 ++++++++++++++++++++----------
 3 files changed, 394 insertions(+), 157 deletions(-)

-- 
1.7.5.4

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

* [U-Boot] [PATCH 1/4] MX5: Modify the PLL decoding algorithm
  2011-09-15  0:09 [U-Boot] [PATCH 0/4] Clock fix and MXC I2C rework series Marek Vasut
@ 2011-09-15  0:09 ` Marek Vasut
  2011-09-22  3:20   ` Jason Hui
  2011-09-23  9:43   ` [U-Boot] [PATCH 1/4 V2] " Marek Vasut
  2011-09-15  0:09 ` [U-Boot] [PATCH 2/4] MX5: Add AHB clock reporting and fix IPG clock reporting Marek Vasut
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-15  0:09 UTC (permalink / raw)
  To: u-boot

The PLL decoding algorithm didn't take into account many configuration bits.
Adjust it according to Linux kernel. Also, add PLL4 for MX53.

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
---
 arch/arm/cpu/armv7/mx5/clock.c           |   77 ++++++++++++++++++++++++++----
 arch/arm/include/asm/arch-mx5/imx-regs.h |    3 +
 2 files changed, 70 insertions(+), 10 deletions(-)

diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c
index 00610a0..9f37f7f 100644
--- a/arch/arm/cpu/armv7/mx5/clock.c
+++ b/arch/arm/cpu/armv7/mx5/clock.c
@@ -29,11 +29,13 @@
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/crm_regs.h>
 #include <asm/arch/clock.h>
+#include <div64.h>
 
 enum pll_clocks {
 	PLL1_CLOCK = 0,
 	PLL2_CLOCK,
 	PLL3_CLOCK,
+	PLL4_CLOCK,
 	PLL_CLOCKS,
 };
 
@@ -41,25 +43,76 @@ struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
 	[PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR,
 	[PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR,
 	[PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR,
+#ifdef	CONFIG_MX53
+	[PLL4_CLOCK] = (struct mxc_pll_reg *)PLL4_BASE_ADDR,
+#endif
 };
 
+#define	MXC_DPLLC_CTL_HFSM		(1 << 7)
+#define	MXC_DPLLC_CTL_DPDCK0_2_EN	(1 << 12)
+
+#define	MXC_DPLLC_OP_PDF_MASK		0xf
+#define	MXC_DPLLC_OP_MFI_MASK		(0xf << 4)
+#define	MXC_DPLLC_OP_MFI_OFFSET		4
+
+#define	MXC_DPLLC_MFD_MFD_MASK		0x7ffffff
+
+#define	MXC_DPLLC_MFN_MFN_MASK		0x7ffffff
+
 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
 
 /*
- * Calculate the frequency of this pll.
+ * Calculate the frequency of PLLn.
  */
-static u32 decode_pll(struct mxc_pll_reg *pll, u32 infreq)
+static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq)
 {
-	u32 mfi, mfn, mfd, pd;
+	uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret;
+	uint64_t refclk, temp;
+	int32_t mfn_abs;
+
+	ctrl = readl(&pll->ctrl);
+
+	if (ctrl & MXC_DPLLC_CTL_HFSM) {
+		mfn = __raw_readl(&pll->hfs_mfn);
+		mfd = __raw_readl(&pll->hfs_mfd);
+		op = __raw_readl(&pll->hfs_op);
+	} else {
+		mfn = __raw_readl(&pll->mfn);
+		mfd = __raw_readl(&pll->mfd);
+		op = __raw_readl(&pll->op);
+	}
 
-	mfn = __raw_readl(&pll->mfn);
-	mfd = __raw_readl(&pll->mfd) + 1;
-	mfi = __raw_readl(&pll->op);
-	pd = (mfi  & 0xF) + 1;
-	mfi = (mfi >> 4) & 0xF;
-	mfi = (mfi >= 5) ? mfi : 5;
+	mfd &= MXC_DPLLC_MFD_MFD_MASK;
+	mfn &= MXC_DPLLC_MFN_MFN_MASK;
+	pdf = op & MXC_DPLLC_OP_PDF_MASK;
+	mfi = (op & MXC_DPLLC_OP_MFI_MASK) >> MXC_DPLLC_OP_MFI_OFFSET;
+
+	/* 21.2.3 */
+	if (mfi < 5)
+		mfi = 5;
+
+	/* Sign extend */
+	if (mfn >= 0x04000000) {
+		mfn |= 0xfc000000;
+		mfn_abs = -mfn;
+	} else
+		mfn_abs = mfn;
+
+	refclk = infreq * 2;
+	if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN)
+		refclk *= 2;
+
+	refclk /= pdf + 1;
+	temp = refclk * mfn_abs;
+	do_div(temp, mfd + 1);
+	ret = refclk * mfi;
+
+	if ((int)mfn < 0)
+		ret -= temp;
+	else
+		ret += temp;
 
-	return ((4 * (infreq / 1000) * (mfi * mfd + mfn)) / (mfd * pd)) * 1000;
+	return ret;
 }
 
 /*
@@ -279,6 +332,10 @@ int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	printf("pll2: %dMHz\n", freq / 1000000);
 	freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
 	printf("pll3: %dMHz\n", freq / 1000000);
+#ifdef	CONFIG_MX53
+	freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
+	printf("pll4: %dMHz\n", freq / 1000000);
+#endif
 	printf("ipg clock     : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
 	printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
 
diff --git a/arch/arm/include/asm/arch-mx5/imx-regs.h b/arch/arm/include/asm/arch-mx5/imx-regs.h
index a4e680b..8a0f9e6 100644
--- a/arch/arm/include/asm/arch-mx5/imx-regs.h
+++ b/arch/arm/include/asm/arch-mx5/imx-regs.h
@@ -100,6 +100,9 @@
 #define PLL1_BASE_ADDR		(AIPS2_BASE_ADDR + 0x00080000)
 #define PLL2_BASE_ADDR		(AIPS2_BASE_ADDR + 0x00084000)
 #define PLL3_BASE_ADDR		(AIPS2_BASE_ADDR + 0x00088000)
+#ifdef	CONFIG_MX53
+#define PLL4_BASE_ADDR		(AIPS2_BASE_ADDR + 0x0008c000)
+#endif
 #define AHBMAX_BASE_ADDR	(AIPS2_BASE_ADDR + 0x00094000)
 #define IIM_BASE_ADDR		(AIPS2_BASE_ADDR + 0x00098000)
 #define CSU_BASE_ADDR		(AIPS2_BASE_ADDR + 0x0009C000)
-- 
1.7.5.4

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

* [U-Boot] [PATCH 2/4] MX5: Add AHB clock reporting and fix IPG clock reporting
  2011-09-15  0:09 [U-Boot] [PATCH 0/4] Clock fix and MXC I2C rework series Marek Vasut
  2011-09-15  0:09 ` [U-Boot] [PATCH 1/4] MX5: Modify the PLL decoding algorithm Marek Vasut
@ 2011-09-15  0:09 ` Marek Vasut
  2011-09-22  3:05   ` Jason Hui
  2011-09-22 19:20   ` [U-Boot] [PATCH 2/4 V2] " Marek Vasut
  2011-09-15  0:09 ` [U-Boot] [PATCH 3/4] MX5: Clean up the output of "clocks" command Marek Vasut
  2011-09-15  0:09 ` [U-Boot] [PATCH 4/4] I2C: mxc_i2c rework Marek Vasut
  3 siblings, 2 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-15  0:09 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
---
 arch/arm/cpu/armv7/mx5/clock.c |   36 +++++++++++++++++++++++++++---------
 1 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c
index 9f37f7f..a9fe81c 100644
--- a/arch/arm/cpu/armv7/mx5/clock.c
+++ b/arch/arm/cpu/armv7/mx5/clock.c
@@ -152,18 +152,35 @@ static u32 get_periph_clk(void)
 }
 
 /*
+ * Get the rate of ahb clock.
+ */
+static u32 get_ahb_clk(void)
+{
+	uint32_t freq, div, reg;
+
+	freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
+
+	reg = __raw_readl(&mxc_ccm->cbcdr);
+	div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
+			MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
+
+	return freq / div;
+}
+
+/*
  * Get the rate of ipg clock.
  */
 static u32 get_ipg_clk(void)
 {
-	u32 ahb_podf, ipg_podf;
-
-	ahb_podf = __raw_readl(&mxc_ccm->cbcdr);
-	ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
-			MXC_CCM_CBCDR_IPG_PODF_OFFSET;
-	ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
-			MXC_CCM_CBCDR_AHB_PODF_OFFSET;
-	return get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1));
+	uint32_t freq, reg, div;
+
+	freq = get_ahb_clk();
+
+	reg = __raw_readl(&mxc_ccm->cbcdr);
+	div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
+			MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1;
+
+	return freq / div;
 }
 
 /*
@@ -290,7 +307,7 @@ unsigned int mxc_get_clock(enum mxc_clock clk)
 	case MXC_ARM_CLK:
 		return get_mcu_main_clk();
 	case MXC_AHB_CLK:
-		break;
+		return get_ahb_clk();
 	case MXC_IPG_CLK:
 		return get_ipg_clk();
 	case MXC_IPG_PERCLK:
@@ -336,6 +353,7 @@ int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
 	printf("pll4: %dMHz\n", freq / 1000000);
 #endif
+	printf("ahb clock     : %dHz\n", mxc_get_clock(MXC_AHB_CLK));
 	printf("ipg clock     : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
 	printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
 
-- 
1.7.5.4

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

* [U-Boot] [PATCH 3/4] MX5: Clean up the output of "clocks" command
  2011-09-15  0:09 [U-Boot] [PATCH 0/4] Clock fix and MXC I2C rework series Marek Vasut
  2011-09-15  0:09 ` [U-Boot] [PATCH 1/4] MX5: Modify the PLL decoding algorithm Marek Vasut
  2011-09-15  0:09 ` [U-Boot] [PATCH 2/4] MX5: Add AHB clock reporting and fix IPG clock reporting Marek Vasut
@ 2011-09-15  0:09 ` Marek Vasut
  2011-09-19 10:03   ` Stefano Babic
  2011-09-22  1:58   ` Jason Hui
  2011-09-15  0:09 ` [U-Boot] [PATCH 4/4] I2C: mxc_i2c rework Marek Vasut
  3 siblings, 2 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-15  0:09 UTC (permalink / raw)
  To: u-boot

The new output looks like this:
> clocks
PLL1            800 MHz
PLL2            665 MHz
PLL3            216 MHz

AHB          133000 kHz
IPG           66500 kHz
IPG PERCLK   665000 kHz

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
---
 arch/arm/cpu/armv7/mx5/clock.c |   16 +++++++++-------
 1 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c
index a9fe81c..dd3615d 100644
--- a/arch/arm/cpu/armv7/mx5/clock.c
+++ b/arch/arm/cpu/armv7/mx5/clock.c
@@ -344,18 +344,20 @@ int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	u32 freq;
 
 	freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
-	printf("pll1: %dMHz\n", freq / 1000000);
+	printf("PLL1       %8d MHz\n", freq / 1000000);
 	freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
-	printf("pll2: %dMHz\n", freq / 1000000);
+	printf("PLL2       %8d MHz\n", freq / 1000000);
 	freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
-	printf("pll3: %dMHz\n", freq / 1000000);
+	printf("PLL3       %8d MHz\n", freq / 1000000);
 #ifdef	CONFIG_MX53
 	freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
-	printf("pll4: %dMHz\n", freq / 1000000);
+	printf("PLL4       %8d MHz\n", freq / 1000000);
 #endif
-	printf("ahb clock     : %dHz\n", mxc_get_clock(MXC_AHB_CLK));
-	printf("ipg clock     : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
-	printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
+
+	printf("\n");
+	printf("AHB        %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000);
+	printf("IPG        %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000);
+	printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000);
 
 	return 0;
 }
-- 
1.7.5.4

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

* [U-Boot] [PATCH 4/4] I2C: mxc_i2c rework
  2011-09-15  0:09 [U-Boot] [PATCH 0/4] Clock fix and MXC I2C rework series Marek Vasut
                   ` (2 preceding siblings ...)
  2011-09-15  0:09 ` [U-Boot] [PATCH 3/4] MX5: Clean up the output of "clocks" command Marek Vasut
@ 2011-09-15  0:09 ` Marek Vasut
  2011-09-15  4:16   ` [U-Boot] [PATCH 4/4 V2] " Marek Vasut
  2011-09-19 10:11   ` [U-Boot] [PATCH 4/4] " Stefano Babic
  3 siblings, 2 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-15  0:09 UTC (permalink / raw)
  To: u-boot

Rewrite the mxc_i2c driver.
 * This version is much closer to Linux implementation.
 * Fixes IPG_PERCLK being incorrectly used as clock source
 * Fixes behaviour of the driver on iMX51
 * Clean up coding style a bit ;-)

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
---
 drivers/i2c/mxc_i2c.c |  423 +++++++++++++++++++++++++++++++++----------------
 1 files changed, 290 insertions(+), 133 deletions(-)

diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index ebde3c5..bc0300d 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -1,7 +1,15 @@
 /*
- * i2c driver for Freescale mx31
+ * i2c driver for Freescale i.MX series
  *
  * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (c) 2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on i2c-imx.c from linux kernel:
+ *  Copyright (C) 2005 Torsten Koschorrek <koschorrek@synertronixx.de>
+ *  Copyright (C) 2005 Matthias Blaschke <blaschke@synertronixx.de>
+ *  Copyright (C) 2007 RightHand Technologies, Inc.
+ *  Copyright (C) 2008 Darius Augulis <darius.augulis@teltonika.lt>
+ *
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -30,11 +38,13 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/imx-regs.h>
 
-#define IADR	0x00
-#define IFDR	0x04
-#define I2CR	0x08
-#define I2SR	0x0c
-#define I2DR	0x10
+struct mxc_i2c_regs {
+	uint32_t	iadr;
+	uint32_t	ifdr;
+	uint32_t	i2cr;
+	uint32_t	i2sr;
+	uint32_t	i2dr;
+};
 
 #define I2CR_IEN	(1 << 7)
 #define I2CR_IIEN	(1 << 6)
@@ -68,215 +78,362 @@
 #endif
 
 #define I2C_MAX_TIMEOUT		10000
-#define I2C_MAX_RETRIES		3
 
-static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144,
-	             160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960,
-	             1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840};
+static u16 i2c_clk_div[50][2] = {
+	{ 22,	0x20 }, { 24,	0x21 }, { 26,	0x22 }, { 28,	0x23 },
+	{ 30,	0x00 }, { 32,	0x24 }, { 36,	0x25 }, { 40,	0x26 },
+	{ 42,	0x03 }, { 44,	0x27 }, { 48,	0x28 }, { 52,	0x05 },
+	{ 56,	0x29 }, { 60,	0x06 }, { 64,	0x2A }, { 72,	0x2B },
+	{ 80,	0x2C }, { 88,	0x09 }, { 96,	0x2D }, { 104,	0x0A },
+	{ 112,	0x2E }, { 128,	0x2F }, { 144,	0x0C }, { 160,	0x30 },
+	{ 192,	0x31 }, { 224,	0x32 }, { 240,	0x0F }, { 256,	0x33 },
+	{ 288,	0x10 }, { 320,	0x34 }, { 384,	0x35 }, { 448,	0x36 },
+	{ 480,	0x13 }, { 512,	0x37 }, { 576,	0x14 }, { 640,	0x38 },
+	{ 768,	0x39 }, { 896,	0x3A }, { 960,	0x17 }, { 1024,	0x3B },
+	{ 1152,	0x18 }, { 1280,	0x3C }, { 1536,	0x3D }, { 1792,	0x3E },
+	{ 1920,	0x1B }, { 2048,	0x3F }, { 2304,	0x1C }, { 2560,	0x1D },
+	{ 3072,	0x1E }, { 3840,	0x1F }
+};
+
+static u8 clk_idx;
 
-static inline void i2c_reset(void)
-{
-	writew(0, I2C_BASE + I2CR);	/* Reset module */
-	writew(0, I2C_BASE + I2SR);
-	writew(I2CR_IEN, I2C_BASE + I2CR);
-}
-
-void i2c_init(int speed, int unused)
+/*
+ * Calculate and set proper clock divider
+ */
+static void i2c_imx_set_clk(unsigned int rate)
 {
-	int freq;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int i2c_clk_rate;
+	unsigned int div;
 	int i;
 
 #if defined(CONFIG_MX31)
 	struct clock_control_regs *sc_regs =
 		(struct clock_control_regs *)CCM_BASE;
+
 	/* start the required I2C clock */
 	writel(readl(&sc_regs->cgr0) | (3 << I2C_CLK_OFFSET),
 		&sc_regs->cgr0);
 #endif
-	freq = mxc_get_clock(MXC_IPG_PERCLK);
 
-	for (i = 0; i < 0x1f; i++)
-		if (freq / div[i] <= speed)
-			break;
+	/* Divider value calculation */
+	i2c_clk_rate = mxc_get_clock(MXC_IPG_CLK);
+	div = (i2c_clk_rate + rate - 1) / rate;
+	if (div < i2c_clk_div[0][0])
+		i = 0;
+	else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
+		i = ARRAY_SIZE(i2c_clk_div) - 1;
+	else
+		for (i = 0; i2c_clk_div[i][0] < div; i++)
+			;
+
+	/* Store divider value */
+	clk_idx = i2c_clk_div[i][1];
+	writeb(clk_idx, &i2c_regs->ifdr);
+}
 
-	debug("%s: speed: %d\n", __func__, speed);
+/*
+ * Reset I2C Controller
+ */
+void i2c_reset(void)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+
+	writeb(0, &i2c_regs->i2cr);	/* Reset module */
+	writeb(0, &i2c_regs->i2sr);
+}
 
-	writew(i, I2C_BASE + IFDR);
+/*
+ * Init I2C Bus
+ */
+void i2c_init(int speed, int unused)
+{
+	i2c_imx_set_clk(speed);
 	i2c_reset();
 }
 
-static int wait_idle(void)
+/*
+ * Wait for bus to be busy (or free if for_busy = 0)
+ *
+ * for_busy = 1: Wait for IBB to be asserted
+ * for_busy = 0: Wait for IBB to be de-asserted
+ */
+int i2c_imx_bus_busy(int for_busy)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp;
+
 	int timeout = I2C_MAX_TIMEOUT;
 
-	while ((readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout) {
-		writew(0, I2C_BASE + I2SR);
+	while (timeout--) {
+		temp = readb(&i2c_regs->i2sr);
+
+		if (for_busy && (temp & I2SR_IBB))
+			return 0;
+		if (!for_busy && !(temp & I2SR_IBB))
+			return 0;
+
 		udelay(1);
 	}
-	return timeout ? timeout : (!(readw(I2C_BASE + I2SR) & I2SR_IBB));
+
+	return 1;
 }
 
-static int wait_busy(void)
+/*
+ * Wait for transaction to complete
+ */
+int i2c_imx_trx_complete(void)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 	int timeout = I2C_MAX_TIMEOUT;
 
-	while (!(readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout)
+	while (timeout--) {
+		if (readb(&i2c_regs->i2sr) & I2SR_IIF) {
+			writeb(0, &i2c_regs->i2sr);
+			return 0;
+		}
+
 		udelay(1);
-	writew(0, I2C_BASE + I2SR); /* clear interrupt */
+	}
 
-	return timeout;
+	return 1;
 }
 
-static int wait_complete(void)
+/*
+ * Check if the transaction was ACKed
+ */
+int i2c_imx_acked(void)
 {
-	int timeout = I2C_MAX_TIMEOUT;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 
-	while ((!(readw(I2C_BASE + I2SR) & I2SR_ICF)) && (--timeout)) {
-		writew(0, I2C_BASE + I2SR);
-		udelay(1);
-	}
-	udelay(200);
+	return readb(&i2c_regs->i2sr) & I2SR_RX_NO_AK;
+}
 
-	writew(0, I2C_BASE + I2SR);	/* clear interrupt */
+/*
+ * Start the controller
+ */
+int i2c_imx_start(void)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp = 0;
+	int result;
 
-	return timeout;
-}
+	writeb(clk_idx, &i2c_regs->ifdr);
 
+	/* Enable I2C controller */
+	writeb(0, &i2c_regs->i2sr);
+	writeb(I2CR_IEN, &i2c_regs->i2cr);
 
-static int tx_byte(u8 byte)
-{
-	writew(byte, I2C_BASE + I2DR);
+	/* Wait controller to be stable */
+	udelay(50);
+
+	/* Start I2C transaction */
+	temp = readb(&i2c_regs->i2cr);
+	temp |= I2CR_MSTA;
+	writeb(temp, &i2c_regs->i2cr);
+
+	result = i2c_imx_bus_busy(1);
+	if (result)
+		return result;
+
+	temp |= I2CR_MTX | I2CR_TX_NO_AK;
+	writeb(temp, &i2c_regs->i2cr);
 
-	if (!wait_complete() || readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)
-		return -1;
 	return 0;
 }
 
-static int rx_byte(int last)
+/*
+ * Stop the controller
+ */
+void i2c_imx_stop()
 {
-	if (!wait_complete())
-		return -1;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp = 0;
+
+	/* Stop I2C transaction */
+	temp = readb(&i2c_regs->i2cr);
+	temp |= ~(I2CR_MSTA | I2CR_MTX);
+	writeb(temp, &i2c_regs->i2cr);
 
-	if (last)
-		writew(I2CR_IEN, I2C_BASE + I2CR);
+	i2c_imx_bus_busy(0);
 
-	return readw(I2C_BASE + I2DR);
+	/* Disable I2C controller */
+	writeb(0, &i2c_regs->i2cr);
 }
 
-int i2c_probe(uchar chip)
+/*
+ * Set chip address and access mode
+ *
+ * read = 1: READ access
+ * read = 0: WRITE access
+ */
+int i2c_imx_set_chip_addr(uchar chip, int read)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 	int ret;
 
-	writew(0, I2C_BASE + I2CR); /* Reset module */
-	writew(I2CR_IEN, I2C_BASE + I2CR);
+	writeb((chip << 1) | read, &i2c_regs->i2dr);
+
+	ret = i2c_imx_trx_complete();
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN |  I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);
-	ret = tx_byte(chip << 1);
-	writew(I2CR_IEN | I2CR_MTX, I2C_BASE + I2CR);
+	ret = i2c_imx_acked();
+	if (ret)
+		return ret;
 
 	return ret;
 }
 
-static int i2c_addr(uchar chip, uint addr, int alen)
+/*
+ * Write register address
+ */
+int i2c_imx_set_reg_addr(uint addr, int alen)
 {
-	int i, retry = 0;
-	for (retry = 0; retry < 3; retry++) {
-		if (wait_idle())
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	int i;
+
+	for (i = 0; i < (8 * alen); i += 8) {
+		writeb((addr >> i) & 0xff, &i2c_regs->i2dr);
+
+		ret = i2c_imx_trx_complete();
+		if (ret)
 			break;
-		i2c_reset();
-		for (i = 0; i < I2C_MAX_TIMEOUT; i++)
-			udelay(1);
-	}
-	if (retry >= I2C_MAX_RETRIES) {
-		debug("%s:bus is busy(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
-	}
-	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);
 
-	if (!wait_busy()) {
-		debug("%s:trigger start fail(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
+		ret = i2c_imx_acked();
+		if (ret)
+			break;
 	}
 
-	if (tx_byte(chip << 1) || (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) {
-		debug("%s:chip address cycle fail(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
-	}
-	while (alen--)
-		if (tx_byte((addr >> (alen * 8)) & 0xff) ||
-		    (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) {
-			debug("%s:device address cycle fail(%x)\n",
-			       __func__, readw(I2C_BASE + I2SR));
-			return -1;
-		}
-	return 0;
+	return ret;
 }
 
-int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+/*
+ * Try if a chip add given address responds (probe the chip)
+ */
+int i2c_probe(uchar chip)
 {
-	int timeout = I2C_MAX_TIMEOUT;
 	int ret;
 
-	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
-		__func__, chip, addr, alen, len);
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
 
-	if (i2c_addr(chip, addr, alen)) {
-		printf("i2c_addr failed\n");
-		return -1;
-	}
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX | I2CR_RSTA, I2C_BASE + I2CR);
+	i2c_imx_stop();
 
-	if (tx_byte(chip << 1 | 1))
-		return -1;
+	return ret;
+}
 
-	writew(I2CR_IEN | I2CR_MSTA |
-		((len == 1) ? I2CR_TX_NO_AK : 0),
-		I2C_BASE + I2CR);
+/*
+ * Read data from I2C device
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	unsigned int temp;
+	int i;
 
-	ret = readw(I2C_BASE + I2DR);
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
+
+	/* write slave address */
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
+
+	ret = i2c_imx_set_reg_addr(addr, alen);
+	if (ret)
+		return ret;
+
+	temp = readb(&i2c_regs->i2cr);
+	temp |= I2CR_RSTA;
+	writeb(temp, &i2c_regs->i2cr);
+
+	ret = i2c_imx_set_chip_addr(chip, 1);
+	if (ret)
+		return ret;
+
+	/* setup bus to read data */
+	temp = readb(&i2c_regs->i2cr);
+	temp &= ~I2CR_MTX;
+	if (len == 1)
+		temp &= ~I2CR_TX_NO_AK;
+	writeb(temp, &i2c_regs->i2cr);
+	readb(&i2c_regs->i2dr);
+
+	/* read data */
+	for (i = 0; i < len; i++) {
+		ret = i2c_imx_trx_complete();
+		if (ret)
+			return ret;
+
+		/*
+		 * It must generate STOP before read I2DR to prevent
+		 * controller from generating another clock cycle
+		 */
+		if (i == (len - 1)) {
+			temp = readb(&i2c_regs->i2cr);
+			temp &= ~(I2CR_MSTA | I2CR_MTX);
+			writeb(temp, &i2c_regs->i2cr);
+			i2c_imx_bus_busy(0);
+		} else if (i == (len - 2)) {
+			temp = readb(&i2c_regs->i2cr);
+			temp |= I2CR_TX_NO_AK;
+			writeb(temp, &i2c_regs->i2cr);
+		}
 
-	while (len--) {
-		ret = rx_byte(len == 0);
-		if (ret  < 0)
-			return -1;
-		*buf++ = ret;
-		if (len <= 1)
-			writew(I2CR_IEN | I2CR_MSTA |
-				I2CR_TX_NO_AK,
-				I2C_BASE + I2CR);
+		buf[i] = readb(&i2c_regs->i2dr);
 	}
 
-	writew(I2CR_IEN, I2C_BASE + I2CR);
-
-	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
-		udelay(1);
+	i2c_imx_stop();
 
-	return 0;
+	return ret;
 }
 
+/*
+ * Write data to I2C device
+ */
 int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
 {
-	int timeout = I2C_MAX_TIMEOUT;
-	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
-		__func__, chip, addr, alen, len);
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	unsigned int temp;
+	int i;
 
-	if (i2c_addr(chip, addr, alen))
-		return -1;
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
 
-	while (len--)
-		if (tx_byte(*buf++))
-			return -1;
+	/* write slave address */
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN, I2C_BASE + I2CR);
+	ret = i2c_imx_set_reg_addr(addr, alen);
+	if (ret)
+		return ret;
 
-	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
-		udelay(1);
+	for (i = 0; i < len; i++) {
+		writeb(buf[i], &i2c_regs->i2dr);
 
-	return 0;
-}
+		ret = i2c_imx_trx_complete();
+		if (ret)
+			return ret;
+
+		ret = i2c_imx_acked();
+		if (ret)
+			return ret;
+	}
 
+	i2c_imx_stop();
+
+	return ret;
+}
 #endif /* CONFIG_HARD_I2C */
-- 
1.7.5.4

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

* [U-Boot] [PATCH 4/4 V2] I2C: mxc_i2c rework
  2011-09-15  0:09 ` [U-Boot] [PATCH 4/4] I2C: mxc_i2c rework Marek Vasut
@ 2011-09-15  4:16   ` Marek Vasut
  2011-09-19  6:13     ` Heiko Schocher
  2011-09-20  2:30     ` [U-Boot] [PATCH 4/4 V3] " Marek Vasut
  2011-09-19 10:11   ` [U-Boot] [PATCH 4/4] " Stefano Babic
  1 sibling, 2 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-15  4:16 UTC (permalink / raw)
  To: u-boot

Rewrite the mxc_i2c driver.
 * This version is much closer to Linux implementation.
 * Fixes IPG_PERCLK being incorrectly used as clock source
 * Fixes behaviour of the driver on iMX51
 * Clean up coding style a bit ;-)

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
---
 drivers/i2c/mxc_i2c.c |  423 +++++++++++++++++++++++++++++++++----------------
 1 files changed, 290 insertions(+), 133 deletions(-)

V2: Use PERCLK as a source.

diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index ebde3c5..c817f9f 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -1,7 +1,15 @@
 /*
- * i2c driver for Freescale mx31
+ * i2c driver for Freescale i.MX series
  *
  * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (c) 2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on i2c-imx.c from linux kernel:
+ *  Copyright (C) 2005 Torsten Koschorrek <koschorrek@synertronixx.de>
+ *  Copyright (C) 2005 Matthias Blaschke <blaschke@synertronixx.de>
+ *  Copyright (C) 2007 RightHand Technologies, Inc.
+ *  Copyright (C) 2008 Darius Augulis <darius.augulis@teltonika.lt>
+ *
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -30,11 +38,13 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/imx-regs.h>
 
-#define IADR	0x00
-#define IFDR	0x04
-#define I2CR	0x08
-#define I2SR	0x0c
-#define I2DR	0x10
+struct mxc_i2c_regs {
+	uint32_t	iadr;
+	uint32_t	ifdr;
+	uint32_t	i2cr;
+	uint32_t	i2sr;
+	uint32_t	i2dr;
+};
 
 #define I2CR_IEN	(1 << 7)
 #define I2CR_IIEN	(1 << 6)
@@ -68,215 +78,362 @@
 #endif
 
 #define I2C_MAX_TIMEOUT		10000
-#define I2C_MAX_RETRIES		3
 
-static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144,
-	             160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960,
-	             1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840};
+static u16 i2c_clk_div[50][2] = {
+	{ 22,	0x20 }, { 24,	0x21 }, { 26,	0x22 }, { 28,	0x23 },
+	{ 30,	0x00 }, { 32,	0x24 }, { 36,	0x25 }, { 40,	0x26 },
+	{ 42,	0x03 }, { 44,	0x27 }, { 48,	0x28 }, { 52,	0x05 },
+	{ 56,	0x29 }, { 60,	0x06 }, { 64,	0x2A }, { 72,	0x2B },
+	{ 80,	0x2C }, { 88,	0x09 }, { 96,	0x2D }, { 104,	0x0A },
+	{ 112,	0x2E }, { 128,	0x2F }, { 144,	0x0C }, { 160,	0x30 },
+	{ 192,	0x31 }, { 224,	0x32 }, { 240,	0x0F }, { 256,	0x33 },
+	{ 288,	0x10 }, { 320,	0x34 }, { 384,	0x35 }, { 448,	0x36 },
+	{ 480,	0x13 }, { 512,	0x37 }, { 576,	0x14 }, { 640,	0x38 },
+	{ 768,	0x39 }, { 896,	0x3A }, { 960,	0x17 }, { 1024,	0x3B },
+	{ 1152,	0x18 }, { 1280,	0x3C }, { 1536,	0x3D }, { 1792,	0x3E },
+	{ 1920,	0x1B }, { 2048,	0x3F }, { 2304,	0x1C }, { 2560,	0x1D },
+	{ 3072,	0x1E }, { 3840,	0x1F }
+};
+
+static u8 clk_idx;
 
-static inline void i2c_reset(void)
-{
-	writew(0, I2C_BASE + I2CR);	/* Reset module */
-	writew(0, I2C_BASE + I2SR);
-	writew(I2CR_IEN, I2C_BASE + I2CR);
-}
-
-void i2c_init(int speed, int unused)
+/*
+ * Calculate and set proper clock divider
+ */
+static void i2c_imx_set_clk(unsigned int rate)
 {
-	int freq;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int i2c_clk_rate;
+	unsigned int div;
 	int i;
 
 #if defined(CONFIG_MX31)
 	struct clock_control_regs *sc_regs =
 		(struct clock_control_regs *)CCM_BASE;
+
 	/* start the required I2C clock */
 	writel(readl(&sc_regs->cgr0) | (3 << I2C_CLK_OFFSET),
 		&sc_regs->cgr0);
 #endif
-	freq = mxc_get_clock(MXC_IPG_PERCLK);
 
-	for (i = 0; i < 0x1f; i++)
-		if (freq / div[i] <= speed)
-			break;
+	/* Divider value calculation */
+	i2c_clk_rate = mxc_get_clock(MXC_IPG_PERCLK);
+	div = (i2c_clk_rate + rate - 1) / rate;
+	if (div < i2c_clk_div[0][0])
+		i = 0;
+	else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
+		i = ARRAY_SIZE(i2c_clk_div) - 1;
+	else
+		for (i = 0; i2c_clk_div[i][0] < div; i++)
+			;
+
+	/* Store divider value */
+	clk_idx = i2c_clk_div[i][1];
+	writeb(clk_idx, &i2c_regs->ifdr);
+}
 
-	debug("%s: speed: %d\n", __func__, speed);
+/*
+ * Reset I2C Controller
+ */
+void i2c_reset(void)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+
+	writeb(0, &i2c_regs->i2cr);	/* Reset module */
+	writeb(0, &i2c_regs->i2sr);
+}
 
-	writew(i, I2C_BASE + IFDR);
+/*
+ * Init I2C Bus
+ */
+void i2c_init(int speed, int unused)
+{
+	i2c_imx_set_clk(speed);
 	i2c_reset();
 }
 
-static int wait_idle(void)
+/*
+ * Wait for bus to be busy (or free if for_busy = 0)
+ *
+ * for_busy = 1: Wait for IBB to be asserted
+ * for_busy = 0: Wait for IBB to be de-asserted
+ */
+int i2c_imx_bus_busy(int for_busy)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp;
+
 	int timeout = I2C_MAX_TIMEOUT;
 
-	while ((readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout) {
-		writew(0, I2C_BASE + I2SR);
+	while (timeout--) {
+		temp = readb(&i2c_regs->i2sr);
+
+		if (for_busy && (temp & I2SR_IBB))
+			return 0;
+		if (!for_busy && !(temp & I2SR_IBB))
+			return 0;
+
 		udelay(1);
 	}
-	return timeout ? timeout : (!(readw(I2C_BASE + I2SR) & I2SR_IBB));
+
+	return 1;
 }
 
-static int wait_busy(void)
+/*
+ * Wait for transaction to complete
+ */
+int i2c_imx_trx_complete(void)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 	int timeout = I2C_MAX_TIMEOUT;
 
-	while (!(readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout)
+	while (timeout--) {
+		if (readb(&i2c_regs->i2sr) & I2SR_IIF) {
+			writeb(0, &i2c_regs->i2sr);
+			return 0;
+		}
+
 		udelay(1);
-	writew(0, I2C_BASE + I2SR); /* clear interrupt */
+	}
 
-	return timeout;
+	return 1;
 }
 
-static int wait_complete(void)
+/*
+ * Check if the transaction was ACKed
+ */
+int i2c_imx_acked(void)
 {
-	int timeout = I2C_MAX_TIMEOUT;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 
-	while ((!(readw(I2C_BASE + I2SR) & I2SR_ICF)) && (--timeout)) {
-		writew(0, I2C_BASE + I2SR);
-		udelay(1);
-	}
-	udelay(200);
+	return readb(&i2c_regs->i2sr) & I2SR_RX_NO_AK;
+}
 
-	writew(0, I2C_BASE + I2SR);	/* clear interrupt */
+/*
+ * Start the controller
+ */
+int i2c_imx_start(void)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp = 0;
+	int result;
 
-	return timeout;
-}
+	writeb(clk_idx, &i2c_regs->ifdr);
 
+	/* Enable I2C controller */
+	writeb(0, &i2c_regs->i2sr);
+	writeb(I2CR_IEN, &i2c_regs->i2cr);
 
-static int tx_byte(u8 byte)
-{
-	writew(byte, I2C_BASE + I2DR);
+	/* Wait controller to be stable */
+	udelay(50);
+
+	/* Start I2C transaction */
+	temp = readb(&i2c_regs->i2cr);
+	temp |= I2CR_MSTA;
+	writeb(temp, &i2c_regs->i2cr);
+
+	result = i2c_imx_bus_busy(1);
+	if (result)
+		return result;
+
+	temp |= I2CR_MTX | I2CR_TX_NO_AK;
+	writeb(temp, &i2c_regs->i2cr);
 
-	if (!wait_complete() || readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)
-		return -1;
 	return 0;
 }
 
-static int rx_byte(int last)
+/*
+ * Stop the controller
+ */
+void i2c_imx_stop()
 {
-	if (!wait_complete())
-		return -1;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp = 0;
+
+	/* Stop I2C transaction */
+	temp = readb(&i2c_regs->i2cr);
+	temp |= ~(I2CR_MSTA | I2CR_MTX);
+	writeb(temp, &i2c_regs->i2cr);
 
-	if (last)
-		writew(I2CR_IEN, I2C_BASE + I2CR);
+	i2c_imx_bus_busy(0);
 
-	return readw(I2C_BASE + I2DR);
+	/* Disable I2C controller */
+	writeb(0, &i2c_regs->i2cr);
 }
 
-int i2c_probe(uchar chip)
+/*
+ * Set chip address and access mode
+ *
+ * read = 1: READ access
+ * read = 0: WRITE access
+ */
+int i2c_imx_set_chip_addr(uchar chip, int read)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 	int ret;
 
-	writew(0, I2C_BASE + I2CR); /* Reset module */
-	writew(I2CR_IEN, I2C_BASE + I2CR);
+	writeb((chip << 1) | read, &i2c_regs->i2dr);
+
+	ret = i2c_imx_trx_complete();
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN |  I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);
-	ret = tx_byte(chip << 1);
-	writew(I2CR_IEN | I2CR_MTX, I2C_BASE + I2CR);
+	ret = i2c_imx_acked();
+	if (ret)
+		return ret;
 
 	return ret;
 }
 
-static int i2c_addr(uchar chip, uint addr, int alen)
+/*
+ * Write register address
+ */
+int i2c_imx_set_reg_addr(uint addr, int alen)
 {
-	int i, retry = 0;
-	for (retry = 0; retry < 3; retry++) {
-		if (wait_idle())
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	int i;
+
+	for (i = 0; i < (8 * alen); i += 8) {
+		writeb((addr >> i) & 0xff, &i2c_regs->i2dr);
+
+		ret = i2c_imx_trx_complete();
+		if (ret)
 			break;
-		i2c_reset();
-		for (i = 0; i < I2C_MAX_TIMEOUT; i++)
-			udelay(1);
-	}
-	if (retry >= I2C_MAX_RETRIES) {
-		debug("%s:bus is busy(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
-	}
-	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);
 
-	if (!wait_busy()) {
-		debug("%s:trigger start fail(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
+		ret = i2c_imx_acked();
+		if (ret)
+			break;
 	}
 
-	if (tx_byte(chip << 1) || (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) {
-		debug("%s:chip address cycle fail(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
-	}
-	while (alen--)
-		if (tx_byte((addr >> (alen * 8)) & 0xff) ||
-		    (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) {
-			debug("%s:device address cycle fail(%x)\n",
-			       __func__, readw(I2C_BASE + I2SR));
-			return -1;
-		}
-	return 0;
+	return ret;
 }
 
-int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+/*
+ * Try if a chip add given address responds (probe the chip)
+ */
+int i2c_probe(uchar chip)
 {
-	int timeout = I2C_MAX_TIMEOUT;
 	int ret;
 
-	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
-		__func__, chip, addr, alen, len);
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
 
-	if (i2c_addr(chip, addr, alen)) {
-		printf("i2c_addr failed\n");
-		return -1;
-	}
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX | I2CR_RSTA, I2C_BASE + I2CR);
+	i2c_imx_stop();
 
-	if (tx_byte(chip << 1 | 1))
-		return -1;
+	return ret;
+}
 
-	writew(I2CR_IEN | I2CR_MSTA |
-		((len == 1) ? I2CR_TX_NO_AK : 0),
-		I2C_BASE + I2CR);
+/*
+ * Read data from I2C device
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	unsigned int temp;
+	int i;
 
-	ret = readw(I2C_BASE + I2DR);
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
+
+	/* write slave address */
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
+
+	ret = i2c_imx_set_reg_addr(addr, alen);
+	if (ret)
+		return ret;
+
+	temp = readb(&i2c_regs->i2cr);
+	temp |= I2CR_RSTA;
+	writeb(temp, &i2c_regs->i2cr);
+
+	ret = i2c_imx_set_chip_addr(chip, 1);
+	if (ret)
+		return ret;
+
+	/* setup bus to read data */
+	temp = readb(&i2c_regs->i2cr);
+	temp &= ~I2CR_MTX;
+	if (len == 1)
+		temp &= ~I2CR_TX_NO_AK;
+	writeb(temp, &i2c_regs->i2cr);
+	readb(&i2c_regs->i2dr);
+
+	/* read data */
+	for (i = 0; i < len; i++) {
+		ret = i2c_imx_trx_complete();
+		if (ret)
+			return ret;
+
+		/*
+		 * It must generate STOP before read I2DR to prevent
+		 * controller from generating another clock cycle
+		 */
+		if (i == (len - 1)) {
+			temp = readb(&i2c_regs->i2cr);
+			temp &= ~(I2CR_MSTA | I2CR_MTX);
+			writeb(temp, &i2c_regs->i2cr);
+			i2c_imx_bus_busy(0);
+		} else if (i == (len - 2)) {
+			temp = readb(&i2c_regs->i2cr);
+			temp |= I2CR_TX_NO_AK;
+			writeb(temp, &i2c_regs->i2cr);
+		}
 
-	while (len--) {
-		ret = rx_byte(len == 0);
-		if (ret  < 0)
-			return -1;
-		*buf++ = ret;
-		if (len <= 1)
-			writew(I2CR_IEN | I2CR_MSTA |
-				I2CR_TX_NO_AK,
-				I2C_BASE + I2CR);
+		buf[i] = readb(&i2c_regs->i2dr);
 	}
 
-	writew(I2CR_IEN, I2C_BASE + I2CR);
-
-	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
-		udelay(1);
+	i2c_imx_stop();
 
-	return 0;
+	return ret;
 }
 
+/*
+ * Write data to I2C device
+ */
 int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
 {
-	int timeout = I2C_MAX_TIMEOUT;
-	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
-		__func__, chip, addr, alen, len);
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	unsigned int temp;
+	int i;
 
-	if (i2c_addr(chip, addr, alen))
-		return -1;
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
 
-	while (len--)
-		if (tx_byte(*buf++))
-			return -1;
+	/* write slave address */
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN, I2C_BASE + I2CR);
+	ret = i2c_imx_set_reg_addr(addr, alen);
+	if (ret)
+		return ret;
 
-	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
-		udelay(1);
+	for (i = 0; i < len; i++) {
+		writeb(buf[i], &i2c_regs->i2dr);
 
-	return 0;
-}
+		ret = i2c_imx_trx_complete();
+		if (ret)
+			return ret;
+
+		ret = i2c_imx_acked();
+		if (ret)
+			return ret;
+	}
 
+	i2c_imx_stop();
+
+	return ret;
+}
 #endif /* CONFIG_HARD_I2C */
-- 
1.7.5.4

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

* [U-Boot] [PATCH 4/4 V2] I2C: mxc_i2c rework
  2011-09-15  4:16   ` [U-Boot] [PATCH 4/4 V2] " Marek Vasut
@ 2011-09-19  6:13     ` Heiko Schocher
  2011-09-20  2:30     ` [U-Boot] [PATCH 4/4 V3] " Marek Vasut
  1 sibling, 0 replies; 34+ messages in thread
From: Heiko Schocher @ 2011-09-19  6:13 UTC (permalink / raw)
  To: u-boot

Hello Marek,

Marek Vasut wrote:
> Rewrite the mxc_i2c driver.
>  * This version is much closer to Linux implementation.
>  * Fixes IPG_PERCLK being incorrectly used as clock source
>  * Fixes behaviour of the driver on iMX51
>  * Clean up coding style a bit ;-)
> 
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> ---
>  drivers/i2c/mxc_i2c.c |  423 +++++++++++++++++++++++++++++++++----------------
>  1 files changed, 290 insertions(+), 133 deletions(-)
> 
> V2: Use PERCLK as a source.

Acked-by: Heiko Schocher <hs@denx.de>

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

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

* [U-Boot] [PATCH 3/4] MX5: Clean up the output of "clocks" command
  2011-09-15  0:09 ` [U-Boot] [PATCH 3/4] MX5: Clean up the output of "clocks" command Marek Vasut
@ 2011-09-19 10:03   ` Stefano Babic
  2011-09-22  1:58   ` Jason Hui
  1 sibling, 0 replies; 34+ messages in thread
From: Stefano Babic @ 2011-09-19 10:03 UTC (permalink / raw)
  To: u-boot

On 09/15/2011 02:09 AM, Marek Vasut wrote:
> The new output looks like this:
>> clocks
> PLL1            800 MHz
> PLL2            665 MHz
> PLL3            216 MHz
> 
> AHB          133000 kHz
> IPG           66500 kHz
> IPG PERCLK   665000 kHz
> 
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> ---

Thanks cleaning up !

Acked-by: Stefano Babic <sbabic@denx.de>

Best regards,
Stefano Babic

-- 
=====================================================================
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
=====================================================================

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

* [U-Boot] [PATCH 4/4] I2C: mxc_i2c rework
  2011-09-15  0:09 ` [U-Boot] [PATCH 4/4] I2C: mxc_i2c rework Marek Vasut
  2011-09-15  4:16   ` [U-Boot] [PATCH 4/4 V2] " Marek Vasut
@ 2011-09-19 10:11   ` Stefano Babic
  2011-09-19 10:24     ` Marek Vasut
  2011-09-20 10:07     ` Jason Liu
  1 sibling, 2 replies; 34+ messages in thread
From: Stefano Babic @ 2011-09-19 10:11 UTC (permalink / raw)
  To: u-boot

On 09/15/2011 02:09 AM, Marek Vasut wrote:
> Rewrite the mxc_i2c driver.
>  * This version is much closer to Linux implementation.
>  * Fixes IPG_PERCLK being incorrectly used as clock source
>  * Fixes behaviour of the driver on iMX51
>  * Clean up coding style a bit ;-)
> 
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> ---

Hi Marek,

you miss to set the version number of your patchset. This can confuse
us, as confuses patchwork.

Jason, do you have any issue with the last version of this patch (again,
without version number, sent by Marek last 15/9) ? I saw Heiko's ACK in
a previous version, but I won't push if some boards/SOC will be broken
by this patchset. Any comments ?

Best regards,
Stefano Babic

-- 
=====================================================================
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
=====================================================================

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

* [U-Boot] [PATCH 4/4] I2C: mxc_i2c rework
  2011-09-19 10:11   ` [U-Boot] [PATCH 4/4] " Stefano Babic
@ 2011-09-19 10:24     ` Marek Vasut
  2011-09-20 10:07     ` Jason Liu
  1 sibling, 0 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-19 10:24 UTC (permalink / raw)
  To: u-boot

On Monday, September 19, 2011 12:11:55 PM Stefano Babic wrote:
> On 09/15/2011 02:09 AM, Marek Vasut wrote:
> > Rewrite the mxc_i2c driver.
> > 
> >  * This version is much closer to Linux implementation.
> >  * Fixes IPG_PERCLK being incorrectly used as clock source
> >  * Fixes behaviour of the driver on iMX51
> >  * Clean up coding style a bit ;-)
> > 
> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> > ---
> 
> Hi Marek,
> 
> you miss to set the version number of your patchset. This can confuse
> us, as confuses patchwork.

Oh damn ... sorry. I'll do better next time ;-)

> 
> Jason, do you have any issue with the last version of this patch (again,
> without version number, sent by Marek last 15/9) ? I saw Heiko's ACK in
> a previous version, but I won't push if some boards/SOC will be broken
> by this patchset. Any comments ?

I think this one was acked by Heiko today too.

Cheers

> 
> Best regards,
> Stefano Babic

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

* [U-Boot] [PATCH 4/4 V3] I2C: mxc_i2c rework
  2011-09-15  4:16   ` [U-Boot] [PATCH 4/4 V2] " Marek Vasut
  2011-09-19  6:13     ` Heiko Schocher
@ 2011-09-20  2:30     ` Marek Vasut
  2011-09-20  2:35       ` [U-Boot] [PATCH 4/4 V4] " Marek Vasut
  1 sibling, 1 reply; 34+ messages in thread
From: Marek Vasut @ 2011-09-20  2:30 UTC (permalink / raw)
  To: u-boot

Rewrite the mxc_i2c driver.
 * This version is much closer to Linux implementation.
 * Fixes IPG_PERCLK being incorrectly used as clock source
 * Fixes behaviour of the driver on iMX51
 * Clean up coding style a bit ;-)

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
---
 drivers/i2c/mxc_i2c.c |  422 +++++++++++++++++++++++++++++++++----------------
 1 files changed, 289 insertions(+), 133 deletions(-)

V2: Use PERCLK as a source.

V3: Remove forgotten unused variables.

diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index ebde3c5..75052e5 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -1,7 +1,15 @@
 /*
- * i2c driver for Freescale mx31
+ * i2c driver for Freescale i.MX series
  *
  * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (c) 2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on i2c-imx.c from linux kernel:
+ *  Copyright (C) 2005 Torsten Koschorrek <koschorrek@synertronixx.de>
+ *  Copyright (C) 2005 Matthias Blaschke <blaschke@synertronixx.de>
+ *  Copyright (C) 2007 RightHand Technologies, Inc.
+ *  Copyright (C) 2008 Darius Augulis <darius.augulis@teltonika.lt>
+ *
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -30,11 +38,13 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/imx-regs.h>
 
-#define IADR	0x00
-#define IFDR	0x04
-#define I2CR	0x08
-#define I2SR	0x0c
-#define I2DR	0x10
+struct mxc_i2c_regs {
+	uint32_t	iadr;
+	uint32_t	ifdr;
+	uint32_t	i2cr;
+	uint32_t	i2sr;
+	uint32_t	i2dr;
+};
 
 #define I2CR_IEN	(1 << 7)
 #define I2CR_IIEN	(1 << 6)
@@ -68,215 +78,361 @@
 #endif
 
 #define I2C_MAX_TIMEOUT		10000
-#define I2C_MAX_RETRIES		3
 
-static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144,
-	             160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960,
-	             1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840};
+static u16 i2c_clk_div[50][2] = {
+	{ 22,	0x20 }, { 24,	0x21 }, { 26,	0x22 }, { 28,	0x23 },
+	{ 30,	0x00 }, { 32,	0x24 }, { 36,	0x25 }, { 40,	0x26 },
+	{ 42,	0x03 }, { 44,	0x27 }, { 48,	0x28 }, { 52,	0x05 },
+	{ 56,	0x29 }, { 60,	0x06 }, { 64,	0x2A }, { 72,	0x2B },
+	{ 80,	0x2C }, { 88,	0x09 }, { 96,	0x2D }, { 104,	0x0A },
+	{ 112,	0x2E }, { 128,	0x2F }, { 144,	0x0C }, { 160,	0x30 },
+	{ 192,	0x31 }, { 224,	0x32 }, { 240,	0x0F }, { 256,	0x33 },
+	{ 288,	0x10 }, { 320,	0x34 }, { 384,	0x35 }, { 448,	0x36 },
+	{ 480,	0x13 }, { 512,	0x37 }, { 576,	0x14 }, { 640,	0x38 },
+	{ 768,	0x39 }, { 896,	0x3A }, { 960,	0x17 }, { 1024,	0x3B },
+	{ 1152,	0x18 }, { 1280,	0x3C }, { 1536,	0x3D }, { 1792,	0x3E },
+	{ 1920,	0x1B }, { 2048,	0x3F }, { 2304,	0x1C }, { 2560,	0x1D },
+	{ 3072,	0x1E }, { 3840,	0x1F }
+};
+
+static u8 clk_idx;
 
-static inline void i2c_reset(void)
-{
-	writew(0, I2C_BASE + I2CR);	/* Reset module */
-	writew(0, I2C_BASE + I2SR);
-	writew(I2CR_IEN, I2C_BASE + I2CR);
-}
-
-void i2c_init(int speed, int unused)
+/*
+ * Calculate and set proper clock divider
+ */
+static void i2c_imx_set_clk(unsigned int rate)
 {
-	int freq;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int i2c_clk_rate;
+	unsigned int div;
 	int i;
 
 #if defined(CONFIG_MX31)
 	struct clock_control_regs *sc_regs =
 		(struct clock_control_regs *)CCM_BASE;
+
 	/* start the required I2C clock */
 	writel(readl(&sc_regs->cgr0) | (3 << I2C_CLK_OFFSET),
 		&sc_regs->cgr0);
 #endif
-	freq = mxc_get_clock(MXC_IPG_PERCLK);
 
-	for (i = 0; i < 0x1f; i++)
-		if (freq / div[i] <= speed)
-			break;
+	/* Divider value calculation */
+	i2c_clk_rate = mxc_get_clock(MXC_IPG_PERCLK);
+	div = (i2c_clk_rate + rate - 1) / rate;
+	if (div < i2c_clk_div[0][0])
+		i = 0;
+	else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
+		i = ARRAY_SIZE(i2c_clk_div) - 1;
+	else
+		for (i = 0; i2c_clk_div[i][0] < div; i++)
+			;
+
+	/* Store divider value */
+	clk_idx = i2c_clk_div[i][1];
+	writeb(clk_idx, &i2c_regs->ifdr);
+}
 
-	debug("%s: speed: %d\n", __func__, speed);
+/*
+ * Reset I2C Controller
+ */
+void i2c_reset(void)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+
+	writeb(0, &i2c_regs->i2cr);	/* Reset module */
+	writeb(0, &i2c_regs->i2sr);
+}
 
-	writew(i, I2C_BASE + IFDR);
+/*
+ * Init I2C Bus
+ */
+void i2c_init(int speed, int unused)
+{
+	i2c_imx_set_clk(speed);
 	i2c_reset();
 }
 
-static int wait_idle(void)
+/*
+ * Wait for bus to be busy (or free if for_busy = 0)
+ *
+ * for_busy = 1: Wait for IBB to be asserted
+ * for_busy = 0: Wait for IBB to be de-asserted
+ */
+int i2c_imx_bus_busy(int for_busy)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp;
+
 	int timeout = I2C_MAX_TIMEOUT;
 
-	while ((readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout) {
-		writew(0, I2C_BASE + I2SR);
+	while (timeout--) {
+		temp = readb(&i2c_regs->i2sr);
+
+		if (for_busy && (temp & I2SR_IBB))
+			return 0;
+		if (!for_busy && !(temp & I2SR_IBB))
+			return 0;
+
 		udelay(1);
 	}
-	return timeout ? timeout : (!(readw(I2C_BASE + I2SR) & I2SR_IBB));
+
+	return 1;
 }
 
-static int wait_busy(void)
+/*
+ * Wait for transaction to complete
+ */
+int i2c_imx_trx_complete(void)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 	int timeout = I2C_MAX_TIMEOUT;
 
-	while (!(readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout)
+	while (timeout--) {
+		if (readb(&i2c_regs->i2sr) & I2SR_IIF) {
+			writeb(0, &i2c_regs->i2sr);
+			return 0;
+		}
+
 		udelay(1);
-	writew(0, I2C_BASE + I2SR); /* clear interrupt */
+	}
 
-	return timeout;
+	return 1;
 }
 
-static int wait_complete(void)
+/*
+ * Check if the transaction was ACKed
+ */
+int i2c_imx_acked(void)
 {
-	int timeout = I2C_MAX_TIMEOUT;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 
-	while ((!(readw(I2C_BASE + I2SR) & I2SR_ICF)) && (--timeout)) {
-		writew(0, I2C_BASE + I2SR);
-		udelay(1);
-	}
-	udelay(200);
+	return readb(&i2c_regs->i2sr) & I2SR_RX_NO_AK;
+}
 
-	writew(0, I2C_BASE + I2SR);	/* clear interrupt */
+/*
+ * Start the controller
+ */
+int i2c_imx_start(void)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp = 0;
+	int result;
 
-	return timeout;
-}
+	writeb(clk_idx, &i2c_regs->ifdr);
 
+	/* Enable I2C controller */
+	writeb(0, &i2c_regs->i2sr);
+	writeb(I2CR_IEN, &i2c_regs->i2cr);
 
-static int tx_byte(u8 byte)
-{
-	writew(byte, I2C_BASE + I2DR);
+	/* Wait controller to be stable */
+	udelay(50);
+
+	/* Start I2C transaction */
+	temp = readb(&i2c_regs->i2cr);
+	temp |= I2CR_MSTA;
+	writeb(temp, &i2c_regs->i2cr);
+
+	result = i2c_imx_bus_busy(1);
+	if (result)
+		return result;
+
+	temp |= I2CR_MTX | I2CR_TX_NO_AK;
+	writeb(temp, &i2c_regs->i2cr);
 
-	if (!wait_complete() || readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)
-		return -1;
 	return 0;
 }
 
-static int rx_byte(int last)
+/*
+ * Stop the controller
+ */
+void i2c_imx_stop(void)
 {
-	if (!wait_complete())
-		return -1;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp = 0;
+
+	/* Stop I2C transaction */
+	temp = readb(&i2c_regs->i2cr);
+	temp |= ~(I2CR_MSTA | I2CR_MTX);
+	writeb(temp, &i2c_regs->i2cr);
 
-	if (last)
-		writew(I2CR_IEN, I2C_BASE + I2CR);
+	i2c_imx_bus_busy(0);
 
-	return readw(I2C_BASE + I2DR);
+	/* Disable I2C controller */
+	writeb(0, &i2c_regs->i2cr);
 }
 
-int i2c_probe(uchar chip)
+/*
+ * Set chip address and access mode
+ *
+ * read = 1: READ access
+ * read = 0: WRITE access
+ */
+int i2c_imx_set_chip_addr(uchar chip, int read)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 	int ret;
 
-	writew(0, I2C_BASE + I2CR); /* Reset module */
-	writew(I2CR_IEN, I2C_BASE + I2CR);
+	writeb((chip << 1) | read, &i2c_regs->i2dr);
+
+	ret = i2c_imx_trx_complete();
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN |  I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);
-	ret = tx_byte(chip << 1);
-	writew(I2CR_IEN | I2CR_MTX, I2C_BASE + I2CR);
+	ret = i2c_imx_acked();
+	if (ret)
+		return ret;
 
 	return ret;
 }
 
-static int i2c_addr(uchar chip, uint addr, int alen)
+/*
+ * Write register address
+ */
+int i2c_imx_set_reg_addr(uint addr, int alen)
 {
-	int i, retry = 0;
-	for (retry = 0; retry < 3; retry++) {
-		if (wait_idle())
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	int i;
+
+	for (i = 0; i < (8 * alen); i += 8) {
+		writeb((addr >> i) & 0xff, &i2c_regs->i2dr);
+
+		ret = i2c_imx_trx_complete();
+		if (ret)
 			break;
-		i2c_reset();
-		for (i = 0; i < I2C_MAX_TIMEOUT; i++)
-			udelay(1);
-	}
-	if (retry >= I2C_MAX_RETRIES) {
-		debug("%s:bus is busy(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
-	}
-	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);
 
-	if (!wait_busy()) {
-		debug("%s:trigger start fail(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
+		ret = i2c_imx_acked();
+		if (ret)
+			break;
 	}
 
-	if (tx_byte(chip << 1) || (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) {
-		debug("%s:chip address cycle fail(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
-	}
-	while (alen--)
-		if (tx_byte((addr >> (alen * 8)) & 0xff) ||
-		    (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) {
-			debug("%s:device address cycle fail(%x)\n",
-			       __func__, readw(I2C_BASE + I2SR));
-			return -1;
-		}
-	return 0;
+	return ret;
 }
 
-int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+/*
+ * Try if a chip add given address responds (probe the chip)
+ */
+int i2c_probe(uchar chip)
 {
-	int timeout = I2C_MAX_TIMEOUT;
 	int ret;
 
-	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
-		__func__, chip, addr, alen, len);
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
 
-	if (i2c_addr(chip, addr, alen)) {
-		printf("i2c_addr failed\n");
-		return -1;
-	}
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX | I2CR_RSTA, I2C_BASE + I2CR);
+	i2c_imx_stop();
 
-	if (tx_byte(chip << 1 | 1))
-		return -1;
+	return ret;
+}
 
-	writew(I2CR_IEN | I2CR_MSTA |
-		((len == 1) ? I2CR_TX_NO_AK : 0),
-		I2C_BASE + I2CR);
+/*
+ * Read data from I2C device
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	unsigned int temp;
+	int i;
 
-	ret = readw(I2C_BASE + I2DR);
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
+
+	/* write slave address */
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
+
+	ret = i2c_imx_set_reg_addr(addr, alen);
+	if (ret)
+		return ret;
+
+	temp = readb(&i2c_regs->i2cr);
+	temp |= I2CR_RSTA;
+	writeb(temp, &i2c_regs->i2cr);
+
+	ret = i2c_imx_set_chip_addr(chip, 1);
+	if (ret)
+		return ret;
+
+	/* setup bus to read data */
+	temp = readb(&i2c_regs->i2cr);
+	temp &= ~I2CR_MTX;
+	if (len == 1)
+		temp &= ~I2CR_TX_NO_AK;
+	writeb(temp, &i2c_regs->i2cr);
+	readb(&i2c_regs->i2dr);
+
+	/* read data */
+	for (i = 0; i < len; i++) {
+		ret = i2c_imx_trx_complete();
+		if (ret)
+			return ret;
+
+		/*
+		 * It must generate STOP before read I2DR to prevent
+		 * controller from generating another clock cycle
+		 */
+		if (i == (len - 1)) {
+			temp = readb(&i2c_regs->i2cr);
+			temp &= ~(I2CR_MSTA | I2CR_MTX);
+			writeb(temp, &i2c_regs->i2cr);
+			i2c_imx_bus_busy(0);
+		} else if (i == (len - 2)) {
+			temp = readb(&i2c_regs->i2cr);
+			temp |= I2CR_TX_NO_AK;
+			writeb(temp, &i2c_regs->i2cr);
+		}
 
-	while (len--) {
-		ret = rx_byte(len == 0);
-		if (ret  < 0)
-			return -1;
-		*buf++ = ret;
-		if (len <= 1)
-			writew(I2CR_IEN | I2CR_MSTA |
-				I2CR_TX_NO_AK,
-				I2C_BASE + I2CR);
+		buf[i] = readb(&i2c_regs->i2dr);
 	}
 
-	writew(I2CR_IEN, I2C_BASE + I2CR);
-
-	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
-		udelay(1);
+	i2c_imx_stop();
 
-	return 0;
+	return ret;
 }
 
+/*
+ * Write data to I2C device
+ */
 int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
 {
-	int timeout = I2C_MAX_TIMEOUT;
-	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
-		__func__, chip, addr, alen, len);
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	int i;
 
-	if (i2c_addr(chip, addr, alen))
-		return -1;
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
 
-	while (len--)
-		if (tx_byte(*buf++))
-			return -1;
+	/* write slave address */
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN, I2C_BASE + I2CR);
+	ret = i2c_imx_set_reg_addr(addr, alen);
+	if (ret)
+		return ret;
 
-	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
-		udelay(1);
+	for (i = 0; i < len; i++) {
+		writeb(buf[i], &i2c_regs->i2dr);
 
-	return 0;
-}
+		ret = i2c_imx_trx_complete();
+		if (ret)
+			return ret;
+
+		ret = i2c_imx_acked();
+		if (ret)
+			return ret;
+	}
 
+	i2c_imx_stop();
+
+	return ret;
+}
 #endif /* CONFIG_HARD_I2C */
-- 
1.7.5.4

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

* [U-Boot] [PATCH 4/4 V4] I2C: mxc_i2c rework
  2011-09-20  2:30     ` [U-Boot] [PATCH 4/4 V3] " Marek Vasut
@ 2011-09-20  2:35       ` Marek Vasut
  2011-09-22  2:45         ` Jason Hui
  2011-09-22 19:22         ` [U-Boot] [PATCH 4/4 V5] " Marek Vasut
  0 siblings, 2 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-20  2:35 UTC (permalink / raw)
  To: u-boot

Rewrite the mxc_i2c driver.
 * This version is much closer to Linux implementation.
 * Fixes IPG_PERCLK being incorrectly used as clock source
 * Fixes behaviour of the driver on iMX51
 * Clean up coding style a bit ;-)

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Cc: Stefano Babic <sbabic@denx.de>
Cc: Heiko Schocher <hs@denx.de>
Cc: Jason Hui <jason.hui@linaro.org>
---
 drivers/i2c/mxc_i2c.c |  422 +++++++++++++++++++++++++++++++++----------------
 1 files changed, 289 insertions(+), 133 deletions(-)

V2: Use PERCLK as a source.

V3: Remove forgotten unused variables.

V4: Add missing Cc field to commit message

diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index ebde3c5..75052e5 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -1,7 +1,15 @@
 /*
- * i2c driver for Freescale mx31
+ * i2c driver for Freescale i.MX series
  *
  * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (c) 2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on i2c-imx.c from linux kernel:
+ *  Copyright (C) 2005 Torsten Koschorrek <koschorrek@synertronixx.de>
+ *  Copyright (C) 2005 Matthias Blaschke <blaschke@synertronixx.de>
+ *  Copyright (C) 2007 RightHand Technologies, Inc.
+ *  Copyright (C) 2008 Darius Augulis <darius.augulis@teltonika.lt>
+ *
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -30,11 +38,13 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/imx-regs.h>
 
-#define IADR	0x00
-#define IFDR	0x04
-#define I2CR	0x08
-#define I2SR	0x0c
-#define I2DR	0x10
+struct mxc_i2c_regs {
+	uint32_t	iadr;
+	uint32_t	ifdr;
+	uint32_t	i2cr;
+	uint32_t	i2sr;
+	uint32_t	i2dr;
+};
 
 #define I2CR_IEN	(1 << 7)
 #define I2CR_IIEN	(1 << 6)
@@ -68,215 +78,361 @@
 #endif
 
 #define I2C_MAX_TIMEOUT		10000
-#define I2C_MAX_RETRIES		3
 
-static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144,
-	             160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960,
-	             1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840};
+static u16 i2c_clk_div[50][2] = {
+	{ 22,	0x20 }, { 24,	0x21 }, { 26,	0x22 }, { 28,	0x23 },
+	{ 30,	0x00 }, { 32,	0x24 }, { 36,	0x25 }, { 40,	0x26 },
+	{ 42,	0x03 }, { 44,	0x27 }, { 48,	0x28 }, { 52,	0x05 },
+	{ 56,	0x29 }, { 60,	0x06 }, { 64,	0x2A }, { 72,	0x2B },
+	{ 80,	0x2C }, { 88,	0x09 }, { 96,	0x2D }, { 104,	0x0A },
+	{ 112,	0x2E }, { 128,	0x2F }, { 144,	0x0C }, { 160,	0x30 },
+	{ 192,	0x31 }, { 224,	0x32 }, { 240,	0x0F }, { 256,	0x33 },
+	{ 288,	0x10 }, { 320,	0x34 }, { 384,	0x35 }, { 448,	0x36 },
+	{ 480,	0x13 }, { 512,	0x37 }, { 576,	0x14 }, { 640,	0x38 },
+	{ 768,	0x39 }, { 896,	0x3A }, { 960,	0x17 }, { 1024,	0x3B },
+	{ 1152,	0x18 }, { 1280,	0x3C }, { 1536,	0x3D }, { 1792,	0x3E },
+	{ 1920,	0x1B }, { 2048,	0x3F }, { 2304,	0x1C }, { 2560,	0x1D },
+	{ 3072,	0x1E }, { 3840,	0x1F }
+};
+
+static u8 clk_idx;
 
-static inline void i2c_reset(void)
-{
-	writew(0, I2C_BASE + I2CR);	/* Reset module */
-	writew(0, I2C_BASE + I2SR);
-	writew(I2CR_IEN, I2C_BASE + I2CR);
-}
-
-void i2c_init(int speed, int unused)
+/*
+ * Calculate and set proper clock divider
+ */
+static void i2c_imx_set_clk(unsigned int rate)
 {
-	int freq;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int i2c_clk_rate;
+	unsigned int div;
 	int i;
 
 #if defined(CONFIG_MX31)
 	struct clock_control_regs *sc_regs =
 		(struct clock_control_regs *)CCM_BASE;
+
 	/* start the required I2C clock */
 	writel(readl(&sc_regs->cgr0) | (3 << I2C_CLK_OFFSET),
 		&sc_regs->cgr0);
 #endif
-	freq = mxc_get_clock(MXC_IPG_PERCLK);
 
-	for (i = 0; i < 0x1f; i++)
-		if (freq / div[i] <= speed)
-			break;
+	/* Divider value calculation */
+	i2c_clk_rate = mxc_get_clock(MXC_IPG_PERCLK);
+	div = (i2c_clk_rate + rate - 1) / rate;
+	if (div < i2c_clk_div[0][0])
+		i = 0;
+	else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
+		i = ARRAY_SIZE(i2c_clk_div) - 1;
+	else
+		for (i = 0; i2c_clk_div[i][0] < div; i++)
+			;
+
+	/* Store divider value */
+	clk_idx = i2c_clk_div[i][1];
+	writeb(clk_idx, &i2c_regs->ifdr);
+}
 
-	debug("%s: speed: %d\n", __func__, speed);
+/*
+ * Reset I2C Controller
+ */
+void i2c_reset(void)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+
+	writeb(0, &i2c_regs->i2cr);	/* Reset module */
+	writeb(0, &i2c_regs->i2sr);
+}
 
-	writew(i, I2C_BASE + IFDR);
+/*
+ * Init I2C Bus
+ */
+void i2c_init(int speed, int unused)
+{
+	i2c_imx_set_clk(speed);
 	i2c_reset();
 }
 
-static int wait_idle(void)
+/*
+ * Wait for bus to be busy (or free if for_busy = 0)
+ *
+ * for_busy = 1: Wait for IBB to be asserted
+ * for_busy = 0: Wait for IBB to be de-asserted
+ */
+int i2c_imx_bus_busy(int for_busy)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp;
+
 	int timeout = I2C_MAX_TIMEOUT;
 
-	while ((readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout) {
-		writew(0, I2C_BASE + I2SR);
+	while (timeout--) {
+		temp = readb(&i2c_regs->i2sr);
+
+		if (for_busy && (temp & I2SR_IBB))
+			return 0;
+		if (!for_busy && !(temp & I2SR_IBB))
+			return 0;
+
 		udelay(1);
 	}
-	return timeout ? timeout : (!(readw(I2C_BASE + I2SR) & I2SR_IBB));
+
+	return 1;
 }
 
-static int wait_busy(void)
+/*
+ * Wait for transaction to complete
+ */
+int i2c_imx_trx_complete(void)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 	int timeout = I2C_MAX_TIMEOUT;
 
-	while (!(readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout)
+	while (timeout--) {
+		if (readb(&i2c_regs->i2sr) & I2SR_IIF) {
+			writeb(0, &i2c_regs->i2sr);
+			return 0;
+		}
+
 		udelay(1);
-	writew(0, I2C_BASE + I2SR); /* clear interrupt */
+	}
 
-	return timeout;
+	return 1;
 }
 
-static int wait_complete(void)
+/*
+ * Check if the transaction was ACKed
+ */
+int i2c_imx_acked(void)
 {
-	int timeout = I2C_MAX_TIMEOUT;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 
-	while ((!(readw(I2C_BASE + I2SR) & I2SR_ICF)) && (--timeout)) {
-		writew(0, I2C_BASE + I2SR);
-		udelay(1);
-	}
-	udelay(200);
+	return readb(&i2c_regs->i2sr) & I2SR_RX_NO_AK;
+}
 
-	writew(0, I2C_BASE + I2SR);	/* clear interrupt */
+/*
+ * Start the controller
+ */
+int i2c_imx_start(void)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp = 0;
+	int result;
 
-	return timeout;
-}
+	writeb(clk_idx, &i2c_regs->ifdr);
 
+	/* Enable I2C controller */
+	writeb(0, &i2c_regs->i2sr);
+	writeb(I2CR_IEN, &i2c_regs->i2cr);
 
-static int tx_byte(u8 byte)
-{
-	writew(byte, I2C_BASE + I2DR);
+	/* Wait controller to be stable */
+	udelay(50);
+
+	/* Start I2C transaction */
+	temp = readb(&i2c_regs->i2cr);
+	temp |= I2CR_MSTA;
+	writeb(temp, &i2c_regs->i2cr);
+
+	result = i2c_imx_bus_busy(1);
+	if (result)
+		return result;
+
+	temp |= I2CR_MTX | I2CR_TX_NO_AK;
+	writeb(temp, &i2c_regs->i2cr);
 
-	if (!wait_complete() || readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)
-		return -1;
 	return 0;
 }
 
-static int rx_byte(int last)
+/*
+ * Stop the controller
+ */
+void i2c_imx_stop(void)
 {
-	if (!wait_complete())
-		return -1;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp = 0;
+
+	/* Stop I2C transaction */
+	temp = readb(&i2c_regs->i2cr);
+	temp |= ~(I2CR_MSTA | I2CR_MTX);
+	writeb(temp, &i2c_regs->i2cr);
 
-	if (last)
-		writew(I2CR_IEN, I2C_BASE + I2CR);
+	i2c_imx_bus_busy(0);
 
-	return readw(I2C_BASE + I2DR);
+	/* Disable I2C controller */
+	writeb(0, &i2c_regs->i2cr);
 }
 
-int i2c_probe(uchar chip)
+/*
+ * Set chip address and access mode
+ *
+ * read = 1: READ access
+ * read = 0: WRITE access
+ */
+int i2c_imx_set_chip_addr(uchar chip, int read)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 	int ret;
 
-	writew(0, I2C_BASE + I2CR); /* Reset module */
-	writew(I2CR_IEN, I2C_BASE + I2CR);
+	writeb((chip << 1) | read, &i2c_regs->i2dr);
+
+	ret = i2c_imx_trx_complete();
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN |  I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);
-	ret = tx_byte(chip << 1);
-	writew(I2CR_IEN | I2CR_MTX, I2C_BASE + I2CR);
+	ret = i2c_imx_acked();
+	if (ret)
+		return ret;
 
 	return ret;
 }
 
-static int i2c_addr(uchar chip, uint addr, int alen)
+/*
+ * Write register address
+ */
+int i2c_imx_set_reg_addr(uint addr, int alen)
 {
-	int i, retry = 0;
-	for (retry = 0; retry < 3; retry++) {
-		if (wait_idle())
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	int i;
+
+	for (i = 0; i < (8 * alen); i += 8) {
+		writeb((addr >> i) & 0xff, &i2c_regs->i2dr);
+
+		ret = i2c_imx_trx_complete();
+		if (ret)
 			break;
-		i2c_reset();
-		for (i = 0; i < I2C_MAX_TIMEOUT; i++)
-			udelay(1);
-	}
-	if (retry >= I2C_MAX_RETRIES) {
-		debug("%s:bus is busy(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
-	}
-	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);
 
-	if (!wait_busy()) {
-		debug("%s:trigger start fail(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
+		ret = i2c_imx_acked();
+		if (ret)
+			break;
 	}
 
-	if (tx_byte(chip << 1) || (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) {
-		debug("%s:chip address cycle fail(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
-	}
-	while (alen--)
-		if (tx_byte((addr >> (alen * 8)) & 0xff) ||
-		    (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) {
-			debug("%s:device address cycle fail(%x)\n",
-			       __func__, readw(I2C_BASE + I2SR));
-			return -1;
-		}
-	return 0;
+	return ret;
 }
 
-int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+/*
+ * Try if a chip add given address responds (probe the chip)
+ */
+int i2c_probe(uchar chip)
 {
-	int timeout = I2C_MAX_TIMEOUT;
 	int ret;
 
-	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
-		__func__, chip, addr, alen, len);
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
 
-	if (i2c_addr(chip, addr, alen)) {
-		printf("i2c_addr failed\n");
-		return -1;
-	}
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX | I2CR_RSTA, I2C_BASE + I2CR);
+	i2c_imx_stop();
 
-	if (tx_byte(chip << 1 | 1))
-		return -1;
+	return ret;
+}
 
-	writew(I2CR_IEN | I2CR_MSTA |
-		((len == 1) ? I2CR_TX_NO_AK : 0),
-		I2C_BASE + I2CR);
+/*
+ * Read data from I2C device
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	unsigned int temp;
+	int i;
 
-	ret = readw(I2C_BASE + I2DR);
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
+
+	/* write slave address */
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
+
+	ret = i2c_imx_set_reg_addr(addr, alen);
+	if (ret)
+		return ret;
+
+	temp = readb(&i2c_regs->i2cr);
+	temp |= I2CR_RSTA;
+	writeb(temp, &i2c_regs->i2cr);
+
+	ret = i2c_imx_set_chip_addr(chip, 1);
+	if (ret)
+		return ret;
+
+	/* setup bus to read data */
+	temp = readb(&i2c_regs->i2cr);
+	temp &= ~I2CR_MTX;
+	if (len == 1)
+		temp &= ~I2CR_TX_NO_AK;
+	writeb(temp, &i2c_regs->i2cr);
+	readb(&i2c_regs->i2dr);
+
+	/* read data */
+	for (i = 0; i < len; i++) {
+		ret = i2c_imx_trx_complete();
+		if (ret)
+			return ret;
+
+		/*
+		 * It must generate STOP before read I2DR to prevent
+		 * controller from generating another clock cycle
+		 */
+		if (i == (len - 1)) {
+			temp = readb(&i2c_regs->i2cr);
+			temp &= ~(I2CR_MSTA | I2CR_MTX);
+			writeb(temp, &i2c_regs->i2cr);
+			i2c_imx_bus_busy(0);
+		} else if (i == (len - 2)) {
+			temp = readb(&i2c_regs->i2cr);
+			temp |= I2CR_TX_NO_AK;
+			writeb(temp, &i2c_regs->i2cr);
+		}
 
-	while (len--) {
-		ret = rx_byte(len == 0);
-		if (ret  < 0)
-			return -1;
-		*buf++ = ret;
-		if (len <= 1)
-			writew(I2CR_IEN | I2CR_MSTA |
-				I2CR_TX_NO_AK,
-				I2C_BASE + I2CR);
+		buf[i] = readb(&i2c_regs->i2dr);
 	}
 
-	writew(I2CR_IEN, I2C_BASE + I2CR);
-
-	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
-		udelay(1);
+	i2c_imx_stop();
 
-	return 0;
+	return ret;
 }
 
+/*
+ * Write data to I2C device
+ */
 int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
 {
-	int timeout = I2C_MAX_TIMEOUT;
-	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
-		__func__, chip, addr, alen, len);
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	int i;
 
-	if (i2c_addr(chip, addr, alen))
-		return -1;
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
 
-	while (len--)
-		if (tx_byte(*buf++))
-			return -1;
+	/* write slave address */
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN, I2C_BASE + I2CR);
+	ret = i2c_imx_set_reg_addr(addr, alen);
+	if (ret)
+		return ret;
 
-	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
-		udelay(1);
+	for (i = 0; i < len; i++) {
+		writeb(buf[i], &i2c_regs->i2dr);
 
-	return 0;
-}
+		ret = i2c_imx_trx_complete();
+		if (ret)
+			return ret;
+
+		ret = i2c_imx_acked();
+		if (ret)
+			return ret;
+	}
 
+	i2c_imx_stop();
+
+	return ret;
+}
 #endif /* CONFIG_HARD_I2C */
-- 
1.7.5.4

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

* [U-Boot] [PATCH 4/4] I2C: mxc_i2c rework
  2011-09-19 10:11   ` [U-Boot] [PATCH 4/4] " Stefano Babic
  2011-09-19 10:24     ` Marek Vasut
@ 2011-09-20 10:07     ` Jason Liu
  1 sibling, 0 replies; 34+ messages in thread
From: Jason Liu @ 2011-09-20 10:07 UTC (permalink / raw)
  To: u-boot

Hi, Stefano,

2011/9/19 Stefano Babic <sbabic@denx.de>:
> On 09/15/2011 02:09 AM, Marek Vasut wrote:
>> Rewrite the mxc_i2c driver.
>> ?* This version is much closer to Linux implementation.
>> ?* Fixes IPG_PERCLK being incorrectly used as clock source
>> ?* Fixes behaviour of the driver on iMX51
>> ?* Clean up coding style a bit ;-)
>>
>> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
>> ---
>
> Hi Marek,
>
> you miss to set the version number of your patchset. This can confuse
> us, as confuses patchwork.
>
> Jason, do you have any issue with the last version of this patch (again,
> without version number, sent by Marek last 15/9) ? I saw Heiko's ACK in
> a previous version, but I won't push if some boards/SOC will be broken
> by this patchset. Any comments ?

I will give one test on the latest patch set (v4) tomorrow and send out the test
result. Sorry for the delay.

Jason

>
> Best regards,
> Stefano Babic
>
> --
> =====================================================================
> DENX Software Engineering GmbH, ? ? MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 ?Email: office at denx.de
> =====================================================================
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>

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

* [U-Boot] [PATCH 3/4] MX5: Clean up the output of "clocks" command
  2011-09-15  0:09 ` [U-Boot] [PATCH 3/4] MX5: Clean up the output of "clocks" command Marek Vasut
  2011-09-19 10:03   ` Stefano Babic
@ 2011-09-22  1:58   ` Jason Hui
  1 sibling, 0 replies; 34+ messages in thread
From: Jason Hui @ 2011-09-22  1:58 UTC (permalink / raw)
  To: u-boot

Hi, Marek,

On Thu, Sep 15, 2011 at 8:09 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> The new output looks like this:
>> clocks
> PLL1 ? ? ? ? ? ?800 MHz
> PLL2 ? ? ? ? ? ?665 MHz
> PLL3 ? ? ? ? ? ?216 MHz
>
> AHB ? ? ? ? ?133000 kHz
> IPG ? ? ? ? ? 66500 kHz
> IPG PERCLK ? 665000 kHz
>
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> ---
> ?arch/arm/cpu/armv7/mx5/clock.c | ? 16 +++++++++-------
> ?1 files changed, 9 insertions(+), 7 deletions(-)
>


Acked-by Jason Liu <Jason.hui@linaro.org>

Jason

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

* [U-Boot] [PATCH 4/4 V4] I2C: mxc_i2c rework
  2011-09-20  2:35       ` [U-Boot] [PATCH 4/4 V4] " Marek Vasut
@ 2011-09-22  2:45         ` Jason Hui
  2011-09-22  3:43           ` Marek Vasut
  2011-09-22 19:22         ` [U-Boot] [PATCH 4/4 V5] " Marek Vasut
  1 sibling, 1 reply; 34+ messages in thread
From: Jason Hui @ 2011-09-22  2:45 UTC (permalink / raw)
  To: u-boot

Hi, Marek,

On Tue, Sep 20, 2011 at 10:35 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Rewrite the mxc_i2c driver.
> ?* This version is much closer to Linux implementation.
> ?* Fixes IPG_PERCLK being incorrectly used as clock source
> ?* Fixes behaviour of the driver on iMX51
> ?* Clean up coding style a bit ;-)
>
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> Cc: Stefano Babic <sbabic@denx.de>
> Cc: Heiko Schocher <hs@denx.de>
> Cc: Jason Hui <jason.hui@linaro.org>
> ---
> ?drivers/i2c/mxc_i2c.c | ?422 +++++++++++++++++++++++++++++++++----------------
> ?1 files changed, 289 insertions(+), 133 deletions(-)
>
> V2: Use PERCLK as a source.
>
> V3: Remove forgotten unused variables.
>
> V4: Add missing Cc field to commit message
>

Test result on i.mx53evk, it shows that this patch does not work well,
here is the log:

MX53EVK U-Boot > pmic dump 10
PMIC ID: 0x0000ffff [Rev: unknown]

0x00: 0001ffff 00ffffff 0039ffff 0000ffff 00ffffff 0000ffff 0000ffff 0000ffff
0x08: 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff 0040ffff

Without the patch, i2c work well, here is the log:

MX53EVK U-Boot > pmic dump 10
PMIC ID: 0x000045d0 [Rev: 2.0]

0x00: 00015088 00ffffff 00395208 00004081 00fff7ff 0000401c 00000418 000045d0
0x08: 00000000 00000000 00000001 00000000 00000000 00000040 00000000 00400000

The source code is based on top of the latest master and then apply
your v4 patch on top of it.

commit 6dcee21ee3a809d4d99ab168593c0d15ea8d6df3
Author: Marek Vasut <marek.vasut@gmail.com>
Date:   Tue Sep 20 04:35:38 2011 +0200

    I2C: mxc_i2c rework

    Rewrite the mxc_i2c driver.
     * This version is much closer to Linux implementation.
     * Fixes IPG_PERCLK being incorrectly used as clock source
     * Fixes behaviour of the driver on iMX51
     * Clean up coding style a bit ;-)

    Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
    Cc: Stefano Babic <sbabic@denx.de>
    Cc: Heiko Schocher <hs@denx.de>
    Cc: Jason Hui <jason.hui@linaro.org>

commit 6478021f12db3e248b8b495dde02c51d05a38054
Author: Holger Brunck <holger.brunck@keymile.com>
Date:   Tue Sep 20 05:05:55 2011 +0000

    km/common: fix bug in IVM mac address access

    The MAC address stored in the inventory eeprom begins at offset 1.

    Signed-off-by: Holger Brunck <holger.brunck@keymile.com>
    Signed-off-by: Valentin Longchamp <valentin.longchamp@keymile.com>
    cc: Wolfgang Denk <wd@denx.de>


Did I missed something?

Jason

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

* [U-Boot] [PATCH 2/4] MX5: Add AHB clock reporting and fix IPG clock reporting
  2011-09-15  0:09 ` [U-Boot] [PATCH 2/4] MX5: Add AHB clock reporting and fix IPG clock reporting Marek Vasut
@ 2011-09-22  3:05   ` Jason Hui
  2011-09-22  3:41     ` Marek Vasut
  2011-09-22 19:20   ` [U-Boot] [PATCH 2/4 V2] " Marek Vasut
  1 sibling, 1 reply; 34+ messages in thread
From: Jason Hui @ 2011-09-22  3:05 UTC (permalink / raw)
  To: u-boot

Hi, Marek

On Thu, Sep 15, 2011 at 8:09 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> ---
> ?arch/arm/cpu/armv7/mx5/clock.c | ? 36 +++++++++++++++++++++++++++---------
> ?1 files changed, 27 insertions(+), 9 deletions(-)
>
> diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c
> index 9f37f7f..a9fe81c 100644
> --- a/arch/arm/cpu/armv7/mx5/clock.c
> +++ b/arch/arm/cpu/armv7/mx5/clock.c
> @@ -152,18 +152,35 @@ static u32 get_periph_clk(void)
> ?}
>
> ?/*
> + * Get the rate of ahb clock.
> + */
> +static u32 get_ahb_clk(void)
> +{
> + ? ? ? uint32_t freq, div, reg;
> +
> + ? ? ? freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
> +
> + ? ? ? reg = __raw_readl(&mxc_ccm->cbcdr);
> + ? ? ? div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
> + ? ? ? ? ? ? ? ? ? ? ? MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
> +
> + ? ? ? return freq / div;
> +}

This is not correct, ahb clock is not fixed-source from PLL2.

Currently implementation,we did not take care the ahb_bypass clock setting
and don't consider the lp-apm mode for main-bus clock input.

Jason Liu

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

* [U-Boot] [PATCH 1/4] MX5: Modify the PLL decoding algorithm
  2011-09-15  0:09 ` [U-Boot] [PATCH 1/4] MX5: Modify the PLL decoding algorithm Marek Vasut
@ 2011-09-22  3:20   ` Jason Hui
  2011-09-23  9:15     ` Stefano Babic
  2011-09-23  9:43   ` [U-Boot] [PATCH 1/4 V2] " Marek Vasut
  1 sibling, 1 reply; 34+ messages in thread
From: Jason Hui @ 2011-09-22  3:20 UTC (permalink / raw)
  To: u-boot

On Thu, Sep 15, 2011 at 8:09 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> The PLL decoding algorithm didn't take into account many configuration bits.
> Adjust it according to Linux kernel. Also, add PLL4 for MX53.
>
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> ---
> ?arch/arm/cpu/armv7/mx5/clock.c ? ? ? ? ? | ? 77 ++++++++++++++++++++++++++----
> ?arch/arm/include/asm/arch-mx5/imx-regs.h | ? ?3 +
> ?2 files changed, 70 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c
> index 00610a0..9f37f7f 100644
> --- a/arch/arm/cpu/armv7/mx5/clock.c
> +++ b/arch/arm/cpu/armv7/mx5/clock.c
> @@ -29,11 +29,13 @@
> ?#include <asm/arch/imx-regs.h>
> ?#include <asm/arch/crm_regs.h>
> ?#include <asm/arch/clock.h>
> +#include <div64.h>
>
> ?enum pll_clocks {
> ? ? ? ?PLL1_CLOCK = 0,
> ? ? ? ?PLL2_CLOCK,
> ? ? ? ?PLL3_CLOCK,
> + ? ? ? PLL4_CLOCK,
> ? ? ? ?PLL_CLOCKS,
> ?};
>
> @@ -41,25 +43,76 @@ struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
> ? ? ? ?[PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR,
> ? ? ? ?[PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR,
> ? ? ? ?[PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR,
> +#ifdef CONFIG_MX53
> + ? ? ? [PLL4_CLOCK] = (struct mxc_pll_reg *)PLL4_BASE_ADDR,
> +#endif
> ?};
>
> +#define ? ? ? ?MXC_DPLLC_CTL_HFSM ? ? ? ? ? ? ?(1 << 7)
> +#define ? ? ? ?MXC_DPLLC_CTL_DPDCK0_2_EN ? ? ? (1 << 12)
> +
> +#define ? ? ? ?MXC_DPLLC_OP_PDF_MASK ? ? ? ? ? 0xf
> +#define ? ? ? ?MXC_DPLLC_OP_MFI_MASK ? ? ? ? ? (0xf << 4)
> +#define ? ? ? ?MXC_DPLLC_OP_MFI_OFFSET ? ? ? ? 4
> +
> +#define ? ? ? ?MXC_DPLLC_MFD_MFD_MASK ? ? ? ? ?0x7ffffff
> +
> +#define ? ? ? ?MXC_DPLLC_MFN_MFN_MASK ? ? ? ? ?0x7ffffff

Can we put this stuff to crm_reg.h file?

> +
> ?struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
>
> ?/*
> - * Calculate the frequency of this pll.
> + * Calculate the frequency of PLLn.
> ?*/
> -static u32 decode_pll(struct mxc_pll_reg *pll, u32 infreq)
> +static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq)

I found that you prefer to using the uint32_t than u32? what's the
rule for u-boot? Wolfgang?

> ?{
> - ? ? ? u32 mfi, mfn, mfd, pd;
> + ? ? ? uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret;
> + ? ? ? uint64_t refclk, temp;
> + ? ? ? int32_t mfn_abs;
> +
> + ? ? ? ctrl = readl(&pll->ctrl);
> +
> + ? ? ? if (ctrl & MXC_DPLLC_CTL_HFSM) {
> + ? ? ? ? ? ? ? mfn = __raw_readl(&pll->hfs_mfn);
> + ? ? ? ? ? ? ? mfd = __raw_readl(&pll->hfs_mfd);
> + ? ? ? ? ? ? ? op = __raw_readl(&pll->hfs_op);
> + ? ? ? } else {
> + ? ? ? ? ? ? ? mfn = __raw_readl(&pll->mfn);
> + ? ? ? ? ? ? ? mfd = __raw_readl(&pll->mfd);
> + ? ? ? ? ? ? ? op = __raw_readl(&pll->op);
> + ? ? ? }
>
> - ? ? ? mfn = __raw_readl(&pll->mfn);
> - ? ? ? mfd = __raw_readl(&pll->mfd) + 1;
> - ? ? ? mfi = __raw_readl(&pll->op);
> - ? ? ? pd = (mfi ?& 0xF) + 1;
> - ? ? ? mfi = (mfi >> 4) & 0xF;
> - ? ? ? mfi = (mfi >= 5) ? mfi : 5;
> + ? ? ? mfd &= MXC_DPLLC_MFD_MFD_MASK;
> + ? ? ? mfn &= MXC_DPLLC_MFN_MFN_MASK;
> + ? ? ? pdf = op & MXC_DPLLC_OP_PDF_MASK;
> + ? ? ? mfi = (op & MXC_DPLLC_OP_MFI_MASK) >> MXC_DPLLC_OP_MFI_OFFSET;
> +
> + ? ? ? /* 21.2.3 */
> + ? ? ? if (mfi < 5)
> + ? ? ? ? ? ? ? mfi = 5;
> +
> + ? ? ? /* Sign extend */
> + ? ? ? if (mfn >= 0x04000000) {
> + ? ? ? ? ? ? ? mfn |= 0xfc000000;
> + ? ? ? ? ? ? ? mfn_abs = -mfn;
> + ? ? ? } else
> + ? ? ? ? ? ? ? mfn_abs = mfn;
> +
> + ? ? ? refclk = infreq * 2;
> + ? ? ? if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN)
> + ? ? ? ? ? ? ? refclk *= 2;
> +
> + ? ? ? refclk /= pdf + 1;
> + ? ? ? temp = refclk * mfn_abs;
> + ? ? ? do_div(temp, mfd + 1);
> + ? ? ? ret = refclk * mfi;
> +
> + ? ? ? if ((int)mfn < 0)
> + ? ? ? ? ? ? ? ret -= temp;
> + ? ? ? else
> + ? ? ? ? ? ? ? ret += temp;
>
> - ? ? ? return ((4 * (infreq / 1000) * (mfi * mfd + mfn)) / (mfd * pd)) * 1000;
> + ? ? ? return ret;
> ?}

This decode schema is correct. Thanks,

>
> ?/*
> @@ -279,6 +332,10 @@ int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> ? ? ? ?printf("pll2: %dMHz\n", freq / 1000000);
> ? ? ? ?freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
> ? ? ? ?printf("pll3: %dMHz\n", freq / 1000000);
> +#ifdef CONFIG_MX53
> + ? ? ? freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
> + ? ? ? printf("pll4: %dMHz\n", freq / 1000000);
> +#endif
> ? ? ? ?printf("ipg clock ? ? : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
> ? ? ? ?printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));

In fact, no one use PLL4 in u-boot. But I'm not against to put it in.

>
> diff --git a/arch/arm/include/asm/arch-mx5/imx-regs.h b/arch/arm/include/asm/arch-mx5/imx-regs.h
> index a4e680b..8a0f9e6 100644
> --- a/arch/arm/include/asm/arch-mx5/imx-regs.h
> +++ b/arch/arm/include/asm/arch-mx5/imx-regs.h
> @@ -100,6 +100,9 @@
> ?#define PLL1_BASE_ADDR ? ? ? ? (AIPS2_BASE_ADDR + 0x00080000)
> ?#define PLL2_BASE_ADDR ? ? ? ? (AIPS2_BASE_ADDR + 0x00084000)
> ?#define PLL3_BASE_ADDR ? ? ? ? (AIPS2_BASE_ADDR + 0x00088000)
> +#ifdef CONFIG_MX53
> +#define PLL4_BASE_ADDR ? ? ? ? (AIPS2_BASE_ADDR + 0x0008c000)
> +#endif
> ?#define AHBMAX_BASE_ADDR ? ? ? (AIPS2_BASE_ADDR + 0x00094000)
> ?#define IIM_BASE_ADDR ? ? ? ? ?(AIPS2_BASE_ADDR + 0x00098000)
> ?#define CSU_BASE_ADDR ? ? ? ? ?(AIPS2_BASE_ADDR + 0x0009C000)
> --

Tested on i.mx53evk, it outputs:

MX53EVK U-Boot > clocks
PLL1            800 MHz
PLL2            400 MHz
PLL3            216 MHz
PLL4            594 MHz

AHB          133333 kHz
IPG           66666 kHz
IPG PERCLK    20000 kHz


Test-by: Jason Liu <Jason.hui@linaro.org>

Jason Liu

> 1.7.5.4
>
>

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

* [U-Boot] [PATCH 2/4] MX5: Add AHB clock reporting and fix IPG clock reporting
  2011-09-22  3:05   ` Jason Hui
@ 2011-09-22  3:41     ` Marek Vasut
  2011-09-22  4:46       ` Jason Hui
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Vasut @ 2011-09-22  3:41 UTC (permalink / raw)
  To: u-boot

On Thursday, September 22, 2011 05:05:43 AM Jason Hui wrote:
> Hi, Marek
> 
> On Thu, Sep 15, 2011 at 8:09 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> > ---
> >  arch/arm/cpu/armv7/mx5/clock.c |   36
> > +++++++++++++++++++++++++++--------- 1 files changed, 27 insertions(+),
> > 9 deletions(-)
> > 
> > diff --git a/arch/arm/cpu/armv7/mx5/clock.c
> > b/arch/arm/cpu/armv7/mx5/clock.c index 9f37f7f..a9fe81c 100644
> > --- a/arch/arm/cpu/armv7/mx5/clock.c
> > +++ b/arch/arm/cpu/armv7/mx5/clock.c
> > @@ -152,18 +152,35 @@ static u32 get_periph_clk(void)
> >  }
> > 
> >  /*
> > + * Get the rate of ahb clock.
> > + */
> > +static u32 get_ahb_clk(void)
> > +{
> > +       uint32_t freq, div, reg;
> > +
> > +       freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
> > +
> > +       reg = __raw_readl(&mxc_ccm->cbcdr);
> > +       div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
> > +                       MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
> > +
> > +       return freq / div;
> > +}
> 
> This is not correct, ahb clock is not fixed-source from PLL2.
> 
> Currently implementation,we did not take care the ahb_bypass clock setting
> and don't consider the lp-apm mode for main-bus clock input.

There is no "current implementation". Besides, that's how the BootROM sets it up 
so until someone needs it, this is ok.

> 
> Jason Liu

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

* [U-Boot] [PATCH 4/4 V4] I2C: mxc_i2c rework
  2011-09-22  2:45         ` Jason Hui
@ 2011-09-22  3:43           ` Marek Vasut
  2011-09-22  4:54             ` Jason Hui
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Vasut @ 2011-09-22  3:43 UTC (permalink / raw)
  To: u-boot

On Thursday, September 22, 2011 04:45:20 AM Jason Hui wrote:
> Hi, Marek,
> 
> On Tue, Sep 20, 2011 at 10:35 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> > Rewrite the mxc_i2c driver.
> >  * This version is much closer to Linux implementation.
> >  * Fixes IPG_PERCLK being incorrectly used as clock source
> >  * Fixes behaviour of the driver on iMX51
> >  * Clean up coding style a bit ;-)
> > 
> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> > Cc: Stefano Babic <sbabic@denx.de>
> > Cc: Heiko Schocher <hs@denx.de>
> > Cc: Jason Hui <jason.hui@linaro.org>
> > ---
> >  drivers/i2c/mxc_i2c.c |  422
> > +++++++++++++++++++++++++++++++++---------------- 1 files changed, 289
> > insertions(+), 133 deletions(-)
> > 
> > V2: Use PERCLK as a source.
> > 
> > V3: Remove forgotten unused variables.
> > 
> > V4: Add missing Cc field to commit message
> 
> Test result on i.mx53evk, it shows that this patch does not work well,
> here is the log:
> 
> MX53EVK U-Boot > pmic dump 10
> PMIC ID: 0x0000ffff [Rev: unknown]
> 
> 0x00: 0001ffff 00ffffff 0039ffff 0000ffff 00ffffff 0000ffff 0000ffff
> 0000ffff 0x08: 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff
> 0000ffff 0040ffff
> 

It's strange, reading the registers with i2c md seems to work.

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

* [U-Boot] [PATCH 2/4] MX5: Add AHB clock reporting and fix IPG clock reporting
  2011-09-22  3:41     ` Marek Vasut
@ 2011-09-22  4:46       ` Jason Hui
  0 siblings, 0 replies; 34+ messages in thread
From: Jason Hui @ 2011-09-22  4:46 UTC (permalink / raw)
  To: u-boot

Hi, Marek,

On Thu, Sep 22, 2011 at 11:41 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> On Thursday, September 22, 2011 05:05:43 AM Jason Hui wrote:
>> Hi, Marek
>>
>> On Thu, Sep 15, 2011 at 8:09 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
>> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
>> > ---
>> > ?arch/arm/cpu/armv7/mx5/clock.c | ? 36
>> > +++++++++++++++++++++++++++--------- 1 files changed, 27 insertions(+),
>> > 9 deletions(-)
>> >
>> > diff --git a/arch/arm/cpu/armv7/mx5/clock.c
>> > b/arch/arm/cpu/armv7/mx5/clock.c index 9f37f7f..a9fe81c 100644
>> > --- a/arch/arm/cpu/armv7/mx5/clock.c
>> > +++ b/arch/arm/cpu/armv7/mx5/clock.c
>> > @@ -152,18 +152,35 @@ static u32 get_periph_clk(void)
>> > ?}
>> >
>> > ?/*
>> > + * Get the rate of ahb clock.
>> > + */
>> > +static u32 get_ahb_clk(void)
>> > +{
>> > + ? ? ? uint32_t freq, div, reg;
>> > +
>> > + ? ? ? freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
>> > +
>> > + ? ? ? reg = __raw_readl(&mxc_ccm->cbcdr);
>> > + ? ? ? div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
>> > + ? ? ? ? ? ? ? ? ? ? ? MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
>> > +
>> > + ? ? ? return freq / div;
>> > +}
>>
>> This is not correct, ahb clock is not fixed-source from PLL2.
>>
>> Currently implementation,we did not take care the ahb_bypass clock setting
>> and don't consider the lp-apm mode for main-bus clock input.
>
> There is no "current implementation".

The current implementation is for the get_periph_clk(..), anyway, the
abh clock should be:

ahb_clk = get_periph_clk()/ahb_pdof,
ipg_clk = ahb_clk/ipg_podf,


> Besides, that's how the BootROM sets it up
> so until someone needs it, this is ok.

u-boot still can change the BootROM setting.

Jason Liu
>
>>
>> Jason Liu
>

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

* [U-Boot] [PATCH 4/4 V4] I2C: mxc_i2c rework
  2011-09-22  3:43           ` Marek Vasut
@ 2011-09-22  4:54             ` Jason Hui
  2011-09-22  5:47               ` Marek Vasut
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Hui @ 2011-09-22  4:54 UTC (permalink / raw)
  To: u-boot

Hi, Marek,

On Thu, Sep 22, 2011 at 11:43 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> On Thursday, September 22, 2011 04:45:20 AM Jason Hui wrote:
>> Hi, Marek,
>>
>> On Tue, Sep 20, 2011 at 10:35 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
>> > Rewrite the mxc_i2c driver.
>> > ?* This version is much closer to Linux implementation.
>> > ?* Fixes IPG_PERCLK being incorrectly used as clock source
>> > ?* Fixes behaviour of the driver on iMX51
>> > ?* Clean up coding style a bit ;-)
>> >
>> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
>> > Cc: Stefano Babic <sbabic@denx.de>
>> > Cc: Heiko Schocher <hs@denx.de>
>> > Cc: Jason Hui <jason.hui@linaro.org>
>> > ---
>> > ?drivers/i2c/mxc_i2c.c | ?422
>> > +++++++++++++++++++++++++++++++++---------------- 1 files changed, 289
>> > insertions(+), 133 deletions(-)
>> >
>> > V2: Use PERCLK as a source.
>> >
>> > V3: Remove forgotten unused variables.
>> >
>> > V4: Add missing Cc field to commit message
>>
>> Test result on i.mx53evk, it shows that this patch does not work well,
>> here is the log:
>>
>> MX53EVK U-Boot > pmic dump 10
>> PMIC ID: 0x0000ffff [Rev: unknown]
>>
>> 0x00: 0001ffff 00ffffff 0039ffff 0000ffff 00ffffff 0000ffff 0000ffff
>> 0000ffff 0x08: 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff
>> 0000ffff 0040ffff
>>
>
> It's strange, reading the registers with i2c md seems to work.

Here is i2c md output:
MX53EVK U-Boot > i2c md 8 0
0000: 01 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................

seems not ok.

Jason Liu
>

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

* [U-Boot] [PATCH 4/4 V4] I2C: mxc_i2c rework
  2011-09-22  4:54             ` Jason Hui
@ 2011-09-22  5:47               ` Marek Vasut
  2011-09-22  6:49                 ` Jason Hui
  0 siblings, 1 reply; 34+ messages in thread
From: Marek Vasut @ 2011-09-22  5:47 UTC (permalink / raw)
  To: u-boot

On Thursday, September 22, 2011 06:54:22 AM Jason Hui wrote:
> Hi, Marek,
> 
> On Thu, Sep 22, 2011 at 11:43 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> > On Thursday, September 22, 2011 04:45:20 AM Jason Hui wrote:
> >> Hi, Marek,
> >> 
> >> On Tue, Sep 20, 2011 at 10:35 AM, Marek Vasut <marek.vasut@gmail.com> 
wrote:
> >> > Rewrite the mxc_i2c driver.
> >> >  * This version is much closer to Linux implementation.
> >> >  * Fixes IPG_PERCLK being incorrectly used as clock source
> >> >  * Fixes behaviour of the driver on iMX51
> >> >  * Clean up coding style a bit ;-)
> >> > 
> >> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> >> > Cc: Stefano Babic <sbabic@denx.de>
> >> > Cc: Heiko Schocher <hs@denx.de>
> >> > Cc: Jason Hui <jason.hui@linaro.org>
> >> > ---
> >> >  drivers/i2c/mxc_i2c.c |  422
> >> > +++++++++++++++++++++++++++++++++---------------- 1 files changed, 289
> >> > insertions(+), 133 deletions(-)
> >> > 
> >> > V2: Use PERCLK as a source.
> >> > 
> >> > V3: Remove forgotten unused variables.
> >> > 
> >> > V4: Add missing Cc field to commit message
> >> 
> >> Test result on i.mx53evk, it shows that this patch does not work well,
> >> here is the log:
> >> 
> >> MX53EVK U-Boot > pmic dump 10
> >> PMIC ID: 0x0000ffff [Rev: unknown]
> >> 
> >> 0x00: 0001ffff 00ffffff 0039ffff 0000ffff 00ffffff 0000ffff 0000ffff
> >> 0000ffff 0x08: 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff
> >> 0000ffff 0040ffff
> > 
> > It's strange, reading the registers with i2c md seems to work.
> 
> Here is i2c md output:
> MX53EVK U-Boot > i2c md 8 0
> 0000: 01 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
> 
> seems not ok.

8 seems certainly not ok since the pmic is at 0x48

> 
> Jason Liu

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

* [U-Boot] [PATCH 4/4 V4] I2C: mxc_i2c rework
  2011-09-22  5:47               ` Marek Vasut
@ 2011-09-22  6:49                 ` Jason Hui
  0 siblings, 0 replies; 34+ messages in thread
From: Jason Hui @ 2011-09-22  6:49 UTC (permalink / raw)
  To: u-boot

Hi, Marek,

On Thu, Sep 22, 2011 at 1:47 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> On Thursday, September 22, 2011 06:54:22 AM Jason Hui wrote:
>> Hi, Marek,
>>
>> On Thu, Sep 22, 2011 at 11:43 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
>> > On Thursday, September 22, 2011 04:45:20 AM Jason Hui wrote:
>> >> Hi, Marek,
>> >>
>> >> On Tue, Sep 20, 2011 at 10:35 AM, Marek Vasut <marek.vasut@gmail.com>
> wrote:
>> >> > Rewrite the mxc_i2c driver.
>> >> > ?* This version is much closer to Linux implementation.
>> >> > ?* Fixes IPG_PERCLK being incorrectly used as clock source
>> >> > ?* Fixes behaviour of the driver on iMX51
>> >> > ?* Clean up coding style a bit ;-)
>> >> >
>> >> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
>> >> > Cc: Stefano Babic <sbabic@denx.de>
>> >> > Cc: Heiko Schocher <hs@denx.de>
>> >> > Cc: Jason Hui <jason.hui@linaro.org>
>> >> > ---
>> >> > ?drivers/i2c/mxc_i2c.c | ?422
>> >> > +++++++++++++++++++++++++++++++++---------------- 1 files changed, 289
>> >> > insertions(+), 133 deletions(-)
>> >> >
>> >> > V2: Use PERCLK as a source.
>> >> >
>> >> > V3: Remove forgotten unused variables.
>> >> >
>> >> > V4: Add missing Cc field to commit message
>> >>
>> >> Test result on i.mx53evk, it shows that this patch does not work well,
>> >> here is the log:
>> >>
>> >> MX53EVK U-Boot > pmic dump 10
>> >> PMIC ID: 0x0000ffff [Rev: unknown]
>> >>
>> >> 0x00: 0001ffff 00ffffff 0039ffff 0000ffff 00ffffff 0000ffff 0000ffff
>> >> 0000ffff 0x08: 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff 0000ffff
>> >> 0000ffff 0040ffff
>> >
>> > It's strange, reading the registers with i2c md seems to work.
>>
>> Here is i2c md output:
>> MX53EVK U-Boot > i2c md 8 0
>> 0000: 01 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ? ?................
>>
>> seems not ok.
>
> 8 seems certainly not ok since the pmic is at 0x48

On mx53evk board, there is one PMIC(FSL, Atlas), but
on mx53loco board, there is one PMIC(DLG9053).

Both are I2C interface, I just test the patch on mx53evk board.

>
>>
>> Jason Liu
>

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

* [U-Boot] [PATCH 2/4 V2] MX5: Add AHB clock reporting and fix IPG clock reporting
  2011-09-15  0:09 ` [U-Boot] [PATCH 2/4] MX5: Add AHB clock reporting and fix IPG clock reporting Marek Vasut
  2011-09-22  3:05   ` Jason Hui
@ 2011-09-22 19:20   ` Marek Vasut
  2011-09-23  2:09     ` Jason Hui
  1 sibling, 1 reply; 34+ messages in thread
From: Marek Vasut @ 2011-09-22 19:20 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Cc: Stefano Babic <sbabic@denx.de>
Cc: Jason Hui <jason.hui@linaro.org>
---
 arch/arm/cpu/armv7/mx5/clock.c |   36 +++++++++++++++++++++++++++---------
 1 files changed, 27 insertions(+), 9 deletions(-)

V2: Use get_periph_clock() as AHB clocksource.

diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c
index 9f37f7f..b87b29e 100644
--- a/arch/arm/cpu/armv7/mx5/clock.c
+++ b/arch/arm/cpu/armv7/mx5/clock.c
@@ -152,18 +152,35 @@ static u32 get_periph_clk(void)
 }
 
 /*
+ * Get the rate of ahb clock.
+ */
+static u32 get_ahb_clk(void)
+{
+	uint32_t freq, div, reg;
+
+	freq = get_periph_clk();
+
+	reg = __raw_readl(&mxc_ccm->cbcdr);
+	div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
+			MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
+
+	return freq / div;
+}
+
+/*
  * Get the rate of ipg clock.
  */
 static u32 get_ipg_clk(void)
 {
-	u32 ahb_podf, ipg_podf;
-
-	ahb_podf = __raw_readl(&mxc_ccm->cbcdr);
-	ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
-			MXC_CCM_CBCDR_IPG_PODF_OFFSET;
-	ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
-			MXC_CCM_CBCDR_AHB_PODF_OFFSET;
-	return get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1));
+	uint32_t freq, reg, div;
+
+	freq = get_ahb_clk();
+
+	reg = __raw_readl(&mxc_ccm->cbcdr);
+	div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
+			MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1;
+
+	return freq / div;
 }
 
 /*
@@ -290,7 +307,7 @@ unsigned int mxc_get_clock(enum mxc_clock clk)
 	case MXC_ARM_CLK:
 		return get_mcu_main_clk();
 	case MXC_AHB_CLK:
-		break;
+		return get_ahb_clk();
 	case MXC_IPG_CLK:
 		return get_ipg_clk();
 	case MXC_IPG_PERCLK:
@@ -336,6 +353,7 @@ int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
 	printf("pll4: %dMHz\n", freq / 1000000);
 #endif
+	printf("ahb clock     : %dHz\n", mxc_get_clock(MXC_AHB_CLK));
 	printf("ipg clock     : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
 	printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
 
-- 
1.7.5.4

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

* [U-Boot] [PATCH 4/4 V5] I2C: mxc_i2c rework
  2011-09-20  2:35       ` [U-Boot] [PATCH 4/4 V4] " Marek Vasut
  2011-09-22  2:45         ` Jason Hui
@ 2011-09-22 19:22         ` Marek Vasut
  2011-09-23  3:32           ` Jason Hui
  2011-10-14 16:28           ` Anatolij Gustschin
  1 sibling, 2 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-22 19:22 UTC (permalink / raw)
  To: u-boot

Rewrite the mxc_i2c driver.
 * This version is much closer to Linux implementation.
 * Fixes IPG_PERCLK being incorrectly used as clock source
 * Fixes behaviour of the driver on iMX51
 * Clean up coding style a bit ;-)

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Cc: Stefano Babic <sbabic@denx.de>
Cc: Heiko Schocher <hs@denx.de>
Cc: Jason Hui <jason.hui@linaro.org>
---
 drivers/i2c/mxc_i2c.c |  422 +++++++++++++++++++++++++++++++++----------------
 1 files changed, 289 insertions(+), 133 deletions(-)

V2: Use PERCLK as a source.
V3: Remove forgotten unused variables.
V4: Add missing Cc field to commit message.
V5: Correct TX_NO_AK bit handling.

diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index ebde3c5..a805bf6 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -1,7 +1,15 @@
 /*
- * i2c driver for Freescale mx31
+ * i2c driver for Freescale i.MX series
  *
  * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ * (c) 2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on i2c-imx.c from linux kernel:
+ *  Copyright (C) 2005 Torsten Koschorrek <koschorrek@synertronixx.de>
+ *  Copyright (C) 2005 Matthias Blaschke <blaschke@synertronixx.de>
+ *  Copyright (C) 2007 RightHand Technologies, Inc.
+ *  Copyright (C) 2008 Darius Augulis <darius.augulis@teltonika.lt>
+ *
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -30,11 +38,13 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/imx-regs.h>
 
-#define IADR	0x00
-#define IFDR	0x04
-#define I2CR	0x08
-#define I2SR	0x0c
-#define I2DR	0x10
+struct mxc_i2c_regs {
+	uint32_t	iadr;
+	uint32_t	ifdr;
+	uint32_t	i2cr;
+	uint32_t	i2sr;
+	uint32_t	i2dr;
+};
 
 #define I2CR_IEN	(1 << 7)
 #define I2CR_IIEN	(1 << 6)
@@ -68,215 +78,361 @@
 #endif
 
 #define I2C_MAX_TIMEOUT		10000
-#define I2C_MAX_RETRIES		3
 
-static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144,
-	             160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960,
-	             1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840};
+static u16 i2c_clk_div[50][2] = {
+	{ 22,	0x20 }, { 24,	0x21 }, { 26,	0x22 }, { 28,	0x23 },
+	{ 30,	0x00 }, { 32,	0x24 }, { 36,	0x25 }, { 40,	0x26 },
+	{ 42,	0x03 }, { 44,	0x27 }, { 48,	0x28 }, { 52,	0x05 },
+	{ 56,	0x29 }, { 60,	0x06 }, { 64,	0x2A }, { 72,	0x2B },
+	{ 80,	0x2C }, { 88,	0x09 }, { 96,	0x2D }, { 104,	0x0A },
+	{ 112,	0x2E }, { 128,	0x2F }, { 144,	0x0C }, { 160,	0x30 },
+	{ 192,	0x31 }, { 224,	0x32 }, { 240,	0x0F }, { 256,	0x33 },
+	{ 288,	0x10 }, { 320,	0x34 }, { 384,	0x35 }, { 448,	0x36 },
+	{ 480,	0x13 }, { 512,	0x37 }, { 576,	0x14 }, { 640,	0x38 },
+	{ 768,	0x39 }, { 896,	0x3A }, { 960,	0x17 }, { 1024,	0x3B },
+	{ 1152,	0x18 }, { 1280,	0x3C }, { 1536,	0x3D }, { 1792,	0x3E },
+	{ 1920,	0x1B }, { 2048,	0x3F }, { 2304,	0x1C }, { 2560,	0x1D },
+	{ 3072,	0x1E }, { 3840,	0x1F }
+};
+
+static u8 clk_idx;
 
-static inline void i2c_reset(void)
-{
-	writew(0, I2C_BASE + I2CR);	/* Reset module */
-	writew(0, I2C_BASE + I2SR);
-	writew(I2CR_IEN, I2C_BASE + I2CR);
-}
-
-void i2c_init(int speed, int unused)
+/*
+ * Calculate and set proper clock divider
+ */
+static void i2c_imx_set_clk(unsigned int rate)
 {
-	int freq;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int i2c_clk_rate;
+	unsigned int div;
 	int i;
 
 #if defined(CONFIG_MX31)
 	struct clock_control_regs *sc_regs =
 		(struct clock_control_regs *)CCM_BASE;
+
 	/* start the required I2C clock */
 	writel(readl(&sc_regs->cgr0) | (3 << I2C_CLK_OFFSET),
 		&sc_regs->cgr0);
 #endif
-	freq = mxc_get_clock(MXC_IPG_PERCLK);
 
-	for (i = 0; i < 0x1f; i++)
-		if (freq / div[i] <= speed)
-			break;
+	/* Divider value calculation */
+	i2c_clk_rate = mxc_get_clock(MXC_IPG_PERCLK);
+	div = (i2c_clk_rate + rate - 1) / rate;
+	if (div < i2c_clk_div[0][0])
+		i = 0;
+	else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
+		i = ARRAY_SIZE(i2c_clk_div) - 1;
+	else
+		for (i = 0; i2c_clk_div[i][0] < div; i++)
+			;
+
+	/* Store divider value */
+	clk_idx = i2c_clk_div[i][1];
+	writeb(clk_idx, &i2c_regs->ifdr);
+}
 
-	debug("%s: speed: %d\n", __func__, speed);
+/*
+ * Reset I2C Controller
+ */
+void i2c_reset(void)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+
+	writeb(0, &i2c_regs->i2cr);	/* Reset module */
+	writeb(0, &i2c_regs->i2sr);
+}
 
-	writew(i, I2C_BASE + IFDR);
+/*
+ * Init I2C Bus
+ */
+void i2c_init(int speed, int unused)
+{
+	i2c_imx_set_clk(speed);
 	i2c_reset();
 }
 
-static int wait_idle(void)
+/*
+ * Wait for bus to be busy (or free if for_busy = 0)
+ *
+ * for_busy = 1: Wait for IBB to be asserted
+ * for_busy = 0: Wait for IBB to be de-asserted
+ */
+int i2c_imx_bus_busy(int for_busy)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp;
+
 	int timeout = I2C_MAX_TIMEOUT;
 
-	while ((readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout) {
-		writew(0, I2C_BASE + I2SR);
+	while (timeout--) {
+		temp = readb(&i2c_regs->i2sr);
+
+		if (for_busy && (temp & I2SR_IBB))
+			return 0;
+		if (!for_busy && !(temp & I2SR_IBB))
+			return 0;
+
 		udelay(1);
 	}
-	return timeout ? timeout : (!(readw(I2C_BASE + I2SR) & I2SR_IBB));
+
+	return 1;
 }
 
-static int wait_busy(void)
+/*
+ * Wait for transaction to complete
+ */
+int i2c_imx_trx_complete(void)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 	int timeout = I2C_MAX_TIMEOUT;
 
-	while (!(readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout)
+	while (timeout--) {
+		if (readb(&i2c_regs->i2sr) & I2SR_IIF) {
+			writeb(0, &i2c_regs->i2sr);
+			return 0;
+		}
+
 		udelay(1);
-	writew(0, I2C_BASE + I2SR); /* clear interrupt */
+	}
 
-	return timeout;
+	return 1;
 }
 
-static int wait_complete(void)
+/*
+ * Check if the transaction was ACKed
+ */
+int i2c_imx_acked(void)
 {
-	int timeout = I2C_MAX_TIMEOUT;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 
-	while ((!(readw(I2C_BASE + I2SR) & I2SR_ICF)) && (--timeout)) {
-		writew(0, I2C_BASE + I2SR);
-		udelay(1);
-	}
-	udelay(200);
+	return readb(&i2c_regs->i2sr) & I2SR_RX_NO_AK;
+}
 
-	writew(0, I2C_BASE + I2SR);	/* clear interrupt */
+/*
+ * Start the controller
+ */
+int i2c_imx_start(void)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp = 0;
+	int result;
 
-	return timeout;
-}
+	writeb(clk_idx, &i2c_regs->ifdr);
 
+	/* Enable I2C controller */
+	writeb(0, &i2c_regs->i2sr);
+	writeb(I2CR_IEN, &i2c_regs->i2cr);
 
-static int tx_byte(u8 byte)
-{
-	writew(byte, I2C_BASE + I2DR);
+	/* Wait controller to be stable */
+	udelay(50);
+
+	/* Start I2C transaction */
+	temp = readb(&i2c_regs->i2cr);
+	temp |= I2CR_MSTA;
+	writeb(temp, &i2c_regs->i2cr);
+
+	result = i2c_imx_bus_busy(1);
+	if (result)
+		return result;
+
+	temp |= I2CR_MTX | I2CR_TX_NO_AK;
+	writeb(temp, &i2c_regs->i2cr);
 
-	if (!wait_complete() || readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)
-		return -1;
 	return 0;
 }
 
-static int rx_byte(int last)
+/*
+ * Stop the controller
+ */
+void i2c_imx_stop(void)
 {
-	if (!wait_complete())
-		return -1;
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	unsigned int temp = 0;
+
+	/* Stop I2C transaction */
+	temp = readb(&i2c_regs->i2cr);
+	temp |= ~(I2CR_MSTA | I2CR_MTX);
+	writeb(temp, &i2c_regs->i2cr);
 
-	if (last)
-		writew(I2CR_IEN, I2C_BASE + I2CR);
+	i2c_imx_bus_busy(0);
 
-	return readw(I2C_BASE + I2DR);
+	/* Disable I2C controller */
+	writeb(0, &i2c_regs->i2cr);
 }
 
-int i2c_probe(uchar chip)
+/*
+ * Set chip address and access mode
+ *
+ * read = 1: READ access
+ * read = 0: WRITE access
+ */
+int i2c_imx_set_chip_addr(uchar chip, int read)
 {
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
 	int ret;
 
-	writew(0, I2C_BASE + I2CR); /* Reset module */
-	writew(I2CR_IEN, I2C_BASE + I2CR);
+	writeb((chip << 1) | read, &i2c_regs->i2dr);
+
+	ret = i2c_imx_trx_complete();
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN |  I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);
-	ret = tx_byte(chip << 1);
-	writew(I2CR_IEN | I2CR_MTX, I2C_BASE + I2CR);
+	ret = i2c_imx_acked();
+	if (ret)
+		return ret;
 
 	return ret;
 }
 
-static int i2c_addr(uchar chip, uint addr, int alen)
+/*
+ * Write register address
+ */
+int i2c_imx_set_reg_addr(uint addr, int alen)
 {
-	int i, retry = 0;
-	for (retry = 0; retry < 3; retry++) {
-		if (wait_idle())
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	int i;
+
+	for (i = 0; i < (8 * alen); i += 8) {
+		writeb((addr >> i) & 0xff, &i2c_regs->i2dr);
+
+		ret = i2c_imx_trx_complete();
+		if (ret)
 			break;
-		i2c_reset();
-		for (i = 0; i < I2C_MAX_TIMEOUT; i++)
-			udelay(1);
-	}
-	if (retry >= I2C_MAX_RETRIES) {
-		debug("%s:bus is busy(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
-	}
-	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);
 
-	if (!wait_busy()) {
-		debug("%s:trigger start fail(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
+		ret = i2c_imx_acked();
+		if (ret)
+			break;
 	}
 
-	if (tx_byte(chip << 1) || (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) {
-		debug("%s:chip address cycle fail(%x)\n",
-		       __func__, readw(I2C_BASE + I2SR));
-		return -1;
-	}
-	while (alen--)
-		if (tx_byte((addr >> (alen * 8)) & 0xff) ||
-		    (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) {
-			debug("%s:device address cycle fail(%x)\n",
-			       __func__, readw(I2C_BASE + I2SR));
-			return -1;
-		}
-	return 0;
+	return ret;
 }
 
-int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+/*
+ * Try if a chip add given address responds (probe the chip)
+ */
+int i2c_probe(uchar chip)
 {
-	int timeout = I2C_MAX_TIMEOUT;
 	int ret;
 
-	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
-		__func__, chip, addr, alen, len);
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
 
-	if (i2c_addr(chip, addr, alen)) {
-		printf("i2c_addr failed\n");
-		return -1;
-	}
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX | I2CR_RSTA, I2C_BASE + I2CR);
+	i2c_imx_stop();
 
-	if (tx_byte(chip << 1 | 1))
-		return -1;
+	return ret;
+}
 
-	writew(I2CR_IEN | I2CR_MSTA |
-		((len == 1) ? I2CR_TX_NO_AK : 0),
-		I2C_BASE + I2CR);
+/*
+ * Read data from I2C device
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	unsigned int temp;
+	int i;
 
-	ret = readw(I2C_BASE + I2DR);
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
+
+	/* write slave address */
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
+
+	ret = i2c_imx_set_reg_addr(addr, alen);
+	if (ret)
+		return ret;
+
+	temp = readb(&i2c_regs->i2cr);
+	temp |= I2CR_RSTA;
+	writeb(temp, &i2c_regs->i2cr);
+
+	ret = i2c_imx_set_chip_addr(chip, 1);
+	if (ret)
+		return ret;
+
+	/* setup bus to read data */
+	temp = readb(&i2c_regs->i2cr);
+	temp &= ~(I2CR_MTX | I2CR_TX_NO_AK);
+	if (len == 1)
+		temp |= I2CR_TX_NO_AK;
+	writeb(temp, &i2c_regs->i2cr);
+	readb(&i2c_regs->i2dr);
+
+	/* read data */
+	for (i = 0; i < len; i++) {
+		ret = i2c_imx_trx_complete();
+		if (ret)
+			return ret;
+
+		/*
+		 * It must generate STOP before read I2DR to prevent
+		 * controller from generating another clock cycle
+		 */
+		if (i == (len - 1)) {
+			temp = readb(&i2c_regs->i2cr);
+			temp &= ~(I2CR_MSTA | I2CR_MTX);
+			writeb(temp, &i2c_regs->i2cr);
+			i2c_imx_bus_busy(0);
+		} else if (i == (len - 2)) {
+			temp = readb(&i2c_regs->i2cr);
+			temp |= I2CR_TX_NO_AK;
+			writeb(temp, &i2c_regs->i2cr);
+		}
 
-	while (len--) {
-		ret = rx_byte(len == 0);
-		if (ret  < 0)
-			return -1;
-		*buf++ = ret;
-		if (len <= 1)
-			writew(I2CR_IEN | I2CR_MSTA |
-				I2CR_TX_NO_AK,
-				I2C_BASE + I2CR);
+		buf[i] = readb(&i2c_regs->i2dr);
 	}
 
-	writew(I2CR_IEN, I2C_BASE + I2CR);
-
-	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
-		udelay(1);
+	i2c_imx_stop();
 
-	return 0;
+	return ret;
 }
 
+/*
+ * Write data to I2C device
+ */
 int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
 {
-	int timeout = I2C_MAX_TIMEOUT;
-	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",
-		__func__, chip, addr, alen, len);
+	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
+	int ret;
+	int i;
 
-	if (i2c_addr(chip, addr, alen))
-		return -1;
+	ret = i2c_imx_start();
+	if (ret)
+		return ret;
 
-	while (len--)
-		if (tx_byte(*buf++))
-			return -1;
+	/* write slave address */
+	ret = i2c_imx_set_chip_addr(chip, 0);
+	if (ret)
+		return ret;
 
-	writew(I2CR_IEN, I2C_BASE + I2CR);
+	ret = i2c_imx_set_reg_addr(addr, alen);
+	if (ret)
+		return ret;
 
-	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
-		udelay(1);
+	for (i = 0; i < len; i++) {
+		writeb(buf[i], &i2c_regs->i2dr);
 
-	return 0;
-}
+		ret = i2c_imx_trx_complete();
+		if (ret)
+			return ret;
+
+		ret = i2c_imx_acked();
+		if (ret)
+			return ret;
+	}
 
+	i2c_imx_stop();
+
+	return ret;
+}
 #endif /* CONFIG_HARD_I2C */
-- 
1.7.5.4

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

* [U-Boot] [PATCH 2/4 V2] MX5: Add AHB clock reporting and fix IPG clock reporting
  2011-09-22 19:20   ` [U-Boot] [PATCH 2/4 V2] " Marek Vasut
@ 2011-09-23  2:09     ` Jason Hui
  0 siblings, 0 replies; 34+ messages in thread
From: Jason Hui @ 2011-09-23  2:09 UTC (permalink / raw)
  To: u-boot

Hi, Marek,

On Fri, Sep 23, 2011 at 3:20 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> Cc: Stefano Babic <sbabic@denx.de>
> Cc: Jason Hui <jason.hui@linaro.org>

Here is: Jason Liu <jason.hui@linaro.org>

> ---
> ?arch/arm/cpu/armv7/mx5/clock.c | ? 36 +++++++++++++++++++++++++++---------
> ?1 files changed, 27 insertions(+), 9 deletions(-)
>
> V2: Use get_periph_clock() as AHB clocksource.
>
> diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c
> index 9f37f7f..b87b29e 100644
> --- a/arch/arm/cpu/armv7/mx5/clock.c
> +++ b/arch/arm/cpu/armv7/mx5/clock.c
> @@ -152,18 +152,35 @@ static u32 get_periph_clk(void)
> ?}
>
> ?/*
> + * Get the rate of ahb clock.
> + */
> +static u32 get_ahb_clk(void)
> +{
> + ? ? ? uint32_t freq, div, reg;
> +
> + ? ? ? freq = get_periph_clk();
> +
> + ? ? ? reg = __raw_readl(&mxc_ccm->cbcdr);
> + ? ? ? div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
> + ? ? ? ? ? ? ? ? ? ? ? MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
> +
> + ? ? ? return freq / div;
> +}
> +
> +/*
> ?* Get the rate of ipg clock.
> ?*/
> ?static u32 get_ipg_clk(void)
> ?{
> - ? ? ? u32 ahb_podf, ipg_podf;
> -
> - ? ? ? ahb_podf = __raw_readl(&mxc_ccm->cbcdr);
> - ? ? ? ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
> - ? ? ? ? ? ? ? ? ? ? ? MXC_CCM_CBCDR_IPG_PODF_OFFSET;
> - ? ? ? ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
> - ? ? ? ? ? ? ? ? ? ? ? MXC_CCM_CBCDR_AHB_PODF_OFFSET;
> - ? ? ? return get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1));
> + ? ? ? uint32_t freq, reg, div;
> +
> + ? ? ? freq = get_ahb_clk();
> +
> + ? ? ? reg = __raw_readl(&mxc_ccm->cbcdr);
> + ? ? ? div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
> + ? ? ? ? ? ? ? ? ? ? ? MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1;
> +
> + ? ? ? return freq / div;
> ?}
>
> ?/*
> @@ -290,7 +307,7 @@ unsigned int mxc_get_clock(enum mxc_clock clk)
> ? ? ? ?case MXC_ARM_CLK:
> ? ? ? ? ? ? ? ?return get_mcu_main_clk();
> ? ? ? ?case MXC_AHB_CLK:
> - ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? return get_ahb_clk();
> ? ? ? ?case MXC_IPG_CLK:
> ? ? ? ? ? ? ? ?return get_ipg_clk();
> ? ? ? ?case MXC_IPG_PERCLK:
> @@ -336,6 +353,7 @@ int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> ? ? ? ?freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
> ? ? ? ?printf("pll4: %dMHz\n", freq / 1000000);
> ?#endif
> + ? ? ? printf("ahb clock ? ? : %dHz\n", mxc_get_clock(MXC_AHB_CLK));
> ? ? ? ?printf("ipg clock ? ? : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
> ? ? ? ?printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
>

Looks good to me.

Acked-by: Jason Liu <jason.hui@linaro.org>

BR
Jason Liu

> --
> 1.7.5.4
>
>

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

* [U-Boot] [PATCH 4/4 V5] I2C: mxc_i2c rework
  2011-09-22 19:22         ` [U-Boot] [PATCH 4/4 V5] " Marek Vasut
@ 2011-09-23  3:32           ` Jason Hui
  2011-09-23  4:31             ` Fabio Estevam
                               ` (2 more replies)
  2011-10-14 16:28           ` Anatolij Gustschin
  1 sibling, 3 replies; 34+ messages in thread
From: Jason Hui @ 2011-09-23  3:32 UTC (permalink / raw)
  To: u-boot

Hi, Marek,

On Fri, Sep 23, 2011 at 3:22 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> Rewrite the mxc_i2c driver.
> ?* This version is much closer to Linux implementation.
> ?* Fixes IPG_PERCLK being incorrectly used as clock source
> ?* Fixes behaviour of the driver on iMX51
> ?* Clean up coding style a bit ;-)
>
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> Cc: Stefano Babic <sbabic@denx.de>
> Cc: Heiko Schocher <hs@denx.de>
> Cc: Jason Hui <jason.hui@linaro.org>
> ---
> ?drivers/i2c/mxc_i2c.c | ?422 +++++++++++++++++++++++++++++++++----------------
> ?1 files changed, 289 insertions(+), 133 deletions(-)
>
> V2: Use PERCLK as a source.
> V3: Remove forgotten unused variables.
> V4: Add missing Cc field to commit message.
> V5: Correct TX_NO_AK bit handling.
>

Test on i.MX53evk, it woks now.

Acked-by: Jason Liu <jason.hui@linro.org>
Tested-by: Jason Liu <jason.hui@linro.org>


BR,
Jason Liu

>

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

* [U-Boot] [PATCH 4/4 V5] I2C: mxc_i2c rework
  2011-09-23  3:32           ` Jason Hui
@ 2011-09-23  4:31             ` Fabio Estevam
  2011-09-23  6:21             ` Marek Vasut
  2011-09-23  7:46             ` Stefano Babic
  2 siblings, 0 replies; 34+ messages in thread
From: Fabio Estevam @ 2011-09-23  4:31 UTC (permalink / raw)
  To: u-boot

On Fri, Sep 23, 2011 at 12:32 AM, Jason Hui <jason.hui@linaro.org> wrote:
> Test on i.MX53evk, it woks now.
>
> Acked-by: Jason Liu <jason.hui@linro.org>
> Tested-by: Jason Liu <jason.hui@linro.org>

I guess you meant linaro.org ;-)

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

* [U-Boot] [PATCH 4/4 V5] I2C: mxc_i2c rework
  2011-09-23  3:32           ` Jason Hui
  2011-09-23  4:31             ` Fabio Estevam
@ 2011-09-23  6:21             ` Marek Vasut
  2011-09-23  7:46             ` Stefano Babic
  2 siblings, 0 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-23  6:21 UTC (permalink / raw)
  To: u-boot

On Friday, September 23, 2011 05:32:13 AM Jason Hui wrote:
> Hi, Marek,
> 
> On Fri, Sep 23, 2011 at 3:22 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
> > Rewrite the mxc_i2c driver.
> >  * This version is much closer to Linux implementation.
> >  * Fixes IPG_PERCLK being incorrectly used as clock source
> >  * Fixes behaviour of the driver on iMX51
> >  * Clean up coding style a bit ;-)
> > 
> > Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> > Cc: Stefano Babic <sbabic@denx.de>
> > Cc: Heiko Schocher <hs@denx.de>
> > Cc: Jason Hui <jason.hui@linaro.org>
> > ---
> >  drivers/i2c/mxc_i2c.c |  422
> > +++++++++++++++++++++++++++++++++---------------- 1 files changed, 289
> > insertions(+), 133 deletions(-)
> > 
> > V2: Use PERCLK as a source.
> > V3: Remove forgotten unused variables.
> > V4: Add missing Cc field to commit message.
> > V5: Correct TX_NO_AK bit handling.
> 
> Test on i.MX53evk, it woks now.
> 
> Acked-by: Jason Liu <jason.hui@linro.org>
> Tested-by: Jason Liu <jason.hui@linro.org>

Thanks.

When can I expect you commiting the DIALOG PMIC of doom code ?

Cheers
> 
> 
> BR,
> Jason Liu

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

* [U-Boot] [PATCH 4/4 V5] I2C: mxc_i2c rework
  2011-09-23  3:32           ` Jason Hui
  2011-09-23  4:31             ` Fabio Estevam
  2011-09-23  6:21             ` Marek Vasut
@ 2011-09-23  7:46             ` Stefano Babic
  2011-09-26  6:30               ` Heiko Schocher
  2 siblings, 1 reply; 34+ messages in thread
From: Stefano Babic @ 2011-09-23  7:46 UTC (permalink / raw)
  To: u-boot

On 09/23/2011 05:32 AM, Jason Hui wrote:
> Hi, Marek,
> 
> On Fri, Sep 23, 2011 at 3:22 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
>> Rewrite the mxc_i2c driver.
>>  * This version is much closer to Linux implementation.
>>  * Fixes IPG_PERCLK being incorrectly used as clock source
>>  * Fixes behaviour of the driver on iMX51
>>  * Clean up coding style a bit ;-)
>>
>> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
>> Cc: Stefano Babic <sbabic@denx.de>
>> Cc: Heiko Schocher <hs@denx.de>
>> Cc: Jason Hui <jason.hui@linaro.org>
>> ---
>>  drivers/i2c/mxc_i2c.c |  422 +++++++++++++++++++++++++++++++++----------------
>>  1 files changed, 289 insertions(+), 133 deletions(-)
>>
>> V2: Use PERCLK as a source.
>> V3: Remove forgotten unused variables.
>> V4: Add missing Cc field to commit message.
>> V5: Correct TX_NO_AK bit handling.
>>
> 
> Test on i.MX53evk, it woks now.
> 
> Acked-by: Jason Liu <jason.hui@linro.org>
> Tested-by: Jason Liu <jason.hui@linro.org>

Thanks everybody for the good work !

I will merge now this series into u-boot-imx. I do not see any open
issus (please correct me if I am wrong !).

Best regards,
Stefano Babic

-- 
=====================================================================
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
=====================================================================

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

* [U-Boot] [PATCH 1/4] MX5: Modify the PLL decoding algorithm
  2011-09-22  3:20   ` Jason Hui
@ 2011-09-23  9:15     ` Stefano Babic
  0 siblings, 0 replies; 34+ messages in thread
From: Stefano Babic @ 2011-09-23  9:15 UTC (permalink / raw)
  To: u-boot

On 09/22/2011 05:20 AM, Jason Hui wrote:
> On Thu, Sep 15, 2011 at 8:09 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
>> The PLL decoding algorithm didn't take into account many configuration bits.
>> Adjust it according to Linux kernel. Also, add PLL4 for MX53.
>>
>> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
>> ---
>>  arch/arm/cpu/armv7/mx5/clock.c           |   77 ++++++++++++++++++++++++++----
>>  arch/arm/include/asm/arch-mx5/imx-regs.h |    3 +
>>  2 files changed, 70 insertions(+), 10 deletions(-)
>>
>> diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c
>> index 00610a0..9f37f7f 100644
>> --- a/arch/arm/cpu/armv7/mx5/clock.c
>> +++ b/arch/arm/cpu/armv7/mx5/clock.c
>> @@ -29,11 +29,13 @@
>>  #include <asm/arch/imx-regs.h>
>>  #include <asm/arch/crm_regs.h>
>>  #include <asm/arch/clock.h>
>> +#include <div64.h>
>>
>>  enum pll_clocks {
>>        PLL1_CLOCK = 0,
>>        PLL2_CLOCK,
>>        PLL3_CLOCK,
>> +       PLL4_CLOCK,
>>        PLL_CLOCKS,
>>  };
>>
>> @@ -41,25 +43,76 @@ struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
>>        [PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR,
>>        [PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR,
>>        [PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR,
>> +#ifdef CONFIG_MX53
>> +       [PLL4_CLOCK] = (struct mxc_pll_reg *)PLL4_BASE_ADDR,
>> +#endif
>>  };
>>
>> +#define        MXC_DPLLC_CTL_HFSM              (1 << 7)
>> +#define        MXC_DPLLC_CTL_DPDCK0_2_EN       (1 << 12)
>> +
>> +#define        MXC_DPLLC_OP_PDF_MASK           0xf
>> +#define        MXC_DPLLC_OP_MFI_MASK           (0xf << 4)
>> +#define        MXC_DPLLC_OP_MFI_OFFSET         4
>> +
>> +#define        MXC_DPLLC_MFD_MFD_MASK          0x7ffffff
>> +
>> +#define        MXC_DPLLC_MFN_MFN_MASK          0x7ffffff
> 
> Can we put this stuff to crm_reg.h file?

Right. Clock related defines are in the crm_reg.h file

Best regards,
Stefano Babic

-- 
=====================================================================
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office at denx.de
=====================================================================

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

* [U-Boot] [PATCH 1/4 V2] MX5: Modify the PLL decoding algorithm
  2011-09-15  0:09 ` [U-Boot] [PATCH 1/4] MX5: Modify the PLL decoding algorithm Marek Vasut
  2011-09-22  3:20   ` Jason Hui
@ 2011-09-23  9:43   ` Marek Vasut
  1 sibling, 0 replies; 34+ messages in thread
From: Marek Vasut @ 2011-09-23  9:43 UTC (permalink / raw)
  To: u-boot

The PLL decoding algorithm didn't take into account many configuration bits.
Adjust it according to Linux kernel. Also, add PLL4 for MX53.

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Cc: Stefano Babic <sbabic@denx.de>
Cc: Jason Hui <jason.hui@linaro.org>
---
 arch/arm/cpu/armv7/mx5/clock.c           |   66 +++++++++++++++++++++++++-----
 arch/arm/include/asm/arch-mx5/crm_regs.h |   11 +++++
 arch/arm/include/asm/arch-mx5/imx-regs.h |    3 +
 3 files changed, 70 insertions(+), 10 deletions(-)

V2: Move register bitfields to crm_regs.h

diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c
index 00610a0..c28c1c3 100644
--- a/arch/arm/cpu/armv7/mx5/clock.c
+++ b/arch/arm/cpu/armv7/mx5/clock.c
@@ -29,11 +29,13 @@
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/crm_regs.h>
 #include <asm/arch/clock.h>
+#include <div64.h>
 
 enum pll_clocks {
 	PLL1_CLOCK = 0,
 	PLL2_CLOCK,
 	PLL3_CLOCK,
+	PLL4_CLOCK,
 	PLL_CLOCKS,
 };
 
@@ -41,25 +43,65 @@ struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
 	[PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR,
 	[PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR,
 	[PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR,
+#ifdef	CONFIG_MX53
+	[PLL4_CLOCK] = (struct mxc_pll_reg *)PLL4_BASE_ADDR,
+#endif
 };
 
 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
 
 /*
- * Calculate the frequency of this pll.
+ * Calculate the frequency of PLLn.
  */
-static u32 decode_pll(struct mxc_pll_reg *pll, u32 infreq)
+static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq)
 {
-	u32 mfi, mfn, mfd, pd;
+	uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret;
+	uint64_t refclk, temp;
+	int32_t mfn_abs;
+
+	ctrl = readl(&pll->ctrl);
+
+	if (ctrl & MXC_DPLLC_CTL_HFSM) {
+		mfn = __raw_readl(&pll->hfs_mfn);
+		mfd = __raw_readl(&pll->hfs_mfd);
+		op = __raw_readl(&pll->hfs_op);
+	} else {
+		mfn = __raw_readl(&pll->mfn);
+		mfd = __raw_readl(&pll->mfd);
+		op = __raw_readl(&pll->op);
+	}
 
-	mfn = __raw_readl(&pll->mfn);
-	mfd = __raw_readl(&pll->mfd) + 1;
-	mfi = __raw_readl(&pll->op);
-	pd = (mfi  & 0xF) + 1;
-	mfi = (mfi >> 4) & 0xF;
-	mfi = (mfi >= 5) ? mfi : 5;
+	mfd &= MXC_DPLLC_MFD_MFD_MASK;
+	mfn &= MXC_DPLLC_MFN_MFN_MASK;
+	pdf = op & MXC_DPLLC_OP_PDF_MASK;
+	mfi = (op & MXC_DPLLC_OP_MFI_MASK) >> MXC_DPLLC_OP_MFI_OFFSET;
+
+	/* 21.2.3 */
+	if (mfi < 5)
+		mfi = 5;
+
+	/* Sign extend */
+	if (mfn >= 0x04000000) {
+		mfn |= 0xfc000000;
+		mfn_abs = -mfn;
+	} else
+		mfn_abs = mfn;
+
+	refclk = infreq * 2;
+	if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN)
+		refclk *= 2;
+
+	refclk /= pdf + 1;
+	temp = refclk * mfn_abs;
+	do_div(temp, mfd + 1);
+	ret = refclk * mfi;
+
+	if ((int)mfn < 0)
+		ret -= temp;
+	else
+		ret += temp;
 
-	return ((4 * (infreq / 1000) * (mfi * mfd + mfn)) / (mfd * pd)) * 1000;
+	return ret;
 }
 
 /*
@@ -279,6 +321,10 @@ int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	printf("pll2: %dMHz\n", freq / 1000000);
 	freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
 	printf("pll3: %dMHz\n", freq / 1000000);
+#ifdef	CONFIG_MX53
+	freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
+	printf("pll4: %dMHz\n", freq / 1000000);
+#endif
 	printf("ipg clock     : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
 	printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
 
diff --git a/arch/arm/include/asm/arch-mx5/crm_regs.h b/arch/arm/include/asm/arch-mx5/crm_regs.h
index 4ed8eb3..fcc0e36 100644
--- a/arch/arm/include/asm/arch-mx5/crm_regs.h
+++ b/arch/arm/include/asm/arch-mx5/crm_regs.h
@@ -200,4 +200,15 @@ struct mxc_ccm_reg {
 /* Define the bits in register CLPCR */
 #define MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS                 (0x1 << 18)
 
+#define	MXC_DPLLC_CTL_HFSM				(1 << 7)
+#define	MXC_DPLLC_CTL_DPDCK0_2_EN			(1 << 12)
+
+#define	MXC_DPLLC_OP_PDF_MASK				0xf
+#define	MXC_DPLLC_OP_MFI_MASK				(0xf << 4)
+#define	MXC_DPLLC_OP_MFI_OFFSET				4
+
+#define	MXC_DPLLC_MFD_MFD_MASK				0x7ffffff
+
+#define	MXC_DPLLC_MFN_MFN_MASK				0x7ffffff
+
 #endif				/* __ARCH_ARM_MACH_MX51_CRM_REGS_H__ */
diff --git a/arch/arm/include/asm/arch-mx5/imx-regs.h b/arch/arm/include/asm/arch-mx5/imx-regs.h
index 098c300..d069209 100644
--- a/arch/arm/include/asm/arch-mx5/imx-regs.h
+++ b/arch/arm/include/asm/arch-mx5/imx-regs.h
@@ -100,6 +100,9 @@
 #define PLL1_BASE_ADDR		(AIPS2_BASE_ADDR + 0x00080000)
 #define PLL2_BASE_ADDR		(AIPS2_BASE_ADDR + 0x00084000)
 #define PLL3_BASE_ADDR		(AIPS2_BASE_ADDR + 0x00088000)
+#ifdef	CONFIG_MX53
+#define PLL4_BASE_ADDR		(AIPS2_BASE_ADDR + 0x0008c000)
+#endif
 #define AHBMAX_BASE_ADDR	(AIPS2_BASE_ADDR + 0x00094000)
 #define IIM_BASE_ADDR		(AIPS2_BASE_ADDR + 0x00098000)
 #define CSU_BASE_ADDR		(AIPS2_BASE_ADDR + 0x0009C000)
-- 
1.7.5.4

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

* [U-Boot] [PATCH 4/4 V5] I2C: mxc_i2c rework
  2011-09-23  7:46             ` Stefano Babic
@ 2011-09-26  6:30               ` Heiko Schocher
  0 siblings, 0 replies; 34+ messages in thread
From: Heiko Schocher @ 2011-09-26  6:30 UTC (permalink / raw)
  To: u-boot

Hello Stefano,

Stefano Babic wrote:
> On 09/23/2011 05:32 AM, Jason Hui wrote:
>> Hi, Marek,
>>
>> On Fri, Sep 23, 2011 at 3:22 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
>>> Rewrite the mxc_i2c driver.
>>>  * This version is much closer to Linux implementation.
>>>  * Fixes IPG_PERCLK being incorrectly used as clock source
>>>  * Fixes behaviour of the driver on iMX51
>>>  * Clean up coding style a bit ;-)
>>>
>>> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
>>> Cc: Stefano Babic <sbabic@denx.de>
>>> Cc: Heiko Schocher <hs@denx.de>
>>> Cc: Jason Hui <jason.hui@linaro.org>
>>> ---
>>>  drivers/i2c/mxc_i2c.c |  422 +++++++++++++++++++++++++++++++++----------------
>>>  1 files changed, 289 insertions(+), 133 deletions(-)
>>>
>>> V2: Use PERCLK as a source.
>>> V3: Remove forgotten unused variables.
>>> V4: Add missing Cc field to commit message.
>>> V5: Correct TX_NO_AK bit handling.
>>>
>> Test on i.MX53evk, it woks now.
>>
>> Acked-by: Jason Liu <jason.hui@linro.org>
>> Tested-by: Jason Liu <jason.hui@linro.org>
> 
> Thanks everybody for the good work !

Yep! Thanks to Marek and Jason.

> I will merge now this series into u-boot-imx. I do not see any open
> issus (please correct me if I am wrong !).

Acked-by: Heiko Schocher <hs@denx.de>

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

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

* [U-Boot] [PATCH 4/4 V5] I2C: mxc_i2c rework
  2011-09-22 19:22         ` [U-Boot] [PATCH 4/4 V5] " Marek Vasut
  2011-09-23  3:32           ` Jason Hui
@ 2011-10-14 16:28           ` Anatolij Gustschin
  1 sibling, 0 replies; 34+ messages in thread
From: Anatolij Gustschin @ 2011-10-14 16:28 UTC (permalink / raw)
  To: u-boot

Hi Marek,

On Thu, 22 Sep 2011 21:22:12 +0200
Marek Vasut <marek.vasut@gmail.com> wrote:

> Rewrite the mxc_i2c driver.
>  * This version is much closer to Linux implementation.
>  * Fixes IPG_PERCLK being incorrectly used as clock source
>  * Fixes behaviour of the driver on iMX51
>  * Clean up coding style a bit ;-)
> 
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> Cc: Stefano Babic <sbabic@denx.de>
> Cc: Heiko Schocher <hs@denx.de>
> Cc: Jason Hui <jason.hui@linaro.org>
> ---
>  drivers/i2c/mxc_i2c.c |  422 +++++++++++++++++++++++++++++++++----------------
>  1 files changed, 289 insertions(+), 133 deletions(-)

Unfortunately this patch breaks accessing the I2C EEPROM on
imx31_phycore board. On this board the U-Boot environment
is stored in the I2C EEPROM. With this patch applied reading
the environment doesn't work correctly, I always get "bad CRC"
warning and fall back to default environment. Some EEPROM data
dumps using i2c commands reveal that the EEPROM data addressing
is broken, this is due to the wrong swapping of address bytes
in the code below:

> +/*
> + * Write register address
> + */
> +int i2c_imx_set_reg_addr(uint addr, int alen)
>  {
> -	int i, retry = 0;
> -	for (retry = 0; retry < 3; retry++) {
> -		if (wait_idle())
> +	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
> +	int ret;
> +	int i;
> +
> +	for (i = 0; i < (8 * alen); i += 8) {
> +		writeb((addr >> i) & 0xff, &i2c_regs->i2dr);
> +
> +		ret = i2c_imx_trx_complete();
> +		if (ret)
>  			break;

Applying the patch below fixes the EEPROM addressing issue,
i2c commands seem to work correctly:
dumping the EEPROM data to memory by

uboot> i2c read 0x52 0.2 1000 80000000
uboot> md 80000000 1
80000000: cf6bcdbd    ..k.

and calculating the checksum by

uboot> crc 80000004 ffc
CRC32 for 80000004 ... 80000fff ==> cf6bcdbd

shows that it works, but when the board boots, the
reading of the environment still doesn't work. Bad CRC
is always reported, even with the below patch applied.
Reverting this driver rework commit fixes the issue.

Any idea where the problem could be?

Thanks,
Anatolij


diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index a805bf6..9984c2a 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -291,11 +291,10 @@ int i2c_imx_set_chip_addr(uchar chip, int read)
 int i2c_imx_set_reg_addr(uint addr, int alen)
 {
 	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE;
-	int ret;
-	int i;
+	int ret = 0;
 
-	for (i = 0; i < (8 * alen); i += 8) {
-		writeb((addr >> i) & 0xff, &i2c_regs->i2dr);
+	while (alen--) {
+		writeb((addr >> (alen * 8)) & 0xff, &i2c_regs->i2dr);
 
 		ret = i2c_imx_trx_complete();
 		if (ret)

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

end of thread, other threads:[~2011-10-14 16:28 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-15  0:09 [U-Boot] [PATCH 0/4] Clock fix and MXC I2C rework series Marek Vasut
2011-09-15  0:09 ` [U-Boot] [PATCH 1/4] MX5: Modify the PLL decoding algorithm Marek Vasut
2011-09-22  3:20   ` Jason Hui
2011-09-23  9:15     ` Stefano Babic
2011-09-23  9:43   ` [U-Boot] [PATCH 1/4 V2] " Marek Vasut
2011-09-15  0:09 ` [U-Boot] [PATCH 2/4] MX5: Add AHB clock reporting and fix IPG clock reporting Marek Vasut
2011-09-22  3:05   ` Jason Hui
2011-09-22  3:41     ` Marek Vasut
2011-09-22  4:46       ` Jason Hui
2011-09-22 19:20   ` [U-Boot] [PATCH 2/4 V2] " Marek Vasut
2011-09-23  2:09     ` Jason Hui
2011-09-15  0:09 ` [U-Boot] [PATCH 3/4] MX5: Clean up the output of "clocks" command Marek Vasut
2011-09-19 10:03   ` Stefano Babic
2011-09-22  1:58   ` Jason Hui
2011-09-15  0:09 ` [U-Boot] [PATCH 4/4] I2C: mxc_i2c rework Marek Vasut
2011-09-15  4:16   ` [U-Boot] [PATCH 4/4 V2] " Marek Vasut
2011-09-19  6:13     ` Heiko Schocher
2011-09-20  2:30     ` [U-Boot] [PATCH 4/4 V3] " Marek Vasut
2011-09-20  2:35       ` [U-Boot] [PATCH 4/4 V4] " Marek Vasut
2011-09-22  2:45         ` Jason Hui
2011-09-22  3:43           ` Marek Vasut
2011-09-22  4:54             ` Jason Hui
2011-09-22  5:47               ` Marek Vasut
2011-09-22  6:49                 ` Jason Hui
2011-09-22 19:22         ` [U-Boot] [PATCH 4/4 V5] " Marek Vasut
2011-09-23  3:32           ` Jason Hui
2011-09-23  4:31             ` Fabio Estevam
2011-09-23  6:21             ` Marek Vasut
2011-09-23  7:46             ` Stefano Babic
2011-09-26  6:30               ` Heiko Schocher
2011-10-14 16:28           ` Anatolij Gustschin
2011-09-19 10:11   ` [U-Boot] [PATCH 4/4] " Stefano Babic
2011-09-19 10:24     ` Marek Vasut
2011-09-20 10:07     ` Jason Liu

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.