Loading Documentation/devicetree/bindings/power/qpnp-vm-bms.txt +4 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,10 @@ Parent node Optional properties The possible values are 1 to 16. - qcom,batt-aging-comp : A boolean that defines if battery aging compensation is enabled. - qcom,use-reported-soc : Bool property to enable the reported_soc logic. To enable this feature, qcom,resume-soc must be defined as a proper value. The BMS is also required to control the charging, discharging and recharging. qcom,batt-pres-status node required properties: - reg : offset and length of the PMIC LBC battery interface BATT_PRES_STATUS Loading drivers/power/qpnp-vm-bms.c +159 −4 Original line number Diff line number Diff line Loading @@ -180,6 +180,7 @@ struct bms_dt_cfg { int cfg_low_temp_threshold; int cfg_ibat_avg_samples; int cfg_battery_aging_comp; bool cfg_use_reported_soc; }; struct qpnp_bms_chip { Loading Loading @@ -271,6 +272,13 @@ struct qpnp_bms_chip { struct power_supply bms_psy; struct power_supply *batt_psy; struct power_supply *usb_psy; bool reported_soc_in_use; bool charger_removed_since_full; bool charger_reinserted; bool reported_soc_high_current; int reported_soc; int reported_soc_change_sec; int reported_soc_delta; }; static struct qpnp_bms_chip *the_chip; Loading Loading @@ -1489,6 +1497,14 @@ static void check_eoc_condition(struct qpnp_bms_chip *chip) chip->ocv_at_100 = -EINVAL; } } if (chip->dt.cfg_use_reported_soc) { /* begin reported_soc process */ chip->reported_soc_in_use = true; chip->charger_removed_since_full = false; chip->charger_reinserted = false; chip->reported_soc = 100; pr_debug("Begin reported_soc process\n"); } } } else { if (chip->last_ocv_uv >= chip->ocv_at_100) { Loading @@ -1502,10 +1518,15 @@ static void check_eoc_condition(struct qpnp_bms_chip *chip) * This gets called once when the SOC falls * below 100. */ if (chip->reported_soc_in_use && chip->reported_soc == 100) { pr_debug("reported_soc=100, last_soc=%d, do not send DISCHARING status\n", chip->last_soc); } else { ret.intval = POWER_SUPPLY_STATUS_DISCHARGING; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &ret); } pr_debug("SOC dropped (%d) discarding ocv_at_100\n", chip->last_soc); chip->ocv_at_100 = -EINVAL; Loading @@ -1520,6 +1541,39 @@ static int report_voltage_based_soc(struct qpnp_bms_chip *chip) return chip->prev_voltage_based_soc; } static int prepare_reported_soc(struct qpnp_bms_chip *chip) { if (chip->charger_removed_since_full == false) { /* * charger is not removed since full, * keep reported_soc as 100 and calculate the delta soc * between reported_soc and last_soc */ chip->reported_soc = 100; chip->reported_soc_delta = 100 - chip->last_soc; pr_debug("Keep at reported_soc 100, reported_soc_delta=%d, last_soc=%d\n", chip->reported_soc_delta, chip->last_soc); } else { /* charger is removed since full */ if (chip->charger_reinserted) { /* * charger reinserted, keep the reported_soc * until it equals to last_soc. */ if (chip->reported_soc == chip->last_soc) { chip->reported_soc_in_use = false; chip->reported_soc_high_current = false; pr_debug("reported_soc equals to last_soc, stop reported_soc process\n"); } chip->reported_soc_change_sec = 0; } } pr_debug("Reporting reported_soc=%d, last_soc=%d\n", chip->reported_soc, chip->last_soc); return chip->reported_soc; } #define SOC_CATCHUP_SEC_MAX 600 #define SOC_CATCHUP_SEC_PER_PERCENT 60 #define MAX_CATCHUP_SOC (SOC_CATCHUP_SEC_MAX / SOC_CATCHUP_SEC_PER_PERCENT) Loading Loading @@ -1648,6 +1702,9 @@ static int report_vm_bms_soc(struct qpnp_bms_chip *chip) backup_ocv_soc(chip, chip->last_ocv_uv, chip->last_soc); if (chip->reported_soc_in_use) return prepare_reported_soc(chip); pr_debug("Reported SOC=%d\n", chip->last_soc); return chip->last_soc; Loading Loading @@ -1894,6 +1951,45 @@ static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip) return 0; } static void calculate_reported_soc(struct qpnp_bms_chip *chip) { union power_supply_propval ret = {0,}; if (chip->reported_soc > chip->last_soc) { /*send DISCHARGING status if the reported_soc drops from 100 */ if (chip->reported_soc == 100) { ret.intval = POWER_SUPPLY_STATUS_DISCHARGING; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &ret); pr_debug("Report discharging status, reported_soc=%d, last_soc=%d\n", chip->reported_soc, chip->last_soc); } /* * reported_soc_delta is used to prevent * the big change in last_soc, * this is not used in high current mode */ if (chip->reported_soc_delta > 0) chip->reported_soc_delta--; if (chip->reported_soc_high_current) chip->reported_soc--; else chip->reported_soc = chip->last_soc + chip->reported_soc_delta; pr_debug("New reported_soc=%d, last_soc is=%d\n", chip->reported_soc, chip->last_soc); } else { chip->reported_soc_in_use = false; chip->reported_soc_high_current = false; pr_debug("reported_soc equals last_soc,stop reported_soc process\n"); } pr_debug("bms power_supply_changed\n"); power_supply_changed(&chip->bms_psy); } #define UI_SOC_CATCHUP_TIME (60) static void monitor_soc_work(struct work_struct *work) { struct qpnp_bms_chip *chip = container_of(work, Loading Loading @@ -1969,6 +2065,20 @@ static void monitor_soc_work(struct work_struct *work) schedule_delayed_work(&chip->monitor_soc_work, msecs_to_jiffies(get_calculation_delay_ms(chip))); if (chip->reported_soc_in_use && chip->charger_removed_since_full && !chip->charger_reinserted) { /* record the elapsed time after last reported_soc change */ chip->reported_soc_change_sec += chip->delta_time_s; pr_debug("reported_soc_change_sec=%d\n", chip->reported_soc_change_sec); /* above the catch up time, calculate new reported_soc */ if (chip->reported_soc_change_sec > UI_SOC_CATCHUP_TIME) { calculate_reported_soc(chip); chip->reported_soc_change_sec = 0; } } mutex_unlock(&chip->last_soc_mutex); bms_relax(&chip->vbms_soc_wake_source); Loading Loading @@ -2251,6 +2361,42 @@ static void battery_status_check(struct qpnp_bms_chip *chip) } } #define HIGH_CURRENT_TH 2 static void reported_soc_check_status(struct qpnp_bms_chip *chip) { u8 present; present = is_charger_present(chip); pr_debug("usb_present=%d\n", present); if (!present && !chip->charger_removed_since_full) { chip->charger_removed_since_full = true; pr_debug("reported_soc: charger removed since full\n"); return; } if (chip->reported_soc_high_current) { pr_debug("reported_soc in high current mode, return\n"); return; } if ((chip->reported_soc - chip->last_soc) > (100 - chip->dt.cfg_soc_resume_limit + HIGH_CURRENT_TH)) { chip->reported_soc_high_current = true; chip->charger_removed_since_full = true; chip->charger_reinserted = false; pr_debug("reported_soc enters high current mode\n"); return; } if (present && chip->charger_removed_since_full) { chip->charger_reinserted = true; pr_debug("reported_soc: charger reinserted\n"); } if (!present && chip->charger_removed_since_full) { chip->charger_reinserted = false; pr_debug("reported_soc: charger removed again\n"); } } static void qpnp_vm_bms_ext_power_changed(struct power_supply *psy) { struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip, Loading @@ -2259,6 +2405,9 @@ static void qpnp_vm_bms_ext_power_changed(struct power_supply *psy) pr_debug("Triggered!\n"); battery_status_check(chip); battery_insertion_check(chip); if (chip->reported_soc_in_use) reported_soc_check_status(chip); } Loading Loading @@ -3083,6 +3232,7 @@ static int show_bms_config(struct seq_file *m, void *data) "force_s3_on_suspend\t=\t%d\n" "report_charger_eoc\t=\t%d\n" "aging_compensation\t=\t%d\n" "use_reported_soc\t=\t%d\n" "s1_sample_interval_ms\t=\t%d\n" "s2_sample_interval_ms\t=\t%d\n" "s1_sample_count\t=\t%d\n" Loading @@ -3104,6 +3254,7 @@ static int show_bms_config(struct seq_file *m, void *data) chip->dt.cfg_force_s3_on_suspend, chip->dt.cfg_report_charger_eoc, chip->dt.cfg_battery_aging_comp, chip->dt.cfg_use_reported_soc, s1_sample_interval, s2_sample_interval, s1_sample_count, Loading Loading @@ -3447,6 +3598,8 @@ static int parse_bms_dt_properties(struct qpnp_bms_chip *chip) "qcom,force-bms-active-on-charger"); chip->dt.cfg_battery_aging_comp = of_property_read_bool( chip->spmi->dev.of_node, "qcom,batt-aging-comp"); chip->dt.cfg_use_reported_soc = of_property_read_bool( chip->spmi->dev.of_node, "qcom,use-reported-soc"); pr_debug("v_cutoff_uv=%d, max_v=%d\n", chip->dt.cfg_v_cutoff_uv, chip->dt.cfg_max_voltage_uv); pr_debug("r_conn=%d shutdown_soc_valid_limit=%d low_temp_threshold=%d ibat_avg_samples=%d\n", Loading @@ -3464,6 +3617,8 @@ static int parse_bms_dt_properties(struct qpnp_bms_chip *chip) chip->dt.cfg_disable_bms, chip->dt.cfg_force_bms_active_on_charger, chip->dt.cfg_battery_aging_comp); pr_debug("use-reported-soc is %d\n", chip->dt.cfg_use_reported_soc); return 0; } Loading Loading
Documentation/devicetree/bindings/power/qpnp-vm-bms.txt +4 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,10 @@ Parent node Optional properties The possible values are 1 to 16. - qcom,batt-aging-comp : A boolean that defines if battery aging compensation is enabled. - qcom,use-reported-soc : Bool property to enable the reported_soc logic. To enable this feature, qcom,resume-soc must be defined as a proper value. The BMS is also required to control the charging, discharging and recharging. qcom,batt-pres-status node required properties: - reg : offset and length of the PMIC LBC battery interface BATT_PRES_STATUS Loading
drivers/power/qpnp-vm-bms.c +159 −4 Original line number Diff line number Diff line Loading @@ -180,6 +180,7 @@ struct bms_dt_cfg { int cfg_low_temp_threshold; int cfg_ibat_avg_samples; int cfg_battery_aging_comp; bool cfg_use_reported_soc; }; struct qpnp_bms_chip { Loading Loading @@ -271,6 +272,13 @@ struct qpnp_bms_chip { struct power_supply bms_psy; struct power_supply *batt_psy; struct power_supply *usb_psy; bool reported_soc_in_use; bool charger_removed_since_full; bool charger_reinserted; bool reported_soc_high_current; int reported_soc; int reported_soc_change_sec; int reported_soc_delta; }; static struct qpnp_bms_chip *the_chip; Loading Loading @@ -1489,6 +1497,14 @@ static void check_eoc_condition(struct qpnp_bms_chip *chip) chip->ocv_at_100 = -EINVAL; } } if (chip->dt.cfg_use_reported_soc) { /* begin reported_soc process */ chip->reported_soc_in_use = true; chip->charger_removed_since_full = false; chip->charger_reinserted = false; chip->reported_soc = 100; pr_debug("Begin reported_soc process\n"); } } } else { if (chip->last_ocv_uv >= chip->ocv_at_100) { Loading @@ -1502,10 +1518,15 @@ static void check_eoc_condition(struct qpnp_bms_chip *chip) * This gets called once when the SOC falls * below 100. */ if (chip->reported_soc_in_use && chip->reported_soc == 100) { pr_debug("reported_soc=100, last_soc=%d, do not send DISCHARING status\n", chip->last_soc); } else { ret.intval = POWER_SUPPLY_STATUS_DISCHARGING; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &ret); } pr_debug("SOC dropped (%d) discarding ocv_at_100\n", chip->last_soc); chip->ocv_at_100 = -EINVAL; Loading @@ -1520,6 +1541,39 @@ static int report_voltage_based_soc(struct qpnp_bms_chip *chip) return chip->prev_voltage_based_soc; } static int prepare_reported_soc(struct qpnp_bms_chip *chip) { if (chip->charger_removed_since_full == false) { /* * charger is not removed since full, * keep reported_soc as 100 and calculate the delta soc * between reported_soc and last_soc */ chip->reported_soc = 100; chip->reported_soc_delta = 100 - chip->last_soc; pr_debug("Keep at reported_soc 100, reported_soc_delta=%d, last_soc=%d\n", chip->reported_soc_delta, chip->last_soc); } else { /* charger is removed since full */ if (chip->charger_reinserted) { /* * charger reinserted, keep the reported_soc * until it equals to last_soc. */ if (chip->reported_soc == chip->last_soc) { chip->reported_soc_in_use = false; chip->reported_soc_high_current = false; pr_debug("reported_soc equals to last_soc, stop reported_soc process\n"); } chip->reported_soc_change_sec = 0; } } pr_debug("Reporting reported_soc=%d, last_soc=%d\n", chip->reported_soc, chip->last_soc); return chip->reported_soc; } #define SOC_CATCHUP_SEC_MAX 600 #define SOC_CATCHUP_SEC_PER_PERCENT 60 #define MAX_CATCHUP_SOC (SOC_CATCHUP_SEC_MAX / SOC_CATCHUP_SEC_PER_PERCENT) Loading Loading @@ -1648,6 +1702,9 @@ static int report_vm_bms_soc(struct qpnp_bms_chip *chip) backup_ocv_soc(chip, chip->last_ocv_uv, chip->last_soc); if (chip->reported_soc_in_use) return prepare_reported_soc(chip); pr_debug("Reported SOC=%d\n", chip->last_soc); return chip->last_soc; Loading Loading @@ -1894,6 +1951,45 @@ static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip) return 0; } static void calculate_reported_soc(struct qpnp_bms_chip *chip) { union power_supply_propval ret = {0,}; if (chip->reported_soc > chip->last_soc) { /*send DISCHARGING status if the reported_soc drops from 100 */ if (chip->reported_soc == 100) { ret.intval = POWER_SUPPLY_STATUS_DISCHARGING; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &ret); pr_debug("Report discharging status, reported_soc=%d, last_soc=%d\n", chip->reported_soc, chip->last_soc); } /* * reported_soc_delta is used to prevent * the big change in last_soc, * this is not used in high current mode */ if (chip->reported_soc_delta > 0) chip->reported_soc_delta--; if (chip->reported_soc_high_current) chip->reported_soc--; else chip->reported_soc = chip->last_soc + chip->reported_soc_delta; pr_debug("New reported_soc=%d, last_soc is=%d\n", chip->reported_soc, chip->last_soc); } else { chip->reported_soc_in_use = false; chip->reported_soc_high_current = false; pr_debug("reported_soc equals last_soc,stop reported_soc process\n"); } pr_debug("bms power_supply_changed\n"); power_supply_changed(&chip->bms_psy); } #define UI_SOC_CATCHUP_TIME (60) static void monitor_soc_work(struct work_struct *work) { struct qpnp_bms_chip *chip = container_of(work, Loading Loading @@ -1969,6 +2065,20 @@ static void monitor_soc_work(struct work_struct *work) schedule_delayed_work(&chip->monitor_soc_work, msecs_to_jiffies(get_calculation_delay_ms(chip))); if (chip->reported_soc_in_use && chip->charger_removed_since_full && !chip->charger_reinserted) { /* record the elapsed time after last reported_soc change */ chip->reported_soc_change_sec += chip->delta_time_s; pr_debug("reported_soc_change_sec=%d\n", chip->reported_soc_change_sec); /* above the catch up time, calculate new reported_soc */ if (chip->reported_soc_change_sec > UI_SOC_CATCHUP_TIME) { calculate_reported_soc(chip); chip->reported_soc_change_sec = 0; } } mutex_unlock(&chip->last_soc_mutex); bms_relax(&chip->vbms_soc_wake_source); Loading Loading @@ -2251,6 +2361,42 @@ static void battery_status_check(struct qpnp_bms_chip *chip) } } #define HIGH_CURRENT_TH 2 static void reported_soc_check_status(struct qpnp_bms_chip *chip) { u8 present; present = is_charger_present(chip); pr_debug("usb_present=%d\n", present); if (!present && !chip->charger_removed_since_full) { chip->charger_removed_since_full = true; pr_debug("reported_soc: charger removed since full\n"); return; } if (chip->reported_soc_high_current) { pr_debug("reported_soc in high current mode, return\n"); return; } if ((chip->reported_soc - chip->last_soc) > (100 - chip->dt.cfg_soc_resume_limit + HIGH_CURRENT_TH)) { chip->reported_soc_high_current = true; chip->charger_removed_since_full = true; chip->charger_reinserted = false; pr_debug("reported_soc enters high current mode\n"); return; } if (present && chip->charger_removed_since_full) { chip->charger_reinserted = true; pr_debug("reported_soc: charger reinserted\n"); } if (!present && chip->charger_removed_since_full) { chip->charger_reinserted = false; pr_debug("reported_soc: charger removed again\n"); } } static void qpnp_vm_bms_ext_power_changed(struct power_supply *psy) { struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip, Loading @@ -2259,6 +2405,9 @@ static void qpnp_vm_bms_ext_power_changed(struct power_supply *psy) pr_debug("Triggered!\n"); battery_status_check(chip); battery_insertion_check(chip); if (chip->reported_soc_in_use) reported_soc_check_status(chip); } Loading Loading @@ -3083,6 +3232,7 @@ static int show_bms_config(struct seq_file *m, void *data) "force_s3_on_suspend\t=\t%d\n" "report_charger_eoc\t=\t%d\n" "aging_compensation\t=\t%d\n" "use_reported_soc\t=\t%d\n" "s1_sample_interval_ms\t=\t%d\n" "s2_sample_interval_ms\t=\t%d\n" "s1_sample_count\t=\t%d\n" Loading @@ -3104,6 +3254,7 @@ static int show_bms_config(struct seq_file *m, void *data) chip->dt.cfg_force_s3_on_suspend, chip->dt.cfg_report_charger_eoc, chip->dt.cfg_battery_aging_comp, chip->dt.cfg_use_reported_soc, s1_sample_interval, s2_sample_interval, s1_sample_count, Loading Loading @@ -3447,6 +3598,8 @@ static int parse_bms_dt_properties(struct qpnp_bms_chip *chip) "qcom,force-bms-active-on-charger"); chip->dt.cfg_battery_aging_comp = of_property_read_bool( chip->spmi->dev.of_node, "qcom,batt-aging-comp"); chip->dt.cfg_use_reported_soc = of_property_read_bool( chip->spmi->dev.of_node, "qcom,use-reported-soc"); pr_debug("v_cutoff_uv=%d, max_v=%d\n", chip->dt.cfg_v_cutoff_uv, chip->dt.cfg_max_voltage_uv); pr_debug("r_conn=%d shutdown_soc_valid_limit=%d low_temp_threshold=%d ibat_avg_samples=%d\n", Loading @@ -3464,6 +3617,8 @@ static int parse_bms_dt_properties(struct qpnp_bms_chip *chip) chip->dt.cfg_disable_bms, chip->dt.cfg_force_bms_active_on_charger, chip->dt.cfg_battery_aging_comp); pr_debug("use-reported-soc is %d\n", chip->dt.cfg_use_reported_soc); return 0; } Loading