From d3528a23fc260fb00edea12e67cec543eb134a4b Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Fri, 28 Jan 2022 17:33:55 +0100
Subject: [PATCH 314/446] power: supply: ip5xxx: Handle powerdown state of the
 chip

When IP5209 goes to sleep, it will become unresponsive on I2C bus.
When used with non-I2C regmap, we are notified about this particular
state via -EXDEV error. This is not a fatal error state, so treat it
as if the battery is not charging, and boost is disabled, which
is what happens in reality.

Signed-off-by: Ondrej Jirman <megous@megous.com>
---
 drivers/power/supply/ip5xxx_power.c | 85 +++++++++++++++++++++++++----
 1 file changed, 73 insertions(+), 12 deletions(-)

diff --git a/drivers/power/supply/ip5xxx_power.c b/drivers/power/supply/ip5xxx_power.c
index 4e4e8f214..f9b5dfd2c 100644
--- a/drivers/power/supply/ip5xxx_power.c
+++ b/drivers/power/supply/ip5xxx_power.c
@@ -97,16 +97,24 @@ static int ip5xxx_boost_get_property(struct power_supply *psy,
 	switch (psp) {
 	case POWER_SUPPLY_PROP_ONLINE:
 		ret = regmap_read(ip5xxx->regmap, IP5XXX_SYS_CTL0, &rval);
-		if (ret)
+		if (ret == -EXDEV) {
+			val->intval = 0;
+			return 0;
+		} else if (ret) {
 			return ret;
+		}
 
 		val->intval = !!(rval & IP5XXX_SYS_CTL0_BOOST_EN);
 		return 0;
 
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
 		ret = regmap_read(ip5xxx->regmap, IP5XXX_CHG_CTL1, &rval);
-		if (ret)
+		if (ret == -EXDEV) {
+			val->intval = 4530000;
+			return 0;
+		} else if (ret) {
 			return ret;
+		}
 
 		rval &= IP5XXX_CHG_CTL1_BOOST_UVP_SEL;
 		val->intval = 4530000 + 100000 * (rval >> 2);
@@ -158,6 +166,7 @@ static const struct power_supply_desc ip5xxx_boost_desc = {
 
 static const enum power_supply_property ip5xxx_charger_properties[] = {
 	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_CHARGE_TYPE,
 	POWER_SUPPLY_PROP_HEALTH,
 	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
@@ -176,8 +185,12 @@ static int ip5xxx_charger_get_status(struct ip5xxx *ip5xxx, int *val)
 	int ret;
 
 	ret = regmap_read(ip5xxx->regmap, IP5XXX_READ0, &rval);
-	if (ret)
+	if (ret == -EXDEV) {
+		*val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		return 0;
+	} else if (ret) {
 		return ret;
+	}
 
 	switch (rval & IP5XXX_READ0_CHG_STAT) {
 	case IP5XXX_READ0_CHG_STAT_IDLE:
@@ -208,8 +221,13 @@ static int ip5xxx_charger_get_charge_type(struct ip5xxx *ip5xxx, int *val)
 	int ret;
 
 	ret = regmap_read(ip5xxx->regmap, IP5XXX_READ0, &rval);
-	if (ret)
+	if (ret) {
+		if (ret == -EXDEV) {
+			*val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+			return 0;
+		}
 		return ret;
+	}
 
 	switch (rval & IP5XXX_READ0_CHG_STAT) {
 	case IP5XXX_READ0_CHG_STAT_IDLE:
@@ -238,8 +256,12 @@ static int ip5xxx_charger_get_health(struct ip5xxx *ip5xxx, int *val)
 	int ret;
 
 	ret = regmap_read(ip5xxx->regmap, IP5XXX_READ0, &rval);
-	if (ret)
+	if (ret == -EXDEV) {
+		*val = POWER_SUPPLY_HEALTH_GOOD;
+		return 0;
+	} else if (ret) {
 		return ret;
+	}
 
 	if (rval & IP5XXX_READ0_TIMEOUT)
 		*val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
@@ -255,8 +277,12 @@ static int ip5xxx_charger_get_voltage_max(struct ip5xxx *ip5xxx, int *val)
 	int ret;
 
 	ret = regmap_read(ip5xxx->regmap, IP5XXX_CHG_CTL2, &rval);
-	if (ret)
+	if (ret == -EXDEV) {
+		*val = 4200000;
+		return 0;
+	} else if (ret) {
 		return ret;
+	}
 
 	/*
 	 * It is not clear what this will return if
@@ -316,6 +342,17 @@ static int ip5xxx_charger_get_property(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_CHARGE_TYPE:
 		return ip5xxx_charger_get_charge_type(ip5xxx, &val->intval);
 
+	case POWER_SUPPLY_PROP_PRESENT:
+		ret = regmap_read(ip5xxx->regmap, IP5XXX_READ0, &rval);
+		if (ret == -EXDEV) {
+			val->intval = 0;
+			return 0;
+		} else if (ret) {
+			return ret;
+		}
+		val->intval = 1;
+		return 0;
+
 	case POWER_SUPPLY_PROP_HEALTH:
 		return ip5xxx_charger_get_health(ip5xxx, &val->intval);
 
@@ -325,8 +362,12 @@ static int ip5xxx_charger_get_property(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 		ret = ip5xxx_charger_read_adc(ip5xxx, IP5XXX_BATVADC_DAT0,
 					      IP5XXX_BATVADC_DAT1, &raw);
-		if (ret)
+		if (ret == -EXDEV) {
+			val->intval = 0;
+			return 0;
+		} else if (ret) {
 			return ret;
+		}
 
 		val->intval = (2600 + DIV_ROUND_CLOSEST(raw * 1000, 3724)) * 1000;
 		return 0;
@@ -334,8 +375,12 @@ static int ip5xxx_charger_get_property(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
 		ret = ip5xxx_charger_read_adc(ip5xxx, IP5XXX_BATOCV_DAT0,
 					      IP5XXX_BATOCV_DAT1, &raw);
-		if (ret)
+		if (ret == -EXDEV) {
+			val->intval = 0;
+			return 0;
+		} else if (ret) {
 			return ret;
+		}
 
 		val->intval = (2600 + DIV_ROUND_CLOSEST(raw * 1000, 3724)) * 1000;
 		return 0;
@@ -343,16 +388,24 @@ static int ip5xxx_charger_get_property(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
 		ret = ip5xxx_charger_read_adc(ip5xxx, IP5XXX_BATIADC_DAT0,
 					      IP5XXX_BATIADC_DAT1, &raw);
-		if (ret)
+		if (ret == -EXDEV) {
+			val->intval = 0;
+			return 0;
+		} else if (ret) {
 			return ret;
+		}
 
 		val->intval = DIV_ROUND_CLOSEST(raw * 1000, 1341) * 1000;
 		return 0;
 
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
 		ret = regmap_read(ip5xxx->regmap, IP5XXX_CHG_CTL4A, &rval);
-		if (ret)
+		if (ret == -EXDEV) {
+			val->intval = 0;
+			return 0;
+		} else if (ret) {
 			return ret;
+		}
 
 		rval &= IP5XXX_CHG_CTL4A_CONST_CUR_SEL;
 		val->intval = 100000 * rval;
@@ -364,12 +417,20 @@ static int ip5xxx_charger_get_property(struct power_supply *psy,
 
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
 		ret = ip5xxx_charger_get_voltage_max(ip5xxx, &vmax);
-		if (ret)
+		if (ret == -EXDEV) {
+			val->intval = 4200000;
+			return 0;
+		} else if (ret) {
 			return ret;
+		}
 
 		ret = regmap_read(ip5xxx->regmap, IP5XXX_CHG_CTL2, &rval);
-		if (ret)
+		if (ret == -EXDEV) {
+			val->intval = 4200000;
+			return 0;
+		} else if (ret) {
 			return ret;
+		}
 
 		rval &= IP5XXX_CHG_CTL2_CONST_VOLT_SEL;
 		val->intval = vmax + 14000 * (rval >> 1);
-- 
2.31.1

