Use the new regmap core API regmap_multi_reg_write(), to prevent a rare
problem with the Dialog DA9052/3 PMIC devices that causes the device to
fail.

Signed-off-by: Anthony Olech <anthony.olech.opensou...@diasemi.com>
---

This patch is relative to linux-next repository tag next-20140403

Even though the probability of the problem occurring is exceedingly rare,
the consequences are a bricked device and so this workround is essential.

The patch has been tested using the RTC ALARM function in conjuctions with
an I2C logic analyser.

 drivers/mfd/da9052-i2c.c          |   34 +++++++++-------------------------
 include/linux/mfd/da9052/da9052.h |   24 ++++++++++++++++--------
 2 files changed, 25 insertions(+), 33 deletions(-)

diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
index 6da8ec8..ca6b4f6 100644
--- a/drivers/mfd/da9052-i2c.c
+++ b/drivers/mfd/da9052-i2c.c
@@ -87,27 +87,11 @@ static int da9052_i2c_fix(struct da9052 *da9052, unsigned 
char reg)
        return 0;
 }
 
-/*
- * According to errata item 24, multiwrite mode should be avoided
- * in order to prevent register data corruption after power-down.
- */
-static int da9052_i2c_disable_multiwrite(struct da9052 *da9052)
+static int da9052_i2c_config_multiwrite(struct da9052 *da9052, bool enable)
 {
-       int reg_val, ret;
-
-       ret = regmap_read(da9052->regmap, DA9052_CONTROL_B_REG, &reg_val);
-       if (ret < 0)
-               return ret;
-
-       if (!(reg_val & DA9052_CONTROL_B_WRITEMODE)) {
-               reg_val |= DA9052_CONTROL_B_WRITEMODE;
-               ret = regmap_write(da9052->regmap, DA9052_CONTROL_B_REG,
-                                  reg_val);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
+       return regmap_update_bits(da9052->regmap, DA9052_CONTROL_B_REG,
+                               DA9052_CONTROL_B_WRITEMODE,
+                               enable ? 0xFF : 0);
 }
 
 static const struct i2c_device_id da9052_i2c_id[] = {
@@ -153,6 +137,8 @@ static int da9052_i2c_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, da9052);
 
+       da9052_regmap_config.can_multi_write = true;
+
        da9052->regmap = devm_regmap_init_i2c(client, &da9052_regmap_config);
        if (IS_ERR(da9052->regmap)) {
                ret = PTR_ERR(da9052->regmap);
@@ -161,7 +147,8 @@ static int da9052_i2c_probe(struct i2c_client *client,
                return ret;
        }
 
-       ret = da9052_i2c_disable_multiwrite(da9052);
+       ret = da9052_i2c_config_multiwrite(da9052,
+                                       da9052_regmap_config.can_multi_write);
        if (ret < 0)
                return ret;
 
@@ -182,10 +169,7 @@ static int da9052_i2c_probe(struct i2c_client *client,
        }
 
        ret = da9052_device_init(da9052, id->driver_data);
-       if (ret != 0)
-               return ret;
-
-       return 0;
+       return ret;
 }
 
 static int da9052_i2c_remove(struct i2c_client *client)
diff --git a/include/linux/mfd/da9052/da9052.h 
b/include/linux/mfd/da9052/da9052.h
index bba65f5..967c802 100644
--- a/include/linux/mfd/da9052/da9052.h
+++ b/include/linux/mfd/da9052/da9052.h
@@ -172,20 +172,28 @@ static inline int da9052_group_write(struct da9052 
*da9052, unsigned char reg,
                                      unsigned reg_cnt, unsigned char *val)
 {
        int ret;
+       unsigned char r = reg;
+       struct reg_default *regs;
        int i;
 
+       regs = kmalloc(sizeof(struct reg_default)*reg_cnt, GFP_KERNEL);
+       if (!regs)
+               return -ENOMEM;
+
        for (i = 0; i < reg_cnt; i++) {
-               ret = regmap_write(da9052->regmap, reg + i, val[i]);
-               if (ret < 0)
-                       return ret;
+               regs[i].reg = r++;
+               regs[i].def = val[i];
        }
 
-       if (da9052->fix_io) {
-               ret = da9052->fix_io(da9052, reg);
-               if (ret < 0)
-                       return ret;
-       }
+       ret = regmap_multi_reg_write(da9052->regmap, regs, reg_cnt);
+
+       kfree(regs);
+
+       if (ret < 0)
+               return ret;
 
+       if (da9052->fix_io)
+               ret = da9052->fix_io(da9052, reg+reg_cnt-1);
        return ret;
 }
 
-- 
end-of-patch 1/1 for drivers/mfd: da9052: use multiwrite mode V1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to