Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: typec: tcpm/tcpci_maxim: fix non-contaminant CC handling

tcpci_maxim currently never triggers the TCPM state machine when CC
status has not changed due to a contaminant but due to a real
connection event, i.e. a genuine plug event, meaning the system will
stay idle and not notify any subscribers.

The reason is that the initial state of the port is 'toggling', which
causes _max_tcpci_irq() to only drive the contamination part of the
TCPM state machine (via tcpm_port_clean()).

What should happen instead is that if no contamination was detected,
the TCPM should be notified of the CC change in this case.

To fix this, we update ...is_contaminant() to also allow its caller to
determine if more CC processing is required and then call into the TCPM
as required.

While at it, add a kernel-doc for max_contaminant_is_contaminant().

Note: the code has an issue where I2C errors during contaminant
detection also cause the TCPM state machine to not be updated. This
commit doesn't change this behaviour and should be addressed by
follow-up commit(s).

Signed-off-by: André Draszik <andre.draszik@linaro.org>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20240806-max33359-toggling-v2-1-a66ab37baafb@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

André Draszik and committed by
Greg Kroah-Hartman
c6a6c7d0 38343be0

+27 -7
+5 -2
drivers/usb/typec/tcpm/maxim_contaminant.c
··· 324 324 return 0; 325 325 } 326 326 327 - bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce) 327 + bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce, 328 + bool *cc_handled) 328 329 { 329 330 u8 cc_status, pwr_cntl; 330 331 int ret; 332 + 333 + *cc_handled = true; 331 334 332 335 ret = max_tcpci_read8(chip, TCPC_CC_STATUS, &cc_status); 333 336 if (ret < 0) ··· 373 370 return true; 374 371 } 375 372 } 376 - return false; 377 373 } else if (chip->contaminant_state == DETECTED) { 378 374 if (!(cc_status & TCPC_CC_STATUS_TOGGLING)) { 379 375 chip->contaminant_state = max_contaminant_detect_contaminant(chip); ··· 383 381 } 384 382 } 385 383 384 + *cc_handled = false; 386 385 return false; 387 386 } 388 387
+15 -1
drivers/usb/typec/tcpm/tcpci_maxim.h
··· 81 81 return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8)); 82 82 } 83 83 84 - bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce); 84 + /** 85 + * max_contaminant_is_contaminant - Test if CC was toggled due to contaminant 86 + * 87 + * @chip: Handle to a struct max_tcpci_chip 88 + * @disconnect_while_debounce: Whether the disconnect was detected when CC 89 + * pins were debouncing 90 + * @cc_handled: Returns whether or not update to CC status was handled here 91 + * 92 + * Determine if a contaminant was detected. 93 + * 94 + * Returns: true if a contaminant was detected, false otherwise. cc_handled 95 + * is updated to reflect whether or not further CC handling is required. 96 + */ 97 + bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce, 98 + bool *cc_handled); 85 99 86 100 #endif // TCPCI_MAXIM_H_
+7 -4
drivers/usb/typec/tcpm/tcpci_maxim_core.c
··· 357 357 tcpm_vbus_change(chip->port); 358 358 359 359 if (status & TCPC_ALERT_CC_STATUS) { 360 + bool cc_handled = false; 361 + 360 362 if (chip->contaminant_state == DETECTED || tcpm_port_is_toggling(chip->port)) { 361 - if (!max_contaminant_is_contaminant(chip, false)) 363 + if (!max_contaminant_is_contaminant(chip, false, &cc_handled)) 362 364 tcpm_port_clean(chip->port); 363 - } else { 364 - tcpm_cc_change(chip->port); 365 365 } 366 + if (!cc_handled) 367 + tcpm_cc_change(chip->port); 366 368 } 367 369 368 370 if (status & TCPC_ALERT_POWER_STATUS) ··· 457 455 static void max_tcpci_check_contaminant(struct tcpci *tcpci, struct tcpci_data *tdata) 458 456 { 459 457 struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata); 458 + bool cc_handled; 460 459 461 - if (!max_contaminant_is_contaminant(chip, true)) 460 + if (!max_contaminant_is_contaminant(chip, true, &cc_handled)) 462 461 tcpm_port_clean(chip->port); 463 462 } 464 463