587b03ad73
[ci:skip-build]: already built successfully in CI
178 lines
6 KiB
Diff
178 lines
6 KiB
Diff
From 64524afd6b6598addcf77c92832abdcd508fc8b4 Mon Sep 17 00:00:00 2001
|
|
From: Potato <nikko@faint.day>
|
|
Date: Sat, 4 Nov 2023 19:02:17 +0800
|
|
Subject: [PATCH 6/6] power: axp20x_battery: implement calibration
|
|
|
|
- add sysfs interface to initiate calibration
|
|
- capacity/energy is read from PMU rather than using a predefined value
|
|
- energy_full_designed is loaded from either
|
|
energy-full-design-microwatt-hours or charge-full-design-microamp-hours
|
|
- default is 8Wh
|
|
---
|
|
drivers/power/supply/axp20x_battery.c | 78 +++++++++++++++++++++++----
|
|
1 file changed, 68 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c
|
|
index 53b53137a480..609d240305a2 100644
|
|
--- a/drivers/power/supply/axp20x_battery.c
|
|
+++ b/drivers/power/supply/axp20x_battery.c
|
|
@@ -56,6 +56,10 @@
|
|
|
|
#define AXP20X_V_OFF_MASK GENMASK(2, 0)
|
|
|
|
+#define AXP228_FULL_CAPACITY_CALIBRATE_EN BIT(5)
|
|
+#define AXP228_CAPACITY_CALIBRATE BIT(4)
|
|
+#define AXP228_CALIBRATE_MASK (BIT(4) | BIT(5))
|
|
+
|
|
struct axp20x_batt_ps;
|
|
|
|
struct axp_data {
|
|
@@ -75,6 +79,7 @@ struct axp20x_batt_ps {
|
|
struct iio_channel *batt_v;
|
|
/* Maximum constant charge current */
|
|
unsigned int max_ccc;
|
|
+ int energy_full_design;
|
|
const struct axp_data *data;
|
|
};
|
|
|
|
@@ -328,6 +333,7 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
|
|
|
|
case POWER_SUPPLY_PROP_ENERGY_FULL:
|
|
case POWER_SUPPLY_PROP_ENERGY_NOW:
|
|
+ case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
|
|
/* When no battery is present, return 0 */
|
|
ret = regmap_read(axp20x_batt->regmap, AXP20X_PWR_OP_MODE,
|
|
®);
|
|
@@ -339,8 +345,29 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
|
|
return 0;
|
|
}
|
|
|
|
+ if(psp == POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN) {
|
|
+ val->intval = axp20x_batt->energy_full_design;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* read capacity from PMU */
|
|
+ val->intval = axp20x_batt->energy_full_design;
|
|
+
|
|
+ ret = regmap_read(axp20x_batt->regmap, AXP288_FG_DES_CAP0_REG, ®); // [7:0]
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ val1 = reg;
|
|
+
|
|
+ ret = regmap_read(axp20x_batt->regmap, AXP288_FG_DES_CAP1_REG, ®); // [14:8]
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ val1 |= (reg & 0x3F) << 8; // capacity report from pmu, unit 1.456mAh
|
|
+ val1 = val1 * 1456 * 36 / 10; // uWh
|
|
+
|
|
if(psp == POWER_SUPPLY_PROP_ENERGY_FULL) {
|
|
- val->intval = 8000000;
|
|
+ val->intval = val1;
|
|
return 0;
|
|
}
|
|
|
|
@@ -351,15 +378,18 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
|
|
if (axp20x_batt->data->has_fg_valid && !(reg & AXP22X_FG_VALID))
|
|
return -EINVAL;
|
|
|
|
- val1 = reg & AXP209_FG_PERCENT;
|
|
- if (val1 > 90)
|
|
- val1= 80;
|
|
- else if (val1 < 10)
|
|
- val1 = 0;
|
|
- else
|
|
- val1 -= 10;
|
|
+ reg = reg & AXP209_FG_PERCENT;
|
|
+ reg = max(min(reg, 100), 0);
|
|
+ val->intval = (reg * ((long long int)(val1))) / 100;
|
|
+ break;
|
|
|
|
- val->intval = val1 * 100000;
|
|
+ case POWER_SUPPLY_PROP_CALIBRATE:
|
|
+ /* report both calibrate enable flag and calibration status */
|
|
+ ret = regmap_read(axp20x_batt->regmap, AXP20X_CC_CTRL, ®);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ val1 = reg & AXP228_CALIBRATE_MASK;
|
|
+ val->intval = val1;
|
|
break;
|
|
|
|
default:
|
|
@@ -490,6 +520,7 @@ static int axp20x_battery_set_prop(struct power_supply *psy,
|
|
const union power_supply_propval *val)
|
|
{
|
|
struct axp20x_batt_ps *axp20x_batt = power_supply_get_drvdata(psy);
|
|
+ int val1;
|
|
|
|
switch (psp) {
|
|
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
|
|
@@ -504,6 +535,15 @@ static int axp20x_battery_set_prop(struct power_supply *psy,
|
|
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
|
|
return axp20x_set_max_constant_charge_current(axp20x_batt,
|
|
val->intval);
|
|
+ case POWER_SUPPLY_PROP_CALIBRATE:
|
|
+ if (val->intval) {
|
|
+ // enable calibrate
|
|
+ val1 = AXP228_FULL_CAPACITY_CALIBRATE_EN | AXP228_CAPACITY_CALIBRATE;
|
|
+ } else {
|
|
+ // disable calibrate
|
|
+ val1 = 0;
|
|
+ }
|
|
+ return regmap_update_bits(axp20x_batt->regmap, AXP20X_CC_CTRL, AXP228_CALIBRATE_MASK, val1);
|
|
case POWER_SUPPLY_PROP_STATUS:
|
|
switch (val->intval) {
|
|
case POWER_SUPPLY_STATUS_CHARGING:
|
|
@@ -535,6 +575,8 @@ static enum power_supply_property axp20x_battery_props[] = {
|
|
POWER_SUPPLY_PROP_CAPACITY,
|
|
POWER_SUPPLY_PROP_ENERGY_FULL,
|
|
POWER_SUPPLY_PROP_ENERGY_NOW,
|
|
+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
|
|
+ POWER_SUPPLY_PROP_CALIBRATE,
|
|
};
|
|
|
|
static int axp20x_battery_prop_writeable(struct power_supply *psy,
|
|
@@ -544,7 +586,8 @@ static int axp20x_battery_prop_writeable(struct power_supply *psy,
|
|
psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
|
|
psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
|
|
psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||
|
|
- psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
|
|
+ psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX ||
|
|
+ psp == POWER_SUPPLY_PROP_CALIBRATE;
|
|
}
|
|
|
|
static const struct power_supply_desc axp20x_batt_ps_desc = {
|
|
@@ -654,6 +697,7 @@ static int axp20x_power_probe(struct platform_device *pdev)
|
|
if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) {
|
|
int vmin = info->voltage_min_design_uv;
|
|
int ccc = info->constant_charge_current_max_ua;
|
|
+ int cfd = info->charge_full_design_uah;
|
|
|
|
if (vmin > 0 && axp20x_set_voltage_min_design(axp20x_batt,
|
|
vmin))
|
|
@@ -671,6 +715,20 @@ static int axp20x_power_probe(struct platform_device *pdev)
|
|
axp20x_batt->max_ccc = ccc;
|
|
axp20x_set_constant_charge_current(axp20x_batt, ccc);
|
|
}
|
|
+
|
|
+ if (info->energy_full_design_uwh != info->charge_full_design_uah) {
|
|
+ if (info->energy_full_design_uwh == -EINVAL)
|
|
+ dev_warn(axp20x_batt->dev, "missing battery:energy-full-design-microwatt-hours\n");
|
|
+ else if (info->charge_full_design_uah == -EINVAL)
|
|
+ dev_warn(axp20x_batt->dev, "missing battery:charge-full-design-microamp-hours\n");
|
|
+ }
|
|
+
|
|
+ if (info->energy_full_design_uwh != -EINVAL)
|
|
+ axp20x_batt->energy_full_design = info->energy_full_design_uwh;
|
|
+ else if (info->charge_full_design_uah != -EINVAL)
|
|
+ axp20x_batt->energy_full_design = cfd / 10 * 36; // assume standard voltage 3.6V
|
|
+ else
|
|
+ axp20x_batt->energy_full_design = 8000000; // default capacity, 8Wh
|
|
}
|
|
|
|
/*
|
|
--
|
|
2.43.0
|
|
|