From 275ce5a224b1e854c4caa4999aa34795e714e874 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megi@xff.cz>
Date: Sun, 6 Aug 2023 02:55:22 +0200
Subject: [PATCH 425/480] power: supply: rk817-charger: Add input current limit
 setting

This is useful for proper USB input current limiting.

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

diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c
index fe0fbb2fac6a..8a2a88dedb50 100644
--- a/drivers/power/supply/rk817_charger.c
+++ b/drivers/power/supply/rk817_charger.c
@@ -534,11 +534,72 @@ static int rk817_bat_get_prop(struct power_supply *ps,
 	return 0;
 }
 
+static const int rk817_usb_input_current_limits[] = {
+	1, 80000,
+	0, 450000,
+	2, 850000,
+	3, 1500000,
+	4, 1750000,
+	5, 2000000,
+	6, 2500000,
+	7, 3000000,
+};
+
+static int rk817_usb_set_input_current_max(struct rk817_charger *cg,
+					   int val)
+{
+	int ret, i;
+
+	for (i = ARRAY_SIZE(rk817_usb_input_current_limits) / 2 - 1; i > 0; i--) {
+		if (val >= rk817_usb_input_current_limits[2 * i + 1])
+			break;
+	}
+
+	dev_info(cg->dev, "applying input current limit %d mA\n",
+		 rk817_usb_input_current_limits[2 * i + 1] / 1000);
+
+	ret = regmap_write_bits(cg->rk808->regmap, RK817_PMIC_CHRG_IN,
+			        RK817_USB_ILIM_SEL,
+			        rk817_usb_input_current_limits[2 * i]);
+	if (ret)
+		dev_err(cg->dev,
+			"USB input current limit setting failed (%d)\n", ret);
+
+	return ret;
+}
+
+static int rk817_usb_get_input_current_max(struct rk817_charger *cg,
+					   int *val)
+{
+	unsigned reg;
+	int ret;
+
+	ret = regmap_read(cg->rk808->regmap, RK817_PMIC_CHRG_IN, &reg);
+	if (ret) {
+		dev_err(cg->dev,
+			"USB input current limit getting failed (%d)\n", ret);
+		return ret;
+	}
+
+	reg &= RK817_USB_ILIM_SEL;
+
+	for (int i = 0; i < ARRAY_SIZE(rk817_usb_input_current_limits) / 2; i++) {
+		int r = rk817_usb_input_current_limits[2 * i];
+		if (r == reg) {
+			*val = rk817_usb_input_current_limits[2 * i + 1];
+			break;
+		}
+	}
+
+	return 0;
+}
+
 static int rk817_chg_get_prop(struct power_supply *ps,
 			      enum power_supply_property prop,
 			      union power_supply_propval *val)
 {
 	struct rk817_charger *charger = power_supply_get_drvdata(ps);
+	int ret;
 
 	switch (prop) {
 	case POWER_SUPPLY_PROP_ONLINE:
@@ -555,6 +616,11 @@ static int rk817_chg_get_prop(struct power_supply *ps,
 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
 		val->intval = charger->charger_input_volt_avg_uv;
 		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		ret = rk817_usb_get_input_current_max(charger, &val->intval);
+		if (ret)
+			return ret;
+		break;
 	/*
 	 * While it's possible that other implementations could use different
 	 * USB types, the current implementation for this PMIC (the Odroid Go
@@ -567,6 +633,25 @@ static int rk817_chg_get_prop(struct power_supply *ps,
 		return -EINVAL;
 	}
 	return 0;
+}
+
+static int rk817_chg_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;
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		ret = rk817_usb_set_input_current_max(charger, val->intval);
+		if (ret)
+			return ret;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
 
 }
 
@@ -610,15 +695,6 @@ static irqreturn_t rk817_plug_out_isr(int irq, void *cg)
 	regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_VLIM_EN,
 			  (0x01 << 7));
 
-	/*
-	 * Set average USB input current limit to 1.5A and enable USB current
-	 * input limit.
-	 */
-	regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN,
-			  RK817_USB_ILIM_SEL, 0x03);
-	regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_ILIM_EN,
-			  (0x01 << 3));
-
 	rk817_read_props(charger);
 
 	dev_dbg(charger->dev, "Power Cord Removed\n");
@@ -644,6 +720,17 @@ static int rk817_bat_set_prop(struct power_supply *ps,
 	}
 }
 
+static int rk817_charger_prop_writeable(struct power_supply *psy,
+					enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
 static enum power_supply_property rk817_bat_props[] = {
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_STATUS,
@@ -667,6 +754,7 @@ static enum power_supply_property rk817_chg_props[] = {
 	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
 	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
 	POWER_SUPPLY_PROP_VOLTAGE_AVG,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
 };
 
 static int rk817_bat_prop_writeable(struct power_supply *psy,
@@ -697,7 +785,9 @@ static const struct power_supply_desc rk817_chg_desc = {
 		     BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),
 	.properties = rk817_chg_props,
 	.num_properties = ARRAY_SIZE(rk817_chg_props),
+	.property_is_writeable	= rk817_charger_prop_writeable,
 	.get_property = rk817_chg_get_prop,
+	.set_property = rk817_chg_set_prop,
 };
 
 static int rk817_read_battery_nvram_values(struct rk817_charger *charger)
@@ -1029,10 +1119,6 @@ static int rk817_battery_init(struct rk817_charger *charger,
 	 * Set average USB input current limit to 1.5A and enable USB current
 	 * input limit.
 	 */
-	regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN,
-			  RK817_USB_ILIM_SEL, 0x03);
-	regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_ILIM_EN,
-			  (0x01 << 3));
 
 	return 0;
 }
-- 
2.49.0

