Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: da9052: Avoid multiwrite mode due to silicon errata

DA9053 (up to revision bc) can corrupt internal registers when multi-write
mode is enabled and power is removed or during shutdown.

Signed-off-by: David Jander <david@protonic.nl>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

David Jander and committed by
Lee Jones
43e30f23 61e6cfa8

+22 -10
+8 -4
drivers/mfd/da9052-i2c.c
··· 86 86 return 0; 87 87 } 88 88 89 - static int da9052_i2c_enable_multiwrite(struct da9052 *da9052) 89 + /* 90 + * According to errata item 24, multiwrite mode should be avoided 91 + * in order to prevent register data corruption after power-down. 92 + */ 93 + static int da9052_i2c_disable_multiwrite(struct da9052 *da9052) 90 94 { 91 95 int reg_val, ret; 92 96 ··· 98 94 if (ret < 0) 99 95 return ret; 100 96 101 - if (reg_val & DA9052_CONTROL_B_WRITEMODE) { 102 - reg_val &= ~DA9052_CONTROL_B_WRITEMODE; 97 + if (!(reg_val & DA9052_CONTROL_B_WRITEMODE)) { 98 + reg_val |= DA9052_CONTROL_B_WRITEMODE; 103 99 ret = regmap_write(da9052->regmap, DA9052_CONTROL_B_REG, 104 100 reg_val); 105 101 if (ret < 0) ··· 158 154 return ret; 159 155 } 160 156 161 - ret = da9052_i2c_enable_multiwrite(da9052); 157 + ret = da9052_i2c_disable_multiwrite(da9052); 162 158 if (ret < 0) 163 159 return ret; 164 160
+14 -6
include/linux/mfd/da9052/da9052.h
··· 148 148 unsigned reg_cnt, unsigned char *val) 149 149 { 150 150 int ret; 151 + unsigned int tmp; 152 + int i; 151 153 152 - ret = regmap_bulk_read(da9052->regmap, reg, val, reg_cnt); 153 - if (ret < 0) 154 - return ret; 154 + for (i = 0; i < reg_cnt; i++) { 155 + ret = regmap_read(da9052->regmap, reg + i, &tmp); 156 + val[i] = (unsigned char)tmp; 157 + if (ret < 0) 158 + return ret; 159 + } 155 160 156 161 if (da9052->fix_io) { 157 162 ret = da9052->fix_io(da9052, reg); ··· 171 166 unsigned reg_cnt, unsigned char *val) 172 167 { 173 168 int ret; 169 + int i; 174 170 175 - ret = regmap_raw_write(da9052->regmap, reg, val, reg_cnt); 176 - if (ret < 0) 177 - return ret; 171 + for (i = 0; i < reg_cnt; i++) { 172 + ret = regmap_write(da9052->regmap, reg + i, val[i]); 173 + if (ret < 0) 174 + return ret; 175 + } 178 176 179 177 if (da9052->fix_io) { 180 178 ret = da9052->fix_io(da9052, reg);