diff options
-rw-r--r-- | drivers/rtc/rtc-rv3029c2.c | 106 |
1 files changed, 103 insertions, 3 deletions
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index e59b8a54d9a7..b416ed026168 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -10,9 +10,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * NOTE: Currently this driver only supports the bare minimum for read - * and write the RTC and alarms. The extra features provided by this chip - * (trickle charger, eeprom, T° compensation) are unavailable. */ #include <linux/module.h> @@ -528,6 +525,107 @@ static int rv3029_rtc_set_time(struct device *dev, struct rtc_time *tm) return rv3029_i2c_set_time(to_i2c_client(dev), tm); } +static const struct rv3029_trickle_tab_elem { + u32 r; /* resistance in ohms */ + u8 conf; /* trickle config bits */ +} rv3029_trickle_tab[] = { + { + .r = 1076, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, + }, { + .r = 1091, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_20K, + }, { + .r = 1137, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_80K, + }, { + .r = 1154, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K, + }, { + .r = 1371, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K | + RV3029_TRICKLE_80K, + }, { + .r = 1395, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K, + }, { + .r = 1472, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K, + }, { + .r = 1500, + .conf = RV3029_TRICKLE_1K, + }, { + .r = 3810, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K | + RV3029_TRICKLE_80K, + }, { + .r = 4000, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K, + }, { + .r = 4706, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K, + }, { + .r = 5000, + .conf = RV3029_TRICKLE_5K, + }, { + .r = 16000, + .conf = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, + }, { + .r = 20000, + .conf = RV3029_TRICKLE_20K, + }, { + .r = 80000, + .conf = RV3029_TRICKLE_80K, + }, +}; + +static void rv3029_trickle_config(struct i2c_client *client) +{ + struct device_node *of_node = client->dev.of_node; + const struct rv3029_trickle_tab_elem *elem; + int i, err; + u32 ohms; + u8 eectrl; + + if (!of_node) + return; + + /* Configure the trickle charger. */ + err = rv3029_eeprom_read(client, RV3029_CONTROL_E2P_EECTRL, + &eectrl, 1); + if (err < 0) { + dev_err(&client->dev, + "Failed to read trickle charger config\n"); + return; + } + err = of_property_read_u32(of_node, "trickle-resistor-ohms", &ohms); + if (err) { + /* Disable trickle charger. */ + eectrl &= ~RV3029_TRICKLE_MASK; + } else { + /* Enable trickle charger. */ + for (i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++) { + elem = &rv3029_trickle_tab[i]; + if (elem->r >= ohms) + break; + } + eectrl &= ~RV3029_TRICKLE_MASK; + eectrl |= elem->conf; + dev_info(&client->dev, + "Trickle charger enabled at %d ohms resistance.\n", + elem->r); + } + err = rv3029_eeprom_write(client, RV3029_CONTROL_E2P_EECTRL, + &eectrl, 1); + if (err < 0) { + dev_err(&client->dev, + "Failed to write trickle charger config\n"); + } +} + static const struct rtc_class_ops rv3029_rtc_ops = { .read_time = rv3029_rtc_read_time, .set_time = rv3029_rtc_set_time, @@ -558,6 +656,8 @@ static int rv3029_probe(struct i2c_client *client, return rc; } + rv3029_trickle_config(client); + rtc = devm_rtc_device_register(&client->dev, client->name, &rv3029_rtc_ops, THIS_MODULE); |