Re: [PATCH] rtc: rv3028: configure backup switch mode from device tree
From: Dhaval Shiroya
Date: Wed Aug 26 2026 - 02:45:49 EST
Hi Alexandre,
>On 22/08/2026 14:59:11+0530, Dhaval Shiroya wrote:
>> Enable and set the backup switch mode directly from the device tree at
>> probe, instead of requiring a userspace RTC_PARAM_BACKUP_SWITCH_MODE
>> ioctl on every unit.
>>
>
>No, just use the ioctl.
Thanks for the reply.
Instead, can we enable the FEDE bit, as the datasheet recommends enabling it when switching to RTC Backup Switchover Mode?
Could you please share your thoughts on this?
>
>> Signed-off-by: Dhaval Shiroya <dhaval.shiroya@xxxxxxxxxxxxxxxxx>
>>
>> diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c
>> index d96f6bb68850..5dde1aed76dd 100644
>> --- a/drivers/rtc/rtc-rv3028.c
>> +++ b/drivers/rtc/rtc-rv3028.c
>> @@ -80,6 +80,7 @@
>> #define RV3028_EEBUSY_TIMEOUT 100000
>>
>> #define RV3028_BACKUP_TCE BIT(5)
>> +#define RV3028_BACKUP_FEDE BIT(4)
>> #define RV3028_BACKUP_TCR_MASK GENMASK(1,0)
>> #define RV3028_BACKUP_BSM GENMASK(3,2)
>>
>> @@ -519,70 +520,6 @@ static int rv3028_set_offset(struct device *dev, long offset)
>>
>> }
>>
>> -static int rv3028_param_get(struct device *dev, struct rtc_param *param)
>> -{
>> - struct rv3028_data *rv3028 = dev_get_drvdata(dev);
>> - int ret;
>> - u32 value;
>> -
>> - switch(param->param) {
>> - case RTC_PARAM_BACKUP_SWITCH_MODE:
>> - ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value);
>> - if (ret < 0)
>> - return ret;
>> -
>> - value = FIELD_GET(RV3028_BACKUP_BSM, value);
>> -
>> - switch(value) {
>> - case RV3028_BACKUP_BSM_DSM:
>> - param->uvalue = RTC_BSM_DIRECT;
>> - break;
>> - case RV3028_BACKUP_BSM_LSM:
>> - param->uvalue = RTC_BSM_LEVEL;
>> - break;
>> - default:
>> - param->uvalue = RTC_BSM_DISABLED;
>> - }
>> - break;
>> -
>> - default:
>> - return -EINVAL;
>> - }
>> -
>> - return 0;
>> -}
>> -
>> -static int rv3028_param_set(struct device *dev, struct rtc_param *param)
>> -{
>> - struct rv3028_data *rv3028 = dev_get_drvdata(dev);
>> - u8 mode;
>> -
>> - switch(param->param) {
>> - case RTC_PARAM_BACKUP_SWITCH_MODE:
>> - switch (param->uvalue) {
>> - case RTC_BSM_DISABLED:
>> - mode = 0;
>> - break;
>> - case RTC_BSM_DIRECT:
>> - mode = RV3028_BACKUP_BSM_DSM;
>> - break;
>> - case RTC_BSM_LEVEL:
>> - mode = RV3028_BACKUP_BSM_LSM;
>> - break;
>> - default:
>> - return -EINVAL;
>> - }
>> -
>> - return rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_BSM,
>> - FIELD_PREP(RV3028_BACKUP_BSM, mode));
>> -
>> - default:
>> - return -EINVAL;
>> - }
>> -
>> - return 0;
>> -}
>> -
>> static int rv3028_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
>> {
>> struct rv3028_data *rv3028 = dev_get_drvdata(dev);
>> @@ -852,8 +789,6 @@ static const struct rtc_class_ops rv3028_rtc_ops = {
>> .read_offset = rv3028_read_offset,
>> .set_offset = rv3028_set_offset,
>> .ioctl = rv3028_ioctl,
>> - .param_get = rv3028_param_get,
>> - .param_set = rv3028_param_set,
>> };
>>
>> static const struct regmap_config regmap_config = {
>> @@ -920,6 +855,65 @@ static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028,
>> return ret;
>> }
>>
>> +/*
>> + * Configure backup switchover mode from device tree.
>> + * 0 = disabled
>> + * 1 = DSM (Direct Switching Mode) - switch when VDD < VBACKUP
>> + * 3 = LSM (Level Switching Mode) - switch when VDD < 2.0V
>> + */
>> +static int rv3028_set_bsm_from_dt(struct rv3028_data *rv3028,
>> + struct i2c_client *client)
>> +{
>> + u32 val_old, bsm_dt, bsm_bits;
>> + int ret;
>> +
>> + if (device_property_read_u32(&client->dev, "backup-switch-mode",
>> + &bsm_dt))
>> + return 0;
>> +
>> + /* Validate and convert DT value to register bits */
>> + switch (bsm_dt) {
>> + case 0:
>> + bsm_bits = 0;
>> + break;
>> + case 1:
>> + bsm_bits = FIELD_PREP(RV3028_BACKUP_BSM, RV3028_BACKUP_BSM_DSM);
>> + break;
>> + case 3:
>> + bsm_bits = FIELD_PREP(RV3028_BACKUP_BSM, RV3028_BACKUP_BSM_LSM);
>> + break;
>> + default:
>> + dev_warn(&client->dev,
>> + "invalid backup-switch-mode %u (use 0, 1, or 3)\n",
>> + bsm_dt);
>> + return 0;
>> + }
>> +
>> + /* Read current BACKUP register */
>> + ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &val_old);
>> + if (ret < 0)
>> + return ret;
>> +
>> + /* Check if BSM and FEDE already match desired values */
>> + if ((val_old & (RV3028_BACKUP_BSM | RV3028_BACKUP_FEDE)) ==
>> + (bsm_bits | RV3028_BACKUP_FEDE)) {
>> + dev_dbg(&client->dev,
>> + "backup switch mode already set to %u\n", bsm_dt);
>> + return 0;
>> + }
>> +
>> + dev_info(&client->dev,
>> + "setting backup switch mode to %u (reg 0x37: 0x%02x -> 0x%02x)\n",
>> + bsm_dt, val_old,
>> + (val_old & ~(RV3028_BACKUP_BSM | RV3028_BACKUP_FEDE)) |
>> + bsm_bits | RV3028_BACKUP_FEDE);
>> +
>> + /* Set BSM and always enable FEDE as recommended by datasheet */
>> + return rv3028_update_cfg(rv3028, RV3028_BACKUP,
>> + RV3028_BACKUP_BSM | RV3028_BACKUP_FEDE,
>> + bsm_bits | RV3028_BACKUP_FEDE);
>> +}
>> +
>> static int rv3028_probe(struct i2c_client *client)
>> {
>> struct rv3028_data *rv3028;
>> @@ -1005,11 +999,14 @@ static int rv3028_probe(struct i2c_client *client)
>> if (ret)
>> return ret;
>>
>> - ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
>> + /* Configure backup switchover mode from device tree */
>> + ret = rv3028_set_bsm_from_dt(rv3028, client);
>> if (ret)
>> return ret;
>>
>> - set_bit(RTC_FEATURE_BACKUP_SWITCH_MODE, rv3028->rtc->features);
>> + ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
>> + if (ret)
>> + return ret;
>>
>> rv3028->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
>> rv3028->rtc->range_max = RTC_TIMESTAMP_END_2099;
>> --
>> 2.34.1
>>
>
>--
>Alexandre Belloni, co-owner and COO, Bootlin
>Embedded Linux and Kernel engineering
>https://bootlin.com
Best Regards,
Dhaval Shiroya