OSDN Git Service

smb-lib: ignore disconnects during power role swap
authorAbhijeet Dharmapurikar <adharmap@codeaurora.org>
Thu, 25 May 2017 03:52:09 +0000 (20:52 -0700)
committerAbhijeet Dharmapurikar <adharmap@codeaurora.org>
Fri, 26 May 2017 21:29:13 +0000 (14:29 -0700)
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 <adharmap@codeaurora.org>
drivers/power/supply/qcom/qpnp-smb2.c
drivers/power/supply/qcom/smb-lib.c
drivers/power/supply/qcom/smb-lib.h

index d3abfbf..fa4232d 100644 (file)
@@ -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;
index 4c66bc5..dee387b 100644 (file)
@@ -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 *
  ***************/
index 41015d4..70219e2 100644 (file)
@@ -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);