rtc: rv3028: Mirror BSM and TCE/TCR to EEPROM

Periodically the RV3028 refreshes registers from the EEPROM. When this
happens, some settings that have only been committed to registers are
lost. Change the handling of backup-switchover-mode and
trickle-resistor-ohms to write the EEPROM as well (if something has
changed).

See: https://github.com/raspberrypi/linux/issues/2912

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
This commit is contained in:
Phil Elwell
2020-05-15 16:28:32 +01:00
parent 355bbe0f81
commit 3af3e39f2a

View File

@@ -19,6 +19,7 @@
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
//#include "rtc-core.h"
#define RV3028_SEC 0x00
#define RV3028_MIN 0x01
@@ -80,7 +81,7 @@
#define RV3028_BACKUP_TCE BIT(5)
#define RV3028_BACKUP_TCR_MASK GENMASK(1,0)
#define RV3028_BACKUP_BSM_MASK 0x0C
#define RV3028_BACKUP_BSM_MASK GENMASK(3,2)
#define OFFSET_STEP_PPT 953674
@@ -790,7 +791,8 @@ static int rv3028_probe(struct i2c_client *client)
struct rv3028_data *rv3028;
int ret, status;
u32 ohms;
u8 bsm;
u32 bsm;
u8 backup, backup_bits, backup_mask;
struct nvmem_config nvmem_cfg = {
.name = "rv3028_nvram",
.word_size = 1,
@@ -857,16 +859,16 @@ static int rv3028_probe(struct i2c_client *client)
if (ret)
return ret;
/* setup backup switchover mode */
if (!device_property_read_u8(&client->dev, "backup-switchover-mode",
&bsm)) {
if (bsm <= 3) {
ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP,
RV3028_BACKUP_BSM_MASK,
(bsm & 0x03) << 2);
backup_bits = 0;
backup_mask = 0;
if (ret)
return ret;
/* setup backup switchover mode */
if (!device_property_read_u32(&client->dev,
"backup-switchover-mode",
&bsm)) {
if (bsm <= 3) {
backup_bits |= (u8)(bsm << 2);
backup_mask |= RV3028_BACKUP_BSM_MASK;
} else {
dev_warn(&client->dev, "invalid backup switchover mode value\n");
}
@@ -882,15 +884,34 @@ static int rv3028_probe(struct i2c_client *client)
break;
if (i < ARRAY_SIZE(rv3028_trickle_resistors)) {
ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE |
RV3028_BACKUP_TCR_MASK, RV3028_BACKUP_TCE | i);
if (ret)
return ret;
backup_bits |= RV3028_BACKUP_TCE | i;
backup_mask |= RV3028_BACKUP_TCE |
RV3028_BACKUP_TCR_MASK;
} else {
dev_warn(&client->dev, "invalid trickle resistor value\n");
dev_warn(&client->dev,
"invalid trickle resistor value\n");
}
}
if (backup_mask) {
ret = rv3028_eeprom_read((void *)(rv3028->regmap),
RV3028_BACKUP,
(void *)&backup, 1);
/* Write register and EEPROM if needed */
if (!ret && (backup & backup_mask) != backup_bits) {
backup = (backup & ~backup_mask) | backup_bits;
ret = rv3028_update_cfg(rv3028, RV3028_BACKUP,
backup_mask, backup_bits);
}
/* In the event of an EEPROM failure, just update the register */
if (ret)
ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP,
backup_mask, backup_bits);
if (ret)
return ret;
}
ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
if (ret)
return ret;