diff options
author | Alex Gonzalez <alex.gonzalez@digi.com> | 2012-02-07 16:08:22 +0100 |
---|---|---|
committer | Alex Gonzalez <alex.gonzalez@digi.com> | 2012-02-07 16:17:22 +0100 |
commit | 7be23f852c3ce901c3e6b60d75dee924f4741ff8 (patch) | |
tree | aea6d3d1695ff60c830b890bee8aa134e76385b1 | |
parent | be39b7625170fccd03b29354e803c283407b8a29 (diff) |
ccxmx5x: mma7455, minimize the possibility of an interrupted read.
The MMA7455 seems to have a hardware bug that makes it keep the data line
low if an I2C read transfer is interrupted between writing the register
address and reading the data.
For the CCWMX53 this means leaving the bus where the PMIC is inaccessible,
making it impossible to suspend or reboot, and needing a cold boot with
the coin cell disabled to recover.
Without a definitive fix for the hardware problem I have implemented a
patch to make the situation highly unlikely.
1) The register read is changed from two i2c transfers (one for writing
the register address and one for reading) to a single I2C transfer.
2) I have also added a 10ms delay between sysfs reads which helps
minimize the window of opportunity for the signal to interrupt the
I2C transfer.
These makes the problem very rare both for the MX51 and MX53.
I have not been able to repro it manually after the changes, but probably
an automated test could.
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
-rw-r--r-- | drivers/input/misc/mma7455l.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/drivers/input/misc/mma7455l.c b/drivers/input/misc/mma7455l.c index 433d83124803..9c74a605b6c9 100644 --- a/drivers/input/misc/mma7455l.c +++ b/drivers/input/misc/mma7455l.c @@ -139,6 +139,8 @@ struct mma7455l_info { #define WRITE_BIT (1 << 7) #define ADDR_SHIFT 1 + +#if !defined(CONFIG_MODULE_CCXMX5X) /* Defaults to I2c access */ static inline u_int8_t __reg_read(struct mma7455l_info *mma, u_int8_t reg) { @@ -154,6 +156,37 @@ static inline u_int8_t __reg_read(struct mma7455l_info *mma, u_int8_t reg) return ret; return buf; } +#else +static inline u_int8_t __reg_read(struct mma7455l_info *mma, u_int8_t reg) +{ + unsigned char buf[2] = {0, 0}; + struct i2c_msg i2cmsg[2]; + int ret = 0; + + buf[0] = reg; + + /* Write the register to access */ + i2cmsg[0].addr = mma->client->addr; + i2cmsg[0].len = 2; + i2cmsg[0].buf = &buf[0]; + i2cmsg[0].flags = 0; + + /* Read the data */ + i2cmsg[1].addr = mma->client->addr; + i2cmsg[1].len = 1; + i2cmsg[1].buf = &buf[1]; + i2cmsg[1].flags = I2C_M_RD; + + ret = i2c_transfer(mma->client->adapter, i2cmsg, 2); + + if (ret < 0) { + dev_dbg(&mma->client->dev,"%s:master_xfer Failed!!\n", __func__); + return -EIO; + } + + return buf[1]; +} +#endif static inline int __reg_write(struct mma7455l_info *mma, u_int8_t reg, u_int8_t val) @@ -312,6 +345,10 @@ static ssize_t show_measure(struct device *dev, y = reg_read(mma, MMA7455L_REG_YOUT8); z = reg_read(mma, MMA7455L_REG_ZOUT8); +#if defined(CONFIG_MODULE_CCXMX5X) + msleep(10); +#endif + set_mode(mma, old_Mode, old_gSelect); return sprintf(buf, "%d %d %d\n", x, y, z); } |