Loading Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +6 −0 Original line number Diff line number Diff line Loading @@ -245,6 +245,12 @@ Charger specific properties: This is only applicable to certain PMICs like PMI632 which has SCHGM_FLASH peripheral. - 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 - SMB5 Charger Peripherals ============================================= Loading arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -172,6 +172,7 @@ qcom,battery-data = <&mtp_batterydata>; qcom,step-charging-enable; qcom,sw-jeita-enable; qcom,fcc-stepping-enable; qcom,sec-charger-config = <3>; }; Loading arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,7 @@ qcom,battery-data = <&mtp_batterydata>; qcom,step-charging-enable; qcom,sw-jeita-enable; qcom,fcc-stepping-enable; qcom,sec-charger-config = <1>; }; Loading drivers/power/supply/qcom/battery.c +395 −86 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ #define USBIN_I_VOTER "USBIN_I_VOTER" #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" #define ICL_LIMIT_VOTER "ICL_LIMIT_VOTER" #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER" struct pl_data { int pl_mode; Loading @@ -52,6 +53,7 @@ struct pl_data { int pl_min_icl_ua; int slave_pct; int slave_fcc_ua; int main_fcc_ua; int restricted_current; bool restricted_charging_enabled; struct votable *fcc_votable; Loading @@ -65,15 +67,25 @@ struct pl_data { struct work_struct pl_disable_forever_work; struct work_struct pl_taper_work; struct delayed_work pl_awake_work; struct delayed_work fcc_stepper_work; bool taper_work_running; struct power_supply *main_psy; struct power_supply *pl_psy; struct power_supply *batt_psy; struct power_supply *usb_psy; struct power_supply *dc_psy; int charge_type; int total_settled_ua; int pl_settled_ua; int pl_fcc_max; int fcc_stepper_enable; 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; int step_fcc; u32 wa_flags; struct class qcom_batt_class; struct wakeup_source *pl_ws; Loading Loading @@ -111,6 +123,7 @@ enum { SLAVE_PCT, RESTRICT_CHG_ENABLE, RESTRICT_CHG_CURRENT, FCC_STEPPING_IN_PROGRESS, }; /******* Loading Loading @@ -258,7 +271,6 @@ static void split_settled(struct pl_data *chip) chip->total_settled_ua = total_settled_ua; chip->pl_settled_ua = slave_ua; } static ssize_t version_show(struct class *c, struct class_attribute *attr, Loading Loading @@ -378,11 +390,26 @@ static ssize_t restrict_cur_store(struct class *c, struct class_attribute *attr, } static CLASS_ATTR_RW(restrict_cur); /**************************** * FCC STEPPING IN PROGRESS * ****************************/ static ssize_t fcc_stepping_in_progress_show(struct class *c, struct class_attribute *attr, char *ubuf) { struct pl_data *chip = container_of(c, struct pl_data, qcom_batt_class); return snprintf(ubuf, PAGE_SIZE, "%d\n", chip->step_fcc); } static CLASS_ATTR_RO(fcc_stepping_in_progress); static struct attribute *batt_class_attrs[] = { [VER] = &class_attr_version.attr, [SLAVE_PCT] = &class_attr_slave_pct.attr, [RESTRICT_CHG_ENABLE] = &class_attr_restrict_chg.attr, [RESTRICT_CHG_CURRENT] = &class_attr_restrict_cur.attr, [FCC_STEPPING_IN_PROGRESS] = &class_attr_fcc_stepping_in_progress.attr, NULL, }; ATTRIBUTE_GROUPS(batt_class); Loading @@ -391,6 +418,10 @@ ATTRIBUTE_GROUPS(batt_class); * 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 @@ -443,6 +474,47 @@ static void get_fcc_split(struct pl_data *chip, int total_ua, *master_ua = max(0, total_ua - *slave_ua); } static void get_fcc_stepper_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; if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual || chip->main_step_fcc_count || chip->main_step_fcc_residual) chip->step_fcc = 1; 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); } #define MINIMUM_PARALLEL_FCC_UA 500000 #define PL_TAPER_WORK_DELAY_MS 500 #define TAPER_RESIDUAL_PCT 90 Loading Loading @@ -562,6 +634,195 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, return 0; } static void fcc_stepper_work(struct work_struct *work) { struct pl_data *chip = container_of(work, struct pl_data, fcc_stepper_work.work); union power_supply_propval pval = {0, }; int reschedule_ms = 0, rc = 0, charger_present = 0; int main_fcc = chip->main_fcc_ua; int parallel_fcc = chip->slave_fcc_ua; /* 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); charger_present = pval.intval; /*Check whether DC charger is present or not */ if (!chip->dc_psy) chip->dc_psy = power_supply_get_by_name("dc"); if (chip->dc_psy) { rc = power_supply_get_property(chip->dc_psy, POWER_SUPPLY_PROP_PRESENT, &pval); if (rc < 0) pr_err("Couldn't get DC Present status, rc=%d\n", rc); charger_present |= pval.intval; } /* * If USB is not present, then set parallel FCC to min value and * main FCC to the effective value of FCC votable and exit. */ if (!charger_present) { /* Disable parallel */ parallel_fcc = 0; if (chip->pl_psy) { 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); goto out; } chip->pl_disable = true; power_supply_changed(chip->pl_psy); } 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); goto out; } 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 (parallel_fcc < chip->slave_fcc_ua) { /* Set parallel FCC */ if (chip->pl_psy && !chip->pl_disable) { 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); goto out; } if (IS_USBIN(chip->pl_mode)) split_settled(chip); parallel_fcc = 0; chip->parallel_step_fcc_count = 0; chip->parallel_step_fcc_residual = 0; chip->total_settled_ua = 0; chip->pl_settled_ua = 0; chip->pl_disable = true; power_supply_changed(chip->pl_psy); } else { /* 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); goto out; } } } /* 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); goto out; } } else { /* 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); goto out; } /* Set parallel FCC */ if (chip->pl_psy) { 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); goto out; } /* * Enable parallel charger only if it was disabled * earlier and configured slave fcc is greater than or * equal to minimum parallel FCC value. */ if (chip->pl_disable && parallel_fcc >= MINIMUM_PARALLEL_FCC_UA) { 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); goto out; } if (IS_USBIN(chip->pl_mode)) split_settled(chip); chip->pl_disable = false; power_supply_changed(chip->pl_psy); } } } stepper_exit: chip->main_fcc_ua = main_fcc; chip->slave_fcc_ua = parallel_fcc; if (reschedule_ms) { schedule_delayed_work(&chip->fcc_stepper_work, msecs_to_jiffies(reschedule_ms)); pr_debug("Rescheduling FCC_STEPPER work\n"); return; } out: chip->step_fcc = 0; 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 @@ -700,6 +961,17 @@ static bool is_main_available(struct pl_data *chip) return !!chip->main_psy; } static bool is_batt_available(struct pl_data *chip) { if (!chip->batt_psy) chip->batt_psy = power_supply_get_by_name("battery"); if (!chip->batt_psy) return false; return true; } static int pl_disable_vote_callback(struct votable *votable, void *data, int pl_disable, const char *client) { Loading @@ -712,6 +984,28 @@ static int pl_disable_vote_callback(struct votable *votable, if (!is_main_available(chip)) return -ENODEV; if (!is_batt_available(chip)) return -ENODEV; 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 -ENODEV; } 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_stepper_enable = pval.intval; pr_debug("FCC Stepper %s\n", pval.intval ? "enabled" : "disabled"); if (chip->fcc_stepper_enable) cancel_delayed_work_sync(&chip->fcc_stepper_work); total_fcc_ua = get_effective_result_locked(chip->fcc_votable); if (chip->pl_mode != POWER_SUPPLY_PL_NONE && !pl_disable) { Loading Loading @@ -747,6 +1041,15 @@ static int pl_disable_vote_callback(struct votable *votable, get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua); if (chip->fcc_stepper_enable) { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, true, 0); get_fcc_stepper_params(chip, master_fcc_ua, slave_fcc_ua); if (chip->step_fcc) schedule_delayed_work(&chip->fcc_stepper_work, 0); } else { /* * If there is an increase in slave share * (Also handles parallel enable case) Loading @@ -761,7 +1064,8 @@ static int pl_disable_vote_callback(struct votable *votable, 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 @@ -794,7 +1098,8 @@ static int pl_disable_vote_callback(struct votable *votable, 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 @@ -813,6 +1118,8 @@ static int pl_disable_vote_callback(struct votable *votable, if (IS_USBIN(chip->pl_mode)) split_settled(chip); } /* * we could have been enabled while in taper mode, * start the taper work if so Loading @@ -838,6 +1145,7 @@ static int pl_disable_vote_callback(struct votable *votable, (master_fcc_ua * 100) / total_fcc_ua, (slave_fcc_ua * 100) / total_fcc_ua); } else { if (!chip->fcc_stepper_enable) { if (IS_USBIN(chip->pl_mode)) split_settled(chip); Loading @@ -863,18 +1171,27 @@ static int pl_disable_vote_callback(struct votable *votable, /* reset parallel FCC */ chip->slave_fcc_ua = 0; chip->total_settled_ua = 0; chip->pl_settled_ua = 0; } else { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, true, 0); get_fcc_stepper_params(chip, total_fcc_ua, 0); if (chip->step_fcc) schedule_delayed_work(&chip->fcc_stepper_work, 0); } rerun_election(chip->fv_votable); cancel_delayed_work_sync(&chip->pl_awake_work); schedule_delayed_work(&chip->pl_awake_work, msecs_to_jiffies(5000)); chip->total_settled_ua = 0; chip->pl_settled_ua = 0; } /* notify parallel state change */ if (chip->pl_psy && (chip->pl_disable != pl_disable)) { if (chip->pl_psy && (chip->pl_disable != pl_disable) && !chip->fcc_stepper_enable) { power_supply_changed(chip->pl_psy); chip->pl_disable = (bool)pl_disable; } Loading Loading @@ -909,17 +1226,6 @@ static int pl_awake_vote_callback(struct votable *votable, return 0; } static bool is_batt_available(struct pl_data *chip) { if (!chip->batt_psy) chip->batt_psy = power_supply_get_by_name("battery"); if (!chip->batt_psy) return false; return true; } static bool is_parallel_available(struct pl_data *chip) { union power_supply_propval pval = {0, }; Loading Loading @@ -1083,6 +1389,7 @@ static void handle_settled_icl_change(struct pl_data *chip) else vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0); rerun_election(chip->fcc_votable); if (IS_USBIN(chip->pl_mode)) { /* Loading Loading @@ -1331,6 +1638,7 @@ int qcom_batt_init(int smb_version) INIT_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_stepper_work, fcc_stepper_work); rc = pl_register_notifier(chip); if (rc < 0) { Loading Loading @@ -1386,6 +1694,7 @@ void qcom_batt_deinit(void) cancel_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_stepper_work); power_supply_unreg_notifier(&chip->nb); destroy_votable(chip->pl_enable_votable_indirect); Loading drivers/power/supply/qcom/qpnp-smb5.c +6 −0 Original line number Diff line number Diff line Loading @@ -440,6 +440,9 @@ static int smb5_parse_dt(struct smb5 *chip) if (rc < 0) chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS; chg->fcc_stepper_enable = of_property_read_bool(node, "qcom,fcc-stepping-enable"); rc = of_property_match_string(node, "io-channel-names", "usb_in_voltage"); if (rc >= 0) { Loading Loading @@ -1176,6 +1179,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_RECHARGE_SOC, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_FORCE_RECHARGE, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, }; static int smb5_batt_get_prop(struct power_supply *psy, Loading Loading @@ -1293,6 +1297,8 @@ static int smb5_batt_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_FORCE_RECHARGE: val->intval = 0; case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: val->intval = chg->fcc_stepper_enable; break; default: pr_err("batt power supply prop %d not supported\n", psp); Loading Loading
Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +6 −0 Original line number Diff line number Diff line Loading @@ -245,6 +245,12 @@ Charger specific properties: This is only applicable to certain PMICs like PMI632 which has SCHGM_FLASH peripheral. - 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 - SMB5 Charger Peripherals ============================================= Loading
arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -172,6 +172,7 @@ qcom,battery-data = <&mtp_batterydata>; qcom,step-charging-enable; qcom,sw-jeita-enable; qcom,fcc-stepping-enable; qcom,sec-charger-config = <3>; }; Loading
arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,7 @@ qcom,battery-data = <&mtp_batterydata>; qcom,step-charging-enable; qcom,sw-jeita-enable; qcom,fcc-stepping-enable; qcom,sec-charger-config = <1>; }; Loading
drivers/power/supply/qcom/battery.c +395 −86 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ #define USBIN_I_VOTER "USBIN_I_VOTER" #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" #define ICL_LIMIT_VOTER "ICL_LIMIT_VOTER" #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER" struct pl_data { int pl_mode; Loading @@ -52,6 +53,7 @@ struct pl_data { int pl_min_icl_ua; int slave_pct; int slave_fcc_ua; int main_fcc_ua; int restricted_current; bool restricted_charging_enabled; struct votable *fcc_votable; Loading @@ -65,15 +67,25 @@ struct pl_data { struct work_struct pl_disable_forever_work; struct work_struct pl_taper_work; struct delayed_work pl_awake_work; struct delayed_work fcc_stepper_work; bool taper_work_running; struct power_supply *main_psy; struct power_supply *pl_psy; struct power_supply *batt_psy; struct power_supply *usb_psy; struct power_supply *dc_psy; int charge_type; int total_settled_ua; int pl_settled_ua; int pl_fcc_max; int fcc_stepper_enable; 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; int step_fcc; u32 wa_flags; struct class qcom_batt_class; struct wakeup_source *pl_ws; Loading Loading @@ -111,6 +123,7 @@ enum { SLAVE_PCT, RESTRICT_CHG_ENABLE, RESTRICT_CHG_CURRENT, FCC_STEPPING_IN_PROGRESS, }; /******* Loading Loading @@ -258,7 +271,6 @@ static void split_settled(struct pl_data *chip) chip->total_settled_ua = total_settled_ua; chip->pl_settled_ua = slave_ua; } static ssize_t version_show(struct class *c, struct class_attribute *attr, Loading Loading @@ -378,11 +390,26 @@ static ssize_t restrict_cur_store(struct class *c, struct class_attribute *attr, } static CLASS_ATTR_RW(restrict_cur); /**************************** * FCC STEPPING IN PROGRESS * ****************************/ static ssize_t fcc_stepping_in_progress_show(struct class *c, struct class_attribute *attr, char *ubuf) { struct pl_data *chip = container_of(c, struct pl_data, qcom_batt_class); return snprintf(ubuf, PAGE_SIZE, "%d\n", chip->step_fcc); } static CLASS_ATTR_RO(fcc_stepping_in_progress); static struct attribute *batt_class_attrs[] = { [VER] = &class_attr_version.attr, [SLAVE_PCT] = &class_attr_slave_pct.attr, [RESTRICT_CHG_ENABLE] = &class_attr_restrict_chg.attr, [RESTRICT_CHG_CURRENT] = &class_attr_restrict_cur.attr, [FCC_STEPPING_IN_PROGRESS] = &class_attr_fcc_stepping_in_progress.attr, NULL, }; ATTRIBUTE_GROUPS(batt_class); Loading @@ -391,6 +418,10 @@ ATTRIBUTE_GROUPS(batt_class); * 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 @@ -443,6 +474,47 @@ static void get_fcc_split(struct pl_data *chip, int total_ua, *master_ua = max(0, total_ua - *slave_ua); } static void get_fcc_stepper_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; if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual || chip->main_step_fcc_count || chip->main_step_fcc_residual) chip->step_fcc = 1; 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); } #define MINIMUM_PARALLEL_FCC_UA 500000 #define PL_TAPER_WORK_DELAY_MS 500 #define TAPER_RESIDUAL_PCT 90 Loading Loading @@ -562,6 +634,195 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, return 0; } static void fcc_stepper_work(struct work_struct *work) { struct pl_data *chip = container_of(work, struct pl_data, fcc_stepper_work.work); union power_supply_propval pval = {0, }; int reschedule_ms = 0, rc = 0, charger_present = 0; int main_fcc = chip->main_fcc_ua; int parallel_fcc = chip->slave_fcc_ua; /* 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); charger_present = pval.intval; /*Check whether DC charger is present or not */ if (!chip->dc_psy) chip->dc_psy = power_supply_get_by_name("dc"); if (chip->dc_psy) { rc = power_supply_get_property(chip->dc_psy, POWER_SUPPLY_PROP_PRESENT, &pval); if (rc < 0) pr_err("Couldn't get DC Present status, rc=%d\n", rc); charger_present |= pval.intval; } /* * If USB is not present, then set parallel FCC to min value and * main FCC to the effective value of FCC votable and exit. */ if (!charger_present) { /* Disable parallel */ parallel_fcc = 0; if (chip->pl_psy) { 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); goto out; } chip->pl_disable = true; power_supply_changed(chip->pl_psy); } 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); goto out; } 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 (parallel_fcc < chip->slave_fcc_ua) { /* Set parallel FCC */ if (chip->pl_psy && !chip->pl_disable) { 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); goto out; } if (IS_USBIN(chip->pl_mode)) split_settled(chip); parallel_fcc = 0; chip->parallel_step_fcc_count = 0; chip->parallel_step_fcc_residual = 0; chip->total_settled_ua = 0; chip->pl_settled_ua = 0; chip->pl_disable = true; power_supply_changed(chip->pl_psy); } else { /* 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); goto out; } } } /* 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); goto out; } } else { /* 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); goto out; } /* Set parallel FCC */ if (chip->pl_psy) { 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); goto out; } /* * Enable parallel charger only if it was disabled * earlier and configured slave fcc is greater than or * equal to minimum parallel FCC value. */ if (chip->pl_disable && parallel_fcc >= MINIMUM_PARALLEL_FCC_UA) { 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); goto out; } if (IS_USBIN(chip->pl_mode)) split_settled(chip); chip->pl_disable = false; power_supply_changed(chip->pl_psy); } } } stepper_exit: chip->main_fcc_ua = main_fcc; chip->slave_fcc_ua = parallel_fcc; if (reschedule_ms) { schedule_delayed_work(&chip->fcc_stepper_work, msecs_to_jiffies(reschedule_ms)); pr_debug("Rescheduling FCC_STEPPER work\n"); return; } out: chip->step_fcc = 0; 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 @@ -700,6 +961,17 @@ static bool is_main_available(struct pl_data *chip) return !!chip->main_psy; } static bool is_batt_available(struct pl_data *chip) { if (!chip->batt_psy) chip->batt_psy = power_supply_get_by_name("battery"); if (!chip->batt_psy) return false; return true; } static int pl_disable_vote_callback(struct votable *votable, void *data, int pl_disable, const char *client) { Loading @@ -712,6 +984,28 @@ static int pl_disable_vote_callback(struct votable *votable, if (!is_main_available(chip)) return -ENODEV; if (!is_batt_available(chip)) return -ENODEV; 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 -ENODEV; } 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_stepper_enable = pval.intval; pr_debug("FCC Stepper %s\n", pval.intval ? "enabled" : "disabled"); if (chip->fcc_stepper_enable) cancel_delayed_work_sync(&chip->fcc_stepper_work); total_fcc_ua = get_effective_result_locked(chip->fcc_votable); if (chip->pl_mode != POWER_SUPPLY_PL_NONE && !pl_disable) { Loading Loading @@ -747,6 +1041,15 @@ static int pl_disable_vote_callback(struct votable *votable, get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua); if (chip->fcc_stepper_enable) { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, true, 0); get_fcc_stepper_params(chip, master_fcc_ua, slave_fcc_ua); if (chip->step_fcc) schedule_delayed_work(&chip->fcc_stepper_work, 0); } else { /* * If there is an increase in slave share * (Also handles parallel enable case) Loading @@ -761,7 +1064,8 @@ static int pl_disable_vote_callback(struct votable *votable, 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 @@ -794,7 +1098,8 @@ static int pl_disable_vote_callback(struct votable *votable, 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 @@ -813,6 +1118,8 @@ static int pl_disable_vote_callback(struct votable *votable, if (IS_USBIN(chip->pl_mode)) split_settled(chip); } /* * we could have been enabled while in taper mode, * start the taper work if so Loading @@ -838,6 +1145,7 @@ static int pl_disable_vote_callback(struct votable *votable, (master_fcc_ua * 100) / total_fcc_ua, (slave_fcc_ua * 100) / total_fcc_ua); } else { if (!chip->fcc_stepper_enable) { if (IS_USBIN(chip->pl_mode)) split_settled(chip); Loading @@ -863,18 +1171,27 @@ static int pl_disable_vote_callback(struct votable *votable, /* reset parallel FCC */ chip->slave_fcc_ua = 0; chip->total_settled_ua = 0; chip->pl_settled_ua = 0; } else { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, true, 0); get_fcc_stepper_params(chip, total_fcc_ua, 0); if (chip->step_fcc) schedule_delayed_work(&chip->fcc_stepper_work, 0); } rerun_election(chip->fv_votable); cancel_delayed_work_sync(&chip->pl_awake_work); schedule_delayed_work(&chip->pl_awake_work, msecs_to_jiffies(5000)); chip->total_settled_ua = 0; chip->pl_settled_ua = 0; } /* notify parallel state change */ if (chip->pl_psy && (chip->pl_disable != pl_disable)) { if (chip->pl_psy && (chip->pl_disable != pl_disable) && !chip->fcc_stepper_enable) { power_supply_changed(chip->pl_psy); chip->pl_disable = (bool)pl_disable; } Loading Loading @@ -909,17 +1226,6 @@ static int pl_awake_vote_callback(struct votable *votable, return 0; } static bool is_batt_available(struct pl_data *chip) { if (!chip->batt_psy) chip->batt_psy = power_supply_get_by_name("battery"); if (!chip->batt_psy) return false; return true; } static bool is_parallel_available(struct pl_data *chip) { union power_supply_propval pval = {0, }; Loading Loading @@ -1083,6 +1389,7 @@ static void handle_settled_icl_change(struct pl_data *chip) else vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0); rerun_election(chip->fcc_votable); if (IS_USBIN(chip->pl_mode)) { /* Loading Loading @@ -1331,6 +1638,7 @@ int qcom_batt_init(int smb_version) INIT_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_stepper_work, fcc_stepper_work); rc = pl_register_notifier(chip); if (rc < 0) { Loading Loading @@ -1386,6 +1694,7 @@ void qcom_batt_deinit(void) cancel_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_stepper_work); power_supply_unreg_notifier(&chip->nb); destroy_votable(chip->pl_enable_votable_indirect); Loading
drivers/power/supply/qcom/qpnp-smb5.c +6 −0 Original line number Diff line number Diff line Loading @@ -440,6 +440,9 @@ static int smb5_parse_dt(struct smb5 *chip) if (rc < 0) chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS; chg->fcc_stepper_enable = of_property_read_bool(node, "qcom,fcc-stepping-enable"); rc = of_property_match_string(node, "io-channel-names", "usb_in_voltage"); if (rc >= 0) { Loading Loading @@ -1176,6 +1179,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_RECHARGE_SOC, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_FORCE_RECHARGE, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, }; static int smb5_batt_get_prop(struct power_supply *psy, Loading Loading @@ -1293,6 +1297,8 @@ static int smb5_batt_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_FORCE_RECHARGE: val->intval = 0; case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: val->intval = chg->fcc_stepper_enable; break; default: pr_err("batt power supply prop %d not supported\n", psp); Loading