summaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorIskren Chernev <iskren.chernev@gmail.com>2020-09-22 14:42:36 +0300
committerSebastian Reichel <sebastian.reichel@collabora.com>2020-10-03 19:18:28 +0200
commit1779c6e3496a53d9cbbbcd248b234b2b6a07435c (patch)
treebd57ea17ce24d44871345b799226f28136cb2c7b /drivers/power
parentb973c9d518199bd8362aeae13d208d8889283287 (diff)
power: supply: max17040: Support setting rcomp
The Maxim ModelGauge family supports fine-tuning by setting a compensation value (named rcomp in the docs). The value is affected by battery chemistry and ambient temperature. Add support for reading maxim,rcomp from DT and configuring the device with the supplied value. Temperature adjustment is not implemented at the moment, because there is no provision for receiving the ambient temperature at the moment. Signed-off-by: Iskren Chernev <iskren.chernev@gmail.com> Tested-by: Jonathan Bakker <xc-racer2@live.ca> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/supply/max17040_battery.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c
index 4bcec86d9209..ae39ca5c6753 100644
--- a/drivers/power/supply/max17040_battery.c
+++ b/drivers/power/supply/max17040_battery.c
@@ -30,9 +30,11 @@
#define MAX17040_DELAY 1000
#define MAX17040_BATTERY_FULL 95
+#define MAX17040_RCOMP_DEFAULT 0x9700
#define MAX17040_ATHD_MASK 0x3f
#define MAX17040_ATHD_DEFAULT_POWER_UP 4
+#define MAX17040_CFG_RCOMP_MASK 0xff00
enum chip_id {
ID_MAX17040,
@@ -52,6 +54,7 @@ struct chip_data {
u16 vcell_mul;
u16 vcell_div;
u8 has_low_soc_alert;
+ u8 rcomp_bytes;
};
static struct chip_data max17040_family[] = {
@@ -61,6 +64,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 1250,
.vcell_div = 1,
.has_low_soc_alert = 0,
+ .rcomp_bytes = 2,
},
[ID_MAX17041] = {
.reset_val = 0x0054,
@@ -68,6 +72,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 2500,
.vcell_div = 1,
.has_low_soc_alert = 0,
+ .rcomp_bytes = 2,
},
[ID_MAX17043] = {
.reset_val = 0x0054,
@@ -75,6 +80,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 1250,
.vcell_div = 1,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
[ID_MAX17044] = {
.reset_val = 0x0054,
@@ -82,6 +88,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 2500,
.vcell_div = 1,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
[ID_MAX17048] = {
.reset_val = 0x5400,
@@ -89,6 +96,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 625,
.vcell_div = 8,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
[ID_MAX17049] = {
.reset_val = 0x5400,
@@ -96,6 +104,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 625,
.vcell_div = 4,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
[ID_MAX17058] = {
.reset_val = 0x5400,
@@ -103,6 +112,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 625,
.vcell_div = 8,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
[ID_MAX17059] = {
.reset_val = 0x5400,
@@ -110,6 +120,7 @@ static struct chip_data max17040_family[] = {
.vcell_mul = 625,
.vcell_div = 4,
.has_low_soc_alert = 1,
+ .rcomp_bytes = 1,
},
};
@@ -129,6 +140,8 @@ struct max17040_chip {
u32 low_soc_alert;
/* some devices return twice the capacity */
bool quirk_double_soc;
+ /* higher 8 bits for 17043+, 16 bits for 17040,41 */
+ u16 rcomp;
};
static int max17040_reset(struct max17040_chip *chip)
@@ -143,6 +156,14 @@ static int max17040_set_low_soc_alert(struct max17040_chip *chip, u32 level)
MAX17040_ATHD_MASK, level);
}
+static int max17040_set_rcomp(struct max17040_chip *chip, u16 rcomp)
+{
+ u16 mask = chip->data.rcomp_bytes == 2 ?
+ 0xffff : MAX17040_CFG_RCOMP_MASK;
+
+ return regmap_update_bits(chip->regmap, MAX17040_CONFIG, mask, rcomp);
+}
+
static int max17040_raw_vcell_to_uvolts(struct max17040_chip *chip, u16 vcell)
{
struct chip_data *d = &chip->data;
@@ -206,6 +227,10 @@ static int max17040_get_status(struct max17040_chip *chip)
static int max17040_get_of_data(struct max17040_chip *chip)
{
struct device *dev = &chip->client->dev;
+ struct chip_data *data = &max17040_family[
+ (enum chip_id) of_device_get_match_data(dev)];
+ int rcomp_len;
+ u8 rcomp[2];
chip->quirk_double_soc = device_property_read_bool(dev,
"maxim,double-soc");
@@ -221,6 +246,19 @@ static int max17040_get_of_data(struct max17040_chip *chip)
return -EINVAL;
}
+ rcomp_len = device_property_count_u8(dev, "maxim,rcomp");
+ chip->rcomp = MAX17040_RCOMP_DEFAULT;
+ if (rcomp_len == data->rcomp_bytes) {
+ device_property_read_u8_array(dev, "maxim,rcomp",
+ rcomp, rcomp_len);
+ chip->rcomp = rcomp_len == 2 ?
+ rcomp[0] << 8 | rcomp[1] :
+ rcomp[0] << 8;
+ } else if (rcomp_len > 0) {
+ dev_err(dev, "maxim,rcomp has incorrect length\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -430,6 +468,8 @@ static int max17040_probe(struct i2c_client *client,
if (chip_id == ID_MAX17040 || chip_id == ID_MAX17041)
max17040_reset(chip);
+ max17040_set_rcomp(chip, chip->rcomp);
+
/* check interrupt */
if (client->irq && chip->data.has_low_soc_alert) {
ret = max17040_set_low_soc_alert(chip, chip->low_soc_alert);