2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

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

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>
This commit is contained in:
Amit Sunil Dhamne 2025-08-15 11:31:52 -07:00 committed by Greg Kroah-Hartman
parent cabb6c5f4d
commit a381c6d6f6

View File

@ -329,6 +329,39 @@ 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,
FIELD_PREP(CCLPMODESEL,
LOW_POWER_MODE_DISABLE));
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 |
FIELD_PREP(TCPC_ROLE_CTRL_CC1,
TCPC_ROLE_CTRL_CC_RD) |
FIELD_PREP(TCPC_ROLE_CTRL_CC2,
TCPC_ROLE_CTRL_CC_RD));
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,
bool *cc_handled)
{
@ -345,6 +378,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);
@ -377,6 +416,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);
}
} else if (chip->contaminant_state == DETECTED) {
if (!(cc_status & TCPC_CC_STATUS_TOGGLING)) {
@ -384,6 +429,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;
}
}
}
}