pmaports/device/testing/linux-clockworkpi-uconsole-cm4/0006-power-axp20x_battery-implement-calibration.patch
Federico Amedeo Izzo 587b03ad73
clockworkpi-uconsole-cm4: new device (MR 4751)
[ci:skip-build]: already built successfully in CI
2024-02-18 19:08:43 +00:00

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,
&reg);
@@ -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, &reg); // [7:0]
+ if (ret)
+ return ret;
+
+ val1 = reg;
+
+ ret = regmap_read(axp20x_batt->regmap, AXP288_FG_DES_CAP1_REG, &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, &reg);
+ 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