From: Timur Tabi <timur@freescale.com>
To: u-boot@lists.denx.de
Subject: [U-Boot-Users] [PATCH] 83xx: Add support for CFG_I2C_SPEED in fsl_i2c.c
Date: Wed, 9 Jan 2008 10:18:41 -0600 [thread overview]
Message-ID: <11998955213899-git-send-email-timur@freescale.com> (raw)
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@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
next reply other threads:[~2008-01-09 16:18 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-01-09 16:18 Timur Tabi [this message]
2008-01-09 20:34 ` [U-Boot-Users] [PATCH] 83xx: Add support for CFG_I2C_SPEED in fsl_i2c.c Timur Tabi
2008-03-11 15:17 ` Jens Gehrlein
2008-03-11 15:18 ` Timur Tabi
2008-03-11 15:48 ` Jens Gehrlein
2008-03-11 15:51 ` Timur Tabi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=11998955213899-git-send-email-timur@freescale.com \
--to=timur@freescale.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.