power: pm8921-bms: calculate real_fcc
real_fcc is the remaining capacity in the battery when the charger
driver indicates that the battery is fully charged. This value needs
to be calculated when charging ends with a fully charged battery.
The userspace can read this value via module parameter and preserve it
between restarts.
The real reason for calculating this is to indicate how much the battery
capacity has dropped w.r.t the profiled battery data use this deviation
in calculations.
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 1307da4..7ac2f42 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -101,6 +101,7 @@
static int last_rbatt = -EINVAL;
static int last_ocv_uv = -EINVAL;
static int last_soc = -EINVAL;
+static int last_real_fcc = -EINVAL;
static int last_chargecycles = DEFAULT_CHARGE_CYCLES;
static int last_charge_increase;
@@ -109,6 +110,7 @@
module_param(last_ocv_uv, int, 0644);
module_param(last_chargecycles, int, 0644);
module_param(last_charge_increase, int, 0644);
+module_param(last_real_fcc, int, 0644);
static int pm_bms_get_rt_status(struct pm8921_bms_chip *chip, int irq_id)
{
@@ -742,31 +744,71 @@
return (fcc * pc) / 100;
}
+static void calculate_charging_params(struct pm8921_bms_chip *chip,
+ int batt_temp, int chargecycles,
+ int *fcc,
+ int *unusable_charge,
+ int *remaining_charge,
+ int64_t *cc_mah)
+{
+ int coulumb_counter;
+
+ *fcc = calculate_fcc(chip, batt_temp, chargecycles);
+ pr_debug("FCC = %umAh batt_temp = %d, cycles = %d",
+ *fcc, batt_temp, chargecycles);
+
+ *unusable_charge = calculate_unusable_charge_mah(chip, *fcc,
+ batt_temp, chargecycles);
+
+ pr_debug("UUC = %umAh", *unusable_charge);
+
+ /* calculate remainging charge */
+ *remaining_charge = calculate_remaining_charge_mah(chip, *fcc,
+ batt_temp, chargecycles);
+ pr_debug("RC = %umAh\n", *remaining_charge);
+
+ /* 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);
+}
+
+static int calculate_real_fcc(struct pm8921_bms_chip *chip,
+ int batt_temp, int chargecycles)
+{
+ int fcc, unusable_charge;
+ int remaining_charge;
+ int64_t cc_mah;
+ int real_fcc;
+
+ calculate_charging_params(chip, batt_temp, chargecycles,
+ &fcc,
+ &unusable_charge,
+ &remaining_charge,
+ &cc_mah);
+
+ real_fcc = remaining_charge - cc_mah;
+
+ return real_fcc;
+}
+/*
+ * Remaining Usable Charge = remaining_charge (charge at ocv instance)
+ * - coloumb counter charge
+ * - unusable charge (due to battery resistance)
+ * SOC% = (remaining usable charge/ fcc - usable_charge);
+ */
static int calculate_state_of_charge(struct pm8921_bms_chip *chip,
int batt_temp, int chargecycles)
{
int remaining_usable_charge, fcc, unusable_charge;
- int remaining_charge, soc, coulumb_counter;
+ int remaining_charge, soc;
int update_userspace = 1;
int64_t cc_mah;
- fcc = calculate_fcc(chip, batt_temp, chargecycles);
- pr_debug("FCC = %umAh batt_temp = %d, cycles = %d",
- fcc, batt_temp, chargecycles);
-
- unusable_charge = calculate_unusable_charge_mah(chip, fcc,
- batt_temp, chargecycles);
-
- pr_debug("UUC = %umAh", unusable_charge);
-
- /* calculate remainging charge */
- remaining_charge = calculate_remaining_charge_mah(chip, fcc, batt_temp,
- chargecycles);
- pr_debug("RC = %umAh\n", remaining_charge);
-
- /* 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);
+ calculate_charging_params(chip, batt_temp, chargecycles,
+ &fcc,
+ &unusable_charge,
+ &remaining_charge,
+ &cc_mah);
/* calculate remaining usable charge */
remaining_usable_charge = remaining_charge - cc_mah - unusable_charge;
@@ -935,8 +977,26 @@
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
-void pm8921_bms_charging_end(void)
+void pm8921_bms_charging_end(int is_battery_full)
{
+ if (is_battery_full && the_chip != NULL) {
+ int batt_temp, rc;
+ struct pm8921_adc_chan_result result;
+
+ rc = pm8921_adc_read(the_chip->batt_temp_channel, &result);
+ if (rc) {
+ pr_err("error reading adc channel = %d, rc = %d\n",
+ the_chip->batt_temp_channel, rc);
+ goto charge_cycle_calculation;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
+ result.measurement);
+ batt_temp = (int)result.physical;
+ last_real_fcc = calculate_real_fcc(the_chip,
+ batt_temp, last_chargecycles);
+ }
+
+charge_cycle_calculation:
end_percent = pm8921_bms_get_percent_charge();
if (end_percent > start_percent) {
last_charge_increase = end_percent - start_percent;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index fba714e..257ad35 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -150,6 +150,7 @@
};
struct bms_notify {
+ int is_battery_full;
int is_charging;
struct work_struct work;
};
@@ -755,10 +756,12 @@
{
struct bms_notify *n = container_of(work, struct bms_notify, work);
- if (n->is_charging)
+ if (n->is_charging) {
pm8921_bms_charging_began();
- else
- pm8921_bms_charging_end();
+ } else {
+ pm8921_bms_charging_end(n->is_battery_full);
+ n->is_battery_full = 0;
+ }
}
static void bms_notify_check(struct pm8921_chg_chip *chip)
@@ -1340,6 +1343,9 @@
power_supply_changed(&chip->usb_psy);
power_supply_changed(&chip->dc_psy);
+ chip->bms_notify.is_battery_full = 1;
+ bms_notify_check(chip);
+
/*
* since charging is now done, start monitoring for
* battery voltage below resume voltage
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 10d295b..5d186df 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -164,7 +164,7 @@
* has stopped. Used by the bms driver to keep
* track of chargecycles
*/
-void pm8921_bms_charging_end(void);
+void pm8921_bms_charging_end(int is_battery_full);
#else
static inline int pm8921_bms_get_vsense_avg(int *result)
{
@@ -185,7 +185,7 @@
static inline void pm8921_bms_charging_began(void)
{
}
-static inline void pm8921_bms_charging_end(void)
+static inline void pm8921_bms_charging_end(int is_battery_full)
{
}
#endif