power: supply: axp20x_battery: add DT support for battery max constant charge current

This adds the ability to set the maximum constant charge current,
supported by the battery, delivered by this battery power supply to the
battery.

The maximum constant charge current set in DT will also set the default
constant charge current supplied by this supply.

The actual user can modify the constant charge current within the range
of 0 to maximum constant charge current via sysfs.
The user can also modify the maximum constant charge current to widen
the range of possible constant charge current. While this seems quite
risky, a message is printed on the console to warn the user this might
damage the battery. The reason for letting the user change the maximum
constant charge current is for letting users change the battery and
thus, let them adjust the maximum constant charge current according to
what the battery can support.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
This commit is contained in:
Quentin Schulz 2017-05-11 15:42:20 +02:00 committed by Sebastian Reichel
parent f8c91bae0c
commit c800384490
1 changed files with 70 additions and 8 deletions

View File

@ -60,6 +60,8 @@ struct axp20x_batt_ps {
struct iio_channel *batt_chrg_i; struct iio_channel *batt_chrg_i;
struct iio_channel *batt_dischrg_i; struct iio_channel *batt_dischrg_i;
struct iio_channel *batt_v; struct iio_channel *batt_v;
/* Maximum constant charge current */
unsigned int max_ccc;
u8 axp_id; u8 axp_id;
}; };
@ -129,6 +131,14 @@ static void raw_to_constant_charge_current(struct axp20x_batt_ps *axp, int *val)
*val = *val * 150000 + 300000; *val = *val * 150000 + 300000;
} }
static void constant_charge_current_to_raw(struct axp20x_batt_ps *axp, int *val)
{
if (axp->axp_id == AXP209_ID)
*val = (*val - 300000) / 100000;
else
*val = (*val - 300000) / 150000;
}
static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp, static int axp20x_get_constant_charge_current(struct axp20x_batt_ps *axp,
int *val) int *val)
{ {
@ -221,9 +231,7 @@ static int axp20x_battery_get_prop(struct power_supply *psy,
break; break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
val->intval = AXP20X_CHRG_CTRL1_TGT_CURR; val->intval = axp20x_batt->max_ccc;
raw_to_constant_charge_current(axp20x_batt, &val->intval);
break; break;
case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_CURRENT_NOW:
@ -340,10 +348,10 @@ static int axp20x_battery_set_max_voltage(struct axp20x_batt_ps *axp20x_batt,
static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt, static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt,
int charge_current) int charge_current)
{ {
if (axp_batt->axp_id == AXP209_ID) if (charge_current > axp_batt->max_ccc)
charge_current = (charge_current - 300000) / 100000; return -EINVAL;
else
charge_current = (charge_current - 300000) / 150000; constant_charge_current_to_raw(axp_batt, &charge_current);
if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0) if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
return -EINVAL; return -EINVAL;
@ -352,6 +360,36 @@ static int axp20x_set_constant_charge_current(struct axp20x_batt_ps *axp_batt,
AXP20X_CHRG_CTRL1_TGT_CURR, charge_current); AXP20X_CHRG_CTRL1_TGT_CURR, charge_current);
} }
static int axp20x_set_max_constant_charge_current(struct axp20x_batt_ps *axp,
int charge_current)
{
bool lower_max = false;
constant_charge_current_to_raw(axp, &charge_current);
if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0)
return -EINVAL;
raw_to_constant_charge_current(axp, &charge_current);
if (charge_current > axp->max_ccc)
dev_warn(axp->dev,
"Setting max constant charge current higher than previously defined. Note that increasing the constant charge current may damage your battery.\n");
else
lower_max = true;
axp->max_ccc = charge_current;
if (lower_max) {
int current_cc;
axp20x_get_constant_charge_current(axp, &current_cc);
if (current_cc > charge_current)
axp20x_set_constant_charge_current(axp, charge_current);
}
return 0;
}
static int axp20x_set_voltage_min_design(struct axp20x_batt_ps *axp_batt, static int axp20x_set_voltage_min_design(struct axp20x_batt_ps *axp_batt,
int min_voltage) int min_voltage)
{ {
@ -380,6 +418,9 @@ static int axp20x_battery_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
return axp20x_set_constant_charge_current(axp20x_batt, return axp20x_set_constant_charge_current(axp20x_batt,
val->intval); val->intval);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
return axp20x_set_max_constant_charge_current(axp20x_batt,
val->intval);
default: default:
return -EINVAL; return -EINVAL;
@ -405,7 +446,8 @@ static int axp20x_battery_prop_writeable(struct power_supply *psy,
{ {
return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN || return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ||
psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN || psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ||
psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT; psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT ||
psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
} }
static const struct power_supply_desc axp20x_batt_ps_desc = { static const struct power_supply_desc axp20x_batt_ps_desc = {
@ -487,13 +529,33 @@ static int axp20x_power_probe(struct platform_device *pdev)
if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) { if (!power_supply_get_battery_info(axp20x_batt->batt, &info)) {
int vmin = info.voltage_min_design_uv; int vmin = info.voltage_min_design_uv;
int ccc = info.constant_charge_current_max_ua;
if (vmin > 0 && axp20x_set_voltage_min_design(axp20x_batt, if (vmin > 0 && axp20x_set_voltage_min_design(axp20x_batt,
vmin)) vmin))
dev_err(&pdev->dev, dev_err(&pdev->dev,
"couldn't set voltage_min_design\n"); "couldn't set voltage_min_design\n");
/* Set max to unverified value to be able to set CCC */
axp20x_batt->max_ccc = ccc;
if (ccc <= 0 || axp20x_set_constant_charge_current(axp20x_batt,
ccc)) {
dev_err(&pdev->dev,
"couldn't set constant charge current from DT: fallback to minimum value\n");
ccc = 300000;
axp20x_batt->max_ccc = ccc;
axp20x_set_constant_charge_current(axp20x_batt, ccc);
}
} }
/*
* Update max CCC to a valid value if battery info is present or set it
* to current register value by default.
*/
axp20x_get_constant_charge_current(axp20x_batt,
&axp20x_batt->max_ccc);
return 0; return 0;
} }