diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index 2f001c59c61d..f5092447e837 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -913,6 +913,66 @@ static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028, return ret; } +static int config_rtc_backup_mode(struct i2c_client *client, u32 mode) +{ + int ret; + struct rtc_param rtc = { + .param = RTC_PARAM_BACKUP_SWITCH_MODE, + .uvalue = 0 + }; + char msg[] = "unique setup of backup mode"; + + ret = rv3028_param_get(&client->dev, &rtc); + if (ret) + goto out; + + if (rtc.uvalue == mode) + goto out; + + rtc.uvalue = mode; + + ret = rv3028_param_set(&client->dev, &rtc); + if (ret) + goto out; + + dev_warn(&client->dev, "%s done", msg); + +out: + if (ret) + dev_err(&client->dev, "%s failed with %i", msg, ret); + + return 0; +} + +static int disable_trickle_charger(struct i2c_client *client, struct rv3028_data *rv3028) +{ + int ret; + u32 val; + bool enabled = false; + + ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &val); + if (ret < 0) + goto out; + + if (val & (RV3028_BACKUP_TCE)) { + enabled = true; + ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE, 0); + if (ret) + goto out; + } + +out: + if (enabled) + dev_warn(&client->dev, "unexpected enabled trickle charger detected %s", + ret? "" : "and disabled"); + + if (ret) + dev_err(&client->dev, "disabling trickle charger failed with %i", ret); + + return ret; +} + + static int rv3028_probe(struct i2c_client *client) { struct rv3028_data *rv3028; @@ -1018,6 +1078,21 @@ static int rv3028_probe(struct i2c_client *client) rv3028->rtc->max_user_freq = 1; + // If a goldcap is used as backup and it's supplied with higher voltage + // then the RTC itself, a special setup is required to avoid hardware failure. + if (device_property_present(&client->dev, "use-goldcap-with-higher-voltage")) { + ret = disable_trickle_charger(client, rv3028); + if (ret) + return ret; + + ret = config_rtc_backup_mode(client, RTC_BSM_LEVEL); + if (ret) + return ret; + } else { + dev_crit(&client->dev, + "goldcap setup skipped, hardware failure possibly"); + } + #ifdef CONFIG_COMMON_CLK rv3028_clkout_register_clk(rv3028, client); #endif