[U-Boot-Users] [COLDFIRE] I2C patch 547x/548x cpus

The coldfire cpus use a little different i2c device that is not perfectly compatible with the i2c fsl driver present on mpc cpus. consequently the fsl_i2c driver needs some little modification in order to work on these cpus (m547x/m548x and m5445x cpus).
Best regards,
luigi

--- drivers/i2c/fsl_i2c.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 68 insertions(+), 0 deletions(-)
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 0690340..8fd73c0 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -78,6 +78,73 @@ static const struct fsl_i2c *i2c_dev[2] = { * register. See the application note AN2919 "Determining the I2C Frequency * Divider Ratio for SCL" */ +#if defined(CONFIG_MCF547x_8x) || defined(CONFIG_MCF5445x) +static const struct { + u8 fdr; + unsigned short divider; +} fsl_i2c_speed_map[] = { + {.fdr=0x20, .divider= 20}, {.fdr=0x21, .divider= 22}, {.fdr=0x22, .divider= 24}, + {.fdr=0x23, .divider= 26}, {.fdr=0x00, .divider= 28}, {.fdr=0x24, .divider= 28}, + {.fdr=0x01, .divider= 30}, {.fdr=0x25, .divider= 32}, {.fdr=0x02, .divider= 34}, + {.fdr=0x26, .divider= 36}, {.fdr=0x03, .divider= 40}, {.fdr=0x27, .divider= 40}, + {.fdr=0x04, .divider= 44}, {.fdr=0x05, .divider= 48}, /*{.fdr=0x28, .divider= 48},*/ + {.fdr=0x06, .divider= 56}, /*{.fdr=0x29, .divider= 56},*/ {.fdr=0x2A, .divider= 64}, + {.fdr=0x07, .divider= 68}, {.fdr=0x2B, .divider= 72}, {.fdr=0x08, .divider= 80}, + /*{.fdr=0x2C, .divider= 80},*/ {.fdr=0x09, .divider= 88}, {.fdr=0x2D, .divider= 96}, + {.fdr=0x0A, .divider= 104}, {.fdr=0x2E, .divider= 112}, {.fdr=0x0B, .divider= 128}, + /*{.fdr=0x2F, .divider= 128},*/ {.fdr=0x0C, .divider= 144}, {.fdr=0x0D, .divider= 160}, + /*{.fdr=0x30, .divider= 160},*/ {.fdr=0x0E, .divider= 192}, /*{.fdr=0x31, .divider= 192},*/ + {.fdr=0x32, .divider= 224}, {.fdr=0x0F, .divider= 240}, {.fdr=0x33, .divider= 256}, + {.fdr=0x10, .divider= 288}, {.fdr=0x11, .divider= 320}, /*{.fdr=0x34, .divider= 320},*/ + {.fdr=0x12, .divider= 384}, /*{.fdr=0x35, .divider= 384},*/ {.fdr=0x36, .divider= 448}, + /*{.fdr=0x13, .divider= 480},*/ {.fdr=0x37, .divider= 512}, {.fdr=0x14, .divider= 576}, + {.fdr=0x15, .divider= 640}, /*{.fdr=0x38, .divider= 640},*/ {.fdr=0x16, .divider= 768}, + /*{.fdr=0x39, .divider= 768},*/ {.fdr=0x3A, .divider= 896}, {.fdr=0x17, .divider= 960}, + {.fdr=0x3B, .divider=1024}, {.fdr=0x18, .divider=1152}, {.fdr=0x19, .divider=1280}, + /*{.fdr=0x3C, .divider=1280},*/ {.fdr=0x1A, .divider=1536}, /*{.fdr=0x3D, .divider=1536},*/ + {.fdr=0x3E, .divider=1792}, {.fdr=0x1B, .divider=1920}, {.fdr=0x3F, .divider=2048}, + {.fdr=0x1C, .divider=2304}, {.fdr=0x1D, .divider=2560}, {.fdr=0x1E, .divider=3072}, + {.fdr=0x1F, .divider=3840}, {.fdr=0x00, .divider=-1} +}; + +/** + * Set the I2C bus speed for a given I2C device + * + * @param dev: the I2C device + * @i2c_clk: I2C bus clock frequency + * @speed: the desired speed of the bus + * + * The I2C device must be stopped before calling this function. + * + * The return value is the actual bus speed that is set. + */ +static unsigned int set_i2c_bus_speed(const struct fsl_i2c *dev, + unsigned int i2c_clk, unsigned int speed) +{ + unsigned short divider = min(i2c_clk / speed, (unsigned short) -1); + unsigned int i; + u8 fdr = 0; + + /* + * We want to choose an FDR/DFSR that generates an I2C bus speed that + * is equal to or lower than the requested speed. That means that we + * want the first divider that is equal to or greater than the + * calculated divider. + */ + + for (i = 0; i < ARRAY_SIZE(fsl_i2c_speed_map); i++) + if (fsl_i2c_speed_map[i].divider >= divider) { + fdr = fsl_i2c_speed_map[i].fdr; + speed = i2c_clk / fsl_i2c_speed_map[i].divider; + break; + } + + writeb(fdr, &dev->fdr); /* set bus speed */ + + return speed; +} +#else /* ! (defined(CONFIG_MCF547x_8x) || defined(CONFIG_MCF5445x) */ + static const struct { unsigned short divider; u8 dfsr; @@ -140,6 +207,7 @@ static unsigned int set_i2c_bus_speed(const struct fsl_i2c *dev,
return speed; } +#endif /* if (defined(CONFIG_MCF547x_8x) || defined(CONFIG_MCF5445x) */
void i2c_init(int speed, int slaveadd)

--- drivers/i2c/fsl_i2c.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 68 insertions(+), 0 deletions(-)
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 0690340..8fd73c0 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -78,6 +78,73 @@ static const struct fsl_i2c *i2c_dev[2] = { * register. See the application note AN2919 "Determining the I2C Frequency * Divider Ratio for SCL" */ +#if defined(CONFIG_MCF547x_8x) || defined(CONFIG_MCF5445x) +static const struct { + u8 fdr; + unsigned short divider; +} fsl_i2c_speed_map[] = { + {.fdr=0x20, .divider= 20}, {.fdr=0x21, .divider= 22}, {.fdr=0x22, .divider= 24}, + {.fdr=0x23, .divider= 26}, {.fdr=0x00, .divider= 28}, {.fdr=0x24, .divider= 28}, + {.fdr=0x01, .divider= 30}, {.fdr=0x25, .divider= 32}, {.fdr=0x02, .divider= 34}, + {.fdr=0x26, .divider= 36}, {.fdr=0x03, .divider= 40}, {.fdr=0x27, .divider= 40}, + {.fdr=0x04, .divider= 44}, {.fdr=0x05, .divider= 48}, /*{.fdr=0x28, .divider= 48},*/ + {.fdr=0x06, .divider= 56}, /*{.fdr=0x29, .divider= 56},*/ {.fdr=0x2A, .divider= 64}, + {.fdr=0x07, .divider= 68}, {.fdr=0x2B, .divider= 72}, {.fdr=0x08, .divider= 80}, + /*{.fdr=0x2C, .divider= 80},*/ {.fdr=0x09, .divider= 88}, {.fdr=0x2D, .divider= 96}, + {.fdr=0x0A, .divider= 104}, {.fdr=0x2E, .divider= 112}, {.fdr=0x0B, .divider= 128}, + /*{.fdr=0x2F, .divider= 128},*/ {.fdr=0x0C, .divider= 144}, {.fdr=0x0D, .divider= 160}, + /*{.fdr=0x30, .divider= 160},*/ {.fdr=0x0E, .divider= 192}, /*{.fdr=0x31, .divider= 192},*/ + {.fdr=0x32, .divider= 224}, {.fdr=0x0F, .divider= 240}, {.fdr=0x33, .divider= 256}, + {.fdr=0x10, .divider= 288}, {.fdr=0x11, .divider= 320}, /*{.fdr=0x34, .divider= 320},*/ + {.fdr=0x12, .divider= 384}, /*{.fdr=0x35, .divider= 384},*/ {.fdr=0x36, .divider= 448}, + /*{.fdr=0x13, .divider= 480},*/ {.fdr=0x37, .divider= 512}, {.fdr=0x14, .divider= 576}, + {.fdr=0x15, .divider= 640}, /*{.fdr=0x38, .divider= 640},*/ {.fdr=0x16, .divider= 768}, + /*{.fdr=0x39, .divider= 768},*/ {.fdr=0x3A, .divider= 896}, {.fdr=0x17, .divider= 960}, + {.fdr=0x3B, .divider=1024}, {.fdr=0x18, .divider=1152}, {.fdr=0x19, .divider=1280}, + /*{.fdr=0x3C, .divider=1280},*/ {.fdr=0x1A, .divider=1536}, /*{.fdr=0x3D, .divider=1536},*/ + {.fdr=0x3E, .divider=1792}, {.fdr=0x1B, .divider=1920}, {.fdr=0x3F, .divider=2048}, + {.fdr=0x1C, .divider=2304}, {.fdr=0x1D, .divider=2560}, {.fdr=0x1E, .divider=3072}, + {.fdr=0x1F, .divider=3840}, {.fdr=0x00, .divider=-1} +}; + +/** + * Set the I2C bus speed for a given I2C device + * + * @param dev: the I2C device + * @i2c_clk: I2C bus clock frequency + * @speed: the desired speed of the bus + * + * The I2C device must be stopped before calling this function. + * + * The return value is the actual bus speed that is set. + */ +static unsigned int set_i2c_bus_speed(const struct fsl_i2c *dev, + unsigned int i2c_clk, unsigned int speed) +{ + unsigned short divider = min(i2c_clk / speed, (unsigned short) -1); + unsigned int i; + u8 fdr = 0; + + /* + * We want to choose an FDR/DFSR that generates an I2C bus speed that + * is equal to or lower than the requested speed. That means that we + * want the first divider that is equal to or greater than the + * calculated divider. + */ + + for (i = 0; i < ARRAY_SIZE(fsl_i2c_speed_map); i++) + if (fsl_i2c_speed_map[i].divider >= divider) { + fdr = fsl_i2c_speed_map[i].fdr; + speed = i2c_clk / fsl_i2c_speed_map[i].divider; + break; + } + + writeb(fdr, &dev->fdr); /* set bus speed */ + + return speed; +} +#else /* ! (defined(CONFIG_MCF547x_8x) || defined(CONFIG_MCF5445x) */ + static const struct { unsigned short divider; u8 dfsr; @@ -140,6 +207,7 @@ static unsigned int set_i2c_bus_speed(const struct fsl_i2c *dev,
return speed; } +#endif /* if (defined(CONFIG_MCF547x_8x) || defined(CONFIG_MCF5445x) */
void i2c_init(int speed, int slaveadd)

On Jul 7, 2008, at 10:17 AM, Luigi 'Comio' Mantellini wrote:
drivers/i2c/fsl_i2c.c | 68 ++++++++++++++++++++++++++++++++++++++++ +++++++++ 1 files changed, 68 insertions(+), 0 deletions(-)
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 0690340..8fd73c0 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -78,6 +78,73 @@ static const struct fsl_i2c *i2c_dev[2] = {
- register. See the application note AN2919 "Determining the I2C
Frequency
- Divider Ratio for SCL"
*/ +#if defined(CONFIG_MCF547x_8x) || defined(CONFIG_MCF5445x) +static const struct {
- u8 fdr;
- unsigned short divider;
+} fsl_i2c_speed_map[] = {
{.fdr=0x20, .divider= 20}, {.fdr=0x21, .divider= 22},
{.fdr=0x22, .divider= 24},
{.fdr=0x23, .divider= 26}, {.fdr=0x00, .divider= 28},
{.fdr=0x24, .divider= 28},
{.fdr=0x01, .divider= 30}, {.fdr=0x25, .divider= 32},
{.fdr=0x02, .divider= 34},
{.fdr=0x26, .divider= 36}, {.fdr=0x03, .divider= 40},
{.fdr=0x27, .divider= 40},
{.fdr=0x04, .divider= 44}, {.fdr=0x05, .divider= 48}, /
*{.fdr=0x28, .divider= 48},*/
{.fdr=0x06, .divider= 56}, /*{.fdr=0x29, .divider= 56},*/
{.fdr=0x2A, .divider= 64},
{.fdr=0x07, .divider= 68}, {.fdr=0x2B, .divider= 72},
{.fdr=0x08, .divider= 80},
- /*{.fdr=0x2C, .divider= 80},*/ {.fdr=0x09, .divider= 88},
{.fdr=0x2D, .divider= 96},
{.fdr=0x0A, .divider= 104}, {.fdr=0x2E, .divider= 112},
{.fdr=0x0B, .divider= 128},
- /*{.fdr=0x2F, .divider= 128},*/ {.fdr=0x0C, .divider= 144},
{.fdr=0x0D, .divider= 160},
- /*{.fdr=0x30, .divider= 160},*/ {.fdr=0x0E, .divider= 192}, /
*{.fdr=0x31, .divider= 192},*/
{.fdr=0x32, .divider= 224}, {.fdr=0x0F, .divider= 240},
{.fdr=0x33, .divider= 256},
{.fdr=0x10, .divider= 288}, {.fdr=0x11, .divider= 320}, /
*{.fdr=0x34, .divider= 320},*/
{.fdr=0x12, .divider= 384}, /*{.fdr=0x35, .divider= 384},*/
{.fdr=0x36, .divider= 448},
- /*{.fdr=0x13, .divider= 480},*/ {.fdr=0x37, .divider= 512},
{.fdr=0x14, .divider= 576},
{.fdr=0x15, .divider= 640}, /*{.fdr=0x38, .divider= 640},*/
{.fdr=0x16, .divider= 768},
- /*{.fdr=0x39, .divider= 768},*/ {.fdr=0x3A, .divider= 896},
{.fdr=0x17, .divider= 960},
{.fdr=0x3B, .divider=1024}, {.fdr=0x18, .divider=1152},
{.fdr=0x19, .divider=1280},
- /*{.fdr=0x3C, .divider=1280},*/ {.fdr=0x1A, .divider=1536}, /
*{.fdr=0x3D, .divider=1536},*/
{.fdr=0x3E, .divider=1792}, {.fdr=0x1B, .divider=1920},
{.fdr=0x3F, .divider=2048},
{.fdr=0x1C, .divider=2304}, {.fdr=0x1D, .divider=2560},
{.fdr=0x1E, .divider=3072},
{.fdr=0x1F, .divider=3840}, {.fdr=0x00, .divider=-1}
+};
NAK. There's a better way to do this. Don't just copy/paste my data structures and comment-out specific fields like this.
I'm on vacation this week. Next week, I'll take a closer look at your patch and suggest something better.
What is the reason you are commenting-out those specific entries in fsl_i2c_speed_map[]?

On mer, 2008-07-09 at 09:25 -0400, Timur Tabi wrote:
On Jul 7, 2008, at 10:17 AM, Luigi 'Comio' Mantellini wrote:
drivers/i2c/fsl_i2c.c | 68 ++++++++++++++++++++++++++++++++++++++++ +++++++++ 1 files changed, 68 insertions(+), 0 deletions(-)
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 0690340..8fd73c0 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -78,6 +78,73 @@ static const struct fsl_i2c *i2c_dev[2] = {
...
{.fdr=0x3B, .divider=1024}, {.fdr=0x18, .divider=1152},
{.fdr=0x19, .divider=1280},
- /*{.fdr=0x3C, .divider=1280},*/ {.fdr=0x1A, .divider=1536}, /
*{.fdr=0x3D, .divider=1536},*/
....
NAK. There's a better way to do this. Don't just copy/paste my data structures and comment-out specific fields like this.
The values are from the 547x manual because the fsl_i2c on coldfire is a little different (e.g. there isn't the default filter register). The entries commented are just synonymous of others. For example the divider 1280 can be obtained using both the fdr values 0x19 and 0x3C (always on coldfire cpus).
I'm on vacation this week. Next week, I'll take a closer look at your patch and suggest something better.
Thanks, I just reported a problem (i think)... the patches is just the quick solution that I have adopted on my application.
Best regards and have a good vacation!
luigi
What is the reason you are commenting-out those specific entries in fsl_i2c_speed_map[]?
Industrie Dial Face S.p.A. Luigi Mantellini R&D - Software Industrie Dial Face S.p.A. Via Canzo, 4 20068 Peschiera Borromeo (MI), Italy Tel.: +39 02 5167 2813 Fax: +39 02 5167 2459 E-mail: luigi.mantellini@idf-hit.com GPG fingerprint: 3DD1 7B71 FBDF 6376 1B4A B003 175F E979 907E 1650
participants (2)
-
Luigi 'Comio' Mantellini
-
Timur Tabi