From 2269a7429683789d4077129f6670e111de51e482 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megi@xff.cz>
Date: Sat, 13 Jan 2024 16:41:44 +0100
Subject: [PATCH 431/480] power: supply: rk817-charger: Add support for runtime
 change of charger limits

This is useful for speeding up, or slowing down charging or for dealing
with lesser quality PSUs or cabling.

Signed-off-by: Ondrej Jirman <megi@xff.cz>
---
 drivers/power/supply/rk817_charger.c | 62 +++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c
index 7a91ea3934d7..22c639ed767e 100644
--- a/drivers/power/supply/rk817_charger.c
+++ b/drivers/power/supply/rk817_charger.c
@@ -600,6 +600,7 @@ static int rk817_chg_get_prop(struct power_supply *ps,
 			      union power_supply_propval *val)
 {
 	struct rk817_charger *charger = power_supply_get_drvdata(ps);
+	unsigned int reg;
 	int ret;
 
 	switch (prop) {
@@ -622,6 +623,13 @@ static int rk817_chg_get_prop(struct power_supply *ps,
 		if (ret)
 			return ret;
 		break;
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		ret = regmap_read(charger->rk808->regmap, RK817_PMIC_CHRG_IN, &reg);
+		if (ret < 0)
+			return ret;
+
+		val->intval = 4000000 + 100000 * ((reg & RK817_USB_VLIM_SEL) >> 4);
+		break;
 	/*
 	 * While it's possible that other implementations could use different
 	 * USB types, the current implementation for this PMIC (the Odroid Go
@@ -641,7 +649,7 @@ static int rk817_chg_set_prop(struct power_supply *ps,
 			      const union power_supply_propval *val)
 {
 	struct rk817_charger *charger = power_supply_get_drvdata(ps);
-	int ret;
+	int ret, reg;
 
 	switch (prop) {
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
@@ -649,9 +657,18 @@ static int rk817_chg_set_prop(struct power_supply *ps,
 		if (ret)
 			return ret;
 		break;
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		// 0 = 4.0V - 7 = 4.7V, 0.1V step
+		reg = (clamp(val->intval, 4000000, 4700000) - 4000000) / 100000;
+		ret = regmap_write_bits(charger->rk808->regmap, RK817_PMIC_CHRG_IN,
+					RK817_USB_VLIM_SEL, (reg << 4));
+		if (ret)
+			return ret;
+		break;
 	default:
 		return -EINVAL;
 	}
+
 	return 0;
 
 }
@@ -740,6 +757,7 @@ static int rk817_bat_set_prop(struct power_supply *ps,
 			      const union power_supply_propval *val)
 {
 	struct rk817_charger *charger = power_supply_get_drvdata(ps);
+	int ret, reg;
 
 	switch (prop) {
 	case POWER_SUPPLY_PROP_CHARGE_FULL:
@@ -748,9 +766,47 @@ static int rk817_bat_set_prop(struct power_supply *ps,
 			return -EINVAL;
 		charger->fcc_mah = val->intval / 1000;
 		return rk817_bat_calib_cap(charger);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		reg = rk817_chg_cur_to_reg(val->intval / 1000);
+		if (reg < 0) {
+			dev_err(charger->dev,
+			       "invalid max charger current, value %d unsupported\n",
+			       val->intval);
+			return -EINVAL;
+		}
+
+		ret = regmap_write_bits(charger->rk808->regmap, RK817_PMIC_CHRG_OUT,
+					RK817_CHRG_CUR_SEL, reg);
+		if (ret) {
+			dev_err(charger->dev,
+				"Unable to set max charger current (%d)\n", ret);
+			return ret;
+		}
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		reg = (val->intval / 1000 - 4100) / 50;
+		if (reg < 0 || reg > 7) {
+			dev_err(charger->dev,
+				"invalid max charger voltage, value %d unsupported\n",
+				val->intval);
+			return -EINVAL;
+		}
+
+		ret = regmap_write_bits(charger->rk808->regmap, RK817_PMIC_CHRG_OUT,
+					RK817_CHRG_VOL_SEL, (reg << 4));
+		if (ret) {
+			dev_err(charger->dev,
+				"Unable to set max charger voltage (%d)\n", ret);
+			return ret;
+		}
+		break;
 	default:
 		return -EINVAL;
 	}
+
+	cancel_delayed_work_sync(&charger->work);
+	queue_delayed_work(system_wq, &charger->work, msecs_to_jiffies(50));
+	return 0;
 }
 
 static int rk817_charger_prop_writeable(struct power_supply *psy,
@@ -758,6 +814,7 @@ static int rk817_charger_prop_writeable(struct power_supply *psy,
 {
 	switch (psp) {
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
 		return 1;
 	default:
 		return 0;
@@ -788,6 +845,7 @@ static enum power_supply_property rk817_chg_props[] = {
 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
 	POWER_SUPPLY_PROP_VOLTAGE_AVG,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
 };
 
 static int rk817_bat_prop_writeable(struct power_supply *psy,
@@ -795,6 +853,8 @@ static int rk817_bat_prop_writeable(struct power_supply *psy,
 {
 	switch (psp) {
 	case POWER_SUPPLY_PROP_CHARGE_FULL:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
 		return 1;
 	default:
 		return 0;
-- 
2.49.0

