power: supply: axp20x_battery: add DT support for battery max constant charge current
authorQuentin Schulz <quentin.schulz@free-electrons.com>
Thu, 11 May 2017 13:42:20 +0000 (15:42 +0200)
committerSebastian Reichel <sre@kernel.org>
Thu, 8 Jun 2017 15:57:53 +0000 (17:57 +0200)
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>
drivers/power/supply/axp20x_battery.c

index 66f5305417357fd35af3db2acbeabb62f772512f..7494f0f0eadb2703a91b2005e266af557f3a9bed 100644 (file)
@@ -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, &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,
                                         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;
 }