power: axp20x_battery: implement calibration
This commit is contained in:
parent
3034db8bfb
commit
adc1869bbc
2 changed files with 106 additions and 6 deletions
|
|
@ -13,7 +13,6 @@
|
|||
#include <linux/mfd/axp20x.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/power_supply.h>
|
||||
|
|
@ -53,6 +52,9 @@ static irqreturn_t axp20x_ac_power_irq(int irq, void *devid)
|
|||
{
|
||||
struct axp20x_ac_power *power = devid;
|
||||
|
||||
regmap_update_bits(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, 0x03, 0x00);
|
||||
regmap_update_bits(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, 0x03, 0x03);
|
||||
|
||||
power_supply_changed(power->supply);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
@ -335,7 +337,7 @@ static int axp20x_ac_power_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
axp_data = of_device_get_match_data(&pdev->dev);
|
||||
axp_data = device_get_match_data(&pdev->dev);
|
||||
|
||||
power = devm_kzalloc(&pdev->dev,
|
||||
struct_size(power, irqs, axp_data->num_irq_names),
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/regmap.h>
|
||||
|
|
@ -56,6 +55,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 +78,9 @@ struct axp20x_batt_ps {
|
|||
struct iio_channel *batt_v;
|
||||
/* Maximum constant charge current */
|
||||
unsigned int max_ccc;
|
||||
int energy_full_design;
|
||||
int current_now;
|
||||
int voltage_now;
|
||||
const struct axp_data *data;
|
||||
};
|
||||
|
||||
|
|
@ -276,6 +282,7 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
|
|||
|
||||
/* IIO framework gives mA but Power Supply framework gives uA */
|
||||
val->intval *= 1000;
|
||||
axp20x_batt->current_now = val->intval;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
|
|
@ -324,8 +331,60 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
|
|||
|
||||
/* IIO framework gives mV but Power Supply framework gives uV */
|
||||
val->intval *= 1000;
|
||||
axp20x_batt->current_now = val->intval;
|
||||
break;
|
||||
|
||||
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,
|
||||
®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(reg & AXP20X_PWR_OP_BATT_PRESENT)) {
|
||||
val->intval = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(psp == POWER_SUPPLY_PROP_ENERGY_FULL) {
|
||||
// TODO
|
||||
val->intval = axp20x_batt->energy_full_design;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(psp == POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN) {
|
||||
val->intval = axp20x_batt->energy_full_design;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = regmap_read(axp20x_batt->regmap, AXP20X_FG_RES, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (axp20x_batt->data->has_fg_valid && !(reg & AXP22X_FG_VALID))
|
||||
return -EINVAL;
|
||||
|
||||
val1 = reg & AXP209_FG_PERCENT;
|
||||
val1 = max(min(val1, 100), 0);
|
||||
val->intval = (val1 * ((long long int)axp20x_batt->energy_full_design)) / 100;
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
case POWER_SUPPLY_PROP_POWER_NOW:
|
||||
val->intval = (axp20x_batt->voltage_now / 10000) * axp20x_batt->current_now;
|
||||
val->intval = val->intval / 100; // uW
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -454,6 +513,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:
|
||||
|
|
@ -468,6 +528,16 @@ 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:
|
||||
|
|
@ -497,6 +567,11 @@ static enum power_supply_property axp20x_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_ENERGY_FULL,
|
||||
POWER_SUPPLY_PROP_ENERGY_NOW,
|
||||
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CALIBRATE,
|
||||
POWER_SUPPLY_PROP_POWER_NOW,
|
||||
};
|
||||
|
||||
static int axp20x_battery_prop_writeable(struct power_supply *psy,
|
||||
|
|
@ -506,7 +581,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 = {
|
||||
|
|
@ -602,7 +678,7 @@ static int axp20x_power_probe(struct platform_device *pdev)
|
|||
psy_cfg.drv_data = axp20x_batt;
|
||||
psy_cfg.of_node = pdev->dev.of_node;
|
||||
|
||||
axp20x_batt->data = (struct axp_data *)of_device_get_match_data(dev);
|
||||
axp20x_batt->data = (struct axp_data *)device_get_match_data(dev);
|
||||
|
||||
axp20x_batt->batt = devm_power_supply_register(&pdev->dev,
|
||||
&axp20x_batt_ps_desc,
|
||||
|
|
@ -616,6 +692,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))
|
||||
|
|
@ -633,7 +710,22 @@ static int axp20x_power_probe(struct platform_device *pdev)
|
|||
axp20x_batt->max_ccc = ccc;
|
||||
axp20x_set_constant_charge_current(axp20x_batt, ccc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
axp20x_batt->energy_full_design = info->energy_full_design_uwh;
|
||||
// tell pmic about our battery
|
||||
if (cfd) {
|
||||
// [14:8], [7:0], cfd = Value * 1.456mAh
|
||||
cfd = cfd / 1456;
|
||||
regmap_update_bits(axp20x_batt->regmap, AXP288_FG_DES_CAP0_REG, 0xff, cfd & 0xff);
|
||||
regmap_update_bits(axp20x_batt->regmap, AXP288_FG_DES_CAP1_REG, 0xff, BIT(7) | ((cfd >> 8) & 0xff));
|
||||
} else {
|
||||
dev_warn(axp20x_batt->dev, "charge full design is not set");
|
||||
}
|
||||
} else {
|
||||
axp20x_batt->energy_full_design = 8000000;
|
||||
dev_warn(axp20x_batt->dev, "energy full design is not set, default to %d\n", axp20x_batt->energy_full_design);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update max CCC to a valid value if battery info is present or set it
|
||||
|
|
@ -642,6 +734,12 @@ static int axp20x_power_probe(struct platform_device *pdev)
|
|||
axp20x_get_constant_charge_current(axp20x_batt,
|
||||
&axp20x_batt->max_ccc);
|
||||
|
||||
regmap_update_bits(axp20x_batt->regmap, AXP20X_VBUS_IPSOUT_MGMT, 0x03, 0x03);
|
||||
regmap_update_bits(axp20x_batt->regmap, AXP20X_OFF_CTRL, 0x08, 0x08);
|
||||
regmap_update_bits(axp20x_batt->regmap, AXP20X_CHRG_CTRL2, 0x30, 0x20);
|
||||
regmap_update_bits(axp20x_batt->regmap, AXP20X_PEK_KEY, 0x0f, 0x0b);
|
||||
regmap_update_bits(axp20x_batt->regmap, AXP20X_GPIO0_CTRL, 0x07, 0x00);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue