diff options
author | Chunhe Lan | 2013-08-16 15:10:37 +0800 |
---|---|---|
committer | Heiko Schocher | 2013-08-20 11:15:31 +0200 |
commit | 9c3f77eb3bc0e1e24fc66bd41655fecddb6403ec (patch) | |
tree | c547108292e7d49f91e9c1eb06d06d4de96a7d17 /drivers/i2c/fsl_i2c.c | |
parent | b8ce3343b64434b95b9a25dea0534bf9f1593e8c (diff) |
fsl_i2c: add workaround for the erratum I2C A004447
This workaround is for the erratum I2C A004447. Device reference
manual provides a scheme that allows the I2C master controller
to generate nine SCL pulses, which enable an I2C slave device
that held SDA low to release SDA. However, due to this erratum,
this scheme no longer works. In addition, when I2C is used as
a source of the PBL, the state machine is not able to recover.
At the same time, delete the reduplicative definition of SVR_VER
and SVR_REV. The SVR_REV is the low 8 bits rather than the low 16
bits of svr. And we use the CONFIG_SYS_FSL_A004447_SVR_REV macro
instead of hard-code value 0x10, 0x11 and 0x20.
The CONFIG_SYS_FSL_A004447_SVR_REV = 0x00 represents that one
version of platform has this I2C errata. So enable this errata
by IS_SVR_REV(svr, maj, min) function.
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Chunhe Lan <Chunhe.Lan@freescale.com>
Cc: Scott Wood <scottwood@freescale.com>
Cc: Heiko Schocher <hs@denx.de>
Diffstat (limited to 'drivers/i2c/fsl_i2c.c')
-rw-r--r-- | drivers/i2c/fsl_i2c.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 44b08f76714..291ad946dba 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -211,6 +211,14 @@ static int fsl_i2c_fixup(const struct fsl_i2c *dev) const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT); unsigned long long timeval = 0; int ret = -1; + unsigned int flags = 0; + +#ifdef CONFIG_SYS_FSL_ERRATUM_I2C_A004447 + unsigned int svr = get_svr(); + if ((SVR_SOC_VER(svr) == SVR_8548 && IS_SVR_REV(svr, 3, 1)) || + (SVR_REV(svr) <= CONFIG_SYS_FSL_A004447_SVR_REV)) + flags = I2C_CR_BIT6; +#endif writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr); @@ -224,8 +232,8 @@ static int fsl_i2c_fixup(const struct fsl_i2c *dev) /* SDA is stuck low */ writeb(0, &dev->cr); udelay(100); - writeb(I2C_CR_MSTA, &dev->cr); - writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr); + writeb(I2C_CR_MSTA | flags, &dev->cr); + writeb(I2C_CR_MEN | I2C_CR_MSTA | flags, &dev->cr); } readb(&dev->dr); @@ -238,7 +246,7 @@ static int fsl_i2c_fixup(const struct fsl_i2c *dev) ret = 0; err: - writeb(I2C_CR_MEN, &dev->cr); + writeb(I2C_CR_MEN | flags, &dev->cr); writeb(0, &dev->sr); udelay(100); |