From 437db3081b42f9e235a5cb9d42fa3a5626b3e551 Mon Sep 17 00:00:00 2001 From: Nicholas Troast Date: Tue, 14 Mar 2017 09:06:56 -0700 Subject: [PATCH] power: smb-lib: always assume legacy cable and limit ICL While in DRP the legacy cable detection may fail. When a legacy cable is detected the legacy input current limits are enforced by hardware. Always assume a legacy cable since the legacy cable detection will fail in some cases. Manually enforce the legacy input current limits to ensure USB stability and compliance. As a side effect, non-legacy 22k ohm and 10k ohm Rp adapters will be current limited to legacy standards. To realize this: - Set a limit of 100mA as soon as type-c is connected and remove that limit once PD is confirmed. - If PD is not confirmed: - SDP: Use 100mA vote until USB PHY updates it to 500/900mA - CDP: Use 1.5A vote - DCP: Use 1.5A vote - HVDCP: Use 3A vote Change-Id: I049a7ee2099acd9e58df1b9417847daec4854af5 Signed-off-by: Nicholas Troast --- drivers/power/supply/qcom/smb-lib.c | 50 +++++++++++++++++++++++++++++ drivers/power/supply/qcom/smb-lib.h | 1 + 2 files changed, 51 insertions(+) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 5b9b350893b2..7d2e00dc934b 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -2505,6 +2505,9 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, return rc; } + /* since PD was found the cable must be non-legacy */ + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); + /* clear USB ICL vote for DCP_VOTER */ rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0); if (rc < 0) @@ -3337,6 +3340,37 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg, rising ? "rising" : "falling"); } +static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) +{ + switch (pst) { + case POWER_SUPPLY_TYPE_USB: + /* + * USB_PSY will vote to increase the current to 500/900mA once + * enumeration is done. Ensure that USB_PSY has at least voted + * for 100mA before releasing the LEGACY_UNKNOWN vote + */ + if (!is_client_vote_enabled(chg->usb_icl_votable, + USB_PSY_VOTER)) + vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000); + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); + break; + case POWER_SUPPLY_TYPE_USB_CDP: + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000); + break; + case POWER_SUPPLY_TYPE_USB_DCP: + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000); + break; + case POWER_SUPPLY_TYPE_USB_HVDCP: + case POWER_SUPPLY_TYPE_USB_HVDCP_3: + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000); + break; + default: + smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst); + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000); + break; + } +} + #define HVDCP_DET_MS 2500 static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) { @@ -3346,6 +3380,10 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) return; apsd_result = smblib_update_usb_type(chg); + + if (!chg->pd_active) + smblib_force_legacy_icl(chg, apsd_result->pst); + switch (apsd_result->bit) { case SDP_CHARGER_BIT: case CDP_CHARGER_BIT: @@ -3426,6 +3464,9 @@ static void typec_source_removal(struct smb_charger *chg) { int rc; + /* reset legacy unknown vote */ + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 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); @@ -3479,6 +3520,15 @@ static void typec_source_removal(struct smb_charger *chg) static void typec_source_insertion(struct smb_charger *chg) { + /* + * at any time we want LEGACY_UNKNOWN, PD, or USB_PSY to be voting for + * ICL, so vote LEGACY_UNKNOWN here if none of the above three have + * casted their votes + */ + if (!is_client_vote_enabled(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER) + && !is_client_vote_enabled(chg->usb_icl_votable, PD_VOTER) + && !is_client_vote_enabled(chg->usb_icl_votable, USB_PSY_VOTER)) + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000); } static void typec_sink_insertion(struct smb_charger *chg) diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 2b2106b81a81..de236164e6b2 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -57,6 +57,7 @@ enum print_reason { #define CTM_VOTER "CTM_VOTER" #define SW_QC3_VOTER "SW_QC3_VOTER" #define AICL_RERUN_VOTER "AICL_RERUN_VOTER" +#define LEGACY_UNKNOWN_VOTER "LEGACY_UNKNOWN_VOTER" #define VCONN_MAX_ATTEMPTS 3 #define OTG_MAX_ATTEMPTS 3