[U-Boot-Users] [PATCH] 83xx: Add support for CFG_I2C_SPEED in fsl_i2c.c
Timur Tabi
timur at freescale.com
Wed Jan 9 17:18:41 CET 2008
Add support to fsl_i2c.c for setting and querying the I2C bus speed. Current
83xx boards define the CFG_I2C_SPEED, but fsl_i2c.c ignores the value and
uses a conservative value of 0x3F when programming the I2C bus speed.
Signed-off-by: Timur Tabi <timur at freescale.com>
---
Unfortunately, only 83xx calculates and stores the I2C clock frequencies,
so this code is compiled on 83xx only.
cpu/mpc83xx/cpu.c | 24 +++++++++++
drivers/i2c/fsl_i2c.c | 90 ++++++++++++++++++++++++++++++++++++++++-
include/asm-ppc/fsl_i2c.h | 23 ++++++++++
include/configs/MPC832XEMDS.h | 1 +
4 files changed, 137 insertions(+), 1 deletions(-)
diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c
index f1ea17d..51cb1b7 100644
--- a/cpu/mpc83xx/cpu.c
+++ b/cpu/mpc83xx/cpu.c
@@ -716,3 +716,27 @@ int dma_xfer(void *dest, u32 count, void *src)
return ((int)dma_check());
}
#endif /*CONFIG_DDR_ECC*/
+
+#ifdef CFG_I2C_SPEED
+/*
+ * Map the frequency divider to the FDR. This data is taken from table 17-5
+ * of the MPC8349EA reference manual, with duplicates removed. It also applies
+ * to the 8360.
+ */
+struct fsl_i2c_speed_map fsl_i2c_speed_map[] = {
+ {256, 0x20}, {288, 0x21}, {320, 0x22}, {352, 0x23},
+ {384, 0x24}, {416, 0x01}, {448, 0x25}, {480, 0x02},
+ {512, 0x26}, {576, 0x27}, {640, 0x28}, {704, 0x05},
+ {768, 0x29}, {832, 0x06}, {896, 0x2A}, {1024, 0x2B},
+ {1152, 0x08}, {1280, 0x2C}, {1536, 0x2D}, {1792, 0x2E},
+ {1920, 0x0B}, {2048, 0x2F}, {2304, 0x0C}, {2560, 0x30},
+ {3072, 0x31}, {3584, 0x32}, {3840, 0x0F}, {4096, 0x33},
+ {4608, 0x10}, {5120, 0x34}, {6144, 0x35}, {7168, 0x36},
+ {7680, 0x13}, {8192, 0x37}, {9216, 0x14}, {10240, 0x38},
+ {12288, 0x39}, {14336, 0x3A}, {15360, 0x17}, {16384, 0x3B},
+ {18432, 0x18}, {20480, 0x3C}, {24576, 0x3D}, {28672, 0x3E},
+ {30720, 0x1B}, {32768, 0x3F}, {36864, 0x1C}, {40960, 0x1D},
+ {49152, 0x1E}, {61440, 0x1F},
+ {-1, 0x1F}
+};
+#endif
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index 22485ea..bca2c75 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -32,6 +32,8 @@
#define I2C_READ_BIT 1
#define I2C_WRITE_BIT 0
+DECLARE_GLOBAL_DATA_PTR;
+
/* Initialize the bus pointer to whatever one the SPD EEPROM is on.
* Default is bus 0. This is necessary because the DDR initialization
* runs from ROM, and we can't switch buses because we can't modify
@@ -43,6 +45,8 @@ static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = CFG_SPD_BUS
static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0;
#endif
+static unsigned int i2c_bus_speed[2] = {CFG_I2C_SPEED, CFG_I2C_SPEED};
+
static volatile struct fsl_i2c *i2c_dev[2] = {
(struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET),
#ifdef CFG_I2C2_OFFSET
@@ -50,6 +54,53 @@ static volatile struct fsl_i2c *i2c_dev[2] = {
#endif
};
+#ifdef CONFIG_MPC83XX
+/* Currently, only 83xx determines and stores the I2C clock frequency */
+
+#ifdef CFG_I2C_SPEED
+/* Define a default I2C speed map if a real map isn't defined elsewhere */
+#pragma weak fsl_i2c_speed_map = default_fsl_i2c_speed_map
+
+struct fsl_i2c_speed_map default_fsl_i2c_speed_map[] = {
+ {0, 0x3F}, {-1, 0x3F}
+};
+#endif
+
+/*
+ * Get the I2C FDR value for a given I2C clock and a given I2C bus speed
+ */
+static u8 get_fdr(unsigned int i2c_clk, unsigned int speed)
+{
+#ifdef CFG_I2C_SPEED
+ extern struct fsl_i2c_speed_map fsl_i2c_speed_map[];
+ unsigned int d; /* The I2C clock divider */
+ unsigned int i = 0;
+ unsigned int low, high;
+
+ d = i2c_clk / speed;
+
+ /* Scan fsl_i2c_speed_map[] for the closest matching divider.*/
+
+ while (fsl_i2c_speed_map[i].divider != (unsigned int) -1) {
+ low = fsl_i2c_speed_map[i].divider;
+ high = fsl_i2c_speed_map[i+1].divider;
+
+ if ((d >= low) && (d <= high)) {
+ /* Which one is closer? */
+ if ((d - low) < (high - d))
+ return fsl_i2c_speed_map[i].fdr;
+ else
+ return fsl_i2c_speed_map[i+1].fdr;
+ break;
+ }
+ i++;
+ }
+#endif
+
+ return 0x3F; /* Use a conservative value as the default */
+}
+#endif /* CONFIG_MPC83XX */
+
void
i2c_init(int speed, int slaveadd)
{
@@ -59,23 +110,37 @@ i2c_init(int speed, int slaveadd)
writeb(0, &dev->cr); /* stop I2C controller */
udelay(5); /* let it shutdown in peace */
+#ifdef CONFIG_MPC83XX
+ /* Currently, only 83xx determines and stores the I2C clock frequency */
+ writeb(get_fdr(gd->i2c1_clk, speed), &dev->fdr); /* set bus speed */
+#else
writeb(0x3F, &dev->fdr); /* set bus speed */
+#endif
writeb(0x3F, &dev->dfsrr); /* set default filter */
writeb(slaveadd << 1, &dev->adr); /* write slave address */
writeb(0x0, &dev->sr); /* clear status register */
writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */
+ i2c_bus_speed[0] = speed;
+
#ifdef CFG_I2C2_OFFSET
dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET);
writeb(0, &dev->cr); /* stop I2C controller */
udelay(5); /* let it shutdown in peace */
+#ifdef CONFIG_MPC83XX
+ /* Currently, only 83xx determines and stores the I2C clock frequency */
+ writeb(get_fdr(gd->i2c2_clk, speed), &dev->fdr); /* set bus speed */
+#else
writeb(0x3F, &dev->fdr); /* set bus speed */
+#endif
writeb(0x3F, &dev->dfsrr); /* set default filter */
writeb(slaveadd << 1, &dev->adr); /* write slave address */
writeb(0x0, &dev->sr); /* clear status register */
writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */
-#endif /* CFG_I2C2_OFFSET */
+
+ i2c_bus_speed[1] = speed;
+#endif
}
static __inline__ int
@@ -279,7 +344,23 @@ int i2c_set_bus_num(unsigned int bus)
int i2c_set_bus_speed(unsigned int speed)
{
+#ifdef CONFIG_MPC83XX
+ /* Currently, only 83xx determines and stores the I2C clock frequency */
+
+ unsigned int i2c_clk = (i2c_bus_num == 1) ? gd->i2c2_clk : gd->i2c1_clk;
+ u8 fdr = get_fdr(i2c_clk, speed);
+
+ printf("Writing %x to FDR\n", fdr);
+ writeb(0, &i2c_dev[i2c_bus_num]->cr); /* stop controller */
+ writeb(fdr, &i2c_dev[i2c_bus_num]->fdr); /* set bus speed */
+ writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr); /* start controller */
+
+ i2c_bus_speed[i2c_bus_num] = speed;
+
+ return 0;
+#else
return -1;
+#endif
}
unsigned int i2c_get_bus_num(void)
@@ -289,7 +370,14 @@ unsigned int i2c_get_bus_num(void)
unsigned int i2c_get_bus_speed(void)
{
+#ifdef CONFIG_MPC83XX
+ /* Currently, only 83xx determines and stores the I2C clock frequency */
+
+ return i2c_bus_speed[i2c_bus_num];
+#else
return 0;
+#endif
}
+
#endif /* CONFIG_HARD_I2C */
#endif /* CONFIG_FSL_I2C */
diff --git a/include/asm-ppc/fsl_i2c.h b/include/asm-ppc/fsl_i2c.h
index 4f71341..f84a803 100644
--- a/include/asm-ppc/fsl_i2c.h
+++ b/include/asm-ppc/fsl_i2c.h
@@ -83,4 +83,27 @@ typedef struct fsl_i2c {
u8 res6[0xE8];
} fsl_i2c_t;
+/*
+ * Map I2C frequency dividers to FDR values
+ *
+ * This structure is used to define the elements of a table that maps I2C
+ * frequency divider (I2C clock rate divided by I2C bus speed) to a value to be
+ * programmed into the Frequency Divider Ratio (FDR) register.
+ *
+ * The actual table should be defined in the board file, and it must be called
+ * fsl_i2c_speed_map[].
+ *
+ * The first entry must be {0, X}, where X == fsl_i2c_speed_map[1].fdr.
+ *
+ * The last entry of the table must have a value of {-1,x}, where x is same
+ * FDR value as the second-to-last entry.
+ *
+ * The values of the divider must be in increasing numerical order, i.e.
+ * fsl_i2c_speed_map[x+1].divider > fsl_i2c_speed_map[x].divider.
+ */
+typedef struct fsl_i2c_speed_map {
+ unsigned int divider;
+ u8 fdr;
+} fsl_i2c_speed_map_t;
+
#endif /* _ASM_I2C_H_ */
diff --git a/include/configs/MPC832XEMDS.h b/include/configs/MPC832XEMDS.h
index c9c6d88..d5e588a 100644
--- a/include/configs/MPC832XEMDS.h
+++ b/include/configs/MPC832XEMDS.h
@@ -335,6 +335,7 @@
#define CFG_I2C_SLAVE 0x7F
#define CFG_I2C_NOPROBES {0x51} /* Don't probe these addrs */
#define CFG_I2C_OFFSET 0x3000
+#define CONFIG_I2C_CMD_TREE
/*
* Config on-board RTC
--
1.5.2.4
More information about the U-Boot
mailing list