]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
usb: typec: maxim_contaminant: re-enable cc toggle if cc is open and port is clean
authorAmit Sunil Dhamne <amitsd@google.com>
Sun, 24 Aug 2025 16:49:53 +0000 (12:49 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 28 Aug 2025 14:28:47 +0000 (16:28 +0200)
[ Upstream commit a381c6d6f646226924809d0ad01a9465786da463 ]

Presently in `max_contaminant_is_contaminant()` if there's no
contaminant detected previously, CC is open & stopped toggling and no
contaminant is currently present, TCPC.RC would be programmed to do DRP
toggling. However, it didn't actively look for a connection. This would
lead to Type-C not detect *any* new connections. Hence, in the above
situation, re-enable toggling & program TCPC to look for a new
connection.

Also, return early if TCPC was looking for connection as this indicates
TCPC has neither detected a potential connection nor a change in
contaminant state.

In addition, once dry detection is complete (port is dry), restart
toggling.

Fixes: 02b332a06397e ("usb: typec: maxim_contaminant: Implement check_contaminant callback")
Cc: stable <stable@kernel.org>
Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>
Link: https://lore.kernel.org/r/20250815-fix-upstream-contaminant-v2-2-6c8d6c3adafb@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/tcpm/maxim_contaminant.c

index 60f90272fed3155405ed4007aa7f7d2b6e800246..279dfc84d1788919d05ff33a84bdc509fe1ce999 100644 (file)
@@ -322,6 +322,34 @@ static int max_contaminant_enable_dry_detection(struct max_tcpci_chip *chip)
        return 0;
 }
 
+static int max_contaminant_enable_toggling(struct max_tcpci_chip *chip)
+{
+       struct regmap *regmap = chip->data.regmap;
+       int ret;
+
+       /* Disable dry detection if enabled. */
+       ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK,
+                                ULTRA_LOW_POWER_MODE);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCONNDRY, 0);
+       if (ret)
+               return ret;
+
+       ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP | 0xA);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL,
+                                TCPC_TCPC_CTRL_EN_LK4CONN_ALRT,
+                                TCPC_TCPC_CTRL_EN_LK4CONN_ALRT);
+       if (ret)
+               return ret;
+
+       return max_tcpci_write8(chip, TCPC_COMMAND, TCPC_CMD_LOOK4CONNECTION);
+}
+
 bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce)
 {
        u8 cc_status, pwr_cntl;
@@ -335,6 +363,12 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect
        if (ret < 0)
                return false;
 
+       if (cc_status & TCPC_CC_STATUS_TOGGLING) {
+               if (chip->contaminant_state == DETECTED)
+                       return true;
+               return false;
+       }
+
        if (chip->contaminant_state == NOT_DETECTED || chip->contaminant_state == SINK) {
                if (!disconnect_while_debounce)
                        msleep(100);
@@ -367,6 +401,12 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect
                                max_contaminant_enable_dry_detection(chip);
                                return true;
                        }
+
+                       ret = max_contaminant_enable_toggling(chip);
+                       if (ret)
+                               dev_err(chip->dev,
+                                       "Failed to enable toggling, ret=%d",
+                                       ret);
                }
                return false;
        } else if (chip->contaminant_state == DETECTED) {
@@ -375,6 +415,14 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect
                        if (chip->contaminant_state == DETECTED) {
                                max_contaminant_enable_dry_detection(chip);
                                return true;
+                       } else {
+                               ret = max_contaminant_enable_toggling(chip);
+                               if (ret) {
+                                       dev_err(chip->dev,
+                                               "Failed to enable toggling, ret=%d",
+                                               ret);
+                                       return true;
+                               }
                        }
                }
        }