diff mbox

[4/4] power: supply: axp20x_battery: add DT support for battery max constant charge current

Message ID 20170511134221.5569-5-quentin.schulz@free-electrons.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Quentin Schulz May 11, 2017, 1:42 p.m. UTC
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>
---
 drivers/power/supply/axp20x_battery.c | 78 +++++++++++++++++++++++++++++++----
 1 file changed, 70 insertions(+), 8 deletions(-)

Comments

Sebastian Reichel June 8, 2017, 3:58 p.m. UTC | #1
Hi,

On Thu, May 11, 2017 at 03:42:20PM +0200, Quentin Schulz wrote:
> 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>

Thanks, queued.

-- Sebastian

> ---
>  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, &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;
>  }
>  
> -- 
> 2.11.0
>
diff mbox

Patch

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, &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;
 }