Re: [PATCH] rtc: rv3028: configure backup switch mode from device tree
From: Alexandre Belloni
Date: Sat Aug 22 2026 - 09:09:53 EST
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.
> 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