From dbc533df603115a5e91b9b333ede234b40ffcc75 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Wed, 16 Feb 2022 18:12:56 +0100 Subject: [PATCH 382/469] power: supply: ip5xxx: Report remaining battery capacity This uses OCV tables from device tree. Internal resistance value used by the chip is not very precise. Use the value from DT, too. Signed-off-by: Ondrej Jirman --- drivers/power/supply/ip5xxx_power.c | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/power/supply/ip5xxx_power.c b/drivers/power/supply/ip5xxx_power.c index 00221e9c0bfc..7f79644a976a 100644 --- a/drivers/power/supply/ip5xxx_power.c +++ b/drivers/power/supply/ip5xxx_power.c @@ -76,6 +76,8 @@ struct ip5xxx { struct regmap *regmap; + struct power_supply_battery_info *bat; + int r_int; bool initialized; }; @@ -171,6 +173,8 @@ static const enum power_supply_property ip5xxx_battery_properties[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CALIBRATE, POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_OCV, @@ -316,6 +320,7 @@ static int ip5xxx_battery_get_property(struct power_supply *psy, struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy); int raw, ret, vmax; unsigned int rval; + union power_supply_propval cur, vol; ret = ip5xxx_initialize(psy); if (ret) @@ -331,6 +336,23 @@ static int ip5xxx_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_HEALTH: return ip5xxx_battery_get_health(ip5xxx, &val->intval); + case POWER_SUPPLY_PROP_CAPACITY: + ret = ip5xxx_battery_get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &vol); + if (ret) + return ret; + + ret = ip5xxx_battery_get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &cur); + if (ret) + return ret; + + ret = power_supply_batinfo_ocv2cap(ip5xxx->bat, + vol.intval - cur.intval * ip5xxx->r_int / 1000, 20); + if (ret < 0) + return ret; + + val->intval = ret; + return 0; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: return ip5xxx_battery_get_voltage_max(ip5xxx, &val->intval); @@ -389,6 +411,10 @@ static int ip5xxx_battery_get_property(struct power_supply *psy, val->intval = vmax + 14000 * 3; return 0; + case POWER_SUPPLY_PROP_CALIBRATE: + val->intval = ip5xxx->r_int; + return 0; + default: return -EINVAL; } @@ -472,6 +498,12 @@ static int ip5xxx_battery_set_property(struct power_supply *psy, return ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL2, IP5XXX_CHG_CTL2_CONST_VOLT_SEL, rval); + case POWER_SUPPLY_PROP_CALIBRATE: + if (val->intval < 0 || val->intval > 1000) + return -EINVAL; + ip5xxx->r_int = val->intval; + return 0; + default: return -EINVAL; } @@ -482,6 +514,7 @@ static int ip5xxx_battery_property_is_writeable(struct power_supply *psy, { return psp == POWER_SUPPLY_PROP_STATUS || psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN || + psp == POWER_SUPPLY_PROP_CALIBRATE || psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT || psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE; } @@ -592,6 +625,7 @@ static int ip5xxx_power_probe(struct i2c_client *client) struct device *dev = &client->dev; struct power_supply *psy; struct ip5xxx *ip5xxx; + int ret; ip5xxx = devm_kzalloc(dev, sizeof(*ip5xxx), GFP_KERNEL); if (!ip5xxx) @@ -612,6 +646,15 @@ static int ip5xxx_power_probe(struct i2c_client *client) if (IS_ERR(psy)) return PTR_ERR(psy); + ret = power_supply_get_battery_info(psy, &ip5xxx->bat); + if (ret) + return dev_err_probe(dev, ret, "Failed to get battery info\n"); + + if (ip5xxx->bat->factory_internal_resistance_uohm >= 0) + ip5xxx->r_int = ip5xxx->bat->factory_internal_resistance_uohm / 1000; + else + ip5xxx->r_int = 120; + return 0; } -- 2.34.1