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@xxxxxxxxxxxxxxxxxx> --- drivers/power/supply/axp20x_battery.c | 78 +++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c index 66f530541735..7494f0f0eadb 100644 --- a/drivers/power/supply/axp20x_battery.c +++ b/drivers/power/supply/axp20x_battery.c @@ -60,6 +60,8 @@ struct axp20x_batt_ps { struct iio_channel *batt_chrg_i; struct iio_channel *batt_dischrg_i; struct iio_channel *batt_v; + /* Maximum constant charge current */ + unsigned int max_ccc; 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; } +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, int *val) { @@ -221,9 +231,7 @@ static int axp20x_battery_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: - val->intval = AXP20X_CHRG_CTRL1_TGT_CURR; - raw_to_constant_charge_current(axp20x_batt, &val->intval); - + val->intval = axp20x_batt->max_ccc; break; 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, int charge_current) { - if (axp_batt->axp_id == AXP209_ID) - charge_current = (charge_current - 300000) / 100000; - else - charge_current = (charge_current - 300000) / 150000; + if (charge_current > axp_batt->max_ccc) + return -EINVAL; + + constant_charge_current_to_raw(axp_batt, &charge_current); if (charge_current > AXP20X_CHRG_CTRL1_TGT_CURR || charge_current < 0) 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); } +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, ¤t_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, int min_voltage) { @@ -380,6 +418,9 @@ static int axp20x_battery_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: return axp20x_set_constant_charge_current(axp20x_batt, val->intval); + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + return axp20x_set_max_constant_charge_current(axp20x_batt, + val->intval); default: return -EINVAL; @@ -405,7 +446,8 @@ static int axp20x_battery_prop_writeable(struct power_supply *psy, { return 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 || + psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX; } 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)) { 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, vmin)) dev_err(&pdev->dev, "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; } -- 2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html