power: pm8921-charger: use SoC % value for charging stop and resume
Current pm8921 charger code doesn't consider the SoC % to determine
end of charging and recharging state. This can cause weird UI display
on SoC % and charging state.
For example, charging is completed when SoC % is not reached 100% or
charging is not completed even if SoC % is already 100%.
So this patch change how to determine end of charging and recharging.
Change-Id: Ice658488744d71117fedb64e0fa0eb7ad34c6573
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 6c0e938..cb569b4 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -148,6 +148,9 @@
int ibat_at_cv_ua;
int soc_at_cv;
int prev_chg_soc;
+ int last_reported_soc;
+ int eoc_check_soc;
+ int soc_adjusted;
};
/*
@@ -1928,6 +1931,43 @@
return 1;
}
+
+static int is_eoc_adjust(struct pm8921_bms_chip *chip, int soc)
+{
+ int batt_state = pm8921_get_batt_state();
+ int ret = 0;
+
+ if (soc != 100)
+ return 0;
+
+ switch (batt_state) {
+ case POWER_SUPPLY_STATUS_CHARGING:
+ if (chip->start_percent != -EINVAL
+ && chip->start_percent != 100)
+ ret = 1;
+ break;
+ case POWER_SUPPLY_STATUS_DISCHARGING:
+ case POWER_SUPPLY_STATUS_NOT_CHARGING:
+ if (chip->soc_adjusted == 1)
+ ret = 1;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int is_recharging(struct pm8921_bms_chip *chip, int soc)
+{
+ if (soc == -EINVAL)
+ return 0;
+ if (pm8921_get_batt_state() == POWER_SUPPLY_STATUS_FULL
+ && soc < 100)
+ return 1;
+ return 0;
+}
+
/*
* Remaining Usable Charge = remaining_charge (charge at ocv instance)
* - coloumb counter charge
@@ -2105,6 +2145,13 @@
soc = calculate_state_of_charge(chip, &raw,
batt_temp, last_chargecycles);
+
+ if (chip->eoc_check_soc
+ && is_recharging(chip, chip->last_reported_soc)) {
+ pm8921_force_start_charging();
+ pr_info("Recharging is started\n");
+ }
+
mutex_unlock(&chip->last_ocv_uv_mutex);
schedule_delayed_work(&chip->calculate_soc_delayed_work,
@@ -2177,10 +2224,18 @@
if (last_soc != -EINVAL && last_soc < soc && soc != 100)
soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
+ if (chip->eoc_check_soc && is_eoc_adjust(chip, soc)) {
+ soc = soc - 1;
+ chip->soc_adjusted = 1;
+ } else {
+ chip->soc_adjusted = 0;
+ }
+
last_soc = soc;
backup_soc_and_iavg(chip, batt_temp, last_soc);
pr_debug("Reported SOC = %d\n", last_soc);
chip->t_soc_queried = now;
+ chip->last_reported_soc = last_soc;
return last_soc;
}
@@ -3224,6 +3279,9 @@
chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
chip->revision = pm8xxx_get_revision(chip->dev->parent);
chip->enable_fcc_learning = pdata->enable_fcc_learning;
+ chip->last_reported_soc = -EINVAL;
+ chip->eoc_check_soc = pdata->eoc_check_soc;
+ chip->soc_adjusted = 0;
mutex_init(&chip->calib_mutex);
INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 55fec15..0db0b6f 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -287,6 +287,7 @@
int ext_batt_temp_monitor;
int recent_reported_soc;
unsigned int ext_warm_i_limit;
+ int eoc_check_soc;
};
/* user space parameter to limit usb current */
@@ -546,6 +547,7 @@
ret |= __pm_chg_vddmax_set(chip, current_mv);
}
}
+
ret |= __pm_chg_vddmax_set(chip, voltage);
return ret;
}
@@ -1541,12 +1543,25 @@
if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
|| !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
|| pm_chg_get_rt_status(chip, CHGHOT_IRQ)
- || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ)
+ || (!chip->eoc_check_soc &&
+ pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
|| (chip->ext_batt_temp_monitor &&
(chip->ext_batt_health == POWER_SUPPLY_HEALTH_OVERHEAT)))
batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
}
+
+ if (chip->eoc_check_soc) {
+ if (get_prop_batt_capacity(chip) == 100) {
+ if (batt_state == POWER_SUPPLY_STATUS_CHARGING)
+ batt_state = POWER_SUPPLY_STATUS_FULL;
+ } else {
+ if (batt_state == POWER_SUPPLY_STATUS_FULL)
+ batt_state = POWER_SUPPLY_STATUS_CHARGING;
+ }
+ }
+
+ pr_debug("batt_state = %d fsm_state = %d \n",batt_state, fsm_state);
return batt_state;
}
@@ -1770,6 +1785,32 @@
}
EXPORT_SYMBOL(pm8921_charger_enable);
+int pm8921_force_start_charging(void)
+{
+ int rc;
+
+ if (!the_chip) {
+ pr_err("called before init\n");
+ return -EINVAL;
+ }
+
+ if (the_chip->eoc_check_soc) {
+ rc = pm_chg_vbatdet_set(the_chip,
+ the_chip->max_voltage_mv);
+ if (rc) {
+ pr_err("failed to set vbatdet\n");
+ return rc;
+ }
+ }
+
+ rc = pm_chg_auto_enable(the_chip, 1);
+ if (rc)
+ pr_err("Failed rc=%d\n", rc);
+
+ return rc;
+}
+EXPORT_SYMBOL(pm8921_force_start_charging);
+
int pm8921_is_usb_chg_plugged_in(void)
{
if (!the_chip) {
@@ -2035,6 +2076,27 @@
}
EXPORT_SYMBOL(pm8921_set_ext_battery_health);
+int pm8921_get_batt_state(void)
+{
+ int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
+ int fsm_state;
+ int i;
+
+ if (!the_chip) {
+ pr_err("called before init\n");
+ return -EINVAL;
+ }
+
+ fsm_state = pm_chg_get_fsm_state(the_chip);
+
+ for (i = 0; i < ARRAY_SIZE(map); i++)
+ if (map[i].fsm_state == fsm_state)
+ batt_state = map[i].batt_state;
+
+ pr_debug("batt_state = %d fsm_state = %d \n",batt_state, fsm_state);
+ return batt_state;
+}
+EXPORT_SYMBOL(pm8921_get_batt_state);
int pm8921_batt_temperature(void)
{
@@ -2496,11 +2558,15 @@
high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
if (high_transition) {
- /* enable auto charging */
- pm_chg_auto_enable(chip, !charging_disabled);
- pr_info("batt fell below resume voltage %s\n",
- charging_disabled ? "" : "charger enabled");
+ if (!chip->eoc_check_soc
+ || pm_chg_get_fsm_state(data) == FSM_STATE_ON_BAT_3) {
+ /* enable auto charging */
+ pm_chg_auto_enable(chip, !charging_disabled);
+ pr_info("batt fell below resume voltage %s\n",
+ charging_disabled ? "" : "charger enabled");
+ }
}
+
pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
power_supply_changed(&chip->batt_psy);
@@ -2790,6 +2856,15 @@
{
struct pm8921_chg_chip *chip = data;
int high_transition;
+ int rc;
+
+ if (chip->eoc_check_soc) {
+ rc = pm_chg_vbatdet_set(chip,
+ chip->max_voltage_mv
+ - chip->resume_voltage_delta);
+ if (rc)
+ pr_err("failed to set vbatdet rc=%d\n", rc);
+ }
high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
@@ -2798,6 +2873,7 @@
round_jiffies_relative(msecs_to_jiffies
(EOC_CHECK_PERIOD_MS)));
}
+
power_supply_changed(&chip->batt_psy);
bms_notify_check(chip);
return IRQ_HANDLED;
@@ -3248,6 +3324,7 @@
struct pm8921_chg_chip, eoc_work);
static int count;
int end;
+ int percent_soc;
pm_chg_failed_clear(chip, 1);
end = is_charging_finished(chip);
@@ -3276,6 +3353,12 @@
count = 0;
}
+ if (chip->eoc_check_soc) {
+ percent_soc = get_prop_batt_capacity(chip);
+ if (percent_soc == 100)
+ count = CONSECUTIVE_COUNT;
+ }
+
if (count == CONSECUTIVE_COUNT) {
count = 0;
pr_info("End of Charging\n");
@@ -4419,7 +4502,7 @@
chip->rconn_mohm = pdata->rconn_mohm;
chip->led_src_config = pdata->led_src_config;
chip->ext_batt_temp_monitor = pdata->ext_batt_temp_monitor;
-
+ chip->eoc_check_soc = pdata->eoc_check_soc;
if (chip->ext_batt_temp_monitor)
chip->ext_batt_health = POWER_SUPPLY_HEALTH_GOOD;