Loading drivers/power/supply/qcom/battery.c +88 −14 Original line number Original line Diff line number Diff line Loading @@ -93,6 +93,8 @@ struct pl_data { int parallel_step_fcc_count; int parallel_step_fcc_count; int parallel_step_fcc_residual; int parallel_step_fcc_residual; int step_fcc; int step_fcc; int override_main_fcc_ua; int total_fcc_ua; u32 wa_flags; u32 wa_flags; struct class qcom_batt_class; struct class qcom_batt_class; struct wakeup_source *pl_ws; struct wakeup_source *pl_ws; Loading Loading @@ -135,6 +137,11 @@ enum { RESTRICT_CHG_CURRENT, RESTRICT_CHG_CURRENT, FCC_STEPPING_IN_PROGRESS, FCC_STEPPING_IN_PROGRESS, }; }; enum { PARALLEL_INPUT_MODE, PARALLEL_OUTPUT_MODE, }; /********* /********* * HELPER* * HELPER* *********/ *********/ Loading @@ -147,23 +154,61 @@ static bool is_cp_available(struct pl_data *chip) return !!chip->cp_master_psy; return !!chip->cp_master_psy; } } static bool cp_ilim_boost_enabled(struct pl_data *chip) static int cp_get_parallel_mode(struct pl_data *chip, int mode) { { union power_supply_propval pval = {-1, }; union power_supply_propval pval = {-EINVAL, }; int rc = -EINVAL; if (is_cp_available(chip)) if (!is_cp_available(chip)) power_supply_get_property(chip->cp_master_psy, return -EINVAL; switch (mode) { case PARALLEL_INPUT_MODE: rc = power_supply_get_property(chip->cp_master_psy, POWER_SUPPLY_PROP_PARALLEL_MODE, &pval); break; case PARALLEL_OUTPUT_MODE: rc = power_supply_get_property(chip->cp_master_psy, POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, &pval); POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, &pval); break; default: pr_err("Invalid mode request %d\n", mode); break; } if (rc < 0) pr_err("Failed to read CP topology for mode=%d rc=%d\n", mode, rc); return pval.intval == POWER_SUPPLY_PL_OUTPUT_VPH; return pval.intval; } } /* * Adapter CC Mode: ILIM over-ridden explicitly, below takes no effect. * * Adapter CV mode: Configuration of ILIM for different topology is as below: * MID-VPH: * SMB1390 ILIM: independent of FCC and based on the AICL result or * PD advertised current, handled directly in SMB1390 * driver. * MID-VBAT: * SMB1390 ILIM: based on minimum of FCC portion of SMB1390 or ICL. * USBIN-VBAT: * SMB1390 ILIM: based on FCC portion of SMB1390 and independent of ICL. */ static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim) static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim) { { if (!is_cp_available(chip)) return; if (cp_get_parallel_mode(chip, PARALLEL_OUTPUT_MODE) == POWER_SUPPLY_PL_OUTPUT_VPH) return; if (!chip->cp_ilim_votable) if (!chip->cp_ilim_votable) chip->cp_ilim_votable = find_votable("CP_ILIM"); chip->cp_ilim_votable = find_votable("CP_ILIM"); if (!cp_ilim_boost_enabled(chip) && chip->cp_ilim_votable) if (chip->cp_ilim_votable) vote(chip->cp_ilim_votable, voter, true, ilim); vote(chip->cp_ilim_votable, voter, true, ilim); } } Loading Loading @@ -562,6 +607,28 @@ static void get_main_fcc_config(struct pl_data *chip, int *total_fcc) static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua, static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua, int parallel_fcc_ua) int parallel_fcc_ua) { { int main_set_fcc_ua, total_fcc_ua; if (is_override_vote_enabled_locked(chip->fcc_main_votable)) { /* * FCC stepper params need re-calculation in override mode * only if there is change in Main or total FCC */ main_set_fcc_ua = get_effective_result_locked( chip->fcc_main_votable); total_fcc_ua = main_fcc_ua + parallel_fcc_ua; if ((main_set_fcc_ua != chip->override_main_fcc_ua) || (total_fcc_ua != chip->total_fcc_ua)) { chip->override_main_fcc_ua = main_set_fcc_ua; chip->total_fcc_ua = total_fcc_ua; parallel_fcc_ua += (main_fcc_ua - chip->override_main_fcc_ua); } else { goto skip_fcc_step_update; } } /* Read current FCC of main charger */ /* Read current FCC of main charger */ chip->main_fcc_ua = get_effective_result(chip->fcc_main_votable); chip->main_fcc_ua = get_effective_result(chip->fcc_main_votable); chip->main_step_fcc_dir = (main_fcc_ua > chip->main_fcc_ua) ? chip->main_step_fcc_dir = (main_fcc_ua > chip->main_fcc_ua) ? Loading @@ -578,6 +645,7 @@ static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua, chip->parallel_step_fcc_residual = abs((parallel_fcc_ua - chip->parallel_step_fcc_residual = abs((parallel_fcc_ua - chip->slave_fcc_ua)) % FCC_STEP_SIZE_UA; chip->slave_fcc_ua)) % FCC_STEP_SIZE_UA; skip_fcc_step_update: if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual || chip->main_step_fcc_count || chip->main_step_fcc_residual) || chip->main_step_fcc_count || chip->main_step_fcc_residual) chip->step_fcc = 1; chip->step_fcc = 1; Loading Loading @@ -725,12 +793,13 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, chip->cp_disable_votable = find_votable("CP_DISABLE"); chip->cp_disable_votable = find_votable("CP_DISABLE"); if (chip->cp_disable_votable) { if (chip->cp_disable_votable) { if (cp_ilim_boost_enabled(chip)) { if (cp_get_parallel_mode(chip, PARALLEL_OUTPUT_MODE) == POWER_SUPPLY_PL_OUTPUT_VPH) { power_supply_get_property(chip->cp_master_psy, power_supply_get_property(chip->cp_master_psy, POWER_SUPPLY_PROP_MIN_ICL, &pval); POWER_SUPPLY_PROP_MIN_ICL, &pval); /* /* * With ILIM boost feature ILIM configuration is * With VPH output configuration ILIM is configured * independent of battery FCC, disable CP if FCC/2 * independent of battery FCC, disable CP here if FCC/2 * falls below MIN_ICL supported by CP. * falls below MIN_ICL supported by CP. */ */ if ((total_fcc_ua / 2) < pval.intval) if ((total_fcc_ua / 2) < pval.intval) Loading Loading @@ -925,8 +994,7 @@ static void fcc_stepper_work(struct work_struct *work) stepper_exit: stepper_exit: chip->main_fcc_ua = main_fcc; chip->main_fcc_ua = main_fcc; chip->slave_fcc_ua = parallel_fcc; chip->slave_fcc_ua = parallel_fcc; cp_configure_ilim(chip, FCC_VOTER, chip->slave_fcc_ua / 2); cp_configure_ilim(chip, FCC_VOTER, chip->main_fcc_ua / 2); if (reschedule_ms) { if (reschedule_ms) { schedule_delayed_work(&chip->fcc_stepper_work, schedule_delayed_work(&chip->fcc_stepper_work, Loading Loading @@ -1079,6 +1147,9 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0); vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0); /* Configure ILIM based on AICL result only if input mode is USBMID */ if (cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE) == POWER_SUPPLY_PL_USBMID_USBMID) cp_configure_ilim(chip, ICL_CHANGE_VOTER, icl_ua); cp_configure_ilim(chip, ICL_CHANGE_VOTER, icl_ua); return 0; return 0; Loading Loading @@ -1111,7 +1182,7 @@ 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 = 0, total_fcc_ua = 0, slave_fcc_ua = 0; int master_fcc_ua = 0, total_fcc_ua = 0, slave_fcc_ua = 0; int rc = 0; int rc = 0, cp_ilim; bool disable = false; bool disable = false; if (!is_main_available(chip)) if (!is_main_available(chip)) Loading Loading @@ -1295,7 +1366,10 @@ static int pl_disable_vote_callback(struct votable *votable, /* main psy gets all share */ /* main psy gets all share */ vote(chip->fcc_main_votable, MAIN_FCC_VOTER, true, vote(chip->fcc_main_votable, MAIN_FCC_VOTER, true, total_fcc_ua); total_fcc_ua); cp_configure_ilim(chip, FCC_VOTER, total_fcc_ua / 2); cp_ilim = total_fcc_ua - get_effective_result_locked( chip->fcc_main_votable); if (cp_ilim > 0) cp_configure_ilim(chip, FCC_VOTER, cp_ilim / 2); /* reset parallel FCC */ /* reset parallel FCC */ chip->slave_fcc_ua = 0; chip->slave_fcc_ua = 0; Loading drivers/power/supply/qcom/pmic-voter.c +77 −3 Original line number Original line Diff line number Diff line Loading @@ -173,7 +173,7 @@ static int get_client_id(struct votable *votable, const char *client_str) static char *get_client_str(struct votable *votable, int client_id) static char *get_client_str(struct votable *votable, int client_id) { { if (client_id == -EINVAL) if (!votable || (client_id == -EINVAL)) return NULL; return NULL; return votable->client_strs[client_id]; return votable->client_strs[client_id]; Loading @@ -189,6 +189,38 @@ void unlock_votable(struct votable *votable) mutex_unlock(&votable->vote_lock); mutex_unlock(&votable->vote_lock); } } /** * is_override_vote_enabled() - * is_override_vote_enabled_locked() - * The unlocked and locked variants of getting whether override vote is enabled. * @votable: the votable object * * Returns: * True if the client's vote is enabled; false otherwise. */ bool is_override_vote_enabled_locked(struct votable *votable) { if (!votable) return false; return votable->override_result != -EINVAL; } bool is_override_vote_enabled(struct votable *votable) { bool enable; if (!votable) return false; lock_votable(votable); enable = is_override_vote_enabled_locked(votable); unlock_votable(votable); return enable; } /** /** * is_client_vote_enabled() - * is_client_vote_enabled() - * is_client_vote_enabled_locked() - * is_client_vote_enabled_locked() - Loading @@ -203,8 +235,13 @@ void unlock_votable(struct votable *votable) bool is_client_vote_enabled_locked(struct votable *votable, bool is_client_vote_enabled_locked(struct votable *votable, const char *client_str) const char *client_str) { { int client_id = get_client_id(votable, client_str); int client_id; if (!votable || !client_str) return false; client_id = get_client_id(votable, client_str); if (client_id < 0) if (client_id < 0) return false; return false; Loading @@ -215,6 +252,9 @@ bool is_client_vote_enabled(struct votable *votable, const char *client_str) { { bool enabled; bool enabled; if (!votable || !client_str) return false; lock_votable(votable); lock_votable(votable); enabled = is_client_vote_enabled_locked(votable, client_str); enabled = is_client_vote_enabled_locked(votable, client_str); unlock_votable(votable); unlock_votable(votable); Loading @@ -235,8 +275,12 @@ bool is_client_vote_enabled(struct votable *votable, const char *client_str) */ */ int get_client_vote_locked(struct votable *votable, const char *client_str) int get_client_vote_locked(struct votable *votable, const char *client_str) { { int client_id = get_client_id(votable, client_str); int client_id; if (!votable || !client_str) return -EINVAL; client_id = get_client_id(votable, client_str); if (client_id < 0) if (client_id < 0) return -EINVAL; return -EINVAL; Loading @@ -251,6 +295,9 @@ int get_client_vote(struct votable *votable, const char *client_str) { { int value; int value; if (!votable || !client_str) return -EINVAL; lock_votable(votable); lock_votable(votable); value = get_client_vote_locked(votable, client_str); value = get_client_vote_locked(votable, client_str); unlock_votable(votable); unlock_votable(votable); Loading @@ -276,6 +323,9 @@ int get_client_vote(struct votable *votable, const char *client_str) */ */ int get_effective_result_locked(struct votable *votable) int get_effective_result_locked(struct votable *votable) { { if (!votable) return -EINVAL; if (votable->force_active) if (votable->force_active) return votable->force_val; return votable->force_val; Loading @@ -289,6 +339,9 @@ int get_effective_result(struct votable *votable) { { int value; int value; if (!votable) return -EINVAL; lock_votable(votable); lock_votable(votable); value = get_effective_result_locked(votable); value = get_effective_result_locked(votable); unlock_votable(votable); unlock_votable(votable); Loading @@ -315,6 +368,9 @@ int get_effective_result(struct votable *votable) */ */ const char *get_effective_client_locked(struct votable *votable) const char *get_effective_client_locked(struct votable *votable) { { if (!votable) return NULL; if (votable->force_active) if (votable->force_active) return DEBUG_FORCE_CLIENT; return DEBUG_FORCE_CLIENT; Loading @@ -328,6 +384,9 @@ const char *get_effective_client(struct votable *votable) { { const char *client_str; const char *client_str; if (!votable) return NULL; lock_votable(votable); lock_votable(votable); client_str = get_effective_client_locked(votable); client_str = get_effective_client_locked(votable); unlock_votable(votable); unlock_votable(votable); Loading Loading @@ -365,6 +424,9 @@ int vote(struct votable *votable, const char *client_str, bool enabled, int val) int rc = 0; int rc = 0; bool similar_vote = false; bool similar_vote = false; if (!votable || !client_str) return -EINVAL; lock_votable(votable); lock_votable(votable); client_id = get_client_id(votable, client_str); client_id = get_client_id(votable, client_str); Loading Loading @@ -470,6 +532,9 @@ int vote_override(struct votable *votable, const char *override_client, { { int rc = 0; int rc = 0; if (!votable || !override_client) return -EINVAL; lock_votable(votable); lock_votable(votable); if (votable->force_active) { if (votable->force_active) { votable->override_result = enabled ? val : -EINVAL; votable->override_result = enabled ? val : -EINVAL; Loading Loading @@ -500,6 +565,9 @@ int rerun_election(struct votable *votable) int rc = 0; int rc = 0; int effective_result; int effective_result; if (!votable) return -EINVAL; lock_votable(votable); lock_votable(votable); effective_result = get_effective_result_locked(votable); effective_result = get_effective_result_locked(votable); if (votable->callback) if (votable->callback) Loading @@ -517,6 +585,9 @@ struct votable *find_votable(const char *name) struct votable *v; struct votable *v; bool found = false; bool found = false; if (!name) return NULL; spin_lock_irqsave(&votable_list_slock, flags); spin_lock_irqsave(&votable_list_slock, flags); if (list_empty(&votable_list)) if (list_empty(&votable_list)) goto out; goto out; Loading Loading @@ -649,6 +720,9 @@ struct votable *create_votable(const char *name, struct votable *votable; struct votable *votable; unsigned long flags; unsigned long flags; if (!name) return ERR_PTR(-EINVAL); votable = find_votable(name); votable = find_votable(name); if (votable) if (votable) return ERR_PTR(-EEXIST); return ERR_PTR(-EEXIST); Loading drivers/power/supply/qcom/qpnp-smb5.c +2 −0 Original line number Original line Diff line number Diff line Loading @@ -1267,6 +1267,8 @@ static int smb5_usb_main_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_FORCE_MAIN_FCC: case POWER_SUPPLY_PROP_FORCE_MAIN_FCC: vote_override(chg->fcc_main_votable, CC_MODE_VOTER, vote_override(chg->fcc_main_votable, CC_MODE_VOTER, (val->intval < 0) ? false : true, val->intval); (val->intval < 0) ? false : true, val->intval); /* Main FCC updated re-calculate FCC */ rerun_election(chg->fcc_votable); break; break; case POWER_SUPPLY_PROP_FORCE_MAIN_ICL: case POWER_SUPPLY_PROP_FORCE_MAIN_ICL: vote_override(chg->usb_icl_votable, CC_MODE_VOTER, vote_override(chg->usb_icl_votable, CC_MODE_VOTER, Loading drivers/power/supply/qcom/smb1390-charger-psy.c +41 −22 Original line number Original line Diff line number Diff line Loading @@ -211,6 +211,7 @@ struct smb1390 { u32 max_temp_alarm_degc; u32 max_temp_alarm_degc; u32 max_cutoff_soc; u32 max_cutoff_soc; u32 pl_output_mode; u32 pl_output_mode; u32 pl_input_mode; u32 cp_role; u32 cp_role; enum isns_mode current_capability; enum isns_mode current_capability; bool batt_soc_validated; bool batt_soc_validated; Loading Loading @@ -1001,6 +1002,36 @@ static int smb1390_notifier_cb(struct notifier_block *nb, #define ILIM_NR 10 #define ILIM_NR 10 #define ILIM_DR 8 #define ILIM_DR 8 #define ILIM_FACTOR(ilim) ((ilim * ILIM_NR) / ILIM_DR) #define ILIM_FACTOR(ilim) ((ilim * ILIM_NR) / ILIM_DR) static void smb1390_configure_ilim(struct smb1390 *chip, int mode) { int rc; union power_supply_propval pval = {0, }; /* PPS adapter reply on the current advertised by the adapter */ if ((chip->pl_output_mode == POWER_SUPPLY_PL_OUTPUT_VPH) && (mode == POWER_SUPPLY_CP_PPS)) { rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_PD_CURRENT_MAX, &pval); if (rc < 0) pr_err("Couldn't get PD CURRENT MAX rc=%d\n", rc); else vote(chip->ilim_votable, ICL_VOTER, true, ILIM_FACTOR(pval.intval)); } /* QC3.0/Wireless adapter rely on the settled AICL for USBMID_USBMID */ if ((chip->pl_input_mode == POWER_SUPPLY_PL_USBMID_USBMID) && (mode == POWER_SUPPLY_CP_HVDCP3)) { rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); if (rc < 0) pr_err("Couldn't get usb aicl rc=%d\n", rc); else vote(chip->ilim_votable, ICL_VOTER, true, pval.intval); } } static void smb1390_status_change_work(struct work_struct *work) static void smb1390_status_change_work(struct work_struct *work) { { struct smb1390 *chip = container_of(work, struct smb1390, struct smb1390 *chip = container_of(work, struct smb1390, Loading Loading @@ -1050,28 +1081,7 @@ static void smb1390_status_change_work(struct work_struct *work) pval.intval); pval.intval); } else { } else { vote(chip->ilim_votable, WIRELESS_VOTER, false, 0); vote(chip->ilim_votable, WIRELESS_VOTER, false, 0); if ((chip->pl_output_mode == POWER_SUPPLY_PL_OUTPUT_VPH) smb1390_configure_ilim(chip, pval.intval); && (pval.intval == POWER_SUPPLY_CP_PPS)) { rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_PD_CURRENT_MAX, &pval); if (rc < 0) pr_err("Couldn't get PD CURRENT MAX rc=%d\n", rc); else vote(chip->ilim_votable, ICL_VOTER, true, ILIM_FACTOR(pval.intval)); } else { rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); if (rc < 0) pr_err("Couldn't get usb aicl rc=%d\n", rc); else vote(chip->ilim_votable, ICL_VOTER, true, pval.intval); } } } /* /* Loading Loading @@ -1237,6 +1247,7 @@ static enum power_supply_property smb1390_charge_pump_props[] = { POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_PARALLEL_MODE, }; }; static int smb1390_get_prop(struct power_supply *psy, static int smb1390_get_prop(struct power_supply *psy, Loading Loading @@ -1336,6 +1347,9 @@ static int smb1390_get_prop(struct power_supply *psy, val->strval = (chip->pmic_rev_id->rev4 > 2) ? "SMB1390_V3" : val->strval = (chip->pmic_rev_id->rev4 > 2) ? "SMB1390_V3" : "SMB1390_V2"; "SMB1390_V2"; break; break; case POWER_SUPPLY_PROP_PARALLEL_MODE: val->intval = chip->pl_input_mode; break; default: default: smb1390_dbg(chip, PR_MISC, "charge pump power supply get prop %d not supported\n", smb1390_dbg(chip, PR_MISC, "charge pump power supply get prop %d not supported\n", prop); prop); Loading Loading @@ -1462,6 +1476,11 @@ static int smb1390_parse_dt(struct smb1390 *chip) of_property_read_u32(chip->dev->of_node, "qcom,parallel-output-mode", of_property_read_u32(chip->dev->of_node, "qcom,parallel-output-mode", &chip->pl_output_mode); &chip->pl_output_mode); /* Default parallel input configuration is USBMID connection */ chip->pl_input_mode = POWER_SUPPLY_PL_USBMID_USBMID; of_property_read_u32(chip->dev->of_node, "qcom,parallel-input-mode", &chip->pl_input_mode); chip->cp_slave_thr_taper_ua = chip->min_ilim_ua * 3; chip->cp_slave_thr_taper_ua = chip->min_ilim_ua * 3; of_property_read_u32(chip->dev->of_node, "qcom,cp-slave-thr-taper-ua", of_property_read_u32(chip->dev->of_node, "qcom,cp-slave-thr-taper-ua", &chip->cp_slave_thr_taper_ua); &chip->cp_slave_thr_taper_ua); Loading include/linux/pmic-voter.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,8 @@ enum votable_type { bool is_client_vote_enabled(struct votable *votable, const char *client_str); bool is_client_vote_enabled(struct votable *votable, const char *client_str); bool is_client_vote_enabled_locked(struct votable *votable, bool is_client_vote_enabled_locked(struct votable *votable, const char *client_str); const char *client_str); bool is_override_vote_enabled(struct votable *votable); bool is_override_vote_enabled_locked(struct votable *votable); int get_client_vote(struct votable *votable, const char *client_str); int get_client_vote(struct votable *votable, const char *client_str); int get_client_vote_locked(struct votable *votable, const char *client_str); int get_client_vote_locked(struct votable *votable, const char *client_str); int get_effective_result(struct votable *votable); int get_effective_result(struct votable *votable); Loading Loading
drivers/power/supply/qcom/battery.c +88 −14 Original line number Original line Diff line number Diff line Loading @@ -93,6 +93,8 @@ struct pl_data { int parallel_step_fcc_count; int parallel_step_fcc_count; int parallel_step_fcc_residual; int parallel_step_fcc_residual; int step_fcc; int step_fcc; int override_main_fcc_ua; int total_fcc_ua; u32 wa_flags; u32 wa_flags; struct class qcom_batt_class; struct class qcom_batt_class; struct wakeup_source *pl_ws; struct wakeup_source *pl_ws; Loading Loading @@ -135,6 +137,11 @@ enum { RESTRICT_CHG_CURRENT, RESTRICT_CHG_CURRENT, FCC_STEPPING_IN_PROGRESS, FCC_STEPPING_IN_PROGRESS, }; }; enum { PARALLEL_INPUT_MODE, PARALLEL_OUTPUT_MODE, }; /********* /********* * HELPER* * HELPER* *********/ *********/ Loading @@ -147,23 +154,61 @@ static bool is_cp_available(struct pl_data *chip) return !!chip->cp_master_psy; return !!chip->cp_master_psy; } } static bool cp_ilim_boost_enabled(struct pl_data *chip) static int cp_get_parallel_mode(struct pl_data *chip, int mode) { { union power_supply_propval pval = {-1, }; union power_supply_propval pval = {-EINVAL, }; int rc = -EINVAL; if (is_cp_available(chip)) if (!is_cp_available(chip)) power_supply_get_property(chip->cp_master_psy, return -EINVAL; switch (mode) { case PARALLEL_INPUT_MODE: rc = power_supply_get_property(chip->cp_master_psy, POWER_SUPPLY_PROP_PARALLEL_MODE, &pval); break; case PARALLEL_OUTPUT_MODE: rc = power_supply_get_property(chip->cp_master_psy, POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, &pval); POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, &pval); break; default: pr_err("Invalid mode request %d\n", mode); break; } if (rc < 0) pr_err("Failed to read CP topology for mode=%d rc=%d\n", mode, rc); return pval.intval == POWER_SUPPLY_PL_OUTPUT_VPH; return pval.intval; } } /* * Adapter CC Mode: ILIM over-ridden explicitly, below takes no effect. * * Adapter CV mode: Configuration of ILIM for different topology is as below: * MID-VPH: * SMB1390 ILIM: independent of FCC and based on the AICL result or * PD advertised current, handled directly in SMB1390 * driver. * MID-VBAT: * SMB1390 ILIM: based on minimum of FCC portion of SMB1390 or ICL. * USBIN-VBAT: * SMB1390 ILIM: based on FCC portion of SMB1390 and independent of ICL. */ static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim) static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim) { { if (!is_cp_available(chip)) return; if (cp_get_parallel_mode(chip, PARALLEL_OUTPUT_MODE) == POWER_SUPPLY_PL_OUTPUT_VPH) return; if (!chip->cp_ilim_votable) if (!chip->cp_ilim_votable) chip->cp_ilim_votable = find_votable("CP_ILIM"); chip->cp_ilim_votable = find_votable("CP_ILIM"); if (!cp_ilim_boost_enabled(chip) && chip->cp_ilim_votable) if (chip->cp_ilim_votable) vote(chip->cp_ilim_votable, voter, true, ilim); vote(chip->cp_ilim_votable, voter, true, ilim); } } Loading Loading @@ -562,6 +607,28 @@ static void get_main_fcc_config(struct pl_data *chip, int *total_fcc) static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua, static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua, int parallel_fcc_ua) int parallel_fcc_ua) { { int main_set_fcc_ua, total_fcc_ua; if (is_override_vote_enabled_locked(chip->fcc_main_votable)) { /* * FCC stepper params need re-calculation in override mode * only if there is change in Main or total FCC */ main_set_fcc_ua = get_effective_result_locked( chip->fcc_main_votable); total_fcc_ua = main_fcc_ua + parallel_fcc_ua; if ((main_set_fcc_ua != chip->override_main_fcc_ua) || (total_fcc_ua != chip->total_fcc_ua)) { chip->override_main_fcc_ua = main_set_fcc_ua; chip->total_fcc_ua = total_fcc_ua; parallel_fcc_ua += (main_fcc_ua - chip->override_main_fcc_ua); } else { goto skip_fcc_step_update; } } /* Read current FCC of main charger */ /* Read current FCC of main charger */ chip->main_fcc_ua = get_effective_result(chip->fcc_main_votable); chip->main_fcc_ua = get_effective_result(chip->fcc_main_votable); chip->main_step_fcc_dir = (main_fcc_ua > chip->main_fcc_ua) ? chip->main_step_fcc_dir = (main_fcc_ua > chip->main_fcc_ua) ? Loading @@ -578,6 +645,7 @@ static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua, chip->parallel_step_fcc_residual = abs((parallel_fcc_ua - chip->parallel_step_fcc_residual = abs((parallel_fcc_ua - chip->slave_fcc_ua)) % FCC_STEP_SIZE_UA; chip->slave_fcc_ua)) % FCC_STEP_SIZE_UA; skip_fcc_step_update: if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual || chip->main_step_fcc_count || chip->main_step_fcc_residual) || chip->main_step_fcc_count || chip->main_step_fcc_residual) chip->step_fcc = 1; chip->step_fcc = 1; Loading Loading @@ -725,12 +793,13 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, chip->cp_disable_votable = find_votable("CP_DISABLE"); chip->cp_disable_votable = find_votable("CP_DISABLE"); if (chip->cp_disable_votable) { if (chip->cp_disable_votable) { if (cp_ilim_boost_enabled(chip)) { if (cp_get_parallel_mode(chip, PARALLEL_OUTPUT_MODE) == POWER_SUPPLY_PL_OUTPUT_VPH) { power_supply_get_property(chip->cp_master_psy, power_supply_get_property(chip->cp_master_psy, POWER_SUPPLY_PROP_MIN_ICL, &pval); POWER_SUPPLY_PROP_MIN_ICL, &pval); /* /* * With ILIM boost feature ILIM configuration is * With VPH output configuration ILIM is configured * independent of battery FCC, disable CP if FCC/2 * independent of battery FCC, disable CP here if FCC/2 * falls below MIN_ICL supported by CP. * falls below MIN_ICL supported by CP. */ */ if ((total_fcc_ua / 2) < pval.intval) if ((total_fcc_ua / 2) < pval.intval) Loading Loading @@ -925,8 +994,7 @@ static void fcc_stepper_work(struct work_struct *work) stepper_exit: stepper_exit: chip->main_fcc_ua = main_fcc; chip->main_fcc_ua = main_fcc; chip->slave_fcc_ua = parallel_fcc; chip->slave_fcc_ua = parallel_fcc; cp_configure_ilim(chip, FCC_VOTER, chip->slave_fcc_ua / 2); cp_configure_ilim(chip, FCC_VOTER, chip->main_fcc_ua / 2); if (reschedule_ms) { if (reschedule_ms) { schedule_delayed_work(&chip->fcc_stepper_work, schedule_delayed_work(&chip->fcc_stepper_work, Loading Loading @@ -1079,6 +1147,9 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0); vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0); /* Configure ILIM based on AICL result only if input mode is USBMID */ if (cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE) == POWER_SUPPLY_PL_USBMID_USBMID) cp_configure_ilim(chip, ICL_CHANGE_VOTER, icl_ua); cp_configure_ilim(chip, ICL_CHANGE_VOTER, icl_ua); return 0; return 0; Loading Loading @@ -1111,7 +1182,7 @@ 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 = 0, total_fcc_ua = 0, slave_fcc_ua = 0; int master_fcc_ua = 0, total_fcc_ua = 0, slave_fcc_ua = 0; int rc = 0; int rc = 0, cp_ilim; bool disable = false; bool disable = false; if (!is_main_available(chip)) if (!is_main_available(chip)) Loading Loading @@ -1295,7 +1366,10 @@ static int pl_disable_vote_callback(struct votable *votable, /* main psy gets all share */ /* main psy gets all share */ vote(chip->fcc_main_votable, MAIN_FCC_VOTER, true, vote(chip->fcc_main_votable, MAIN_FCC_VOTER, true, total_fcc_ua); total_fcc_ua); cp_configure_ilim(chip, FCC_VOTER, total_fcc_ua / 2); cp_ilim = total_fcc_ua - get_effective_result_locked( chip->fcc_main_votable); if (cp_ilim > 0) cp_configure_ilim(chip, FCC_VOTER, cp_ilim / 2); /* reset parallel FCC */ /* reset parallel FCC */ chip->slave_fcc_ua = 0; chip->slave_fcc_ua = 0; Loading
drivers/power/supply/qcom/pmic-voter.c +77 −3 Original line number Original line Diff line number Diff line Loading @@ -173,7 +173,7 @@ static int get_client_id(struct votable *votable, const char *client_str) static char *get_client_str(struct votable *votable, int client_id) static char *get_client_str(struct votable *votable, int client_id) { { if (client_id == -EINVAL) if (!votable || (client_id == -EINVAL)) return NULL; return NULL; return votable->client_strs[client_id]; return votable->client_strs[client_id]; Loading @@ -189,6 +189,38 @@ void unlock_votable(struct votable *votable) mutex_unlock(&votable->vote_lock); mutex_unlock(&votable->vote_lock); } } /** * is_override_vote_enabled() - * is_override_vote_enabled_locked() - * The unlocked and locked variants of getting whether override vote is enabled. * @votable: the votable object * * Returns: * True if the client's vote is enabled; false otherwise. */ bool is_override_vote_enabled_locked(struct votable *votable) { if (!votable) return false; return votable->override_result != -EINVAL; } bool is_override_vote_enabled(struct votable *votable) { bool enable; if (!votable) return false; lock_votable(votable); enable = is_override_vote_enabled_locked(votable); unlock_votable(votable); return enable; } /** /** * is_client_vote_enabled() - * is_client_vote_enabled() - * is_client_vote_enabled_locked() - * is_client_vote_enabled_locked() - Loading @@ -203,8 +235,13 @@ void unlock_votable(struct votable *votable) bool is_client_vote_enabled_locked(struct votable *votable, bool is_client_vote_enabled_locked(struct votable *votable, const char *client_str) const char *client_str) { { int client_id = get_client_id(votable, client_str); int client_id; if (!votable || !client_str) return false; client_id = get_client_id(votable, client_str); if (client_id < 0) if (client_id < 0) return false; return false; Loading @@ -215,6 +252,9 @@ bool is_client_vote_enabled(struct votable *votable, const char *client_str) { { bool enabled; bool enabled; if (!votable || !client_str) return false; lock_votable(votable); lock_votable(votable); enabled = is_client_vote_enabled_locked(votable, client_str); enabled = is_client_vote_enabled_locked(votable, client_str); unlock_votable(votable); unlock_votable(votable); Loading @@ -235,8 +275,12 @@ bool is_client_vote_enabled(struct votable *votable, const char *client_str) */ */ int get_client_vote_locked(struct votable *votable, const char *client_str) int get_client_vote_locked(struct votable *votable, const char *client_str) { { int client_id = get_client_id(votable, client_str); int client_id; if (!votable || !client_str) return -EINVAL; client_id = get_client_id(votable, client_str); if (client_id < 0) if (client_id < 0) return -EINVAL; return -EINVAL; Loading @@ -251,6 +295,9 @@ int get_client_vote(struct votable *votable, const char *client_str) { { int value; int value; if (!votable || !client_str) return -EINVAL; lock_votable(votable); lock_votable(votable); value = get_client_vote_locked(votable, client_str); value = get_client_vote_locked(votable, client_str); unlock_votable(votable); unlock_votable(votable); Loading @@ -276,6 +323,9 @@ int get_client_vote(struct votable *votable, const char *client_str) */ */ int get_effective_result_locked(struct votable *votable) int get_effective_result_locked(struct votable *votable) { { if (!votable) return -EINVAL; if (votable->force_active) if (votable->force_active) return votable->force_val; return votable->force_val; Loading @@ -289,6 +339,9 @@ int get_effective_result(struct votable *votable) { { int value; int value; if (!votable) return -EINVAL; lock_votable(votable); lock_votable(votable); value = get_effective_result_locked(votable); value = get_effective_result_locked(votable); unlock_votable(votable); unlock_votable(votable); Loading @@ -315,6 +368,9 @@ int get_effective_result(struct votable *votable) */ */ const char *get_effective_client_locked(struct votable *votable) const char *get_effective_client_locked(struct votable *votable) { { if (!votable) return NULL; if (votable->force_active) if (votable->force_active) return DEBUG_FORCE_CLIENT; return DEBUG_FORCE_CLIENT; Loading @@ -328,6 +384,9 @@ const char *get_effective_client(struct votable *votable) { { const char *client_str; const char *client_str; if (!votable) return NULL; lock_votable(votable); lock_votable(votable); client_str = get_effective_client_locked(votable); client_str = get_effective_client_locked(votable); unlock_votable(votable); unlock_votable(votable); Loading Loading @@ -365,6 +424,9 @@ int vote(struct votable *votable, const char *client_str, bool enabled, int val) int rc = 0; int rc = 0; bool similar_vote = false; bool similar_vote = false; if (!votable || !client_str) return -EINVAL; lock_votable(votable); lock_votable(votable); client_id = get_client_id(votable, client_str); client_id = get_client_id(votable, client_str); Loading Loading @@ -470,6 +532,9 @@ int vote_override(struct votable *votable, const char *override_client, { { int rc = 0; int rc = 0; if (!votable || !override_client) return -EINVAL; lock_votable(votable); lock_votable(votable); if (votable->force_active) { if (votable->force_active) { votable->override_result = enabled ? val : -EINVAL; votable->override_result = enabled ? val : -EINVAL; Loading Loading @@ -500,6 +565,9 @@ int rerun_election(struct votable *votable) int rc = 0; int rc = 0; int effective_result; int effective_result; if (!votable) return -EINVAL; lock_votable(votable); lock_votable(votable); effective_result = get_effective_result_locked(votable); effective_result = get_effective_result_locked(votable); if (votable->callback) if (votable->callback) Loading @@ -517,6 +585,9 @@ struct votable *find_votable(const char *name) struct votable *v; struct votable *v; bool found = false; bool found = false; if (!name) return NULL; spin_lock_irqsave(&votable_list_slock, flags); spin_lock_irqsave(&votable_list_slock, flags); if (list_empty(&votable_list)) if (list_empty(&votable_list)) goto out; goto out; Loading Loading @@ -649,6 +720,9 @@ struct votable *create_votable(const char *name, struct votable *votable; struct votable *votable; unsigned long flags; unsigned long flags; if (!name) return ERR_PTR(-EINVAL); votable = find_votable(name); votable = find_votable(name); if (votable) if (votable) return ERR_PTR(-EEXIST); return ERR_PTR(-EEXIST); Loading
drivers/power/supply/qcom/qpnp-smb5.c +2 −0 Original line number Original line Diff line number Diff line Loading @@ -1267,6 +1267,8 @@ static int smb5_usb_main_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_FORCE_MAIN_FCC: case POWER_SUPPLY_PROP_FORCE_MAIN_FCC: vote_override(chg->fcc_main_votable, CC_MODE_VOTER, vote_override(chg->fcc_main_votable, CC_MODE_VOTER, (val->intval < 0) ? false : true, val->intval); (val->intval < 0) ? false : true, val->intval); /* Main FCC updated re-calculate FCC */ rerun_election(chg->fcc_votable); break; break; case POWER_SUPPLY_PROP_FORCE_MAIN_ICL: case POWER_SUPPLY_PROP_FORCE_MAIN_ICL: vote_override(chg->usb_icl_votable, CC_MODE_VOTER, vote_override(chg->usb_icl_votable, CC_MODE_VOTER, Loading
drivers/power/supply/qcom/smb1390-charger-psy.c +41 −22 Original line number Original line Diff line number Diff line Loading @@ -211,6 +211,7 @@ struct smb1390 { u32 max_temp_alarm_degc; u32 max_temp_alarm_degc; u32 max_cutoff_soc; u32 max_cutoff_soc; u32 pl_output_mode; u32 pl_output_mode; u32 pl_input_mode; u32 cp_role; u32 cp_role; enum isns_mode current_capability; enum isns_mode current_capability; bool batt_soc_validated; bool batt_soc_validated; Loading Loading @@ -1001,6 +1002,36 @@ static int smb1390_notifier_cb(struct notifier_block *nb, #define ILIM_NR 10 #define ILIM_NR 10 #define ILIM_DR 8 #define ILIM_DR 8 #define ILIM_FACTOR(ilim) ((ilim * ILIM_NR) / ILIM_DR) #define ILIM_FACTOR(ilim) ((ilim * ILIM_NR) / ILIM_DR) static void smb1390_configure_ilim(struct smb1390 *chip, int mode) { int rc; union power_supply_propval pval = {0, }; /* PPS adapter reply on the current advertised by the adapter */ if ((chip->pl_output_mode == POWER_SUPPLY_PL_OUTPUT_VPH) && (mode == POWER_SUPPLY_CP_PPS)) { rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_PD_CURRENT_MAX, &pval); if (rc < 0) pr_err("Couldn't get PD CURRENT MAX rc=%d\n", rc); else vote(chip->ilim_votable, ICL_VOTER, true, ILIM_FACTOR(pval.intval)); } /* QC3.0/Wireless adapter rely on the settled AICL for USBMID_USBMID */ if ((chip->pl_input_mode == POWER_SUPPLY_PL_USBMID_USBMID) && (mode == POWER_SUPPLY_CP_HVDCP3)) { rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); if (rc < 0) pr_err("Couldn't get usb aicl rc=%d\n", rc); else vote(chip->ilim_votable, ICL_VOTER, true, pval.intval); } } static void smb1390_status_change_work(struct work_struct *work) static void smb1390_status_change_work(struct work_struct *work) { { struct smb1390 *chip = container_of(work, struct smb1390, struct smb1390 *chip = container_of(work, struct smb1390, Loading Loading @@ -1050,28 +1081,7 @@ static void smb1390_status_change_work(struct work_struct *work) pval.intval); pval.intval); } else { } else { vote(chip->ilim_votable, WIRELESS_VOTER, false, 0); vote(chip->ilim_votable, WIRELESS_VOTER, false, 0); if ((chip->pl_output_mode == POWER_SUPPLY_PL_OUTPUT_VPH) smb1390_configure_ilim(chip, pval.intval); && (pval.intval == POWER_SUPPLY_CP_PPS)) { rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_PD_CURRENT_MAX, &pval); if (rc < 0) pr_err("Couldn't get PD CURRENT MAX rc=%d\n", rc); else vote(chip->ilim_votable, ICL_VOTER, true, ILIM_FACTOR(pval.intval)); } else { rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); if (rc < 0) pr_err("Couldn't get usb aicl rc=%d\n", rc); else vote(chip->ilim_votable, ICL_VOTER, true, pval.intval); } } } /* /* Loading Loading @@ -1237,6 +1247,7 @@ static enum power_supply_property smb1390_charge_pump_props[] = { POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_PARALLEL_MODE, }; }; static int smb1390_get_prop(struct power_supply *psy, static int smb1390_get_prop(struct power_supply *psy, Loading Loading @@ -1336,6 +1347,9 @@ static int smb1390_get_prop(struct power_supply *psy, val->strval = (chip->pmic_rev_id->rev4 > 2) ? "SMB1390_V3" : val->strval = (chip->pmic_rev_id->rev4 > 2) ? "SMB1390_V3" : "SMB1390_V2"; "SMB1390_V2"; break; break; case POWER_SUPPLY_PROP_PARALLEL_MODE: val->intval = chip->pl_input_mode; break; default: default: smb1390_dbg(chip, PR_MISC, "charge pump power supply get prop %d not supported\n", smb1390_dbg(chip, PR_MISC, "charge pump power supply get prop %d not supported\n", prop); prop); Loading Loading @@ -1462,6 +1476,11 @@ static int smb1390_parse_dt(struct smb1390 *chip) of_property_read_u32(chip->dev->of_node, "qcom,parallel-output-mode", of_property_read_u32(chip->dev->of_node, "qcom,parallel-output-mode", &chip->pl_output_mode); &chip->pl_output_mode); /* Default parallel input configuration is USBMID connection */ chip->pl_input_mode = POWER_SUPPLY_PL_USBMID_USBMID; of_property_read_u32(chip->dev->of_node, "qcom,parallel-input-mode", &chip->pl_input_mode); chip->cp_slave_thr_taper_ua = chip->min_ilim_ua * 3; chip->cp_slave_thr_taper_ua = chip->min_ilim_ua * 3; of_property_read_u32(chip->dev->of_node, "qcom,cp-slave-thr-taper-ua", of_property_read_u32(chip->dev->of_node, "qcom,cp-slave-thr-taper-ua", &chip->cp_slave_thr_taper_ua); &chip->cp_slave_thr_taper_ua); Loading
include/linux/pmic-voter.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,8 @@ enum votable_type { bool is_client_vote_enabled(struct votable *votable, const char *client_str); bool is_client_vote_enabled(struct votable *votable, const char *client_str); bool is_client_vote_enabled_locked(struct votable *votable, bool is_client_vote_enabled_locked(struct votable *votable, const char *client_str); const char *client_str); bool is_override_vote_enabled(struct votable *votable); bool is_override_vote_enabled_locked(struct votable *votable); int get_client_vote(struct votable *votable, const char *client_str); int get_client_vote(struct votable *votable, const char *client_str); int get_client_vote_locked(struct votable *votable, const char *client_str); int get_client_vote_locked(struct votable *votable, const char *client_str); int get_effective_result(struct votable *votable); int get_effective_result(struct votable *votable); Loading