diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index 8fa4fe301676..1b63f51088ee 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -983,9 +983,11 @@ static int smb2_init_hw(struct smb2 *chip) /* votes must be cast before configuring software control */ vote(chg->pl_disable_votable, - USBIN_ICL_VOTER, true, 0); + PL_INDIRECT_VOTER, true, 0); vote(chg->pl_disable_votable, CHG_STATE_VOTER, true, 0); + vote(chg->pl_disable_votable, + PARALLEL_PSY_VOTER, true, 0); vote(chg->usb_suspend_votable, DEFAULT_VOTER, chip->dt.no_battery, 0); vote(chg->dc_suspend_votable, @@ -1100,6 +1102,7 @@ static int smb2_init_hw(struct smb2 *chip) static int smb2_setup_wa_flags(struct smb2 *chip) { + struct smb_charger *chg = &chip->chg; struct pmic_revid_data *pmic_rev_id; struct device_node *revid_dev_node; @@ -1122,6 +1125,8 @@ static int smb2_setup_wa_flags(struct smb2 *chip) switch (pmic_rev_id->pmic_subtype) { case PMICOBALT_SUBTYPE: + if (pmic_rev_id->rev4 == PMICOBALT_V1P1_REV4) /* PMI rev 1.1 */ + chg->wa_flags |= QC_CHARGER_DETECTION_WA_BIT; break; default: pr_err("PMIC subtype %d not supported\n", diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index a869fc592474..e9c189ae17e7 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -521,7 +521,7 @@ static int smblib_fcc_max_vote_callback(struct votable *votable, void *data, { struct smb_charger *chg = data; - return vote(chg->fcc_votable, FCC_MAX_RESULT, true, fcc_ua); + return vote(chg->fcc_votable, FCC_MAX_RESULT_VOTER, true, fcc_ua); } static int smblib_fcc_vote_callback(struct votable *votable, void *data, @@ -731,6 +731,17 @@ static int smblib_chg_disable_vote_callback(struct votable *votable, void *data, return 0; } + +static int smblib_pl_enable_indirect_vote_callback(struct votable *votable, + void *data, int chg_enable, const char *client) +{ + struct smb_charger *chg = data; + + vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, !chg_enable, 0); + + return 0; +} + /***************** * OTG REGULATOR * *****************/ @@ -1144,13 +1155,14 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg, chg->system_temp_level = val->intval; if (chg->system_temp_level == chg->thermal_levels) - return vote(chg->chg_disable_votable, THERMAL_DAEMON, true, 0); + return vote(chg->chg_disable_votable, + THERMAL_DAEMON_VOTER, true, 0); - vote(chg->chg_disable_votable, THERMAL_DAEMON, false, 0); + vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0); if (chg->system_temp_level == 0) - return vote(chg->fcc_votable, THERMAL_DAEMON, false, 0); + return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0); - vote(chg->fcc_votable, THERMAL_DAEMON, true, + vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true, chg->thermal_mitigation[chg->system_temp_level]); return 0; } @@ -1589,7 +1601,11 @@ int smblib_set_prop_usb_voltage_min(struct smb_charger *chg, return rc; } - chg->voltage_min_uv = val->intval; + if (chg->mode == PARALLEL_MASTER) + vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, + min_uv > MICRO_5V, 0); + + chg->voltage_min_uv = min_uv; return rc; } @@ -1607,7 +1623,7 @@ int smblib_set_prop_usb_voltage_max(struct smb_charger *chg, return rc; } - chg->voltage_max_uv = val->intval; + chg->voltage_max_uv = max_uv; return rc; } @@ -1875,49 +1891,23 @@ skip_dpdm_float: return IRQ_HANDLED; } -#define MICRO_5P5V 5500000 -#define USB_WEAK_INPUT_MA 1500000 -static bool is_icl_pl_ready(struct smb_charger *chg) -{ - union power_supply_propval pval = {0, }; - int icl_ma; - int rc; - - rc = smblib_get_prop_usb_voltage_now(chg, &pval); - if (rc < 0) { - dev_err(chg->dev, "Couldn't get prop usb voltage rc=%d\n", rc); - return false; - } - - if (pval.intval <= MICRO_5P5V) { - rc = smblib_get_charge_param(chg, - &chg->param.icl_stat, &icl_ma); - if (rc < 0) { - dev_err(chg->dev, "Couldn't get ICL status rc=%d\n", - rc); - return false; - } - - if (icl_ma < USB_WEAK_INPUT_MA) - return false; - } - - /* - * Always enable parallel charging when USB INPUT is higher than 5V - * regardless of the AICL results. Assume chargers above 5V are strong - */ - - return true; -} - +#define USB_WEAK_INPUT_MA 1400000 irqreturn_t smblib_handle_icl_change(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; + int icl_ma; + int rc; + + rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &icl_ma); + if (rc < 0) { + dev_err(chg->dev, "Couldn't get ICL status rc=%d\n", rc); + return IRQ_HANDLED; + } if (chg->mode == PARALLEL_MASTER) - vote(chg->pl_disable_votable, USBIN_ICL_VOTER, - !is_icl_pl_ready(chg), 0); + vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, + icl_ma >= USB_WEAK_INPUT_MA, 0); smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); @@ -1954,12 +1944,27 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, if (!rising) return; + if (chg->mode == PARALLEL_MASTER) + vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0); + /* the APSD done handler will set the USB supply type */ apsd_result = smblib_get_apsd_result(chg); smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n", apsd_result->name); } +static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, + bool rising, bool qc_charger) +{ + if (rising && !qc_charger) { + vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0); + power_supply_changed(chg->usb_psy); + } + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n", + rising ? "rising" : "falling"); +} + /* triggers when HVDCP is detected */ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg, bool rising) @@ -1991,8 +1996,9 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0); break; case DCP_CHARGER_BIT: - schedule_delayed_work(&chg->hvdcp_detect_work, - msecs_to_jiffies(HVDCP_DET_MS)); + if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT) + schedule_delayed_work(&chg->hvdcp_detect_work, + msecs_to_jiffies(HVDCP_DET_MS)); break; default: break; @@ -2026,6 +2032,10 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) smblib_handle_hvdcp_detect_done(chg, (bool)(stat & QC_CHARGER_BIT)); + smblib_handle_hvdcp_check_timeout(chg, + (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT), + (bool)(stat & QC_CHARGER_BIT)); + smblib_handle_hvdcp_3p0_auth_done(chg, (bool)(stat & QC_AUTH_DONE_STATUS_BIT)); @@ -2079,8 +2089,9 @@ static void smblib_handle_typec_debounce_done(struct smb_charger *chg, !rising || sink_attached, 0); if (!rising || sink_attached) { - /* icl votes to disable parallel charging */ - vote(chg->pl_disable_votable, USBIN_ICL_VOTER, true, 0); + /* reset both usbin current and voltage votes */ + vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0); + vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); /* reset taper_end voter here */ vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0); } @@ -2105,11 +2116,6 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) } smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat); - if (stat & TYPEC_VBUS_ERROR_STATUS_BIT) { - dev_err(chg->dev, "IRQ: vbus-error rising\n"); - return IRQ_HANDLED; - } - smblib_handle_typec_cc(chg, (bool)(stat & CC_ATTACHED_BIT)); smblib_handle_typec_debounce_done(chg, @@ -2118,6 +2124,10 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) power_supply_changed(chg->usb_psy); + if (stat & TYPEC_VBUS_ERROR_STATUS_BIT) + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n", + irq_data->name); + return IRQ_HANDLED; } @@ -2178,8 +2188,7 @@ static void smblib_pl_detect_work(struct work_struct *work) struct smb_charger *chg = container_of(work, struct smb_charger, pl_detect_work); - if (!get_effective_result_locked(chg->pl_disable_votable)) - rerun_election(chg->pl_disable_votable); + vote(chg->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); } #define MINIMUM_PARALLEL_FCC_UA 500000 @@ -2204,7 +2213,7 @@ static void smblib_pl_taper_work(struct work_struct *work) } if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) { - vote(chg->awake_votable, PL_VOTER, true, 0); + vote(chg->awake_votable, PL_TAPER_WORK_RUNNING_VOTER, true, 0); /* Reduce the taper percent by 25 percent */ chg->pl.taper_percent = chg->pl.taper_percent * TAPER_RESIDUAL_PERCENT / 100; @@ -2218,7 +2227,7 @@ static void smblib_pl_taper_work(struct work_struct *work) * Master back to Fast Charge, get out of this round of taper reduction */ done: - vote(chg->awake_votable, PL_VOTER, false, 0); + vote(chg->awake_votable, PL_TAPER_WORK_RUNNING_VOTER, false, 0); } static void clear_hdc_work(struct work_struct *work) @@ -2320,6 +2329,15 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } + chg->pl_enable_votable_indirect = create_votable("PL_ENABLE_INDIRECT", + VOTE_SET_ANY, + smblib_pl_enable_indirect_vote_callback, + chg); + if (IS_ERR(chg->pl_enable_votable_indirect)) { + rc = PTR_ERR(chg->pl_enable_votable_indirect); + return rc; + } + return rc; } @@ -2345,6 +2363,10 @@ static void smblib_destroy_votables(struct smb_charger *chg) destroy_votable(chg->awake_votable); if (chg->pl_disable_votable) destroy_votable(chg->pl_disable_votable); + if (chg->chg_disable_votable) + destroy_votable(chg->chg_disable_votable); + if (chg->pl_enable_votable_indirect) + destroy_votable(chg->pl_enable_votable_indirect); } static void smblib_iio_deinit(struct smb_charger *chg) @@ -2381,9 +2403,6 @@ int smblib_init(struct smb_charger *chg) return rc; } - chg->bms_psy = power_supply_get_by_name("bms"); - chg->pl.psy = power_supply_get_by_name("parallel"); - rc = smblib_register_notifier(chg); if (rc < 0) { dev_err(chg->dev, @@ -2391,6 +2410,12 @@ int smblib_init(struct smb_charger *chg) return rc; } + chg->bms_psy = power_supply_get_by_name("bms"); + chg->pl.psy = power_supply_get_by_name("parallel"); + if (chg->pl.psy) + vote(chg->pl_disable_votable, PARALLEL_PSY_VOTER, + false, 0); + break; case PARALLEL_SLAVE: break; diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index 1f2457e04ed6..c9732c25dfcd 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -24,16 +24,19 @@ enum print_reason { PR_MISC = BIT(2), }; -#define DEFAULT_VOTER "DEFAULT_VOTER" -#define USER_VOTER "USER_VOTER" -#define PD_VOTER "PD_VOTER" -#define PL_VOTER "PL_VOTER" -#define USBIN_ICL_VOTER "USBIN_ICL_VOTER" -#define CHG_STATE_VOTER "CHG_STATE_VOTER" -#define TYPEC_SRC_VOTER "TYPEC_SRC_VOTER" -#define TAPER_END_VOTER "TAPER_END_VOTER" -#define FCC_MAX_RESULT "FCC_MAX_RESULT" -#define THERMAL_DAEMON "THERMAL_DAEMON" +#define DEFAULT_VOTER "DEFAULT_VOTER" +#define USER_VOTER "USER_VOTER" +#define PD_VOTER "PD_VOTER" +#define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER" +#define PARALLEL_PSY_VOTER "PARALLEL_PSY_VOTER" +#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER" +#define USBIN_I_VOTER "USBIN_I_VOTER" +#define USBIN_V_VOTER "USBIN_V_VOTER" +#define CHG_STATE_VOTER "CHG_STATE_VOTER" +#define TYPEC_SRC_VOTER "TYPEC_SRC_VOTER" +#define TAPER_END_VOTER "TAPER_END_VOTER" +#define FCC_MAX_RESULT_VOTER "FCC_MAX_RESULT_VOTER" +#define THERMAL_DAEMON_VOTER "THERMAL_DAEMON_VOTER" enum smb_mode { PARALLEL_MASTER = 0, @@ -41,6 +44,10 @@ enum smb_mode { NUM_MODES, }; +enum { + QC_CHARGER_DETECTION_WA_BIT = BIT(0), +}; + struct smb_regulator { struct regulator_dev *rdev; struct regulator_desc rdesc; @@ -139,6 +146,7 @@ struct smb_charger { struct votable *awake_votable; struct votable *pl_disable_votable; struct votable *chg_disable_votable; + struct votable *pl_enable_votable_indirect; /* work */ struct work_struct bms_update_work; diff --git a/drivers/power/qcom-charger/smb-reg.h b/drivers/power/qcom-charger/smb-reg.h index 4a50d2fcbf97..c4ad72e254f9 100644 --- a/drivers/power/qcom-charger/smb-reg.h +++ b/drivers/power/qcom-charger/smb-reg.h @@ -427,7 +427,7 @@ enum { #define APSD_STATUS_REG (USBIN_BASE + 0x07) #define APSD_STATUS_7_BIT BIT(7) -#define APSD_STATUS_6_BIT BIT(6) +#define HVDCP_CHECK_TIMEOUT_BIT BIT(6) #define SLOW_PLUGIN_TIMEOUT_BIT BIT(5) #define ENUMERATION_DONE_BIT BIT(4) #define VADP_CHANGE_DONE_AFTER_AUTH_BIT BIT(3)