[PATCH V1] drivers/mfd: da9052: use multiwrite mode
From: Opensource [Anthony Olech]
Date: Thu Apr 03 2014 - 09:03:01 EST
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.opensource@xxxxxxxxxxx>
---
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, ®_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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/