usb: typec: maxim_contaminant: re-enable cc toggle if cc is open and port is clean

[ 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: 02b332a063 ("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>
This commit is contained in:
Amit Sunil Dhamne
2025-08-24 12:49:53 -04:00
committed by Greg Kroah-Hartman
parent e600de541c
commit f56e75b85b

View 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;
}
}
}
}