Re: [PATCH] rtc: rv3028: configure backup switch mode from device tree

Alexandre Belloni <[email protected]>
Newsgroups org.kernel.vger.linux-rtc,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
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 <[email protected]>
> 
> 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.