Loading Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt +6 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,12 @@ Charger specific properties: Value type: bool Definition: Boolean flag which when present enables sw compensation for jeita - qcom,fcc-stepping-enable Usage: optional Value type: bool Definition: Boolean flag which when present enables stepwise change in FCC. The default stepping rate is 100mA/sec. ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= Loading drivers/power/power_supply_sysfs.c +1 −0 Original line number Diff line number Diff line Loading @@ -305,6 +305,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(pd_voltage_max), POWER_SUPPLY_ATTR(pd_voltage_min), POWER_SUPPLY_ATTR(sdp_current_max), POWER_SUPPLY_ATTR(fcc_stepper_enable), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ Loading drivers/power/supply/qcom/battery.c +337 −50 Original line number Diff line number Diff line Loading @@ -40,12 +40,14 @@ #define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER" #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER" struct pl_data { int pl_mode; int slave_pct; int taper_pct; int slave_fcc_ua; int main_fcc_ua; int restricted_current; bool restricted_charging_enabled; struct votable *fcc_votable; Loading @@ -59,6 +61,7 @@ struct pl_data { struct work_struct pl_disable_forever_work; struct delayed_work pl_taper_work; struct delayed_work pl_awake_work; struct delayed_work fcc_step_update_work; struct power_supply *main_psy; struct power_supply *pl_psy; struct power_supply *batt_psy; Loading @@ -66,6 +69,13 @@ struct pl_data { int charge_type; int total_settled_ua; int pl_settled_ua; int fcc_step_update; int main_step_fcc_dir; int main_step_fcc_count; int main_step_fcc_residual; int parallel_step_fcc_dir; int parallel_step_fcc_count; int parallel_step_fcc_residual; struct class qcom_batt_class; struct wakeup_source *pl_ws; struct notifier_block nb; Loading Loading @@ -380,6 +390,10 @@ done: * FCC * **********/ #define EFFICIENCY_PCT 80 #define FCC_STEP_SIZE_UA 100000 #define FCC_STEP_UPDATE_DELAY_MS 1000 #define STEP_UP 1 #define STEP_DOWN -1 static void get_fcc_split(struct pl_data *chip, int total_ua, int *master_ua, int *slave_ua) { Loading Loading @@ -432,6 +446,43 @@ static void get_fcc_split(struct pl_data *chip, int total_ua, *slave_ua = (*slave_ua * chip->taper_pct) / 100; } static void get_fcc_step_update_params(struct pl_data *chip, int main_fcc_ua, int parallel_fcc_ua) { union power_supply_propval pval = {0, }; int rc; /* Read current FCC of main charger */ rc = power_supply_get_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't get main charger current fcc, rc=%d\n", rc); return; } chip->main_fcc_ua = pval.intval; chip->main_step_fcc_dir = (main_fcc_ua > pval.intval) ? STEP_UP : STEP_DOWN; chip->main_step_fcc_count = abs((main_fcc_ua - pval.intval) / FCC_STEP_SIZE_UA); chip->main_step_fcc_residual = (main_fcc_ua - pval.intval) % FCC_STEP_SIZE_UA; chip->parallel_step_fcc_dir = (parallel_fcc_ua > chip->slave_fcc_ua) ? STEP_UP : STEP_DOWN; chip->parallel_step_fcc_count = abs((parallel_fcc_ua - chip->slave_fcc_ua) / FCC_STEP_SIZE_UA); chip->parallel_step_fcc_residual = (parallel_fcc_ua - chip->slave_fcc_ua) % FCC_STEP_SIZE_UA; pr_debug("Main FCC Stepper parameters: main_step_direction: %d, main_step_count: %d, main_residual_fcc: %d\n", chip->main_step_fcc_dir, chip->main_step_fcc_count, chip->main_step_fcc_residual); pr_debug("Parallel FCC Stepper parameters: parallel_step_direction: %d, parallel_step_count: %d, parallel_residual_fcc: %d\n", chip->parallel_step_fcc_dir, chip->parallel_step_fcc_count, chip->parallel_step_fcc_residual); } static int pl_fcc_vote_callback(struct votable *votable, void *data, int total_fcc_ua, const char *client) { Loading @@ -445,21 +496,57 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, if (!chip->main_psy) return 0; if (!chip->batt_psy) { chip->batt_psy = power_supply_get_by_name("battery"); if (!chip->batt_psy) return 0; rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, &pval); if (rc < 0) { pr_err("Couldn't read FCC step update status, rc=%d\n", rc); return rc; } chip->fcc_step_update = pval.intval; pr_debug("FCC Stepper %s\n", pval.intval ? "enabled" : "disabled"); } if (chip->fcc_step_update) cancel_delayed_work_sync(&chip->fcc_step_update_work); if (chip->pl_mode == POWER_SUPPLY_PL_NONE || get_effective_result_locked(chip->pl_disable_votable)) { if (chip->fcc_step_update) { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, true, 0); get_fcc_step_update_params(chip, total_fcc_ua, 0); schedule_delayed_work(&chip->fcc_step_update_work, 0); return 0; } pval.intval = total_fcc_ua; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) pr_err("Couldn't set main fcc, rc=%d\n", rc); return rc; } if (chip->pl_mode != POWER_SUPPLY_PL_NONE) { get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua); if (chip->fcc_step_update) { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, true, 0); get_fcc_step_update_params(chip, master_fcc_ua, slave_fcc_ua); schedule_delayed_work(&chip->fcc_step_update_work, 0); } else { /* * If there is an increase in slave share * (Also handles parallel enable case) Loading @@ -474,7 +561,8 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Could not set main fcc, rc=%d\n", rc); pr_err("Could not set main fcc, rc=%d\n", rc); return rc; } Loading Loading @@ -507,11 +595,13 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Could not set main fcc, rc=%d\n", rc); pr_err("Could not set main fcc, rc=%d\n", rc); return rc; } } } } pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n", master_fcc_ua, slave_fcc_ua, Loading @@ -521,6 +611,192 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, return 0; } static void fcc_step_update_work(struct work_struct *work) { struct pl_data *chip = container_of(work, struct pl_data, fcc_step_update_work.work); union power_supply_propval pval = {0, }; int reschedule_ms = 0, rc = 0; int main_fcc = chip->main_fcc_ua; int parallel_fcc = chip->slave_fcc_ua; if (!chip->usb_psy) { chip->usb_psy = power_supply_get_by_name("usb"); if (!chip->usb_psy) { pr_err("Couldn't get usb psy\n"); return; } } /* Check whether USB is present or not */ rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_PRESENT, &pval); if (rc < 0) { pr_err("Couldn't get USB Present status, rc=%d\n", rc); return; } /* * If USB is not present, then disable parallel and * Main FCC to the effective value of FCC votable and exit. */ if (!pval.intval) { /* Disable parallel */ parallel_fcc = 0; pval.intval = 1; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); if (rc < 0) pr_err("Couldn't change slave suspend state rc=%d\n", rc); main_fcc = get_effective_result_locked(chip->fcc_votable); pval.intval = main_fcc; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set main charger fcc, rc=%d\n", rc); return; } goto stepper_exit; } if (chip->main_step_fcc_count) { main_fcc += (FCC_STEP_SIZE_UA * chip->main_step_fcc_dir); chip->main_step_fcc_count--; reschedule_ms = FCC_STEP_UPDATE_DELAY_MS; } else if (chip->main_step_fcc_residual) { main_fcc += chip->main_step_fcc_residual; chip->main_step_fcc_residual = 0; } if (chip->parallel_step_fcc_count) { parallel_fcc += (FCC_STEP_SIZE_UA * chip->parallel_step_fcc_dir); chip->parallel_step_fcc_count--; reschedule_ms = FCC_STEP_UPDATE_DELAY_MS; } else if (chip->parallel_step_fcc_residual) { parallel_fcc += chip->parallel_step_fcc_residual; chip->parallel_step_fcc_residual = 0; } if (chip->pl_mode == POWER_SUPPLY_PL_NONE || get_effective_result_locked(chip->pl_disable_votable)) { /* Set Parallel FCC */ pval.intval = parallel_fcc; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel charger fcc, rc=%d\n", rc); return; } /* Set main FCC */ pval.intval = main_fcc; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set main charger fcc, rc=%d\n", rc); return; } if (parallel_fcc < MINIMUM_PARALLEL_FCC_UA) { pval.intval = 1; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); if (rc < 0) { pr_err("Couldn't change slave suspend state rc=%d\n", rc); return; } } } else { if (parallel_fcc < chip->slave_fcc_ua) { pval.intval = parallel_fcc; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel charger fcc, rc=%d\n", rc); return; } pval.intval = main_fcc; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set main charger fcc, rc=%d\n", rc); return; } } else { pval.intval = main_fcc; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set main charger fcc, rc=%d\n", rc); return; } pval.intval = parallel_fcc; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel charger fcc, rc=%d\n", rc); return; } } rc = power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); if (rc < 0) { pr_err("Couldn't get slave suspend status, rc=%d\n", rc); return; } /* * Enable parallel charger only if it was disabled earlier and * configured slave fcc is greater than or equal to 100mA. */ if (pval.intval == 1 && parallel_fcc >= 100000) { pval.intval = 0; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); if (rc < 0) { pr_err("Couldn't change slave suspend state rc=%d\n", rc); return; } if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) split_settled(chip); } } stepper_exit: chip->main_fcc_ua = main_fcc; chip->slave_fcc_ua = parallel_fcc; if (reschedule_ms) { schedule_delayed_work(&chip->fcc_step_update_work, msecs_to_jiffies(reschedule_ms)); pr_debug("Rescheduling FCC_STEPPER work\n"); } else { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, false, 0); } } #define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000 static int pl_fv_vote_callback(struct votable *votable, void *data, int fv_uv, const char *client) Loading Loading @@ -660,6 +936,9 @@ static int pl_disable_vote_callback(struct votable *votable, chip->total_settled_ua = 0; chip->pl_settled_ua = 0; /* Cancel FCC step change work */ cancel_delayed_work_sync(&chip->fcc_step_update_work); if (!pl_disable) { /* enable */ /* keep system awake to talk to slave charger through i2c */ cancel_delayed_work_sync(&chip->pl_awake_work); Loading @@ -685,6 +964,7 @@ static int pl_disable_vote_callback(struct votable *votable, * PARALLEL_PSY_VOTER keeps it disabled unless a pl_psy * is seen. */ if (!chip->fcc_step_update) { pval.intval = 0; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); Loading @@ -692,9 +972,11 @@ static int pl_disable_vote_callback(struct votable *votable, pr_err("Couldn't change slave suspend state rc=%d\n", rc); if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) split_settled(chip); } /* * we could have been enabled while in taper mode, * start the taper work if so Loading @@ -715,6 +997,7 @@ static int pl_disable_vote_callback(struct votable *votable, || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) split_settled(chip); if (!chip->fcc_step_update) { /* pl_psy may be NULL while in the disable branch */ if (chip->pl_psy) { pval.intval = 1; Loading @@ -724,6 +1007,8 @@ static int pl_disable_vote_callback(struct votable *votable, pr_err("Couldn't change slave suspend state rc=%d\n", rc); } } rerun_election(chip->fcc_votable); rerun_election(chip->fv_votable); Loading Loading @@ -1118,6 +1403,7 @@ int qcom_batt_init(void) INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work); INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work); INIT_DELAYED_WORK(&chip->pl_awake_work, pl_awake_work); INIT_DELAYED_WORK(&chip->fcc_step_update_work, fcc_step_update_work); rc = pl_register_notifier(chip); if (rc < 0) { Loading Loading @@ -1172,6 +1458,7 @@ void qcom_batt_deinit(void) cancel_delayed_work_sync(&chip->pl_taper_work); cancel_work_sync(&chip->pl_disable_forever_work); cancel_delayed_work_sync(&chip->pl_awake_work); cancel_delayed_work_sync(&chip->fcc_step_update_work); power_supply_unreg_notifier(&chip->nb); destroy_votable(chip->pl_enable_votable_indirect); Loading drivers/power/supply/qcom/qpnp-smb2.c +7 −0 Original line number Diff line number Diff line Loading @@ -325,6 +325,9 @@ static int smb2_parse_dt(struct smb2 *chip) if (rc < 0) chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS; chg->fcc_stepper_mode = of_property_read_bool(node, "qcom,fcc-stepping-enable"); return 0; } Loading Loading @@ -941,6 +944,7 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_RERUN_AICL, POWER_SUPPLY_PROP_DP_DM, POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, }; static int smb2_batt_get_prop(struct power_supply *psy, Loading Loading @@ -1049,6 +1053,9 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_COUNTER: rc = smblib_get_prop_batt_charge_counter(chg, val); break; case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: val->intval = chg->fcc_stepper_mode; break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; Loading drivers/power/supply/qcom/smb-lib.c +7 −1 Original line number Diff line number Diff line Loading @@ -3360,7 +3360,8 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) rc = smblib_request_dpdm(chg, true); if (rc < 0) smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); if (chg->fcc_stepper_mode) vote(chg->fcc_votable, FCC_STEPPER_VOTER, false, 0); /* Schedule work to enable parallel charger */ vote(chg->awake_votable, PL_DELAY_VOTER, true, 0); schedule_delayed_work(&chg->pl_enable_work, Loading @@ -3379,6 +3380,11 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) } } /* Force 1500mA FCC on removal */ if (chg->fcc_stepper_mode) vote(chg->fcc_votable, FCC_STEPPER_VOTER, true, 1500000); rc = smblib_request_dpdm(chg, false); if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); Loading Loading
Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt +6 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,12 @@ Charger specific properties: Value type: bool Definition: Boolean flag which when present enables sw compensation for jeita - qcom,fcc-stepping-enable Usage: optional Value type: bool Definition: Boolean flag which when present enables stepwise change in FCC. The default stepping rate is 100mA/sec. ============================================= Second Level Nodes - SMB2 Charger Peripherals ============================================= Loading
drivers/power/power_supply_sysfs.c +1 −0 Original line number Diff line number Diff line Loading @@ -305,6 +305,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(pd_voltage_max), POWER_SUPPLY_ATTR(pd_voltage_min), POWER_SUPPLY_ATTR(sdp_current_max), POWER_SUPPLY_ATTR(fcc_stepper_enable), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ Loading
drivers/power/supply/qcom/battery.c +337 −50 Original line number Diff line number Diff line Loading @@ -40,12 +40,14 @@ #define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER" #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER" struct pl_data { int pl_mode; int slave_pct; int taper_pct; int slave_fcc_ua; int main_fcc_ua; int restricted_current; bool restricted_charging_enabled; struct votable *fcc_votable; Loading @@ -59,6 +61,7 @@ struct pl_data { struct work_struct pl_disable_forever_work; struct delayed_work pl_taper_work; struct delayed_work pl_awake_work; struct delayed_work fcc_step_update_work; struct power_supply *main_psy; struct power_supply *pl_psy; struct power_supply *batt_psy; Loading @@ -66,6 +69,13 @@ struct pl_data { int charge_type; int total_settled_ua; int pl_settled_ua; int fcc_step_update; int main_step_fcc_dir; int main_step_fcc_count; int main_step_fcc_residual; int parallel_step_fcc_dir; int parallel_step_fcc_count; int parallel_step_fcc_residual; struct class qcom_batt_class; struct wakeup_source *pl_ws; struct notifier_block nb; Loading Loading @@ -380,6 +390,10 @@ done: * FCC * **********/ #define EFFICIENCY_PCT 80 #define FCC_STEP_SIZE_UA 100000 #define FCC_STEP_UPDATE_DELAY_MS 1000 #define STEP_UP 1 #define STEP_DOWN -1 static void get_fcc_split(struct pl_data *chip, int total_ua, int *master_ua, int *slave_ua) { Loading Loading @@ -432,6 +446,43 @@ static void get_fcc_split(struct pl_data *chip, int total_ua, *slave_ua = (*slave_ua * chip->taper_pct) / 100; } static void get_fcc_step_update_params(struct pl_data *chip, int main_fcc_ua, int parallel_fcc_ua) { union power_supply_propval pval = {0, }; int rc; /* Read current FCC of main charger */ rc = power_supply_get_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't get main charger current fcc, rc=%d\n", rc); return; } chip->main_fcc_ua = pval.intval; chip->main_step_fcc_dir = (main_fcc_ua > pval.intval) ? STEP_UP : STEP_DOWN; chip->main_step_fcc_count = abs((main_fcc_ua - pval.intval) / FCC_STEP_SIZE_UA); chip->main_step_fcc_residual = (main_fcc_ua - pval.intval) % FCC_STEP_SIZE_UA; chip->parallel_step_fcc_dir = (parallel_fcc_ua > chip->slave_fcc_ua) ? STEP_UP : STEP_DOWN; chip->parallel_step_fcc_count = abs((parallel_fcc_ua - chip->slave_fcc_ua) / FCC_STEP_SIZE_UA); chip->parallel_step_fcc_residual = (parallel_fcc_ua - chip->slave_fcc_ua) % FCC_STEP_SIZE_UA; pr_debug("Main FCC Stepper parameters: main_step_direction: %d, main_step_count: %d, main_residual_fcc: %d\n", chip->main_step_fcc_dir, chip->main_step_fcc_count, chip->main_step_fcc_residual); pr_debug("Parallel FCC Stepper parameters: parallel_step_direction: %d, parallel_step_count: %d, parallel_residual_fcc: %d\n", chip->parallel_step_fcc_dir, chip->parallel_step_fcc_count, chip->parallel_step_fcc_residual); } static int pl_fcc_vote_callback(struct votable *votable, void *data, int total_fcc_ua, const char *client) { Loading @@ -445,21 +496,57 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, if (!chip->main_psy) return 0; if (!chip->batt_psy) { chip->batt_psy = power_supply_get_by_name("battery"); if (!chip->batt_psy) return 0; rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, &pval); if (rc < 0) { pr_err("Couldn't read FCC step update status, rc=%d\n", rc); return rc; } chip->fcc_step_update = pval.intval; pr_debug("FCC Stepper %s\n", pval.intval ? "enabled" : "disabled"); } if (chip->fcc_step_update) cancel_delayed_work_sync(&chip->fcc_step_update_work); if (chip->pl_mode == POWER_SUPPLY_PL_NONE || get_effective_result_locked(chip->pl_disable_votable)) { if (chip->fcc_step_update) { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, true, 0); get_fcc_step_update_params(chip, total_fcc_ua, 0); schedule_delayed_work(&chip->fcc_step_update_work, 0); return 0; } pval.intval = total_fcc_ua; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) pr_err("Couldn't set main fcc, rc=%d\n", rc); return rc; } if (chip->pl_mode != POWER_SUPPLY_PL_NONE) { get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua); if (chip->fcc_step_update) { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, true, 0); get_fcc_step_update_params(chip, master_fcc_ua, slave_fcc_ua); schedule_delayed_work(&chip->fcc_step_update_work, 0); } else { /* * If there is an increase in slave share * (Also handles parallel enable case) Loading @@ -474,7 +561,8 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Could not set main fcc, rc=%d\n", rc); pr_err("Could not set main fcc, rc=%d\n", rc); return rc; } Loading Loading @@ -507,11 +595,13 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Could not set main fcc, rc=%d\n", rc); pr_err("Could not set main fcc, rc=%d\n", rc); return rc; } } } } pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n", master_fcc_ua, slave_fcc_ua, Loading @@ -521,6 +611,192 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, return 0; } static void fcc_step_update_work(struct work_struct *work) { struct pl_data *chip = container_of(work, struct pl_data, fcc_step_update_work.work); union power_supply_propval pval = {0, }; int reschedule_ms = 0, rc = 0; int main_fcc = chip->main_fcc_ua; int parallel_fcc = chip->slave_fcc_ua; if (!chip->usb_psy) { chip->usb_psy = power_supply_get_by_name("usb"); if (!chip->usb_psy) { pr_err("Couldn't get usb psy\n"); return; } } /* Check whether USB is present or not */ rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_PRESENT, &pval); if (rc < 0) { pr_err("Couldn't get USB Present status, rc=%d\n", rc); return; } /* * If USB is not present, then disable parallel and * Main FCC to the effective value of FCC votable and exit. */ if (!pval.intval) { /* Disable parallel */ parallel_fcc = 0; pval.intval = 1; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); if (rc < 0) pr_err("Couldn't change slave suspend state rc=%d\n", rc); main_fcc = get_effective_result_locked(chip->fcc_votable); pval.intval = main_fcc; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set main charger fcc, rc=%d\n", rc); return; } goto stepper_exit; } if (chip->main_step_fcc_count) { main_fcc += (FCC_STEP_SIZE_UA * chip->main_step_fcc_dir); chip->main_step_fcc_count--; reschedule_ms = FCC_STEP_UPDATE_DELAY_MS; } else if (chip->main_step_fcc_residual) { main_fcc += chip->main_step_fcc_residual; chip->main_step_fcc_residual = 0; } if (chip->parallel_step_fcc_count) { parallel_fcc += (FCC_STEP_SIZE_UA * chip->parallel_step_fcc_dir); chip->parallel_step_fcc_count--; reschedule_ms = FCC_STEP_UPDATE_DELAY_MS; } else if (chip->parallel_step_fcc_residual) { parallel_fcc += chip->parallel_step_fcc_residual; chip->parallel_step_fcc_residual = 0; } if (chip->pl_mode == POWER_SUPPLY_PL_NONE || get_effective_result_locked(chip->pl_disable_votable)) { /* Set Parallel FCC */ pval.intval = parallel_fcc; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel charger fcc, rc=%d\n", rc); return; } /* Set main FCC */ pval.intval = main_fcc; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set main charger fcc, rc=%d\n", rc); return; } if (parallel_fcc < MINIMUM_PARALLEL_FCC_UA) { pval.intval = 1; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); if (rc < 0) { pr_err("Couldn't change slave suspend state rc=%d\n", rc); return; } } } else { if (parallel_fcc < chip->slave_fcc_ua) { pval.intval = parallel_fcc; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel charger fcc, rc=%d\n", rc); return; } pval.intval = main_fcc; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set main charger fcc, rc=%d\n", rc); return; } } else { pval.intval = main_fcc; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set main charger fcc, rc=%d\n", rc); return; } pval.intval = parallel_fcc; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel charger fcc, rc=%d\n", rc); return; } } rc = power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); if (rc < 0) { pr_err("Couldn't get slave suspend status, rc=%d\n", rc); return; } /* * Enable parallel charger only if it was disabled earlier and * configured slave fcc is greater than or equal to 100mA. */ if (pval.intval == 1 && parallel_fcc >= 100000) { pval.intval = 0; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); if (rc < 0) { pr_err("Couldn't change slave suspend state rc=%d\n", rc); return; } if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) split_settled(chip); } } stepper_exit: chip->main_fcc_ua = main_fcc; chip->slave_fcc_ua = parallel_fcc; if (reschedule_ms) { schedule_delayed_work(&chip->fcc_step_update_work, msecs_to_jiffies(reschedule_ms)); pr_debug("Rescheduling FCC_STEPPER work\n"); } else { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, false, 0); } } #define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000 static int pl_fv_vote_callback(struct votable *votable, void *data, int fv_uv, const char *client) Loading Loading @@ -660,6 +936,9 @@ static int pl_disable_vote_callback(struct votable *votable, chip->total_settled_ua = 0; chip->pl_settled_ua = 0; /* Cancel FCC step change work */ cancel_delayed_work_sync(&chip->fcc_step_update_work); if (!pl_disable) { /* enable */ /* keep system awake to talk to slave charger through i2c */ cancel_delayed_work_sync(&chip->pl_awake_work); Loading @@ -685,6 +964,7 @@ static int pl_disable_vote_callback(struct votable *votable, * PARALLEL_PSY_VOTER keeps it disabled unless a pl_psy * is seen. */ if (!chip->fcc_step_update) { pval.intval = 0; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); Loading @@ -692,9 +972,11 @@ static int pl_disable_vote_callback(struct votable *votable, pr_err("Couldn't change slave suspend state rc=%d\n", rc); if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) split_settled(chip); } /* * we could have been enabled while in taper mode, * start the taper work if so Loading @@ -715,6 +997,7 @@ static int pl_disable_vote_callback(struct votable *votable, || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) split_settled(chip); if (!chip->fcc_step_update) { /* pl_psy may be NULL while in the disable branch */ if (chip->pl_psy) { pval.intval = 1; Loading @@ -724,6 +1007,8 @@ static int pl_disable_vote_callback(struct votable *votable, pr_err("Couldn't change slave suspend state rc=%d\n", rc); } } rerun_election(chip->fcc_votable); rerun_election(chip->fv_votable); Loading Loading @@ -1118,6 +1403,7 @@ int qcom_batt_init(void) INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work); INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work); INIT_DELAYED_WORK(&chip->pl_awake_work, pl_awake_work); INIT_DELAYED_WORK(&chip->fcc_step_update_work, fcc_step_update_work); rc = pl_register_notifier(chip); if (rc < 0) { Loading Loading @@ -1172,6 +1458,7 @@ void qcom_batt_deinit(void) cancel_delayed_work_sync(&chip->pl_taper_work); cancel_work_sync(&chip->pl_disable_forever_work); cancel_delayed_work_sync(&chip->pl_awake_work); cancel_delayed_work_sync(&chip->fcc_step_update_work); power_supply_unreg_notifier(&chip->nb); destroy_votable(chip->pl_enable_votable_indirect); Loading
drivers/power/supply/qcom/qpnp-smb2.c +7 −0 Original line number Diff line number Diff line Loading @@ -325,6 +325,9 @@ static int smb2_parse_dt(struct smb2 *chip) if (rc < 0) chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS; chg->fcc_stepper_mode = of_property_read_bool(node, "qcom,fcc-stepping-enable"); return 0; } Loading Loading @@ -941,6 +944,7 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_RERUN_AICL, POWER_SUPPLY_PROP_DP_DM, POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, }; static int smb2_batt_get_prop(struct power_supply *psy, Loading Loading @@ -1049,6 +1053,9 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_COUNTER: rc = smblib_get_prop_batt_charge_counter(chg, val); break; case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: val->intval = chg->fcc_stepper_mode; break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; Loading
drivers/power/supply/qcom/smb-lib.c +7 −1 Original line number Diff line number Diff line Loading @@ -3360,7 +3360,8 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) rc = smblib_request_dpdm(chg, true); if (rc < 0) smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); if (chg->fcc_stepper_mode) vote(chg->fcc_votable, FCC_STEPPER_VOTER, false, 0); /* Schedule work to enable parallel charger */ vote(chg->awake_votable, PL_DELAY_VOTER, true, 0); schedule_delayed_work(&chg->pl_enable_work, Loading @@ -3379,6 +3380,11 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) } } /* Force 1500mA FCC on removal */ if (chg->fcc_stepper_mode) vote(chg->fcc_votable, FCC_STEPPER_VOTER, true, 1500000); rc = smblib_request_dpdm(chg, false); if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); Loading