Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp7869993pxb; Fri, 19 Feb 2021 01:09:00 -0800 (PST) X-Google-Smtp-Source: ABdhPJyAf9U7sskSsPSS6WwIcf9fBm2H85z44gOVQ3M7ug9jXUzb/tW3VTkSbIfLRdmrzri4deFv X-Received: by 2002:a05:6402:38d:: with SMTP id o13mr8064382edv.155.1613725740490; Fri, 19 Feb 2021 01:09:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1613725740; cv=none; d=google.com; s=arc-20160816; b=A9dh79HqthcZYqBX1XUDvi8CoVQxd01WWsUwFkucg5MYBhh8rzzVaHUph54uGBG4Rw 91oMxvtEL1fz2h4Z0yJdK5AnjgTi9u8iHPZBiYcDkDRN9LjJcszpw/s9FVQkX21/eBNI E55xwdScQblzP5r2XbQVaYjjhcrsVLnyfGFevoOb8/STutEM5sjyDTL07zvbY1cRYmPj dh8LUUN8bhbKqOm4vovcnZoGIb2owF+we3RzYd3Kwgm8PTqYvnUpkbMK0Pa6iVpJYr4+ kV5U4R4oFYI7PpIEMpQxXQV0cms0POUOauruBu3DDcPGNLDHuAOegNc0TpI7ThDslDdY G7eg== 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:mime-version:message-id:date :sender:dkim-signature; bh=CGR9fL8lkODALH6tI/Lf41dYAe2vopzjhEaC221RUXI=; b=FamCBKad6pIOvzj+EvPoayUQH1EZscyt6Q+JvHvxxVjdTkw4rbFbmamfmc/weCmKDI ozDv2cmfCl99SHqNE2WprWNPZI3y+hYNQ7zp4yAf9Ed2NrKP3UCfnE1608hmf0IRFogg KOHHIQAEaOw/jQCzF60/aQV8VJhsSerbJ5Ywv68Jfvo1REnBI7JfXI5GI2qlrhuXtuGz LziGdU+84qStA/iseHySHGm0c5KghM9AAgovD4ZSGYZCfmOUWJcGXnerrfxKI8Sr/FUf SDGzrlnvKQlwxp9fTQP1DLl/PrFBGw3PfzUZbyz7qCO7OPakUTLLMhu4UsBZq17n2YoY O86w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=kjOGxDOu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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 vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id m15si5337797eje.225.2021.02.19.01.08.36; Fri, 19 Feb 2021 01:09:00 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=kjOGxDOu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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 S229555AbhBSJHy (ORCPT + 99 others); Fri, 19 Feb 2021 04:07:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58388 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230029AbhBSJEy (ORCPT ); Fri, 19 Feb 2021 04:04:54 -0500 Received: from mail-qv1-xf4a.google.com (mail-qv1-xf4a.google.com [IPv6:2607:f8b0:4864:20::f4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2A4C9C061788 for ; Fri, 19 Feb 2021 01:04:14 -0800 (PST) Received: by mail-qv1-xf4a.google.com with SMTP id dk3so2831593qvb.1 for ; Fri, 19 Feb 2021 01:04:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:message-id:mime-version:subject:from:to:cc; bh=CGR9fL8lkODALH6tI/Lf41dYAe2vopzjhEaC221RUXI=; b=kjOGxDOu4NduoHkNZJ5LhJIo1OQZSg66MwJ6dXv4ytV/830xQDy3BxpsODu1gi82lt Es2tAr6/Y61r3MG6prqQ0CeCon+3j9sNa8VWol2ZZHJbyB+/o+v0dZdbZnk/tpl84WAN /Jb0SBvJzS5lIxRB/zcxb+5YKxmPGtUEo4fj5377N9PJCsx3oqC+rcuHshQLBd2Vq0Ff drXKtsV53PYZQkbZfKQ0X4cNfu9QZab5kW+BgOmoPjznv1hvdQ9uW0VXma60ccTwrnXX XP1cFxXULULLtbfrSXAezmhzqKx75LNxU6YA+XzWZZra4c2UOM6fTV6tyPaEBL1eURR8 dVuA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:message-id:mime-version:subject:from :to:cc; bh=CGR9fL8lkODALH6tI/Lf41dYAe2vopzjhEaC221RUXI=; b=oi6W9+TwxmPSXZct26v/jKlVnqCMK67KmWZtanBpC9JLiWyOa3fiTyGyNjhjbnr7AQ Iiknxb3QizvnEHUbRBddmN11UA9Po7iGvcbCokYGRpPbXw9DgdG/SFYEo661ZjQD9H9z jRUKfj/91hhrvNUe3s5h15Lj31Jvw/GP/KTzVWJqsFgPhkk9WCmRRwr/IPLB1WoEk43z pdWGTiHuBADQcGXdgXVld0HyvHFhtHXoU5wc1YJ/jp2E26hUkwn3gLQE1OM1TMINviM2 /W95U4NF90hT7ln4R9GaHWrEVLcXzMLIk3jq7EiNXZrB9+IjMAwlKn4x+PZd9P4VETGJ L43A== X-Gm-Message-State: AOAM531UqAOtNQqUzR0nBVb/r2/H2xkYuhEKPXxZHeCFSWcR46L50H7+ 6LZATUPMTSBUi27IUIwYKOXZqOZ7lwk= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:201:4940:ba9e:2dc2:a4ce]) (user=badhri job=sendgmr) by 2002:a0c:8e8f:: with SMTP id x15mr8372883qvb.21.1613725452961; Fri, 19 Feb 2021 01:04:12 -0800 (PST) Date: Fri, 19 Feb 2021 01:04:09 -0800 Message-Id: <20210219090409.325492-1-badhri@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.30.0.617.g56c4b15f3c-goog Subject: [PATCH v2] usb: typec: tcpm: Wait for vbus discharge to VSAFE0V before toggling From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Kyle Tso Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, Badhri Jagan Sridharan Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When vbus auto discharge is enabled, TCPM can sometimes be faster than the TCPC i.e. TCPM can go ahead and move the port to unattached state (involves disabling vbus auto discharge) before TCPC could effectively discharge vbus to VSAFE0V. This leaves vbus with residual charge and increases the decay time which prevents tsafe0v from being met. This change introduces a new state VBUS_DISCHARGE where the TCPM waits for a maximum of tSafe0V(max) for vbus to discharge to VSAFE0V before transitioning to unattached state and re-enable toggling. If vbus discharges to vsafe0v sooner, then, transition to unattached state happens right away. Also, while in SNK_READY, when auto discharge is enabled, drive disconnect based on vbus turning off instead of Rp disappearing on CC pins. Rp disappearing on CC pins is almost instanteous compared to vbus decay. Fixes: f321a02caebd ("usb: typec: tcpm: Implement enabling Auto Discharge disconnect support") Signed-off-by: Badhri Jagan Sridharan --- Changes since V1: - Add Fixes tag --- drivers/usb/typec/tcpm/tcpm.c | 60 +++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index be0b6469dd3d..0ed71725980f 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -62,6 +62,8 @@ S(SNK_TRANSITION_SINK_VBUS), \ S(SNK_READY), \ \ + S(VBUS_DISCHARGE), \ + \ S(ACC_UNATTACHED), \ S(DEBUG_ACC_ATTACHED), \ S(AUDIO_ACC_ATTACHED), \ @@ -438,6 +440,9 @@ struct tcpm_port { enum tcpm_ams next_ams; bool in_ams; + /* Auto vbus discharge state */ + bool auto_vbus_discharge_enabled; + #ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct mutex logbuffer_lock; /* log buffer access lock */ @@ -3413,6 +3418,8 @@ static int tcpm_src_attach(struct tcpm_port *port) if (port->tcpc->enable_auto_vbus_discharge) { ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true); tcpm_log_force(port, "enable vbus discharge ret:%d", ret); + if (!ret) + port->auto_vbus_discharge_enabled = true; } ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port)); @@ -3495,6 +3502,8 @@ static void tcpm_reset_port(struct tcpm_port *port) if (port->tcpc->enable_auto_vbus_discharge) { ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, false); tcpm_log_force(port, "Disable vbus discharge ret:%d", ret); + if (!ret) + port->auto_vbus_discharge_enabled = false; } port->in_ams = false; port->ams = NONE_AMS; @@ -3568,6 +3577,8 @@ static int tcpm_snk_attach(struct tcpm_port *port) tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, VSAFE5V); ret = port->tcpc->enable_auto_vbus_discharge(port->tcpc, true); tcpm_log_force(port, "enable vbus discharge ret:%d", ret); + if (!ret) + port->auto_vbus_discharge_enabled = true; } ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port)); @@ -3684,6 +3695,12 @@ static void run_state_machine(struct tcpm_port *port) switch (port->state) { case TOGGLING: break; + case VBUS_DISCHARGE: + if (port->port_type == TYPEC_PORT_SRC) + tcpm_set_state(port, SRC_UNATTACHED, PD_T_SAFE_0V); + else + tcpm_set_state(port, SNK_UNATTACHED, PD_T_SAFE_0V); + break; /* SRC states */ case SRC_UNATTACHED: if (!port->non_pd_role_swap) @@ -4669,7 +4686,9 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, case SRC_READY: if (tcpm_port_is_disconnected(port) || !tcpm_port_is_source(port)) { - if (port->port_type == TYPEC_PORT_SRC) + if (port->auto_vbus_discharge_enabled && !port->vbus_vsafe0v) + tcpm_set_state(port, VBUS_DISCHARGE, 0); + else if (port->port_type == TYPEC_PORT_SRC) tcpm_set_state(port, SRC_UNATTACHED, 0); else tcpm_set_state(port, SNK_UNATTACHED, 0); @@ -4703,7 +4722,18 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, tcpm_set_state(port, SNK_DEBOUNCED, 0); break; case SNK_READY: - if (tcpm_port_is_disconnected(port)) + /* + * When set_auto_vbus_discharge_threshold is enabled, CC pins go + * away before vbus decays to disconnect threshold. Allow + * disconnect to be driven by vbus disconnect when auto vbus + * discharge is enabled. + * + * EXIT condition is based primarily on vbus disconnect and CC is secondary. + * "A port that has entered into USB PD communications with the Source and + * has seen the CC voltage exceed vRd-USB may monitor the CC pin to detect + * cable disconnect in addition to monitoring VBUS. + */ + if (!port->auto_vbus_discharge_enabled && tcpm_port_is_disconnected(port)) tcpm_set_state(port, unattached_state(port), 0); else if (!port->pd_capable && (cc1 != old_cc1 || cc2 != old_cc2)) @@ -4803,9 +4833,16 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, */ break; + case VBUS_DISCHARGE: + /* Do nothing. Waiting for vsafe0v signal */ + break; default: - if (tcpm_port_is_disconnected(port)) - tcpm_set_state(port, unattached_state(port), 0); + if (tcpm_port_is_disconnected(port)) { + if (port->auto_vbus_discharge_enabled && !port->vbus_vsafe0v) + tcpm_set_state(port, VBUS_DISCHARGE, 0); + else + tcpm_set_state(port, unattached_state(port), 0); + } break; } } @@ -4988,9 +5025,12 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port) break; default: - if (port->pwr_role == TYPEC_SINK && - port->attached) - tcpm_set_state(port, SNK_UNATTACHED, 0); + if (port->pwr_role == TYPEC_SINK && port->attached) { + if (port->auto_vbus_discharge_enabled && !port->vbus_vsafe0v) + tcpm_set_state(port, VBUS_DISCHARGE, 0); + else + tcpm_set_state(port, SNK_UNATTACHED, 0); + } break; } } @@ -5012,6 +5052,12 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port) tcpm_set_state(port, tcpm_try_snk(port) ? SNK_TRY : SRC_ATTACHED, PD_T_CC_DEBOUNCE); break; + case VBUS_DISCHARGE: + if (port->port_type == TYPEC_PORT_SRC) + tcpm_set_state(port, SRC_UNATTACHED, 0); + else + tcpm_set_state(port, SNK_UNATTACHED, 0); + break; default: break; } -- 2.30.0.617.g56c4b15f3c-goog