Commit a381c6d6 authored by Amit Sunil Dhamne's avatar Amit Sunil Dhamne Committed by Greg Kroah-Hartman
Browse files

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: 02b332a0 ("usb: typec: maxim_contaminant: Implement check_contaminant callback")
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarAmit Sunil Dhamne <amitsd@google.com>
Reviewed-by: default avatarBadhri Jagan Sridharan <badhri@google.com>
Link: https://lore.kernel.org/r/20250815-fix-upstream-contaminant-v2-2-6c8d6c3adafb@google.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent cabb6c5f
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -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;
				}
			}
		}
	}