Loading Documentation/devicetree/bindings/power/qpnp-vm-bms.txt +2 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,8 @@ Parent node Optional properties - qcom,low-soc-fifo-length : The fifo length (of S2 STATE) to be used at lower SOCs. If this value is not specified the system uses default lenght. - qcom,resume-soc: Capacity in percent at which charging should resume when a fully charged battery drops below this level. 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 +77 −6 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ struct bms_dt_cfg { int cfg_s2_fifo_length; int cfg_disable_bms; int cfg_s3_ocv_tol_uv; int cfg_soc_resume_limit; }; struct qpnp_bms_chip { Loading Loading @@ -230,6 +231,7 @@ struct qpnp_bms_chip { int iavg_samples_ma[IAVG_SAMPLES]; int iavg_ma; int prev_soc_uuc; int eoc_reported; struct bms_battery_data *batt_data; struct bms_dt_cfg dt; Loading Loading @@ -515,6 +517,22 @@ static bool is_battery_present(struct qpnp_bms_chip *chip) return false; } static bool is_battery_taper_charging(struct qpnp_bms_chip *chip) { union power_supply_propval ret = {0,}; if (chip->batt_psy == NULL) chip->batt_psy = power_supply_get_by_name("battery"); if (chip->batt_psy) { chip->batt_psy->get_property(chip->batt_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &ret); return ret.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER; } return false; } static int master_hold_control(struct qpnp_bms_chip *chip, bool enable) { u8 reg = 0; Loading Loading @@ -1274,8 +1292,11 @@ static int report_eoc(struct qpnp_bms_chip *chip) ret.intval = POWER_SUPPLY_STATUS_FULL; rc = chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &ret); if (rc) if (rc) { pr_err("Unable to set 'STATUS' rc=%d\n", rc); return rc; } chip->eoc_reported = true; } } else { pr_err("battery psy not registered\n"); Loading @@ -1284,10 +1305,46 @@ static int report_eoc(struct qpnp_bms_chip *chip) return rc; } static void check_recharge_condition(struct qpnp_bms_chip *chip) { int rc; union power_supply_propval ret = {0,}; int status = get_battery_status(chip); if (chip->last_soc > chip->dt.cfg_soc_resume_limit) return; if (status == POWER_SUPPLY_STATUS_UNKNOWN) { pr_debug("Unable to read battery status\n"); return; } /* Report recharge to charger for SOC based resume of charging */ if ((status != POWER_SUPPLY_STATUS_CHARGING) && chip->eoc_reported) { ret.intval = POWER_SUPPLY_STATUS_CHARGING; rc = chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &ret); if (rc < 0) { pr_err("Unable to set battery property rc=%d\n", rc); } else { pr_info("soc dropped below resume_soc soc=%d resume_soc=%d, restart charging\n", chip->last_soc, chip->dt.cfg_soc_resume_limit); chip->eoc_reported = false; } } } static void check_eoc_condition(struct qpnp_bms_chip *chip) { int rc; int status = get_battery_status(chip); union power_supply_propval ret = {0,}; if (status == POWER_SUPPLY_STATUS_UNKNOWN) { pr_err("Unable to read battery status\n"); return; } /* * Check battery status: Loading Loading @@ -1328,8 +1385,17 @@ static void check_eoc_condition(struct qpnp_bms_chip *chip) chip->ocv_at_100 = chip->last_ocv_uv; chip->last_soc = 100; } else if (chip->last_soc != 100) { /* * Report that the battery is discharging. * This gets called once when the SOC falls * below 100. */ 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->calculated_soc); chip->last_soc); chip->ocv_at_100 = -EINVAL; } } Loading Loading @@ -1443,6 +1509,8 @@ static int report_vm_bms_soc(struct qpnp_bms_chip *chip) if ((soc != chip->last_soc) || (soc == 100)) { chip->last_soc = soc; check_eoc_condition(chip); if ((chip->dt.cfg_soc_resume_limit > 0) && !charging) check_recharge_condition(chip); } pr_debug("last_soc=%d calculated_soc=%d soc=%d time_since_last_change=%d\n", Loading Loading @@ -1596,8 +1664,9 @@ static void very_low_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv) static void cv_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv) { if (bms_wake_active(&chip->vbms_cv_wake_source)) { if (vbat_uv < (chip->dt.cfg_max_voltage_uv - VBATT_ERROR_MARGIN + CV_DROP_MARGIN)) { if ((vbat_uv < (chip->dt.cfg_max_voltage_uv - VBATT_ERROR_MARGIN + CV_DROP_MARGIN)) && !is_battery_taper_charging(chip)) { pr_debug("Fell below CV, releasing cv ws\n"); chip->in_cv_state = false; bms_relax(&chip->vbms_cv_wake_source); Loading @@ -1608,8 +1677,9 @@ static void cv_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv) } } else if (!bms_wake_active(&chip->vbms_cv_wake_source) && is_battery_charging(chip) && (vbat_uv > (chip->dt.cfg_max_voltage_uv - VBATT_ERROR_MARGIN))) { && ((vbat_uv > (chip->dt.cfg_max_voltage_uv - VBATT_ERROR_MARGIN)) || is_battery_taper_charging(chip))) { pr_debug("CC_TO_CV voltage=%d holding cv ws\n", vbat_uv); chip->in_cv_state = true; bms_stay_awake(&chip->vbms_cv_wake_source); Loading Loading @@ -3181,6 +3251,7 @@ static int parse_bms_dt_properties(struct qpnp_bms_chip *chip) SPMI_PROP_READ_OPTIONAL(cfg_s3_ocv_tol_uv, "s3-ocv-tolerence-uv", rc); SPMI_PROP_READ_OPTIONAL(cfg_low_soc_fifo_length, "low-soc-fifo-length", rc); SPMI_PROP_READ_OPTIONAL(cfg_soc_resume_limit, "resume-soc", rc); chip->dt.cfg_ignore_shutdown_soc = of_property_read_bool( chip->spmi->dev.of_node, "qcom,ignore-shutdown-soc"); Loading Loading
Documentation/devicetree/bindings/power/qpnp-vm-bms.txt +2 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,8 @@ Parent node Optional properties - qcom,low-soc-fifo-length : The fifo length (of S2 STATE) to be used at lower SOCs. If this value is not specified the system uses default lenght. - qcom,resume-soc: Capacity in percent at which charging should resume when a fully charged battery drops below this level. 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 +77 −6 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ struct bms_dt_cfg { int cfg_s2_fifo_length; int cfg_disable_bms; int cfg_s3_ocv_tol_uv; int cfg_soc_resume_limit; }; struct qpnp_bms_chip { Loading Loading @@ -230,6 +231,7 @@ struct qpnp_bms_chip { int iavg_samples_ma[IAVG_SAMPLES]; int iavg_ma; int prev_soc_uuc; int eoc_reported; struct bms_battery_data *batt_data; struct bms_dt_cfg dt; Loading Loading @@ -515,6 +517,22 @@ static bool is_battery_present(struct qpnp_bms_chip *chip) return false; } static bool is_battery_taper_charging(struct qpnp_bms_chip *chip) { union power_supply_propval ret = {0,}; if (chip->batt_psy == NULL) chip->batt_psy = power_supply_get_by_name("battery"); if (chip->batt_psy) { chip->batt_psy->get_property(chip->batt_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &ret); return ret.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER; } return false; } static int master_hold_control(struct qpnp_bms_chip *chip, bool enable) { u8 reg = 0; Loading Loading @@ -1274,8 +1292,11 @@ static int report_eoc(struct qpnp_bms_chip *chip) ret.intval = POWER_SUPPLY_STATUS_FULL; rc = chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &ret); if (rc) if (rc) { pr_err("Unable to set 'STATUS' rc=%d\n", rc); return rc; } chip->eoc_reported = true; } } else { pr_err("battery psy not registered\n"); Loading @@ -1284,10 +1305,46 @@ static int report_eoc(struct qpnp_bms_chip *chip) return rc; } static void check_recharge_condition(struct qpnp_bms_chip *chip) { int rc; union power_supply_propval ret = {0,}; int status = get_battery_status(chip); if (chip->last_soc > chip->dt.cfg_soc_resume_limit) return; if (status == POWER_SUPPLY_STATUS_UNKNOWN) { pr_debug("Unable to read battery status\n"); return; } /* Report recharge to charger for SOC based resume of charging */ if ((status != POWER_SUPPLY_STATUS_CHARGING) && chip->eoc_reported) { ret.intval = POWER_SUPPLY_STATUS_CHARGING; rc = chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &ret); if (rc < 0) { pr_err("Unable to set battery property rc=%d\n", rc); } else { pr_info("soc dropped below resume_soc soc=%d resume_soc=%d, restart charging\n", chip->last_soc, chip->dt.cfg_soc_resume_limit); chip->eoc_reported = false; } } } static void check_eoc_condition(struct qpnp_bms_chip *chip) { int rc; int status = get_battery_status(chip); union power_supply_propval ret = {0,}; if (status == POWER_SUPPLY_STATUS_UNKNOWN) { pr_err("Unable to read battery status\n"); return; } /* * Check battery status: Loading Loading @@ -1328,8 +1385,17 @@ static void check_eoc_condition(struct qpnp_bms_chip *chip) chip->ocv_at_100 = chip->last_ocv_uv; chip->last_soc = 100; } else if (chip->last_soc != 100) { /* * Report that the battery is discharging. * This gets called once when the SOC falls * below 100. */ 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->calculated_soc); chip->last_soc); chip->ocv_at_100 = -EINVAL; } } Loading Loading @@ -1443,6 +1509,8 @@ static int report_vm_bms_soc(struct qpnp_bms_chip *chip) if ((soc != chip->last_soc) || (soc == 100)) { chip->last_soc = soc; check_eoc_condition(chip); if ((chip->dt.cfg_soc_resume_limit > 0) && !charging) check_recharge_condition(chip); } pr_debug("last_soc=%d calculated_soc=%d soc=%d time_since_last_change=%d\n", Loading Loading @@ -1596,8 +1664,9 @@ static void very_low_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv) static void cv_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv) { if (bms_wake_active(&chip->vbms_cv_wake_source)) { if (vbat_uv < (chip->dt.cfg_max_voltage_uv - VBATT_ERROR_MARGIN + CV_DROP_MARGIN)) { if ((vbat_uv < (chip->dt.cfg_max_voltage_uv - VBATT_ERROR_MARGIN + CV_DROP_MARGIN)) && !is_battery_taper_charging(chip)) { pr_debug("Fell below CV, releasing cv ws\n"); chip->in_cv_state = false; bms_relax(&chip->vbms_cv_wake_source); Loading @@ -1608,8 +1677,9 @@ static void cv_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv) } } else if (!bms_wake_active(&chip->vbms_cv_wake_source) && is_battery_charging(chip) && (vbat_uv > (chip->dt.cfg_max_voltage_uv - VBATT_ERROR_MARGIN))) { && ((vbat_uv > (chip->dt.cfg_max_voltage_uv - VBATT_ERROR_MARGIN)) || is_battery_taper_charging(chip))) { pr_debug("CC_TO_CV voltage=%d holding cv ws\n", vbat_uv); chip->in_cv_state = true; bms_stay_awake(&chip->vbms_cv_wake_source); Loading Loading @@ -3181,6 +3251,7 @@ static int parse_bms_dt_properties(struct qpnp_bms_chip *chip) SPMI_PROP_READ_OPTIONAL(cfg_s3_ocv_tol_uv, "s3-ocv-tolerence-uv", rc); SPMI_PROP_READ_OPTIONAL(cfg_low_soc_fifo_length, "low-soc-fifo-length", rc); SPMI_PROP_READ_OPTIONAL(cfg_soc_resume_limit, "resume-soc", rc); chip->dt.cfg_ignore_shutdown_soc = of_property_read_bool( chip->spmi->dev.of_node, "qcom,ignore-shutdown-soc"); Loading