OSDN Git Service

rtc: rv3028: Add support for "aux-voltage-chargeable" property
authorAndrej Picej <andrej.picej@norik.com>
Fri, 23 Jun 2023 08:15:33 +0000 (10:15 +0200)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Thu, 27 Jul 2023 21:13:12 +0000 (23:13 +0200)
Property "trickle-resistor-ohms" allows us to set trickle charger
resistor. However there is no possibility to disable it afterwards.

Add support for "aux-voltage-chargeable" property which can be used to
enable/disable the trickle charger circuit explicitly. The default
behavior of the code is kept as it is!

Additionally, lets make sure we only update internal EEPROM in case of a
change. This prevents wear due to excessive EEPROM writes on each probe.

Signed-off-by: Andrej Picej <andrej.picej@norik.com>
Link: https://lore.kernel.org/r/20230623081533.76334-1-andrej.picej@norik.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
drivers/rtc/rtc-rv3028.c

index 076e56f..e039b47 100644 (file)
@@ -855,11 +855,68 @@ static const struct regmap_config regmap_config = {
         .max_register = 0x37,
 };
 
+static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028,
+                                    struct i2c_client *client)
+{
+       int ret, val_old, val;
+       u32 ohms, chargeable;
+
+       ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &val_old);
+       if (ret < 0)
+               return ret;
+
+       /* mask out only trickle charger bits */
+       val_old = val_old & (RV3028_BACKUP_TCE | RV3028_BACKUP_TCR_MASK);
+       val = val_old;
+
+       /* setup trickle charger */
+       if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
+                                     &ohms)) {
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++)
+                       if (ohms == rv3028_trickle_resistors[i])
+                               break;
+
+               if (i < ARRAY_SIZE(rv3028_trickle_resistors)) {
+                       /* enable trickle charger and its resistor */
+                       val = RV3028_BACKUP_TCE | i;
+               } else {
+                       dev_warn(&client->dev, "invalid trickle resistor value\n");
+               }
+       }
+
+       if (!device_property_read_u32(&client->dev, "aux-voltage-chargeable",
+                                     &chargeable)) {
+               switch (chargeable) {
+               case 0:
+                       val &= ~RV3028_BACKUP_TCE;
+                       break;
+               case 1:
+                       val |= RV3028_BACKUP_TCE;
+                       break;
+               default:
+                       dev_warn(&client->dev,
+                                "unsupported aux-voltage-chargeable value\n");
+                       break;
+               }
+       }
+
+       /* only update EEPROM if changes are necessary */
+       if (val_old != val) {
+               ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE |
+                                               RV3028_BACKUP_TCR_MASK, val);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
+}
+
 static int rv3028_probe(struct i2c_client *client)
 {
        struct rv3028_data *rv3028;
        int ret, status;
-       u32 ohms;
        struct nvmem_config nvmem_cfg = {
                .name = "rv3028_nvram",
                .word_size = 1,
@@ -937,24 +994,9 @@ static int rv3028_probe(struct i2c_client *client)
        if (ret)
                return ret;
 
-       /* setup trickle charger */
-       if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
-                                     &ohms)) {
-               int i;
-
-               for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++)
-                       if (ohms == rv3028_trickle_resistors[i])
-                               break;
-
-               if (i < ARRAY_SIZE(rv3028_trickle_resistors)) {
-                       ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE |
-                                                RV3028_BACKUP_TCR_MASK, RV3028_BACKUP_TCE | i);
-                       if (ret)
-                               return ret;
-               } else {
-                       dev_warn(&client->dev, "invalid trickle resistor value\n");
-               }
-       }
+       ret = rv3028_set_trickle_charger(rv3028, client);
+       if (ret)
+               return ret;
 
        ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group);
        if (ret)