diff options
Diffstat (limited to 'drivers/mfd/da9052-i2c.c')
| -rw-r--r-- | drivers/mfd/da9052-i2c.c | 83 |
1 files changed, 75 insertions, 8 deletions
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index 352c58b5a90..6da8ec8ff80 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c @@ -27,7 +27,71 @@ #include <linux/of_device.h> #endif -static int da9052_i2c_enable_multiwrite(struct da9052 *da9052) +/* I2C safe register check */ +static inline bool i2c_safe_reg(unsigned char reg) +{ + switch (reg) { + case DA9052_STATUS_A_REG: + case DA9052_STATUS_B_REG: + case DA9052_STATUS_C_REG: + case DA9052_STATUS_D_REG: + case DA9052_ADC_RES_L_REG: + case DA9052_ADC_RES_H_REG: + case DA9052_VDD_RES_REG: + case DA9052_ICHG_AV_REG: + case DA9052_TBAT_RES_REG: + case DA9052_ADCIN4_RES_REG: + case DA9052_ADCIN5_RES_REG: + case DA9052_ADCIN6_RES_REG: + case DA9052_TJUNC_RES_REG: + case DA9052_TSI_X_MSB_REG: + case DA9052_TSI_Y_MSB_REG: + case DA9052_TSI_LSB_REG: + case DA9052_TSI_Z_MSB_REG: + return true; + default: + return false; + } +} + +/* + * There is an issue with DA9052 and DA9053_AA/BA/BB PMIC where the PMIC + * gets lockup up or fails to respond following a system reset. + * This fix is to follow any read or write with a dummy read to a safe + * register. + */ +static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg) +{ + int val; + + switch (da9052->chip_id) { + case DA9052: + case DA9053_AA: + case DA9053_BA: + case DA9053_BB: + /* A dummy read to a safe register address. */ + if (!i2c_safe_reg(reg)) + return regmap_read(da9052->regmap, + DA9052_PARK_REGISTER, + &val); + break; + case DA9053_BC: + default: + /* + * For other chips parking of I2C register + * to a safe place is not required. + */ + break; + } + + 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) { int reg_val, ret; @@ -35,8 +99,8 @@ static int da9052_i2c_enable_multiwrite(struct da9052 *da9052) if (ret < 0) return ret; - if (reg_val & DA9052_CONTROL_B_WRITEMODE) { - reg_val &= ~DA9052_CONTROL_B_WRITEMODE; + 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) @@ -51,6 +115,7 @@ static const struct i2c_device_id da9052_i2c_id[] = { {"da9053-aa", DA9053_AA}, {"da9053-ba", DA9053_BA}, {"da9053-bb", DA9053_BB}, + {"da9053-bc", DA9053_BC}, {} }; @@ -58,13 +123,14 @@ static const struct i2c_device_id da9052_i2c_id[] = { static const struct of_device_id dialog_dt_ids[] = { { .compatible = "dlg,da9052", .data = &da9052_i2c_id[0] }, { .compatible = "dlg,da9053-aa", .data = &da9052_i2c_id[1] }, - { .compatible = "dlg,da9053-ab", .data = &da9052_i2c_id[2] }, + { .compatible = "dlg,da9053-ba", .data = &da9052_i2c_id[2] }, { .compatible = "dlg,da9053-bb", .data = &da9052_i2c_id[3] }, + { .compatible = "dlg,da9053-bc", .data = &da9052_i2c_id[4] }, { /* sentinel */ } }; #endif -static int __devinit da9052_i2c_probe(struct i2c_client *client, +static int da9052_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct da9052 *da9052; @@ -83,6 +149,7 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client, da9052->dev = &client->dev; da9052->chip_irq = client->irq; + da9052->fix_io = da9052_i2c_fix; i2c_set_clientdata(client, da9052); @@ -94,7 +161,7 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client, return ret; } - ret = da9052_i2c_enable_multiwrite(da9052); + ret = da9052_i2c_disable_multiwrite(da9052); if (ret < 0) return ret; @@ -121,7 +188,7 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client, return 0; } -static int __devexit da9052_i2c_remove(struct i2c_client *client) +static int da9052_i2c_remove(struct i2c_client *client) { struct da9052 *da9052 = i2c_get_clientdata(client); @@ -131,7 +198,7 @@ static int __devexit da9052_i2c_remove(struct i2c_client *client) static struct i2c_driver da9052_i2c_driver = { .probe = da9052_i2c_probe, - .remove = __devexit_p(da9052_i2c_remove), + .remove = da9052_i2c_remove, .id_table = da9052_i2c_id, .driver = { .name = "da9052", |
