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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user