power: pm8921-bms: adjust OCV and cc for 100% charge

The remaining usable charge is calculated as below
RUC = RC - CC - UUC

RC is the remaining charge when an OCV (open circuit voltage) is
measured by the bms hw. It is some percent of full charge capacity.
The BMS hw continuously monitors the battery current and when it is
low enough it reads the battery voltage and calls it OCV.

CC is the charge based on coulomb counter and represents the
absolute charge provided since an OCV was taken. When OCV happens,
the coulomb counter is reset to zero.

UUC is the unusable charge that the system cannot use because of
internal battery resistance. For the most part this value remains
constant, it changes slowly as the battery ages.

The state of charge (SOC) is calculated as below
SOC = RUC / (FCC - UUC)

When an end of charging event happens, the driver calculates (RC - CC)
and sets that as the new full charge capacity (FCC). However since the
system uses the old OCV value which translates to some percent of full
charge capacity, the soc calculated after this FCC adjustment will be
less than 100%.

To workaround this problem, the software needs to behave as if the
OCV had just happened after charging finishes. IOW force OCV to max
possible value which translates to 100% FCC and force CC to zero.

Substituting RC = 100% FCC = FCC and CC = 0
we get
RUC = FCC - UUC
and
SOC = (FCC - UUC)/ (FCC - UUC)
which is 100%

As the battery now discharges the CC part of the RUC increases lowering
the SOC.

To force CC to zero the driver notes the CC readings when end of charge
happens (cc_reading_at_100) and subtracts this reading for all subsequent
cc reads.
To force an OCV that will translate to 100% FCC the driver uses the
lookup table and picks the highest profiled OCV. This happens to be the
first row and the last column in the profile table.

This software faking the OCV to 100% FCC and CC to zero needs to cease
when a new OCV measurement is taken by the BMS hw. The driver remembers
the old OCV in ocv_reading_at_100 and knows a new OCV is taken if a
different OCV reading is read. It sets the cc_reading_at_100 and
ocv_reading_at_100 to zero.

Note that the system will never read zero as the ocv, a zero OCV
translate to a -ve 2.3986 volt battery voltage - a physical impossibility.

Change-Id: Icfef5b6242185009af7ae443088f86c230ccbe64
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index a6251ff..d7cf3a8 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -92,6 +92,9 @@
 	unsigned int		charging_began;
 	unsigned int		start_percent;
 	unsigned int		end_percent;
+
+	uint16_t		ocv_reading_at_100;
+	int			cc_reading_at_100;
 };
 
 static struct pm8921_bms_chip *the_chip;
@@ -487,6 +490,9 @@
 	}
 	*result = msw << 16 | lsw;
 	pr_debug("msw = %04x lsw = %04x cc = %d\n", msw, lsw, *result);
+	*result = *result - chip->cc_reading_at_100;
+	pr_debug("cc = %d after subtracting %d\n",
+					*result, chip->cc_reading_at_100);
 	return 0;
 }
 
@@ -500,12 +506,29 @@
 		pr_err("fail to read LAST_GOOD_OCV_VALUE rc = %d\n", rc);
 		return rc;
 	}
-	*result = xoadc_reading_to_microvolt(reading);
-	pr_debug("raw = %04x ocv_uV = %u\n", reading, *result);
-	*result = adjust_xo_vbatt_reading(chip, *result);
-	pr_debug("after adj ocv_uV = %u\n", *result);
-	if (*result != 0)
-		last_ocv_uv = *result;
+
+	if (chip->ocv_reading_at_100 != reading) {
+		chip->ocv_reading_at_100 = 0;
+		chip->cc_reading_at_100 = 0;
+		*result = xoadc_reading_to_microvolt(reading);
+		pr_debug("raw = %04x ocv_uV = %u\n", reading, *result);
+		*result = adjust_xo_vbatt_reading(chip, *result);
+		pr_debug("after adj ocv_uV = %u\n", *result);
+		if (*result != 0)
+			last_ocv_uv = *result;
+	} else {
+		/*
+		 * force 100% ocv by selecting the highest profiled ocv
+		 * This is the first row last column entry in the ocv
+		 * lookup table
+		 */
+		int cols = chip->pc_temp_ocv_lut->cols;
+
+		pr_debug("Forcing max voltage %d\n",
+				1000 * chip->pc_temp_ocv_lut->ocv[0][cols-1]);
+		*result = 1000 * chip->pc_temp_ocv_lut->ocv[0][cols-1];
+	}
+
 	return 0;
 }
 
@@ -1034,10 +1057,10 @@
 
 	/* calculate cc milli_volt_hour */
 	calculate_cc_mah(chip, cc_mah, &coulumb_counter);
+	pr_debug("cc_mah = %lldmAh cc = %d\n", *cc_mah, coulumb_counter);
 
 	pm_bms_unlock_output_data(chip);
 	spin_unlock_irqrestore(&chip->bms_output_lock, flags);
-	pr_debug("cc_mah = %lldmAh cc = %d\n", *cc_mah, coulumb_counter);
 }
 
 static int calculate_real_fcc(struct pm8921_bms_chip *chip,
@@ -1055,7 +1078,8 @@
 						&cc_mah);
 
 	real_fcc = remaining_charge - cc_mah;
-
+	pr_debug("real_fcc = %d, RC = %d CC = %lld\n",
+			real_fcc, remaining_charge, cc_mah);
 	return real_fcc;
 }
 /*
@@ -1687,7 +1711,8 @@
 void pm8921_bms_charging_end(int is_battery_full)
 {
 	if (is_battery_full && the_chip != NULL) {
-		int batt_temp, rc;
+		unsigned long flags;
+		int batt_temp, rc, cc_reading;
 		struct pm8921_adc_chan_result result;
 
 		rc = pm8921_adc_read(the_chip->batt_temp_channel, &result);
@@ -1703,6 +1728,18 @@
 						batt_temp, last_chargecycles);
 		last_real_fcc_batt_temp = batt_temp;
 		readjust_fcc_table();
+
+		spin_lock_irqsave(&the_chip->bms_output_lock, flags);
+		pm_bms_lock_output_data(the_chip);
+		pm_bms_read_output_data(the_chip, LAST_GOOD_OCV_VALUE,
+						&the_chip->ocv_reading_at_100);
+		read_cc(the_chip, &cc_reading);
+		pm_bms_unlock_output_data(the_chip);
+		spin_unlock_irqrestore(&the_chip->bms_output_lock, flags);
+		the_chip->cc_reading_at_100 = cc_reading;
+		pr_debug("EOC ocv_reading = 0x%x cc_reading = %d\n",
+				the_chip->ocv_reading_at_100,
+				the_chip->cc_reading_at_100);
 	}
 
 charge_cycle_calculation: