lkml.org 
[lkml]   [2014]   [Apr]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Date
Subject[PATCH V1] drivers/mfd: da9052: use multiwrite mode
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@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


\
 
 \ /
  Last update: 2014-04-06 01:21    [W:0.126 / U:0.020 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site