From 507b5aaf1117c9b42ec21a5aeb1208b48450ccb2 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megi@xff.cz>
Date: Sat, 13 Jan 2024 16:41:44 +0100
Subject: [PATCH 415/463] 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 | 86 +++++++++++++++++++++++++++-
 1 file changed, 85 insertions(+), 1 deletion(-)

diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c
index 241fff9bc2ab5..d7acb998a140b 100644
--- a/drivers/power/supply/rk817_charger.c
+++ b/drivers/power/supply/rk817_charger.c
@@ -557,6 +557,69 @@ static int rk817_bat_get_prop(struct power_supply *ps,
 	return 0;
 }
 
+static int rk817_battery_prop_writeable(struct power_supply *psy,
+					enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int rk817_bat_set_prop(struct power_supply *ps,
+			      enum power_supply_property prop,
+			      const union power_supply_propval *val)
+{
+	struct rk817_charger *charger = power_supply_get_drvdata(ps);
+	int ret, reg;
+
+	switch (prop) {
+	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 const int rk817_usb_input_current_limits[] = {
 	1, 80000,
 	0, 450000,
@@ -622,6 +685,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) {
@@ -644,6 +708,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
@@ -663,7 +734,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:
@@ -671,9 +742,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;
 
 }
@@ -762,6 +842,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;
@@ -792,6 +873,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 enum power_supply_usb_type rk817_usb_type[] = {
@@ -804,7 +886,9 @@ static const struct power_supply_desc rk817_bat_desc = {
 	.type = POWER_SUPPLY_TYPE_BATTERY,
 	.properties = rk817_bat_props,
 	.num_properties = ARRAY_SIZE(rk817_bat_props),
+	.property_is_writeable	= rk817_battery_prop_writeable,
 	.get_property = rk817_bat_get_prop,
+	.set_property = rk817_bat_set_prop,
 };
 
 static const struct power_supply_desc rk817_chg_desc = {
-- 
2.46.0

