max1720x_battery: save/restore cycles through eeprom

Bug: 161177058
Signed-off-by: Jenny Ho <[email protected]>
Change-Id: I91a811a8492d35a727d1a3843144e477e3b81aaf
diff --git a/max1720x_battery.c b/max1720x_battery.c
index fa6e248..dc077b6 100644
--- a/max1720x_battery.c
+++ b/max1720x_battery.c
@@ -487,10 +487,15 @@
 	return div_s64((s64) val * 1000 * rsense, 4096);
 }
 
-static inline int reg_to_cycles(s16 val)
+static inline int reg_to_cycles(s16 val, int gauge_type)
 {
-	/* LSB: 16% of one cycle */
-	return DIV_ROUND_CLOSEST((int) val * 16, 100);
+	if (gauge_type == MAX_M5_GAUGE_TYPE) {
+		/* LSB: 1% of one cycle */
+		return DIV_ROUND_CLOSEST((int) val, 100);
+	} else {
+		/* LSB: 16% of one cycle */
+		return DIV_ROUND_CLOSEST((int) val * 16, 100);
+	}
 }
 
 static inline int reg_to_seconds(s16 val)
@@ -1215,6 +1220,63 @@
 	mutex_unlock(&chip->convgcfg_lock);
 }
 
+#define EEPROM_CC_OVERFLOW_BIT	BIT(15)
+static void max1720x_restore_battery_cycle(struct max1720x_chip *chip)
+{
+	int ret = 0;
+	u16 eeprom_cycle, reg_cycle;
+
+	if (chip->gauge_type != MAX_M5_GAUGE_TYPE)
+		return;
+
+	ret = REGMAP_READ(&chip->regmap, MAX1720X_CYCLES, &reg_cycle);
+	if (ret < 0) {
+		dev_info(chip->dev, "Fail to read reg %#x, ret=%d",
+				MAX1720X_CYCLES, ret);
+		return;
+	}
+
+	ret = gbms_storage_read(GBMS_TAG_CNHS, &eeprom_cycle, sizeof(eeprom_cycle));
+	if (ret < 0) {
+		dev_info(chip->dev, "Fail to read eeprom cycle count, ret=%d", ret);
+		return;
+	}
+
+	if (eeprom_cycle == 0xFFFF) { /* empty storage */
+		reg_cycle /= 2;	/* save half value to record over 655 cycles case */
+		ret = gbms_storage_write(GBMS_TAG_CNHS, &reg_cycle, sizeof(reg_cycle));
+		if (ret < 0)
+			dev_info(chip->dev, "Fail to write eeprom cycle, ret=%d", ret);
+		dev_info(chip->dev, "update eeprom:%d", reg_cycle);
+	} else {
+		eeprom_cycle = (eeprom_cycle & 0x7FFF) << 1;
+		dev_info(chip->dev, "reg_cycle:%d, eeprom_cycle:%d, update:%c",
+			reg_cycle, eeprom_cycle, eeprom_cycle > reg_cycle ? 'Y' : 'N');
+		if (eeprom_cycle > reg_cycle)
+			REGMAP_WRITE(&chip->regmap, MAX1720X_CYCLES, eeprom_cycle);
+	}
+}
+
+static void max1720x_save_battery_cycle(u16 reg_cycle)
+{
+	u16 eeprom_cycle;
+	int ret;
+
+	ret = gbms_storage_read(GBMS_TAG_CNHS, &eeprom_cycle, sizeof(eeprom_cycle));
+	if (ret < 0)
+		return;
+
+	reg_cycle /= 2;	/* save half value to record over 655 cycles case */
+	if (reg_cycle < eeprom_cycle)
+		reg_cycle |= EEPROM_CC_OVERFLOW_BIT;
+	if (reg_cycle > eeprom_cycle) {
+		pr_info("update eeprom cycle %d -> %d", eeprom_cycle, reg_cycle);
+		ret = gbms_storage_write(GBMS_TAG_CNHS, &reg_cycle, sizeof(reg_cycle));
+		if (ret < 0)
+			pr_info("Fail to write %d eeprom cycle count, ret=%d", reg_cycle, ret);
+	}
+}
+
 #define MAXIM_CYCLE_COUNT_RESET 655
 #define MAX17201_HIST_CYCLE_COUNT_OFFSET	0x4
 #define MAX17201_HIST_TIME_OFFSET		0xf
@@ -1228,34 +1290,51 @@
  */
 static int max1720x_get_cycle_count_offset(struct max1720x_chip *chip)
 {
-	int offset = 0, i, history_count;
-	struct max1720x_history hi;
+	int offset = 0;
+	/*
+	 * uses history on devices that have it (max1720x), use EEPROM
+	 * in others. it might be written in terms of storage.
+	 */
+	if (chip->gauge_type == MAX_M5_GAUGE_TYPE) {
+		u16 eeprom_cycle;
+		int ret;
 
-	if (!chip->history_page_size)
-		return 0;
+		ret = gbms_storage_read(GBMS_TAG_CNHS, &eeprom_cycle, sizeof(eeprom_cycle));
+		if (ret < 0)
+			return 0;
 
-	mutex_lock(&chip->history_lock);
-	history_count = max1720x_history_read(chip, &hi);
-	if (history_count < 0) {
-		mutex_unlock(&chip->history_lock);
-		return 0;
-	}
+		if (eeprom_cycle & EEPROM_CC_OVERFLOW_BIT)
+			offset = MAXIM_CYCLE_COUNT_RESET;
+	} else {
+		int i, history_count;
+		struct max1720x_history hi;
 
-	for (i = 0; i < history_count; i++) {
-		u16 *entry = &hi.history[i * chip->history_page_size];
+		if (!chip->history_page_size)
+			return 0;
 
-		if (entry[MAX17201_HIST_CYCLE_COUNT_OFFSET] == 0 &&
-		    entry[MAX17201_HIST_TIME_OFFSET] != 0) {
-			offset += MAXIM_CYCLE_COUNT_RESET;
-			break;
+		mutex_lock(&chip->history_lock);
+		history_count = max1720x_history_read(chip, &hi);
+		if (history_count < 0) {
+			mutex_unlock(&chip->history_lock);
+			return 0;
 		}
+		for (i = 0; i < history_count; i++) {
+			u16 *entry = &hi.history[i * chip->history_page_size];
+
+			if (entry[MAX17201_HIST_CYCLE_COUNT_OFFSET] == 0 &&
+			    entry[MAX17201_HIST_TIME_OFFSET] != 0) {
+				offset += MAXIM_CYCLE_COUNT_RESET;
+				break;
+			}
+		}
+		mutex_unlock(&chip->history_lock);
+
+		dev_dbg(chip->dev, "history_count=%d page_size=%d i=%d offset=%d\n",
+			history_count, chip->history_page_size, i, offset);
+
+		max1720x_history_free(&hi);
 	}
-	mutex_unlock(&chip->history_lock);
 
-	dev_dbg(chip->dev, "history_count=%d page_size=%d i=%d offset=%d\n",
-		history_count, chip->history_page_size, i, offset);
-
-	max1720x_history_free(&hi);
 	return offset;
 }
 
@@ -1268,12 +1347,15 @@
 	if (err < 0)
 		return err;
 
-	cycle_count = reg_to_cycles(temp);
+	cycle_count = reg_to_cycles(temp, chip->gauge_type);
 	if ((chip->cycle_count == -1) ||
 	    ((cycle_count + chip->cycle_count_offset) < chip->cycle_count))
 		chip->cycle_count_offset =
 			max1720x_get_cycle_count_offset(chip);
 
+	if (chip->gauge_type == MAX_M5_GAUGE_TYPE)
+		max1720x_save_battery_cycle(temp);
+
 	chip->cycle_count = cycle_count + chip->cycle_count_offset;
 
 	return chip->cycle_count;
@@ -3775,6 +3857,8 @@
 
 	max1720x_restore_battery_qh_capacity(chip);
 
+	max1720x_restore_battery_cycle(chip);
+
 	return 0;
 }