Received: by 2002:a05:6358:d09b:b0:dc:cd0c:909e with SMTP id jc27csp4615993rwb; Sat, 10 Dec 2022 11:40:33 -0800 (PST) X-Google-Smtp-Source: AA0mqf5mJb5fLapE31VeeJ0yzr2U/cNW1U8aTjq0yIl8Sge+kNVlIr/W1K/BZWtjPjV5pmoXUmhb X-Received: by 2002:a05:6a20:3ca7:b0:a5:df86:eea0 with SMTP id b39-20020a056a203ca700b000a5df86eea0mr17282874pzj.34.1670701233081; Sat, 10 Dec 2022 11:40:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670701233; cv=none; d=google.com; s=arc-20160816; b=lCG1vQHebpqZ67cC2cPKGVmD5fs8Zms6v5GNhFYTxzg/C3yXIy39O0XJS78k3sICYq I3zLRASVWd38P7A0K3vo2EO2skFE2XX8VH7hel+ridk87+gwblqAXqoaZNQh6ruBXk7S J8HmXk7M5dh/tXQDBDcOmB085QI20xJIXX7zaMZ7RIu25n9O0DDlnZ049j3ZbvrQ6d0l 303hgrQwcEPl6jQnKHpWxZJx1G8cHdoqBvNVGeuV9YynWs4W3oOD23rOKtlFMnW/BYl1 0ck8TSy9N3/9hxyeqGN2BN6M4FRXZC/rWc2Uc9oY9a14Hc1ZpaV3/oRl06bOfEmaghxX F5rQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:mime-version:date :dkim-signature; bh=gwa7czJ45jEgM7mSuTeVicD/hswE/frihrPtNZb2UkA=; b=b8cu5S8v5z/6sREwpdv5mHo9DS/Wl8bN2hLHFjAkHnuKmJSObwdSWAU8DFRrf8VTY0 0KHbDaREHAzXy1VF8Yst8+Pz4JNE2dXlauYcgaghyrn/peukFxXqQV+CM0optBbyco77 uvNalmUwOQGCL6crKu7LhjRDeyq82Fnggf7bRFAkVQ0YrT9kEC6vv58MYPKeUy56dozt AVpMjvVqJdRz/YYIEdsUxy4y6D1WLwo/W1gW+RMG5SBn76Pa/R+3nWUUrMEtl7wwlz6u KYrV1xJheRMIPl2U0Cz+uoOViQEwhHyKh41iiwM8R/l7kgo8rfLDzPOf6Yv8PsaQzSCJ yJrA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=LydWnYwh; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 82-20020a630455000000b004701c938a86si4997344pge.517.2022.12.10.11.40.23; Sat, 10 Dec 2022 11:40:33 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=LydWnYwh; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229811AbiLJSvi (ORCPT + 74 others); Sat, 10 Dec 2022 13:51:38 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55056 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229722AbiLJSve (ORCPT ); Sat, 10 Dec 2022 13:51:34 -0500 Received: from mail-pg1-x549.google.com (mail-pg1-x549.google.com [IPv6:2607:f8b0:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8446213F08 for ; Sat, 10 Dec 2022 10:51:33 -0800 (PST) Received: by mail-pg1-x549.google.com with SMTP id x79-20020a633152000000b004785d1cf6bbso4923096pgx.6 for ; Sat, 10 Dec 2022 10:51:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:mime-version:date:from:to:cc:subject :date:message-id:reply-to; bh=gwa7czJ45jEgM7mSuTeVicD/hswE/frihrPtNZb2UkA=; b=LydWnYwhhpQOqXcTF8voNAUoEBX1aMJ0K5xsw5JsiiUZFty7PoUrsrm46+AHHZ6j9o wkEQmLV68DE0U0xkRJ9TAT8vS3x6VPSvicgyr6KH+tmFpNU5qZ1envfAUPjEQWZ1t8J5 y8iNDNDhhnk/Ii/fP2iumC1/1OW6pKKgSMiHem/D74ErmdWVp4yHMmj2ZYckjC3lOhtc qurG2sxYC4sSAwXIpfF1Gz7a2POcGfSar/9BWgh+AIA5FAIxPt6ZT9sNINN1UXNS1+BP ktx9vmVN9tsizWAPhV2LrDQ6LmT87ZTZv3Uz13mOlb7BYcaAbzjDGg1tvQIakoDZlEuW 1sfQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:mime-version:date:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=gwa7czJ45jEgM7mSuTeVicD/hswE/frihrPtNZb2UkA=; b=EGeB3EtPWNnSGKqDRRpE58QCVAG/eFyws7rRiThfmmFIAyvXq/nwsyvQt9q8g1Iabd kn0tbI0TYZMA6D8eanflrxg4qrb+ux90Nm0zN5/ngYzbT8mRgS4kPWUXgZJKDKIKJNwY DOkGpjkMj2E0k9d+8C+w3d7/k6winj3hJQouelpNzjaYCmRmp7so89YZEnU0wxh7L2EY 2o/bBnggU6cJYbgAYQ5fwuAmCdivLE/hbcwbs5o8kIIAoK3WsHI5OW9+qcMhLWg5J/Ff wtdwBbA/qqBzNrtKuHcLlqBPHpdsbejaDif+YFg2N4njBe7etWOCDVYXGKZbz+FjlQOG sBnA== X-Gm-Message-State: ANoB5pmPe+baxserrg+FqF5r79+L3V4Ym+pKhIjjTCx2GHWhDEbWaPKt tZ9g25VgMJFrOtc/G1Sts/+tOIB7zLw= X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:201:bcc6:f018:88f8:a199]) (user=badhri job=sendgmr) by 2002:a17:90b:ec6:b0:219:5b3b:2b9f with SMTP id gz6-20020a17090b0ec600b002195b3b2b9fmr70233pjb.2.1670698292858; Sat, 10 Dec 2022 10:51:32 -0800 (PST) Date: Sat, 10 Dec 2022 10:51:27 -0800 Mime-Version: 1.0 X-Mailer: git-send-email 2.39.0.rc1.256.g54fd8350bd-goog Message-ID: <20221210185129.1094531-1-badhri@google.com> Subject: [PATCH v10 1/3] usb: typec: tcpm: Add callbacks to mitigate wakeups due to contaminant From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kyle Tso , Badhri Jagan Sridharan Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On some of the TCPC implementations, when the Type-C port is exposed to contaminants, such as water, TCPC stops toggling while reporting OPEN either by the time TCPM reads CC pin status or during CC debounce window. This causes TCPM to be stuck in TOGGLING state. If TCPM is made to restart toggling, the behavior recurs causing redundant CPU wakeups till the USB-C port is free of contaminant. [206199.287817] CC1: 0 -> 0, CC2: 0 -> 0 [state TOGGLING, polarity 0, disconnected] [206199.640337] CC1: 0 -> 0, CC2: 0 -> 0 [state TOGGLING, polarity 0, disconnected] [206199.985789] CC1: 0 -> 0, CC2: 0 -> 0 [state TOGGLING, polarity 0, disconnected] (or) [ 7853.867577] Start toggling [ 7853.889921] CC1: 0 -> 0, CC2: 0 -> 0 [state TOGGLING, polarity 0, disconnected] [ 7855.698765] CC1: 0 -> 0, CC2: 0 -> 5 [state TOGGLING, polarity 0, connected] [ 7855.698790] state change TOGGLING -> SNK_ATTACH_WAIT [rev3 NONE_AMS] [ 7855.698826] pending state change SNK_ATTACH_WAIT -> SNK_DEBOUNCED @ 170 ms [rev3 NONE_AMS] [ 7855.703559] CC1: 0 -> 0, CC2: 5 -> 5 [state SNK_ATTACH_WAIT, polarity 0, connected] [ 7855.856555] CC1: 0 -> 0, CC2: 5 -> 0 [state SNK_ATTACH_WAIT, polarity 0, disconnected] [ 7855.856581] state change SNK_ATTACH_WAIT -> SNK_ATTACH_WAIT [rev3 NONE_AMS] [ 7855.856613] pending state change SNK_ATTACH_WAIT -> SNK_UNATTACHED @ 170 ms [rev3 NONE_AMS] [ 7856.027744] state change SNK_ATTACH_WAIT -> SNK_UNATTACHED [delayed 170 ms] [ 7856.181949] CC1: 0 -> 0, CC2: 0 -> 0 [state TOGGLING, polarity 0, disconnected] [ 7856.187896] CC1: 0 -> 0, CC2: 0 -> 0 [state TOGGLING, polarity 0, disconnected] [ 7857.645630] CC1: 0 -> 0, CC2: 0 -> 0 [state TOGGLING, polarity 0, disconnected] [ 7857.647291] CC1: 0 -> 0, CC2: 0 -> 5 [state TOGGLING, polarity 0, connected] [ 7857.647298] state change TOGGLING -> SNK_ATTACH_WAIT [rev3 NONE_AMS] [ 7857.647310] pending state change SNK_ATTACH_WAIT -> SNK_DEBOUNCED @ 170 ms [rev3 NONE_AMS] [ 7857.808106] CC1: 0 -> 0, CC2: 5 -> 0 [state SNK_ATTACH_WAIT, polarity 0, disconnected] [ 7857.808123] state change SNK_ATTACH_WAIT -> SNK_ATTACH_WAIT [rev3 NONE_AMS] [ 7857.808150] pending state change SNK_ATTACH_WAIT -> SNK_UNATTACHED @ 170 ms [rev3 NONE_AMS] [ 7857.978727] state change SNK_ATTACH_WAIT -> SNK_UNATTACHED [delayed 170 ms] To mitigate redundant TCPM wakeups, TCPCs which do have the needed hardware can implement the check_contaminant callback which is invoked by TCPM to evaluate for presence of contaminant. Lower level TCPC driver can restart toggling through TCPM_PORT_CLEAN event when the driver detects that USB-C port is free of contaminant. Signed-off-by: Badhri Jagan Sridharan --- Changes since v9: * Invoke tcpm_start_toggling before transitioning to TOGGLING from * CHECK_CONTAMINANT. Changes since v7: * None. Skipped versions by mistake. Changes since v6: * folded the debounce logic into tcpm state machine and removed tcpm * state export. * Added a helper to determine whether the port is in toggling state. * Excluded CHECK_CONTAMINANT from tcpm_log. Changes since v5: * Updated commit message. Removed change id. Changes since v4: * None Changes since v3: * None Changes since V2: * Offloaded tcpm from maintaining disconnect_while_debouncing logic * to lower level maxim tcpc driver based on feedback. --- drivers/usb/typec/tcpm/tcpm.c | 52 ++++++++++++++++++++++++++++++++++- include/linux/usb/tcpm.h | 8 ++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 904c7b4ce2f0..0019cacee97c 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -36,6 +36,7 @@ #define FOREACH_STATE(S) \ S(INVALID_STATE), \ S(TOGGLING), \ + S(CHECK_CONTAMINANT), \ S(SRC_UNATTACHED), \ S(SRC_ATTACH_WAIT), \ S(SRC_ATTACHED), \ @@ -249,6 +250,7 @@ enum frs_typec_current { #define TCPM_RESET_EVENT BIT(2) #define TCPM_FRS_EVENT BIT(3) #define TCPM_SOURCING_VBUS BIT(4) +#define TCPM_PORT_CLEAN BIT(5) #define LOG_BUFFER_ENTRIES 1024 #define LOG_BUFFER_ENTRY_SIZE 128 @@ -483,6 +485,13 @@ struct tcpm_port { * SNK_READY for non-pd link. */ bool slow_charger_loop; + + /* + * When true indicates that the lower level drivers indicate potential presence + * of contaminant in the connector pins based on the tcpm state machine + * transitions. + */ + bool potential_contaminant; #ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct mutex logbuffer_lock; /* log buffer access lock */ @@ -647,7 +656,7 @@ static void tcpm_log(struct tcpm_port *port, const char *fmt, ...) /* Do not log while disconnected and unattached */ if (tcpm_port_is_disconnected(port) && (port->state == SRC_UNATTACHED || port->state == SNK_UNATTACHED || - port->state == TOGGLING)) + port->state == TOGGLING || port->state == CHECK_CONTAMINANT)) return; va_start(args, fmt); @@ -3904,15 +3913,28 @@ static void run_state_machine(struct tcpm_port *port) unsigned int msecs; enum tcpm_state upcoming_state; + if (port->tcpc->check_contaminant && port->state != CHECK_CONTAMINANT) + port->potential_contaminant = ((port->enter_state == SRC_ATTACH_WAIT && + port->state == SRC_UNATTACHED) || + (port->enter_state == SNK_ATTACH_WAIT && + port->state == SNK_UNATTACHED)); + port->enter_state = port->state; switch (port->state) { case TOGGLING: break; + case CHECK_CONTAMINANT: + port->tcpc->check_contaminant(port->tcpc); + break; /* SRC states */ case SRC_UNATTACHED: if (!port->non_pd_role_swap) tcpm_swap_complete(port, -ENOTCONN); tcpm_src_detach(port); + if (port->potential_contaminant) { + tcpm_set_state(port, CHECK_CONTAMINANT, 0); + break; + } if (tcpm_start_toggling(port, tcpm_rp_cc(port))) { tcpm_set_state(port, TOGGLING, 0); break; @@ -4150,6 +4172,10 @@ static void run_state_machine(struct tcpm_port *port) tcpm_swap_complete(port, -ENOTCONN); tcpm_pps_complete(port, -ENOTCONN); tcpm_snk_detach(port); + if (port->potential_contaminant) { + tcpm_set_state(port, CHECK_CONTAMINANT, 0); + break; + } if (tcpm_start_toggling(port, TYPEC_CC_RD)) { tcpm_set_state(port, TOGGLING, 0); break; @@ -4926,6 +4952,9 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, else if (tcpm_port_is_sink(port)) tcpm_set_state(port, SNK_ATTACH_WAIT, 0); break; + case CHECK_CONTAMINANT: + /* Wait for Toggling to be resumed */ + break; case SRC_UNATTACHED: case ACC_UNATTACHED: if (tcpm_port_is_debug(port) || tcpm_port_is_audio(port) || @@ -5425,6 +5454,12 @@ static void tcpm_pd_event_handler(struct kthread_work *work) port->vbus_source = true; _tcpm_pd_vbus_on(port); } + if (events & TCPM_PORT_CLEAN) { + tcpm_log(port, "port clean"); + if (port->state == CHECK_CONTAMINANT && + tcpm_start_toggling(port, tcpm_rp_cc(port))) + tcpm_set_state(port, TOGGLING, 0); + } spin_lock(&port->pd_event_lock); } @@ -5477,6 +5512,21 @@ void tcpm_sourcing_vbus(struct tcpm_port *port) } EXPORT_SYMBOL_GPL(tcpm_sourcing_vbus); +void tcpm_port_clean(struct tcpm_port *port) +{ + spin_lock(&port->pd_event_lock); + port->pd_events |= TCPM_PORT_CLEAN; + spin_unlock(&port->pd_event_lock); + kthread_queue_work(port->wq, &port->event_work); +} +EXPORT_SYMBOL_GPL(tcpm_port_clean); + +bool tcpm_port_is_toggling(struct tcpm_port *port) +{ + return port->port_type == TYPEC_PORT_DRP && port->state == TOGGLING; +} +EXPORT_SYMBOL_GPL(tcpm_port_is_toggling); + static void tcpm_enable_frs_work(struct kthread_work *work) { struct tcpm_port *port = container_of(work, struct tcpm_port, enable_frs); diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h index bffc8d3e14ad..ab7ca872950b 100644 --- a/include/linux/usb/tcpm.h +++ b/include/linux/usb/tcpm.h @@ -114,6 +114,11 @@ enum tcpm_transmit_type { * Optional; The USB Communications Capable bit indicates if port * partner is capable of communication over the USB data lines * (e.g. D+/- or SS Tx/Rx). Called to notify the status of the bit. + * @check_contaminant: + * Optional; The callback is called when CC pins report open status + * at the end of the deboumce period or when the port is still + * toggling. Chip level drivers are expected to check for contaminant + * and call tcpm_clean_port when the port is clean. */ struct tcpc_dev { struct fwnode_handle *fwnode; @@ -148,6 +153,7 @@ struct tcpc_dev { bool pps_active, u32 requested_vbus_voltage); bool (*is_vbus_vsafe0v)(struct tcpc_dev *dev); void (*set_partner_usb_comm_capable)(struct tcpc_dev *dev, bool enable); + void (*check_contaminant)(struct tcpc_dev *dev); }; struct tcpm_port; @@ -165,5 +171,7 @@ void tcpm_pd_transmit_complete(struct tcpm_port *port, enum tcpm_transmit_status status); void tcpm_pd_hard_reset(struct tcpm_port *port); void tcpm_tcpc_reset(struct tcpm_port *port); +void tcpm_port_clean(struct tcpm_port *port); +bool tcpm_port_is_toggling(struct tcpm_port *port); #endif /* __LINUX_USB_TCPM_H */ base-commit: 1524ceb14dd5ebd6f724d993c5ec1a9a8d445d8e -- 2.39.0.rc1.256.g54fd8350bd-goog