From e697192c09fbc46a90fa9594783a83c4fa10bf7f Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Thu, 18 May 2017 15:28:31 +0530 Subject: qpnp: smb2: fix ICL recovery mechanism ICL recovery mechanism is used by user space daemon to recover from adapter collapse during voltage increment event by reducing the USB ICL. There could be a situation where nobody votes on usb_icl_votable and this could lead to a negative ICL value. Fix this by reading "HW_CURRENT_MAX" property to get ICL in situations where usb_icl_votable is not voted by any client, this ensures ICL reduction will always vote a valid ICL. CRs-Fixed: 2048330 Change-Id: I8e53a945530c1685aaaba0537d16ac5fb11858df Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/smb-lib.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 5a2af79eb568..c9ebe394c53b 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -638,6 +638,7 @@ static void smblib_uusb_removal(struct smb_charger *chg) /* 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); + vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0); cancel_delayed_work_sync(&chg->hvdcp_detect_work); @@ -1985,6 +1986,7 @@ static int smblib_dm_pulse(struct smb_charger *chg) int smblib_dp_dm(struct smb_charger *chg, int val) { int target_icl_ua, rc = 0; + union power_supply_propval pval; switch (val) { case POWER_SUPPLY_DP_DM_DP_PULSE: @@ -2002,10 +2004,35 @@ int smblib_dp_dm(struct smb_charger *chg, int val) rc, chg->pulse_cnt); break; case POWER_SUPPLY_DP_DM_ICL_DOWN: - chg->usb_icl_delta_ua -= 100000; target_icl_ua = get_effective_result(chg->usb_icl_votable); + if (target_icl_ua < 0) { + /* no client vote, get the ICL from charger */ + rc = power_supply_get_property(chg->usb_psy, + POWER_SUPPLY_PROP_HW_CURRENT_MAX, + &pval); + if (rc < 0) { + smblib_err(chg, + "Couldn't get max current rc=%d\n", + rc); + return rc; + } + target_icl_ua = pval.intval; + } + + /* + * Check if any other voter voted on USB_ICL in case of + * voter other than SW_QC3_VOTER reset and restart reduction + * again. + */ + if (target_icl_ua != get_client_vote(chg->usb_icl_votable, + SW_QC3_VOTER)) + chg->usb_icl_delta_ua = 0; + + chg->usb_icl_delta_ua += 100000; vote(chg->usb_icl_votable, SW_QC3_VOTER, true, - target_icl_ua + chg->usb_icl_delta_ua); + target_icl_ua - 100000); + smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n", + target_icl_ua, chg->usb_icl_delta_ua); break; case POWER_SUPPLY_DP_DM_ICL_UP: default: @@ -3620,6 +3647,7 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); vote(chg->usb_icl_votable, DCP_VOTER, false, 0); vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); + vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0); /* reset hvdcp voters */ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0); -- cgit v1.2.3