rtc: rv3032: allow setting BSM

Backup Switch Mode is currently set properly when the trickle charger is
enabled. However, in the case of a non-rechargeable battery, it is
necessary to be able to enable it, only allow that when the trickle charger
is disabled.

Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/20211018151933.76865-8-alexandre.belloni@bootlin.com
This commit is contained in:
Alexandre Belloni 2021-10-18 17:19:33 +02:00
parent 018d959ba7
commit 6084eac38e

View file

@ -106,6 +106,7 @@
struct rv3032_data {
struct regmap *regmap;
struct rtc_device *rtc;
bool trickle_charger_set;
#ifdef CONFIG_COMMON_CLK
struct clk_hw clkout_hw;
#endif
@ -402,6 +403,75 @@ static int rv3032_set_offset(struct device *dev, long offset)
FIELD_PREP(RV3032_OFFSET_MSK, offset));
}
static int rv3032_param_get(struct device *dev, struct rtc_param *param)
{
struct rv3032_data *rv3032 = dev_get_drvdata(dev);
int ret;
switch(param->param) {
u32 value;
case RTC_PARAM_BACKUP_SWITCH_MODE:
ret = regmap_read(rv3032->regmap, RV3032_PMU, &value);
if (ret < 0)
return ret;
value = FIELD_GET(RV3032_PMU_BSM, value);
switch(value) {
case RV3032_PMU_BSM_DSM:
param->uvalue = RTC_BSM_DIRECT;
break;
case RV3032_PMU_BSM_LSM:
param->uvalue = RTC_BSM_LEVEL;
break;
default:
param->uvalue = RTC_BSM_DISABLED;
}
break;
default:
return -EINVAL;
}
return 0;
}
static int rv3032_param_set(struct device *dev, struct rtc_param *param)
{
struct rv3032_data *rv3032 = dev_get_drvdata(dev);
switch(param->param) {
u8 mode;
case RTC_PARAM_BACKUP_SWITCH_MODE:
if (rv3032->trickle_charger_set)
return -EINVAL;
switch (param->uvalue) {
case RTC_BSM_DISABLED:
mode = 0;
break;
case RTC_BSM_DIRECT:
mode = RV3032_PMU_BSM_DSM;
break;
case RTC_BSM_LEVEL:
mode = RV3032_PMU_BSM_LSM;
break;
default:
return -EINVAL;
}
return rv3032_update_cfg(rv3032, RV3032_PMU, RV3032_PMU_BSM,
FIELD_PREP(RV3032_PMU_BSM, mode));
default:
return -EINVAL;
}
return 0;
}
static int rv3032_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
struct rv3032_data *rv3032 = dev_get_drvdata(dev);
@ -541,6 +611,8 @@ static int rv3032_trickle_charger_setup(struct device *dev, struct rv3032_data *
return 0;
}
rv3032->trickle_charger_set = true;
return rv3032_update_cfg(rv3032, RV3032_PMU,
RV3032_PMU_TCR | RV3032_PMU_TCM | RV3032_PMU_BSM,
val | FIELD_PREP(RV3032_PMU_TCR, i));
@ -813,6 +885,8 @@ static const struct rtc_class_ops rv3032_rtc_ops = {
.read_alarm = rv3032_get_alarm,
.set_alarm = rv3032_set_alarm,
.alarm_irq_enable = rv3032_alarm_irq_enable,
.param_get = rv3032_param_get,
.param_set = rv3032_param_set,
};
static const struct regmap_config regmap_config = {
@ -883,6 +957,8 @@ static int rv3032_probe(struct i2c_client *client)
rv3032_trickle_charger_setup(&client->dev, rv3032);
set_bit(RTC_FEATURE_BACKUP_SWITCH_MODE, rv3032->rtc->features);
rv3032->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
rv3032->rtc->range_max = RTC_TIMESTAMP_END_2099;
rv3032->rtc->ops = &rv3032_rtc_ops;