From 86e11556766bf82649950bab320e8ecf349bda3a Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Wed, 24 May 2017 20:52:09 -0700 Subject: [PATCH] smb-lib: ignore disconnects during power role swap During a power_role swap, the CC lines get disconnected for a bit. This causes the charger driver to prematurely declare a disconnection and it resets back to disconnected state. Update the code to distinguish a disconnect caused during PR_SWAP vs a real disconnect. Avoid - resetting the CC line to HW control - switching DRP mode - enabling the crude sensor workaround - enabling APSD during a discconnet caused by PR_SWAP Note that PR_SWAP setting/unsetting needs to done regardless of the connected state of the CC line. When PR_SWAP is notified to be completed and the CC lines are still seen disconnected call the real disconnect code. While at it Vconn can be disabled too in the real disconnect code path. Change-Id: I97ab7ee343c5b2bcf25797e6acbb1de37f5ba00a Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/supply/qcom/qpnp-smb2.c | 7 ++++++ drivers/power/supply/qcom/smb-lib.c | 43 +++++++++++++++++++++++++++++++---- drivers/power/supply/qcom/smb-lib.h | 5 ++++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index d3abfbfbbc43..fa4232d4436c 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -432,6 +432,7 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_CTM_CURRENT_MAX, POWER_SUPPLY_PROP_HW_CURRENT_MAX, POWER_SUPPLY_PROP_REAL_TYPE, + POWER_SUPPLY_PROP_PR_SWAP, }; static int smb2_usb_get_prop(struct power_supply *psy, @@ -536,6 +537,9 @@ static int smb2_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_HW_CURRENT_MAX: rc = smblib_get_charge_current(chg, &val->intval); break; + case POWER_SUPPLY_PROP_PR_SWAP: + rc = smblib_get_prop_pr_swap_in_progress(chg, val); + break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; @@ -594,6 +598,9 @@ static int smb2_usb_set_prop(struct power_supply *psy, rc = vote(chg->usb_icl_votable, CTM_VOTER, val->intval >= 0, val->intval); break; + case POWER_SUPPLY_PROP_PR_SWAP: + rc = smblib_set_prop_pr_swap_in_progress(chg, val); + break; default: pr_err("set prop %d is not supported\n", psp); rc = -EINVAL; diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 4c66bc500ab4..dee387bc87e7 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -3669,6 +3669,17 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc); + mutex_lock(&chg->vconn_oc_lock); + if (!chg->vconn_en) + goto unlock; + + smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + VCONN_EN_VALUE_BIT, 0); + chg->vconn_en = false; + +unlock: + mutex_unlock(&chg->vconn_oc_lock); + typec_sink_removal(chg); smblib_update_usb_type(chg); } @@ -3699,15 +3710,15 @@ static void smblib_handle_typec_debounce_done(struct smb_charger *chg, union power_supply_propval pval = {0, }; if (rising) { - if (!chg->typec_present) { + if (!chg->typec_present && !chg->pr_swap_in_progress) { chg->typec_present = true; - smblib_dbg(chg, PR_MISC, "TypeC insertion\n"); + smblib_dbg(chg, PR_MISC, "TypeC insertion\n"); smblib_handle_typec_insertion(chg, sink_attached); } } else { - if (chg->typec_present) { + if (chg->typec_present && !chg->pr_swap_in_progress) { chg->typec_present = false; - smblib_dbg(chg, PR_MISC, "TypeC removal\n"); + smblib_dbg(chg, PR_MISC, "TypeC removal\n"); smblib_handle_typec_removal(chg); } } @@ -3841,6 +3852,30 @@ irqreturn_t smblib_handle_wdog_bark(int irq, void *data) return IRQ_HANDLED; } +/************** + * Additional USB PSY getters/setters + * that call interrupt functions +***************/ + +int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, + union power_supply_propval *val) +{ + val->intval = chg->pr_swap_in_progress; + return 0; +} + +int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, + const union power_supply_propval *val) +{ + chg->pr_swap_in_progress = val->intval; + /* + * call the cc changed irq to handle real removals while + * PR_SWAP was in progress + */ + smblib_usb_typec_change(chg); + return 0; +} + /*************** * Work Queues * ***************/ diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 41015d49b31e..70219e259e05 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -321,6 +321,7 @@ struct smb_charger { u8 typec_status[5]; bool typec_legacy_valid; int fake_input_current_limited; + bool pr_swap_in_progress; /* workaround flag */ u32 wa_flags; @@ -506,6 +507,10 @@ int smblib_rerun_aicl(struct smb_charger *chg); int smblib_set_icl_current(struct smb_charger *chg, int icl_ua); int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua); int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua); +int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, + const union power_supply_propval *val); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); -- 2.11.0