summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAlex Gonzalez <alex.gonzalez@digi.com>2012-02-07 16:08:22 +0100
committerAlex Gonzalez <alex.gonzalez@digi.com>2012-02-07 16:17:22 +0100
commit7be23f852c3ce901c3e6b60d75dee924f4741ff8 (patch)
treeaea6d3d1695ff60c830b890bee8aa134e76385b1 /drivers
parentbe39b7625170fccd03b29354e803c283407b8a29 (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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/misc/mma7455l.c37
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);
}