Loading drivers/power/supply/qcom/battery.c +110 −38 Original line number Original line Diff line number Diff line Loading @@ -44,10 +44,12 @@ #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" #define ICL_LIMIT_VOTER "ICL_LIMIT_VOTER" struct pl_data { struct pl_data { int pl_mode; int pl_mode; int pl_batfet_mode; int pl_batfet_mode; int pl_min_icl_ua; int slave_pct; int slave_pct; int slave_fcc_ua; int slave_fcc_ua; int restricted_current; int restricted_current; Loading Loading @@ -93,6 +95,8 @@ module_param_named(debug_mask, debug_mask, int, 0600); pr_debug(fmt, ##__VA_ARGS__); \ pr_debug(fmt, ##__VA_ARGS__); \ } while (0) } while (0) #define IS_USBIN(mode) ((mode == POWER_SUPPLY_PL_USBIN_USBIN) \ || (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) enum { enum { VER = 0, VER = 0, SLAVE_PCT, SLAVE_PCT, Loading @@ -103,19 +107,19 @@ enum { /******* /******* * ICL * * ICL * ********/ ********/ static void split_settled(struct pl_data *chip) static int get_settled_split(struct pl_data *chip, int *main_icl_ua, int *slave_icl_ua, int *total_settled_icl_ua) { { int slave_icl_pct, total_current_ua; int slave_icl_pct, total_current_ua; int slave_ua = 0, main_settled_ua = 0; int slave_ua = 0, main_settled_ua = 0; union power_supply_propval pval = {0, }; union power_supply_propval pval = {0, }; int rc, total_settled_ua = 0; int rc, total_settled_ua = 0; if ((chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN) if (!IS_USBIN(chip->pl_mode)) && (chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN_EXT)) return -EINVAL; return; if (!chip->main_psy) if (!chip->main_psy) return; return -EINVAL; if (!get_effective_result_locked(chip->pl_disable_votable)) { if (!get_effective_result_locked(chip->pl_disable_votable)) { /* read the aicl settled value */ /* read the aicl settled value */ Loading @@ -123,11 +127,10 @@ static void split_settled(struct pl_data *chip) POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); if (rc < 0) { if (rc < 0) { pr_err("Couldn't get aicl settled value rc=%d\n", rc); pr_err("Couldn't get aicl settled value rc=%d\n", rc); return; return rc; } } main_settled_ua = pval.intval; main_settled_ua = pval.intval; /* slave gets 10 percent points less for ICL */ slave_icl_pct = max(0, chip->slave_pct); slave_icl_pct = max(0, chip->slave_pct - 10); slave_ua = ((main_settled_ua + chip->pl_settled_ua) slave_ua = ((main_settled_ua + chip->pl_settled_ua) * slave_icl_pct) / 100; * slave_icl_pct) / 100; total_settled_ua = main_settled_ua + chip->pl_settled_ua; total_settled_ua = main_settled_ua + chip->pl_settled_ua; Loading @@ -139,18 +142,63 @@ static void split_settled(struct pl_data *chip) chip->usb_psy = power_supply_get_by_name("usb"); chip->usb_psy = power_supply_get_by_name("usb"); if (!chip->usb_psy) { if (!chip->usb_psy) { pr_err("Couldn't get usbpsy while splitting settled\n"); pr_err("Couldn't get usbpsy while splitting settled\n"); return; return -ENOENT; } } /* no client is voting, so get the total current from charger */ /* no client is voting, so get the total current from charger */ rc = power_supply_get_property(chip->usb_psy, rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_HW_CURRENT_MAX, &pval); POWER_SUPPLY_PROP_HW_CURRENT_MAX, &pval); if (rc < 0) { if (rc < 0) { pr_err("Couldn't get max current rc=%d\n", rc); pr_err("Couldn't get max current rc=%d\n", rc); return; return rc; } } total_current_ua = pval.intval; total_current_ua = pval.intval; } } *main_icl_ua = total_current_ua - slave_ua; *slave_icl_ua = slave_ua; *total_settled_icl_ua = total_settled_ua; pl_dbg(chip, PR_PARALLEL, "Split total_current_ua=%d total_settled_ua=%d main_settled_ua=%d slave_ua=%d\n", total_current_ua, total_settled_ua, main_settled_ua, slave_ua); return 0; } static int validate_parallel_icl(struct pl_data *chip, bool *disable) { int rc = 0; int main_ua = 0, slave_ua = 0, total_settled_ua = 0; if (!IS_USBIN(chip->pl_mode) || get_effective_result_locked(chip->pl_disable_votable)) return 0; rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua); if (rc < 0) { pr_err("Couldn't get split current rc=%d\n", rc); return rc; } if (slave_ua < chip->pl_min_icl_ua) *disable = true; else *disable = false; return 0; } static void split_settled(struct pl_data *chip) { union power_supply_propval pval = {0, }; int rc, main_ua, slave_ua, total_settled_ua; rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua); if (rc < 0) { pr_err("Couldn't get split current rc=%d\n", rc); return; } /* /* * If there is an increase in slave share * If there is an increase in slave share * (Also handles parallel enable case) * (Also handles parallel enable case) Loading @@ -160,7 +208,7 @@ static void split_settled(struct pl_data *chip) * Set slave ICL then main ICL. * Set slave ICL then main ICL. */ */ if (slave_ua > chip->pl_settled_ua) { if (slave_ua > chip->pl_settled_ua) { pval.intval = total_current_ua - slave_ua; pval.intval = main_ua; /* Set ICL on main charger */ /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); POWER_SUPPLY_PROP_CURRENT_MAX, &pval); Loading Loading @@ -188,7 +236,7 @@ static void split_settled(struct pl_data *chip) return; return; } } pval.intval = total_current_ua - slave_ua; pval.intval = main_ua; /* Set ICL on main charger */ /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); POWER_SUPPLY_PROP_CURRENT_MAX, &pval); Loading @@ -202,9 +250,6 @@ static void split_settled(struct pl_data *chip) chip->total_settled_ua = total_settled_ua; chip->total_settled_ua = total_settled_ua; chip->pl_settled_ua = slave_ua; chip->pl_settled_ua = slave_ua; pl_dbg(chip, PR_PARALLEL, "Split total_current_ua=%d main_settled_ua=%d slave_ua=%d\n", total_current_ua, main_settled_ua, slave_ua); } } static ssize_t version_show(struct class *c, struct class_attribute *attr, static ssize_t version_show(struct class *c, struct class_attribute *attr, Loading @@ -229,14 +274,21 @@ static ssize_t slave_pct_show(struct class *c, struct class_attribute *attr, static ssize_t slave_pct_store(struct class *c, struct class_attribute *attr, static ssize_t slave_pct_store(struct class *c, struct class_attribute *attr, const char *ubuf, size_t count) const char *ubuf, size_t count) { { struct pl_data *chip = container_of(c, struct pl_data, struct pl_data *chip = container_of(c, struct pl_data, qcom_batt_class); qcom_batt_class); int rc; unsigned long val; unsigned long val; bool disable = false; if (kstrtoul(ubuf, 10, &val)) if (kstrtoul(ubuf, 10, &val)) return -EINVAL; return -EINVAL; chip->slave_pct = val; chip->slave_pct = val; rc = validate_parallel_icl(chip, &disable); if (rc < 0) return rc; vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, disable, 0); rerun_election(chip->fcc_votable); rerun_election(chip->fcc_votable); rerun_election(chip->fv_votable); rerun_election(chip->fv_votable); split_settled(chip); split_settled(chip); Loading Loading @@ -465,11 +517,9 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, &slave_fcc_ua); &slave_fcc_ua); if (slave_fcc_ua > MINIMUM_PARALLEL_FCC_UA) { if (slave_fcc_ua > MINIMUM_PARALLEL_FCC_UA) { chip->slave_fcc_ua = slave_fcc_ua; vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0); false, 0); } else { } else { chip->slave_fcc_ua = 0; vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, true, 0); true, 0); } } Loading Loading @@ -623,11 +673,9 @@ static int pl_disable_vote_callback(struct votable *votable, { { struct pl_data *chip = data; struct pl_data *chip = data; union power_supply_propval pval = {0, }; union power_supply_propval pval = {0, }; int master_fcc_ua, total_fcc_ua, slave_fcc_ua; int master_fcc_ua = 0, total_fcc_ua = 0, slave_fcc_ua = 0; int rc; int rc = 0; bool disable = false; chip->total_settled_ua = 0; chip->pl_settled_ua = 0; if (!is_main_available(chip)) if (!is_main_available(chip)) return -ENODEV; return -ENODEV; Loading @@ -639,6 +687,16 @@ static int pl_disable_vote_callback(struct votable *votable, cancel_delayed_work_sync(&chip->pl_awake_work); cancel_delayed_work_sync(&chip->pl_awake_work); vote(chip->pl_awake_votable, PL_VOTER, true, 0); vote(chip->pl_awake_votable, PL_VOTER, true, 0); rc = validate_parallel_icl(chip, &disable); if (rc < 0) return rc; if (disable) { pr_info("Parallel ICL is less than min ICL(%d), skipping parallel enable\n", chip->pl_min_icl_ua); return 0; } /* enable parallel charging */ /* enable parallel charging */ rc = power_supply_get_property(chip->pl_psy, rc = power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); Loading Loading @@ -721,8 +779,7 @@ static int pl_disable_vote_callback(struct votable *votable, pr_err("Couldn't change slave suspend state rc=%d\n", pr_err("Couldn't change slave suspend state rc=%d\n", rc); rc); if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) if (IS_USBIN(chip->pl_mode)) || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) split_settled(chip); split_settled(chip); /* /* * we could have been enabled while in taper mode, * we could have been enabled while in taper mode, Loading @@ -749,8 +806,7 @@ static int pl_disable_vote_callback(struct votable *votable, (master_fcc_ua * 100) / total_fcc_ua, (master_fcc_ua * 100) / total_fcc_ua, (slave_fcc_ua * 100) / total_fcc_ua); (slave_fcc_ua * 100) / total_fcc_ua); } else { } else { if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) if (IS_USBIN(chip->pl_mode)) || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) split_settled(chip); split_settled(chip); /* pl_psy may be NULL while in the disable branch */ /* pl_psy may be NULL while in the disable branch */ Loading @@ -773,11 +829,16 @@ static int pl_disable_vote_callback(struct votable *votable, return rc; return rc; } } /* reset parallel FCC */ chip->slave_fcc_ua = 0; rerun_election(chip->fv_votable); rerun_election(chip->fv_votable); cancel_delayed_work_sync(&chip->pl_awake_work); cancel_delayed_work_sync(&chip->pl_awake_work); schedule_delayed_work(&chip->pl_awake_work, schedule_delayed_work(&chip->pl_awake_work, msecs_to_jiffies(5000)); msecs_to_jiffies(5000)); chip->total_settled_ua = 0; chip->pl_settled_ua = 0; } } pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n", pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n", Loading Loading @@ -848,8 +909,7 @@ static bool is_parallel_available(struct pl_data *chip) chip->pl_mode = pval.intval; chip->pl_mode = pval.intval; /* Disable autonomous votage increments for USBIN-USBIN */ /* Disable autonomous votage increments for USBIN-USBIN */ if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) if (IS_USBIN(chip->pl_mode)) { || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) { if (!chip->hvdcp_hw_inov_dis_votable) if (!chip->hvdcp_hw_inov_dis_votable) chip->hvdcp_hw_inov_dis_votable = chip->hvdcp_hw_inov_dis_votable = find_votable("HVDCP_HW_INOV_DIS"); find_votable("HVDCP_HW_INOV_DIS"); Loading @@ -870,6 +930,11 @@ static bool is_parallel_available(struct pl_data *chip) } } chip->pl_batfet_mode = pval.intval; chip->pl_batfet_mode = pval.intval; pval.intval = 0; power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_MIN_ICL, &pval); chip->pl_min_icl_ua = pval.intval; vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); return true; return true; Loading @@ -894,6 +959,7 @@ static void handle_main_charge_type(struct pl_data *chip) vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0); vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0); vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER, vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER, false, 0); false, 0); vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, false, 0); chip->charge_type = pval.intval; chip->charge_type = pval.intval; return; return; } } Loading Loading @@ -932,6 +998,7 @@ static void handle_settled_icl_change(struct pl_data *chip) int main_settled_ua; int main_settled_ua; int main_limited; int main_limited; int total_current_ua; int total_current_ua; bool disable = false; total_current_ua = get_effective_result_locked(chip->usb_icl_votable); total_current_ua = get_effective_result_locked(chip->usb_icl_votable); Loading Loading @@ -967,11 +1034,7 @@ static void handle_settled_icl_change(struct pl_data *chip) rerun_election(chip->fcc_votable); rerun_election(chip->fcc_votable); if (get_effective_result(chip->pl_disable_votable)) if (IS_USBIN(chip->pl_mode)) { return; if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN || chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT) { /* /* * call aicl split only when USBIN_USBIN and enabled * call aicl split only when USBIN_USBIN and enabled * and if settled current has changed by more than 300mA * and if settled current has changed by more than 300mA Loading @@ -985,10 +1048,19 @@ static void handle_settled_icl_change(struct pl_data *chip) /* If ICL change is small skip splitting */ /* If ICL change is small skip splitting */ if (abs(new_total_settled_ua - chip->total_settled_ua) if (abs(new_total_settled_ua - chip->total_settled_ua) > MIN_ICL_CHANGE_DELTA_UA) > MIN_ICL_CHANGE_DELTA_UA) { rc = validate_parallel_icl(chip, &disable); if (rc < 0) return; vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, disable, 0); if (!get_effective_result_locked( chip->pl_disable_votable)) split_settled(chip); split_settled(chip); } } } } } static void handle_parallel_in_taper(struct pl_data *chip) static void handle_parallel_in_taper(struct pl_data *chip) { { Loading Loading
drivers/power/supply/qcom/battery.c +110 −38 Original line number Original line Diff line number Diff line Loading @@ -44,10 +44,12 @@ #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" #define ICL_LIMIT_VOTER "ICL_LIMIT_VOTER" struct pl_data { struct pl_data { int pl_mode; int pl_mode; int pl_batfet_mode; int pl_batfet_mode; int pl_min_icl_ua; int slave_pct; int slave_pct; int slave_fcc_ua; int slave_fcc_ua; int restricted_current; int restricted_current; Loading Loading @@ -93,6 +95,8 @@ module_param_named(debug_mask, debug_mask, int, 0600); pr_debug(fmt, ##__VA_ARGS__); \ pr_debug(fmt, ##__VA_ARGS__); \ } while (0) } while (0) #define IS_USBIN(mode) ((mode == POWER_SUPPLY_PL_USBIN_USBIN) \ || (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) enum { enum { VER = 0, VER = 0, SLAVE_PCT, SLAVE_PCT, Loading @@ -103,19 +107,19 @@ enum { /******* /******* * ICL * * ICL * ********/ ********/ static void split_settled(struct pl_data *chip) static int get_settled_split(struct pl_data *chip, int *main_icl_ua, int *slave_icl_ua, int *total_settled_icl_ua) { { int slave_icl_pct, total_current_ua; int slave_icl_pct, total_current_ua; int slave_ua = 0, main_settled_ua = 0; int slave_ua = 0, main_settled_ua = 0; union power_supply_propval pval = {0, }; union power_supply_propval pval = {0, }; int rc, total_settled_ua = 0; int rc, total_settled_ua = 0; if ((chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN) if (!IS_USBIN(chip->pl_mode)) && (chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN_EXT)) return -EINVAL; return; if (!chip->main_psy) if (!chip->main_psy) return; return -EINVAL; if (!get_effective_result_locked(chip->pl_disable_votable)) { if (!get_effective_result_locked(chip->pl_disable_votable)) { /* read the aicl settled value */ /* read the aicl settled value */ Loading @@ -123,11 +127,10 @@ static void split_settled(struct pl_data *chip) POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); if (rc < 0) { if (rc < 0) { pr_err("Couldn't get aicl settled value rc=%d\n", rc); pr_err("Couldn't get aicl settled value rc=%d\n", rc); return; return rc; } } main_settled_ua = pval.intval; main_settled_ua = pval.intval; /* slave gets 10 percent points less for ICL */ slave_icl_pct = max(0, chip->slave_pct); slave_icl_pct = max(0, chip->slave_pct - 10); slave_ua = ((main_settled_ua + chip->pl_settled_ua) slave_ua = ((main_settled_ua + chip->pl_settled_ua) * slave_icl_pct) / 100; * slave_icl_pct) / 100; total_settled_ua = main_settled_ua + chip->pl_settled_ua; total_settled_ua = main_settled_ua + chip->pl_settled_ua; Loading @@ -139,18 +142,63 @@ static void split_settled(struct pl_data *chip) chip->usb_psy = power_supply_get_by_name("usb"); chip->usb_psy = power_supply_get_by_name("usb"); if (!chip->usb_psy) { if (!chip->usb_psy) { pr_err("Couldn't get usbpsy while splitting settled\n"); pr_err("Couldn't get usbpsy while splitting settled\n"); return; return -ENOENT; } } /* no client is voting, so get the total current from charger */ /* no client is voting, so get the total current from charger */ rc = power_supply_get_property(chip->usb_psy, rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_HW_CURRENT_MAX, &pval); POWER_SUPPLY_PROP_HW_CURRENT_MAX, &pval); if (rc < 0) { if (rc < 0) { pr_err("Couldn't get max current rc=%d\n", rc); pr_err("Couldn't get max current rc=%d\n", rc); return; return rc; } } total_current_ua = pval.intval; total_current_ua = pval.intval; } } *main_icl_ua = total_current_ua - slave_ua; *slave_icl_ua = slave_ua; *total_settled_icl_ua = total_settled_ua; pl_dbg(chip, PR_PARALLEL, "Split total_current_ua=%d total_settled_ua=%d main_settled_ua=%d slave_ua=%d\n", total_current_ua, total_settled_ua, main_settled_ua, slave_ua); return 0; } static int validate_parallel_icl(struct pl_data *chip, bool *disable) { int rc = 0; int main_ua = 0, slave_ua = 0, total_settled_ua = 0; if (!IS_USBIN(chip->pl_mode) || get_effective_result_locked(chip->pl_disable_votable)) return 0; rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua); if (rc < 0) { pr_err("Couldn't get split current rc=%d\n", rc); return rc; } if (slave_ua < chip->pl_min_icl_ua) *disable = true; else *disable = false; return 0; } static void split_settled(struct pl_data *chip) { union power_supply_propval pval = {0, }; int rc, main_ua, slave_ua, total_settled_ua; rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua); if (rc < 0) { pr_err("Couldn't get split current rc=%d\n", rc); return; } /* /* * If there is an increase in slave share * If there is an increase in slave share * (Also handles parallel enable case) * (Also handles parallel enable case) Loading @@ -160,7 +208,7 @@ static void split_settled(struct pl_data *chip) * Set slave ICL then main ICL. * Set slave ICL then main ICL. */ */ if (slave_ua > chip->pl_settled_ua) { if (slave_ua > chip->pl_settled_ua) { pval.intval = total_current_ua - slave_ua; pval.intval = main_ua; /* Set ICL on main charger */ /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); POWER_SUPPLY_PROP_CURRENT_MAX, &pval); Loading Loading @@ -188,7 +236,7 @@ static void split_settled(struct pl_data *chip) return; return; } } pval.intval = total_current_ua - slave_ua; pval.intval = main_ua; /* Set ICL on main charger */ /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); POWER_SUPPLY_PROP_CURRENT_MAX, &pval); Loading @@ -202,9 +250,6 @@ static void split_settled(struct pl_data *chip) chip->total_settled_ua = total_settled_ua; chip->total_settled_ua = total_settled_ua; chip->pl_settled_ua = slave_ua; chip->pl_settled_ua = slave_ua; pl_dbg(chip, PR_PARALLEL, "Split total_current_ua=%d main_settled_ua=%d slave_ua=%d\n", total_current_ua, main_settled_ua, slave_ua); } } static ssize_t version_show(struct class *c, struct class_attribute *attr, static ssize_t version_show(struct class *c, struct class_attribute *attr, Loading @@ -229,14 +274,21 @@ static ssize_t slave_pct_show(struct class *c, struct class_attribute *attr, static ssize_t slave_pct_store(struct class *c, struct class_attribute *attr, static ssize_t slave_pct_store(struct class *c, struct class_attribute *attr, const char *ubuf, size_t count) const char *ubuf, size_t count) { { struct pl_data *chip = container_of(c, struct pl_data, struct pl_data *chip = container_of(c, struct pl_data, qcom_batt_class); qcom_batt_class); int rc; unsigned long val; unsigned long val; bool disable = false; if (kstrtoul(ubuf, 10, &val)) if (kstrtoul(ubuf, 10, &val)) return -EINVAL; return -EINVAL; chip->slave_pct = val; chip->slave_pct = val; rc = validate_parallel_icl(chip, &disable); if (rc < 0) return rc; vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, disable, 0); rerun_election(chip->fcc_votable); rerun_election(chip->fcc_votable); rerun_election(chip->fv_votable); rerun_election(chip->fv_votable); split_settled(chip); split_settled(chip); Loading Loading @@ -465,11 +517,9 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, &slave_fcc_ua); &slave_fcc_ua); if (slave_fcc_ua > MINIMUM_PARALLEL_FCC_UA) { if (slave_fcc_ua > MINIMUM_PARALLEL_FCC_UA) { chip->slave_fcc_ua = slave_fcc_ua; vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0); false, 0); } else { } else { chip->slave_fcc_ua = 0; vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, true, 0); true, 0); } } Loading Loading @@ -623,11 +673,9 @@ static int pl_disable_vote_callback(struct votable *votable, { { struct pl_data *chip = data; struct pl_data *chip = data; union power_supply_propval pval = {0, }; union power_supply_propval pval = {0, }; int master_fcc_ua, total_fcc_ua, slave_fcc_ua; int master_fcc_ua = 0, total_fcc_ua = 0, slave_fcc_ua = 0; int rc; int rc = 0; bool disable = false; chip->total_settled_ua = 0; chip->pl_settled_ua = 0; if (!is_main_available(chip)) if (!is_main_available(chip)) return -ENODEV; return -ENODEV; Loading @@ -639,6 +687,16 @@ static int pl_disable_vote_callback(struct votable *votable, cancel_delayed_work_sync(&chip->pl_awake_work); cancel_delayed_work_sync(&chip->pl_awake_work); vote(chip->pl_awake_votable, PL_VOTER, true, 0); vote(chip->pl_awake_votable, PL_VOTER, true, 0); rc = validate_parallel_icl(chip, &disable); if (rc < 0) return rc; if (disable) { pr_info("Parallel ICL is less than min ICL(%d), skipping parallel enable\n", chip->pl_min_icl_ua); return 0; } /* enable parallel charging */ /* enable parallel charging */ rc = power_supply_get_property(chip->pl_psy, rc = power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); Loading Loading @@ -721,8 +779,7 @@ static int pl_disable_vote_callback(struct votable *votable, pr_err("Couldn't change slave suspend state rc=%d\n", pr_err("Couldn't change slave suspend state rc=%d\n", rc); rc); if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) if (IS_USBIN(chip->pl_mode)) || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) split_settled(chip); split_settled(chip); /* /* * we could have been enabled while in taper mode, * we could have been enabled while in taper mode, Loading @@ -749,8 +806,7 @@ static int pl_disable_vote_callback(struct votable *votable, (master_fcc_ua * 100) / total_fcc_ua, (master_fcc_ua * 100) / total_fcc_ua, (slave_fcc_ua * 100) / total_fcc_ua); (slave_fcc_ua * 100) / total_fcc_ua); } else { } else { if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) if (IS_USBIN(chip->pl_mode)) || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) split_settled(chip); split_settled(chip); /* pl_psy may be NULL while in the disable branch */ /* pl_psy may be NULL while in the disable branch */ Loading @@ -773,11 +829,16 @@ static int pl_disable_vote_callback(struct votable *votable, return rc; return rc; } } /* reset parallel FCC */ chip->slave_fcc_ua = 0; rerun_election(chip->fv_votable); rerun_election(chip->fv_votable); cancel_delayed_work_sync(&chip->pl_awake_work); cancel_delayed_work_sync(&chip->pl_awake_work); schedule_delayed_work(&chip->pl_awake_work, schedule_delayed_work(&chip->pl_awake_work, msecs_to_jiffies(5000)); msecs_to_jiffies(5000)); chip->total_settled_ua = 0; chip->pl_settled_ua = 0; } } pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n", pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n", Loading Loading @@ -848,8 +909,7 @@ static bool is_parallel_available(struct pl_data *chip) chip->pl_mode = pval.intval; chip->pl_mode = pval.intval; /* Disable autonomous votage increments for USBIN-USBIN */ /* Disable autonomous votage increments for USBIN-USBIN */ if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) if (IS_USBIN(chip->pl_mode)) { || (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) { if (!chip->hvdcp_hw_inov_dis_votable) if (!chip->hvdcp_hw_inov_dis_votable) chip->hvdcp_hw_inov_dis_votable = chip->hvdcp_hw_inov_dis_votable = find_votable("HVDCP_HW_INOV_DIS"); find_votable("HVDCP_HW_INOV_DIS"); Loading @@ -870,6 +930,11 @@ static bool is_parallel_available(struct pl_data *chip) } } chip->pl_batfet_mode = pval.intval; chip->pl_batfet_mode = pval.intval; pval.intval = 0; power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_MIN_ICL, &pval); chip->pl_min_icl_ua = pval.intval; vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); return true; return true; Loading @@ -894,6 +959,7 @@ static void handle_main_charge_type(struct pl_data *chip) vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0); vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0); vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER, vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER, false, 0); false, 0); vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, false, 0); chip->charge_type = pval.intval; chip->charge_type = pval.intval; return; return; } } Loading Loading @@ -932,6 +998,7 @@ static void handle_settled_icl_change(struct pl_data *chip) int main_settled_ua; int main_settled_ua; int main_limited; int main_limited; int total_current_ua; int total_current_ua; bool disable = false; total_current_ua = get_effective_result_locked(chip->usb_icl_votable); total_current_ua = get_effective_result_locked(chip->usb_icl_votable); Loading Loading @@ -967,11 +1034,7 @@ static void handle_settled_icl_change(struct pl_data *chip) rerun_election(chip->fcc_votable); rerun_election(chip->fcc_votable); if (get_effective_result(chip->pl_disable_votable)) if (IS_USBIN(chip->pl_mode)) { return; if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN || chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT) { /* /* * call aicl split only when USBIN_USBIN and enabled * call aicl split only when USBIN_USBIN and enabled * and if settled current has changed by more than 300mA * and if settled current has changed by more than 300mA Loading @@ -985,10 +1048,19 @@ static void handle_settled_icl_change(struct pl_data *chip) /* If ICL change is small skip splitting */ /* If ICL change is small skip splitting */ if (abs(new_total_settled_ua - chip->total_settled_ua) if (abs(new_total_settled_ua - chip->total_settled_ua) > MIN_ICL_CHANGE_DELTA_UA) > MIN_ICL_CHANGE_DELTA_UA) { rc = validate_parallel_icl(chip, &disable); if (rc < 0) return; vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, disable, 0); if (!get_effective_result_locked( chip->pl_disable_votable)) split_settled(chip); split_settled(chip); } } } } } static void handle_parallel_in_taper(struct pl_data *chip) static void handle_parallel_in_taper(struct pl_data *chip) { { Loading