From patchwork Mon Sep 21 19:55:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790805 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EC252139F for ; Mon, 21 Sep 2020 19:56:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D24BE22262 for ; Mon, 21 Sep 2020 19:56:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="FfGltcom" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728014AbgIUT4C (ORCPT ); Mon, 21 Sep 2020 15:56:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35476 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726322AbgIUT4B (ORCPT ); Mon, 21 Sep 2020 15:56:01 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 709F7C061755 for ; Mon, 21 Sep 2020 12:56:01 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id p187so14127653ybg.14 for ; Mon, 21 Sep 2020 12:56:01 -0700 (PDT) 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=UYdZsbRRn0ngJ7bp1PZbaVObPNEy0F/LDH2oLgnJ+1Y=; b=FfGltcomG8zE8J9z8QDGQdn1bE5ren29TUCOaytLkD/duuDzhuy+St8rIBXWrrfUkI jqnW3Litk/BDspNQE9AUIyxNApoOUtLYnhcYcpYrm2pGw8tuwuyy+/RX0QZYEuGGtxVm b+7HrlQl4Jb36vcefnKHPpNWkRn4RItmKyb2TKtNYyRF+SMR263h/+h5R0Rbi3zgsLH+ qhoiwzD26yZbHi4UROICtnG3FKoiNaUzo8lCpZeUFNAoGtG5Rv5/jqEHz1ZYgNDm5hGd paqjlBCf5blo1tu2bUaMMcB/qjInBRZ67AacUc642ZNE89uDi6IscpBbYDcd0ilZVWy9 81qw== 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=UYdZsbRRn0ngJ7bp1PZbaVObPNEy0F/LDH2oLgnJ+1Y=; b=bgfFg+HyYAnZpUA1nLG9WGRCaGstUDBsDegar4uThW2Y9d0JRpFGByZ4c+RMq+B9hI WpZ8Gh3t1jm06P40yrmpqVWs/msp+JEsL9p2DlXtimbUxyuO4+DxUoIqd9edzy1B9UFQ yzwy1qEw63PS9DVYY1euothSvBXhe1llUHSkyPY+qiipPY07RaN+Xb0yepV8sInWwiRB flqgbKODGZGsC2rMDX/08Wm0EFGhajzjyHK0wgEZr4APf2kHP1ycy8jNEzPW3eZG6QkM yl9CG64znH0+LKZdIJ/WSISs6SFRpGszLeh34K/I1zo8ep5uvN5KnjZ83ylb5tqBLY3T 5UqQ== X-Gm-Message-State: AOAM533xgfs8zIT/zJ5dyxzwQV4tSh9WibdDU14BC0hnUvkX+aTMSgei aonWdEqOR10dwlisdwv2QKkhl1rqzsg= X-Google-Smtp-Source: ABdhPJxwzYsjMlODwBB0tpJIPRdXie9IZw+XcAwSixFh2guUyZ+jFmUmn/Y4WKWTbZgx9L4MheMdZm2K5eY= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a25:244a:: with SMTP id k71mr2218204ybk.504.1600718160665; Mon, 21 Sep 2020 12:56:00 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:45 -0700 Message-Id: <20200921195555.1050731-1-badhri@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 01/11] usb: typec: tcpci: Add a getter method to retrieve tcpm_port reference From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Allow chip level drivers to retrieve reference to tcpm_port. Signed-off-by: Badhri Jagan Sridharan Reviewed-by: Heikki Krogerus --- Change since v1: - Changing patch version to v6 to fix version number confusion. Change since v6: - Rebase on usb-next - Added Reviewed-by from Heikki. Change since v7: - Rebase on usb-next --- drivers/usb/typec/tcpm/tcpci.c | 6 ++++++ drivers/usb/typec/tcpm/tcpci.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index 7d9491ba62fb..b960fe5a0f28 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -38,6 +38,12 @@ struct tcpci_chip { struct tcpci_data data; }; +struct tcpm_port *tcpci_get_tcpm_port(struct tcpci *tcpci) +{ + return tcpci->port; +} +EXPORT_SYMBOL_GPL(tcpci_get_tcpm_port); + static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) { return container_of(tcpc, struct tcpci, tcpc); diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h index cf9d8b63adcb..04c49a0b0368 100644 --- a/drivers/usb/typec/tcpm/tcpci.h +++ b/drivers/usb/typec/tcpm/tcpci.h @@ -150,4 +150,6 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data); void tcpci_unregister_port(struct tcpci *tcpci); irqreturn_t tcpci_irq(struct tcpci *tcpci); +struct tcpm_port; +struct tcpm_port *tcpci_get_tcpm_port(struct tcpci *tcpci); #endif /* __LINUX_USB_TCPCI_H */ From patchwork Mon Sep 21 19:55:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790807 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7C9A6139F for ; Mon, 21 Sep 2020 19:56:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 60320222BB for ; Mon, 21 Sep 2020 19:56:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="j9ZsGg26" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728178AbgIUT4H (ORCPT ); Mon, 21 Sep 2020 15:56:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35496 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728129AbgIUT4G (ORCPT ); Mon, 21 Sep 2020 15:56:06 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3CC77C0613D0 for ; Mon, 21 Sep 2020 12:56:06 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id i128so9408846pfg.22 for ; Mon, 21 Sep 2020 12:56:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=6uMD4HsE5wC0FHPqT1IgUwtVvbrJJCzXvw4X9r1gCoo=; b=j9ZsGg26S30B6N5/iM7fXF+53vXQJcO2YVcd5aRZLIE/7ujyE/MqHIqiHDx14BwL0G OqXTizS7YYsyQEVGelCrrq7B5YPZYjLqLVlF/J2AK1WNFQ0aHU4J/9qBbmx9IBE2/EsY 46asudGAzeQKnPKgolL1sGnI0Y3IZUgQoN9ROCk89EY7YcDTCdybBtukr+exlXSnLxvY eHHx4TSlrrj5MAC/XH1Sldp0HH6euEtXEhTNsZqfDLKT7vc1MakpGa5LuGxOki5QGhlU tLatCOeMIuRzp4RbSGzjhCkbMCI0QbxZ8IgIse/b4LMh6K6ZzvFPt8h5lm7FM8OW/e2i PmFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=6uMD4HsE5wC0FHPqT1IgUwtVvbrJJCzXvw4X9r1gCoo=; b=LXN6vzJURtiA0piqKALonkkQs+UBBT4mE0grtJAFZVrVUf8WvcOklRSt7vu/n3zGeT dNhWma6zDySHDxV4yhPWqNktmHqIHFegiiPzvtbt9WUwMCAlMe+2bOjJdnEDonJPSdVx G8YSbNrrqXcUYLO1/xU/z6zpmcffFlnIDH5FHHugzmlIgTki06lfVg688GqCtW7eaeIr 9uk5VpCJBdwRDNEf8+qIutbkPI0V7i9SkYqv3hu6qIH44igH48cNMy+k7MfNYIWqxKJ1 KHP4GReCJRvam+NkmcE1BWAyzafWgEIKoU3n8Wn/Zs1x2axwk7DiQvnhR5/ljfiYB8YW AyeQ== X-Gm-Message-State: AOAM533mVdU0Xgig0vyoWYEb2olTqlvrh83mM2Dfydh37JXnG4mPOYgD Yp6kCQ+09GOZQF8D04ctbPwcw9V9ftw= X-Google-Smtp-Source: ABdhPJzhpue5odqawoasR6P5GtcUTRKSdkAueok+xuPOfvxWa+rQs3GHOCYx/o0PTInoBfOLql/G3f8yqWw= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a17:90a:4d84:: with SMTP id m4mr797192pjh.59.1600718165655; Mon, 21 Sep 2020 12:56:05 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:46 -0700 In-Reply-To: <20200921195555.1050731-1-badhri@google.com> Message-Id: <20200921195555.1050731-2-badhri@google.com> Mime-Version: 1.0 References: <20200921195555.1050731-1-badhri@google.com> X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 02/11] usb: typec: tcpci: Add set_vbus tcpci callback From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org set_vbus callback allows TCPC which are TCPCI based, however, does not support turning on sink and source mode through Command.SinkVbus and Command.SourceVbusDefaultVoltage. Signed-off-by: Badhri Jagan Sridharan Reviewed-by: Heikki Krogerus --- Changes since v1: - Changing patch version to v6 to fix version number confusion. Changes since v6: - Rebase on usb-next Changes since v7: - Added Reviewed-by: Heikki - Rebase change --- drivers/usb/typec/tcpm/tcpci.c | 7 +++++++ drivers/usb/typec/tcpm/tcpci.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index b960fe5a0f28..d6a6fac82d48 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -328,6 +328,13 @@ static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink) struct tcpci *tcpci = tcpc_to_tcpci(tcpc); int ret; + if (tcpci->data->set_vbus) { + ret = tcpci->data->set_vbus(tcpci, tcpci->data, source, sink); + /* Bypass when ret > 0 */ + if (ret != 0) + return ret < 0 ? ret : 0; + } + /* Disable both source and sink first before enabling anything */ if (!source) { diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h index 04c49a0b0368..4d441bdf24d5 100644 --- a/drivers/usb/typec/tcpm/tcpci.h +++ b/drivers/usb/typec/tcpm/tcpci.h @@ -144,6 +144,7 @@ struct tcpci_data { bool enable); int (*start_drp_toggling)(struct tcpci *tcpci, struct tcpci_data *data, enum typec_cc_status cc); + int (*set_vbus)(struct tcpci *tcpci, struct tcpci_data *data, bool source, bool sink); }; struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data); From patchwork Mon Sep 21 19:55:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790809 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 41E59139F for ; Mon, 21 Sep 2020 19:56:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 267442223E for ; Mon, 21 Sep 2020 19:56:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Inj3SCX3" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728222AbgIUT4M (ORCPT ); Mon, 21 Sep 2020 15:56:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35504 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728215AbgIUT4I (ORCPT ); Mon, 21 Sep 2020 15:56:08 -0400 Received: from mail-pf1-x449.google.com (mail-pf1-x449.google.com [IPv6:2607:f8b0:4864:20::449]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 55CF1C061755 for ; Mon, 21 Sep 2020 12:56:08 -0700 (PDT) Received: by mail-pf1-x449.google.com with SMTP id c18so9481872pfi.21 for ; Mon, 21 Sep 2020 12:56:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=K2goBvIwkTK8ugnrDDc5GDIaAaKMslFcAhC/ByZKCvs=; b=Inj3SCX3f+N4qO6X8rAdSkgLwhM9zxM3R5bgUUiN+nOkugH69TZicIxvtGgPBAokl9 nOetwc72sVxeU7XuIZxfSE8Ym7Oh3/TMPSyKp2NMaBp4oslgzheazMEO5ppeCkc3cvvb 6KkAPZ3BReVK0pf+hsrqSW0aJcU2m8rGr1CjNza8t0nDPekJcFUSzOmc8aVI5osTTIvp eD+GLHm7RVZECu2heDxGvSs9Oqb7KnYpo7gpeuLK+GKNXZdnRJupUntLUqOgkwpFw/IQ EoT/b2rkVyLTnVbdLlT1qp+QX3rsOFHD92Gbizpm+QwZ17unpYObXX/i5A89NAJ3RDQR gnNQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=K2goBvIwkTK8ugnrDDc5GDIaAaKMslFcAhC/ByZKCvs=; b=ny+K2xnJPmSqHOPNvArXhw6NXyWerLjiYRpao0nICQMm7qpgKrE2A9NxjyxNX8egut y/uyZNnADrhFvF0HSbE2MxIkiw/uPuYhlMLb7GwwEeOPwh6k7VigVHwUWHEddV3UG1KS gSFU7NYFPL2gWJaWcudSI4SoPCDNbN4iAaLBp0rdoJG0rG6RU6irYAN7ccsX51K3QCSL 56+9UxZGlPjm1BnkL45uyNUZc+79MOSAf3kMg9m+SSw9/g/7YuC2lXUvSchET1xVsVRi 4+oZu+6IhQNKg601vl/kPOr3UxsoMw/ksa3A7NPLXBD7PM+MdCXgKGVSEWoegEEIIzo3 5NzA== X-Gm-Message-State: AOAM531KnSh3fC8cZVWsbG9GFKB07/ohQs0I/hbRaLTdH2sPoK/lV4S7 Xd5Uc0kAkhqhPP7c3JCqrss3I6mmCWg= X-Google-Smtp-Source: ABdhPJxa8PoNUt3+xMn2wZBNLQIDKi+Tqcg64dY2s7Be7qqEpouHsl1hTwYDis5Za1ajA91rxB7tnCE5vRQ= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a17:902:a712:b029:d1:cbf4:c583 with SMTP id w18-20020a170902a712b02900d1cbf4c583mr1515621plq.16.1600718167808; Mon, 21 Sep 2020 12:56:07 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:47 -0700 In-Reply-To: <20200921195555.1050731-1-badhri@google.com> Message-Id: <20200921195555.1050731-3-badhri@google.com> Mime-Version: 1.0 References: <20200921195555.1050731-1-badhri@google.com> X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 03/11] dt-bindings: usb: Maxim type-c controller device tree binding document From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Add device tree binding document for Maxim TCPCI based Type-C chip driver Signed-off-by: Badhri Jagan Sridharan --- Changes since v1: - Changing patch version to v6 to fix version number confusion. Changes since v6: - Migrated to yaml format. Changes since v7: - Rebase on usb-next .../devicetree/bindings/usb/maxim,tcpci.yaml | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/maxim,tcpci.yaml diff --git a/Documentation/devicetree/bindings/usb/maxim,tcpci.yaml b/Documentation/devicetree/bindings/usb/maxim,tcpci.yaml new file mode 100644 index 000000000000..8e646b4483eb --- /dev/null +++ b/Documentation/devicetree/bindings/usb/maxim,tcpci.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/usb/maxim,tcpci.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Maxim TCPCI Type-C PD controller DT bindings + +maintainers: + - Badhri Jagan Sridharan + +description: Maxim TCPCI Type-C PD controller + +properties: + compatible: + enum: + - maxim,tcpci + reg: + const: 0x25 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +examples: + - | + #include + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + maxtcpc@25 { + compatible = "maxim,tcpc"; + reg = <0x25>; + interrupt-parent = <&gpa8>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + self-powered; + op-sink-microwatt = <2600000>; + source-pdos = ; + sink-pdos = ; + }; + }; +... From patchwork Mon Sep 21 19:55:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790811 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E85C6139F for ; Mon, 21 Sep 2020 19:56:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BEF08235FC for ; Mon, 21 Sep 2020 19:56:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="rYxC2qaw" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728256AbgIUT4M (ORCPT ); Mon, 21 Sep 2020 15:56:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35528 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728237AbgIUT4M (ORCPT ); Mon, 21 Sep 2020 15:56:12 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AB605C0613D3 for ; Mon, 21 Sep 2020 12:56:10 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id m13so9487769pfk.19 for ; Mon, 21 Sep 2020 12:56:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=o9IUJ0tlDCPC1PWVPa0qbXWcx/7eSWy1+1kv9Noy9DY=; b=rYxC2qawWeMAB/xJ7yNSDHpf4qYFCz1J1lpiCpvJcqTxS4iaBhMZFX3HyitHNbHSIj U0zXVi7x/D2SjEjDMBkR+t6dzLiHhRezlVpUGXQ1jwHwlAgWW5BTEh+QSui/hGWX5GVT fXaNesy8vWvT5UZxvE6BarO/DqiPPTp+uTII8+qVl7xkkBf0yhCHaBPKz76v1338p7op AhExv9uvVDkGTvzgXIrnC03hdPS949wCozrGr7xvs9x5W9TX4ahkHRAVDJrwuKw18V5b BR+UM9+zrQ2NpymZw+mD8dV8o+iH88yjl2ZCQULTnEdHqdMDJntAMu5m6BuzrhEQizP2 F0aw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=o9IUJ0tlDCPC1PWVPa0qbXWcx/7eSWy1+1kv9Noy9DY=; b=KYjQQI5EL/WsGLkTyvoL96OsnvmqbaXARSneO9VNSbDnCXmoduGmH3Gcltaq8C3Xlc YmALLKPFt8nKROCRNjxW9f+MT3CEcuwcFClNpMNsYYV/hGt3eluXxpAnqhEazsRG+aUl LabCcD5G4b66WsnrR3HIAkaV4VpsDrklNaNRX3pEAaHQ/rIanL/dXevc1FT1quM0Vlu0 csR2g9OP2ZH+v0K7MUtkinKIhYw05+3saSInAjRWW0ixDGMPryk9vSK4djd2TQZuEcPI 1xBAvYDG0gpko2Qftj0jcj5ppXqufCrOqpJcS1SULg9acAoGZwVGC94rEjuZIVk9oGhe vRAw== X-Gm-Message-State: AOAM530n4wSlnZUMiHhrg57m61ja8E24vOesxMosr9t4Tbo++8447/RU h5ncn6FX7HaPwad/39o7nVg/+zSEeYc= X-Google-Smtp-Source: ABdhPJybiu9U8HXM8rJLIvx4kfj2E/eabasoVMmGutW/rBO5wJmPqflGmUXE6BGukg2ApUtXMMyQnZo9k0g= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a62:d44e:0:b029:13c:1611:652f with SMTP id u14-20020a62d44e0000b029013c1611652fmr1203218pfl.15.1600718170045; Mon, 21 Sep 2020 12:56:10 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:48 -0700 In-Reply-To: <20200921195555.1050731-1-badhri@google.com> Message-Id: <20200921195555.1050731-4-badhri@google.com> Mime-Version: 1.0 References: <20200921195555.1050731-1-badhri@google.com> X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 04/11] usb: typec: tcpci_maxim: Chip level TCPC driver From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Chip level TCPC driver for Maxim's TCPCI implementation. This TCPC implementation does not support the following commands: COMMAND.SinkVbus, COMMAND.SourceVbusDefaultVoltage, COMMAND.SourceVbusHighVoltage. Instead the sinking and sourcing from vbus is supported by writes to custom registers. Signed-off-by: Badhri Jagan Sridharan Reviewed-by: Heikki Krogerus --- Changes since v1: - Changing patch version to v6 to fix version number confusion. - Removed setting USB_PSY and terminating description with period as suggested by Randy. Changes since v6: - Addressed Heikki comments: - Removed TX discarded message - Removed the redundant TCPC_POWER_STATUS_UNINIT check - Cleaned up irq setup routine Changes since v7: - Added reviewed-by: Heikki --- drivers/usb/typec/tcpm/Kconfig | 5 + drivers/usb/typec/tcpm/Makefile | 15 +- drivers/usb/typec/tcpm/tcpci.h | 1 + drivers/usb/typec/tcpm/tcpci_maxim.c | 461 +++++++++++++++++++++++++++ 4 files changed, 475 insertions(+), 7 deletions(-) create mode 100644 drivers/usb/typec/tcpm/tcpci_maxim.c diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig index 58a64e1bf627..938ab5615687 100644 --- a/drivers/usb/typec/tcpm/Kconfig +++ b/drivers/usb/typec/tcpm/Kconfig @@ -35,6 +35,11 @@ config TYPEC_MT6360 USB Type-C. It works with Type-C Port Controller Manager to provide USB PD and USB Type-C functionalities. +config TYPEC_TCPCI_MAXIM + tristate "Maxim TCPCI based Type-C chip driver" + help + MAXIM TCPCI based Type-C chip driver. + endif # TYPEC_TCPCI config TYPEC_FUSB302 diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile index 7592ccb8c526..7d499f3569fd 100644 --- a/drivers/usb/typec/tcpm/Makefile +++ b/drivers/usb/typec/tcpm/Makefile @@ -1,8 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_TYPEC_TCPM) += tcpm.o -obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o -obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o -typec_wcove-y := wcove.o -obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o -obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o -obj-$(CONFIG_TYPEC_MT6360) += tcpci_mt6360.o +obj-$(CONFIG_TYPEC_TCPM) += tcpm.o +obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o +obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o +typec_wcove-y := wcove.o +obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o +obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o +obj-$(CONFIG_TYPEC_MT6360) += tcpci_mt6360.o +obj-$(CONFIG_TYPEC_TCPCI_MAXIM) += tcpci_maxim.o diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h index 4d441bdf24d5..82f021a82456 100644 --- a/drivers/usb/typec/tcpm/tcpci.h +++ b/drivers/usb/typec/tcpm/tcpci.h @@ -109,6 +109,7 @@ #define TCPC_RX_BYTE_CNT 0x30 #define TCPC_RX_BUF_FRAME_TYPE 0x31 +#define TCPC_RX_BUF_FRAME_TYPE_SOP 0 #define TCPC_RX_HDR 0x32 #define TCPC_RX_DATA 0x34 /* through 0x4f */ diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.c b/drivers/usb/typec/tcpm/tcpci_maxim.c new file mode 100644 index 000000000000..91337ddb4962 --- /dev/null +++ b/drivers/usb/typec/tcpm/tcpci_maxim.c @@ -0,0 +1,461 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020, Google LLC + * + * MAXIM TCPCI based TCPC driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tcpci.h" + +#define PD_ACTIVITY_TIMEOUT_MS 10000 + +#define TCPC_VENDOR_ALERT 0x80 + +#define TCPC_RECEIVE_BUFFER_COUNT_OFFSET 0 +#define TCPC_RECEIVE_BUFFER_FRAME_TYPE_OFFSET 1 +#define TCPC_RECEIVE_BUFFER_RX_BYTE_BUF_OFFSET 2 + +/* + * LongMessage not supported, hence 32 bytes for buf to be read from RECEIVE_BUFFER. + * DEVICE_CAPABILITIES_2.LongMessage = 0, the value in READABLE_BYTE_COUNT reg shall be + * less than or equal to 31. Since, RECEIVE_BUFFER len = 31 + 1(READABLE_BYTE_COUNT). + */ +#define TCPC_RECEIVE_BUFFER_LEN 32 + +#define MAX_BUCK_BOOST_SID 0x69 +#define MAX_BUCK_BOOST_OP 0xb9 +#define MAX_BUCK_BOOST_OFF 0 +#define MAX_BUCK_BOOST_SOURCE 0xa +#define MAX_BUCK_BOOST_SINK 0x5 + +struct max_tcpci_chip { + struct tcpci_data data; + struct tcpci *tcpci; + struct device *dev; + struct i2c_client *client; + struct tcpm_port *port; +}; + +static const struct regmap_range max_tcpci_tcpci_range[] = { + regmap_reg_range(0x00, 0x95) +}; + +const struct regmap_access_table max_tcpci_tcpci_write_table = { + .yes_ranges = max_tcpci_tcpci_range, + .n_yes_ranges = ARRAY_SIZE(max_tcpci_tcpci_range), +}; + +static const struct regmap_config max_tcpci_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x95, + .wr_table = &max_tcpci_tcpci_write_table, +}; + +static struct max_tcpci_chip *tdata_to_max_tcpci(struct tcpci_data *tdata) +{ + return container_of(tdata, struct max_tcpci_chip, data); +} + +static int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val) +{ + return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u16)); +} + +static int max_tcpci_write16(struct max_tcpci_chip *chip, unsigned int reg, u16 val) +{ + return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u16)); +} + +static int max_tcpci_read8(struct max_tcpci_chip *chip, unsigned int reg, u8 *val) +{ + return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u8)); +} + +static int max_tcpci_write8(struct max_tcpci_chip *chip, unsigned int reg, u8 val) +{ + return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8)); +} + +static void max_tcpci_init_regs(struct max_tcpci_chip *chip) +{ + u16 alert_mask = 0; + int ret; + + ret = max_tcpci_write16(chip, TCPC_ALERT, 0xffff); + if (ret < 0) { + dev_err(chip->dev, "Error writing to TCPC_ALERT ret:%d\n", ret); + return; + } + + ret = max_tcpci_write16(chip, TCPC_VENDOR_ALERT, 0xffff); + if (ret < 0) { + dev_err(chip->dev, "Error writing to TCPC_VENDOR_ALERT ret:%d\n", ret); + return; + } + + alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED | + TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS | + TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS; + + ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask); + if (ret < 0) { + dev_err(chip->dev, "Error writing to TCPC_ALERT_MASK ret:%d\n", ret); + return; + } + + /* Enable vbus voltage monitoring and voltage alerts */ + ret = max_tcpci_write8(chip, TCPC_POWER_CTRL, 0); + if (ret < 0) { + dev_err(chip->dev, "Error writing to TCPC_POWER_CTRL ret:%d\n", ret); + return; + } +} + +static void process_rx(struct max_tcpci_chip *chip, u16 status) +{ + struct pd_message msg; + u8 count, frame_type, rx_buf[TCPC_RECEIVE_BUFFER_LEN]; + int ret, payload_index; + u8 *rx_buf_ptr; + + /* + * READABLE_BYTE_COUNT: Indicates the number of bytes in the RX_BUF_BYTE_x registers + * plus one (for the RX_BUF_FRAME_TYPE) Table 4-36. + * Read the count and frame type. + */ + ret = regmap_raw_read(chip->data.regmap, TCPC_RX_BYTE_CNT, rx_buf, 2); + if (ret < 0) { + dev_err(chip->dev, "TCPC_RX_BYTE_CNT read failed ret:%d", ret); + return; + } + + count = rx_buf[TCPC_RECEIVE_BUFFER_COUNT_OFFSET]; + frame_type = rx_buf[TCPC_RECEIVE_BUFFER_FRAME_TYPE_OFFSET]; + + if (count == 0 || frame_type != TCPC_RX_BUF_FRAME_TYPE_SOP) { + max_tcpci_write16(chip, TCPC_ALERT, TCPC_ALERT_RX_STATUS); + dev_err(chip->dev, "%s", count == 0 ? "error: count is 0" : + "error frame_type is not SOP"); + return; + } + + if (count > sizeof(struct pd_message) || count + 1 > TCPC_RECEIVE_BUFFER_LEN) { + dev_err(chip->dev, "Invalid TCPC_RX_BYTE_CNT %d", count); + return; + } + + /* + * Read count + 1 as RX_BUF_BYTE_x is hidden and can only be read through + * TCPC_RX_BYTE_CNT + */ + count += 1; + ret = regmap_raw_read(chip->data.regmap, TCPC_RX_BYTE_CNT, rx_buf, count); + if (ret < 0) { + dev_err(chip->dev, "Error: TCPC_RX_BYTE_CNT read failed: %d", ret); + return; + } + + rx_buf_ptr = rx_buf + TCPC_RECEIVE_BUFFER_RX_BYTE_BUF_OFFSET; + msg.header = cpu_to_le16(*(u16 *)rx_buf_ptr); + rx_buf_ptr = rx_buf_ptr + sizeof(msg.header); + for (payload_index = 0; payload_index < pd_header_cnt_le(msg.header); payload_index++, + rx_buf_ptr += sizeof(msg.payload[0])) + msg.payload[payload_index] = cpu_to_le32(*(u32 *)rx_buf_ptr); + + /* + * Read complete, clear RX status alert bit. + * Clear overflow as well if set. + */ + ret = max_tcpci_write16(chip, TCPC_ALERT, status & TCPC_ALERT_RX_BUF_OVF ? + TCPC_ALERT_RX_STATUS | TCPC_ALERT_RX_BUF_OVF : + TCPC_ALERT_RX_STATUS); + if (ret < 0) + return; + + tcpm_pd_receive(chip->port, &msg); +} + +static int max_tcpci_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata, bool source, bool sink) +{ + struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata); + u8 buffer_source[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_SOURCE}; + u8 buffer_sink[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_SINK}; + u8 buffer_none[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_OFF}; + struct i2c_client *i2c = chip->client; + int ret; + + struct i2c_msg msgs[] = { + { + .addr = MAX_BUCK_BOOST_SID, + .flags = i2c->flags & I2C_M_TEN, + .len = 2, + .buf = source ? buffer_source : sink ? buffer_sink : buffer_none, + }, + }; + + if (source && sink) { + dev_err(chip->dev, "Both source and sink set\n"); + return -EINVAL; + } + + ret = i2c_transfer(i2c->adapter, msgs, 1); + + return ret < 0 ? ret : 1; +} + +static void process_power_status(struct max_tcpci_chip *chip) +{ + u8 pwr_status; + int ret; + + ret = max_tcpci_read8(chip, TCPC_POWER_STATUS, &pwr_status); + if (ret < 0) + return; + + if (pwr_status == 0xff) + max_tcpci_init_regs(chip); + else + tcpm_vbus_change(chip->port); +} + +static void process_tx(struct max_tcpci_chip *chip, u16 status) +{ + if (status & TCPC_ALERT_TX_SUCCESS) + tcpm_pd_transmit_complete(chip->port, TCPC_TX_SUCCESS); + else if (status & TCPC_ALERT_TX_DISCARDED) + tcpm_pd_transmit_complete(chip->port, TCPC_TX_DISCARDED); + else if (status & TCPC_ALERT_TX_FAILED) + tcpm_pd_transmit_complete(chip->port, TCPC_TX_FAILED); + + /* Reinit regs as Hard reset sets them to default value */ + if ((status & TCPC_ALERT_TX_SUCCESS) && (status & TCPC_ALERT_TX_FAILED)) + max_tcpci_init_regs(chip); +} + +static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status) +{ + u16 mask; + int ret; + + /* + * Clear alert status for everything except RX_STATUS, which shouldn't + * be cleared until we have successfully retrieved message. + */ + if (status & ~TCPC_ALERT_RX_STATUS) { + mask = status & TCPC_ALERT_RX_BUF_OVF ? + status & ~(TCPC_ALERT_RX_STATUS | TCPC_ALERT_RX_BUF_OVF) : + status & ~TCPC_ALERT_RX_STATUS; + ret = max_tcpci_write16(chip, TCPC_ALERT, mask); + if (ret < 0) { + dev_err(chip->dev, "ALERT clear failed\n"); + return ret; + } + } + + if (status & TCPC_ALERT_RX_BUF_OVF && !(status & TCPC_ALERT_RX_STATUS)) { + ret = max_tcpci_write16(chip, TCPC_ALERT, (TCPC_ALERT_RX_STATUS | + TCPC_ALERT_RX_BUF_OVF)); + if (ret < 0) { + dev_err(chip->dev, "ALERT clear failed\n"); + return ret; + } + } + + if (status & TCPC_ALERT_RX_STATUS) + process_rx(chip, status); + + if (status & TCPC_ALERT_VBUS_DISCNCT) + tcpm_vbus_change(chip->port); + + if (status & TCPC_ALERT_CC_STATUS) + tcpm_cc_change(chip->port); + + if (status & TCPC_ALERT_POWER_STATUS) + process_power_status(chip); + + if (status & TCPC_ALERT_RX_HARD_RST) { + tcpm_pd_hard_reset(chip->port); + max_tcpci_init_regs(chip); + } + + if (status & TCPC_ALERT_TX_SUCCESS || status & TCPC_ALERT_TX_DISCARDED || status & + TCPC_ALERT_TX_FAILED) + process_tx(chip, status); + + return IRQ_HANDLED; +} + +static irqreturn_t max_tcpci_irq(int irq, void *dev_id) +{ + struct max_tcpci_chip *chip = dev_id; + u16 status; + irqreturn_t irq_return; + int ret; + + if (!chip->port) + return IRQ_HANDLED; + + ret = max_tcpci_read16(chip, TCPC_ALERT, &status); + if (ret < 0) { + dev_err(chip->dev, "ALERT read failed\n"); + return ret; + } + while (status) { + irq_return = _max_tcpci_irq(chip, status); + /* Do not return if the ALERT is already set. */ + ret = max_tcpci_read16(chip, TCPC_ALERT, &status); + if (ret < 0) + break; + } + + return irq_return; +} + +static irqreturn_t max_tcpci_isr(int irq, void *dev_id) +{ + struct max_tcpci_chip *chip = dev_id; + + pm_wakeup_event(chip->dev, PD_ACTIVITY_TIMEOUT_MS); + + if (!chip->port) + return IRQ_HANDLED; + + return IRQ_WAKE_THREAD; +} + +static int max_tcpci_init_alert(struct max_tcpci_chip *chip, struct i2c_client *client) +{ + int ret; + + ret = devm_request_threaded_irq(chip->dev, client->irq, max_tcpci_isr, max_tcpci_irq, + (IRQF_TRIGGER_LOW | IRQF_ONESHOT), dev_name(chip->dev), + chip); + + if (ret < 0) + return ret; + + enable_irq_wake(client->irq); + return 0; +} + +static int max_tcpci_start_toggling(struct tcpci *tcpci, struct tcpci_data *tdata, + enum typec_cc_status cc) +{ + struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata); + + max_tcpci_init_regs(chip); + + return 0; +} + +static int tcpci_init(struct tcpci *tcpci, struct tcpci_data *data) +{ + /* + * Generic TCPCI overwrites the regs once this driver initializes + * them. Prevent this by returning -1. + */ + return -1; +} + +static int max_tcpci_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) +{ + int ret; + struct max_tcpci_chip *chip; + u8 power_status; + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->client = client; + chip->data.regmap = devm_regmap_init_i2c(client, &max_tcpci_regmap_config); + if (IS_ERR(chip->data.regmap)) { + dev_err(&client->dev, "Regmap init failed\n"); + return PTR_ERR(chip->data.regmap); + } + + chip->dev = &client->dev; + i2c_set_clientdata(client, chip); + + ret = max_tcpci_read8(chip, TCPC_POWER_STATUS, &power_status); + if (ret < 0) + return ret; + + /* Chip level tcpci callbacks */ + chip->data.set_vbus = max_tcpci_set_vbus; + chip->data.start_drp_toggling = max_tcpci_start_toggling; + chip->data.TX_BUF_BYTE_x_hidden = true; + chip->data.init = tcpci_init; + + max_tcpci_init_regs(chip); + chip->tcpci = tcpci_register_port(chip->dev, &chip->data); + if (IS_ERR_OR_NULL(chip->tcpci)) { + dev_err(&client->dev, "TCPCI port registration failed"); + ret = PTR_ERR(chip->tcpci); + return PTR_ERR(chip->tcpci); + } + chip->port = tcpci_get_tcpm_port(chip->tcpci); + ret = max_tcpci_init_alert(chip, client); + if (ret < 0) + goto unreg_port; + + device_init_wakeup(chip->dev, true); + return 0; + +unreg_port: + tcpci_unregister_port(chip->tcpci); + + return ret; +} + +static int max_tcpci_remove(struct i2c_client *client) +{ + struct max_tcpci_chip *chip = i2c_get_clientdata(client); + + if (!IS_ERR_OR_NULL(chip->tcpci)) + tcpci_unregister_port(chip->tcpci); + + return 0; +} + +static const struct i2c_device_id max_tcpci_id[] = { + { "maxtcpc", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max_tcpci_id); + +#ifdef CONFIG_OF +static const struct of_device_id max_tcpci_of_match[] = { + { .compatible = "maxim,tcpc", }, + {}, +}; +MODULE_DEVICE_TABLE(of, max_tcpci_of_match); +#endif + +static struct i2c_driver max_tcpci_i2c_driver = { + .driver = { + .name = "maxtcpc", + .of_match_table = of_match_ptr(max_tcpci_of_match), + }, + .probe = max_tcpci_probe, + .remove = max_tcpci_remove, + .id_table = max_tcpci_id, +}; +module_i2c_driver(max_tcpci_i2c_driver); + +MODULE_AUTHOR("Badhri Jagan Sridharan "); +MODULE_DESCRIPTION("Maxim TCPCI based USB Type-C Port Controller Interface Driver"); +MODULE_LICENSE("GPL v2"); From patchwork Mon Sep 21 19:55:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790813 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 712D8139F for ; Mon, 21 Sep 2020 19:56:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 557362223E for ; Mon, 21 Sep 2020 19:56:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="HQP4hkQP" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728321AbgIUT4V (ORCPT ); Mon, 21 Sep 2020 15:56:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35538 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728281AbgIUT4N (ORCPT ); Mon, 21 Sep 2020 15:56:13 -0400 Received: from mail-qk1-x74a.google.com (mail-qk1-x74a.google.com [IPv6:2607:f8b0:4864:20::74a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E05CFC0613CF for ; Mon, 21 Sep 2020 12:56:12 -0700 (PDT) Received: by mail-qk1-x74a.google.com with SMTP id j5so11829160qka.7 for ; Mon, 21 Sep 2020 12:56:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=5FrumbcAeu54idbHYrGk3eIL/4JmYNsuV6pzKeioD/A=; b=HQP4hkQPyaPQaPeZMQKr/WG/vHJn4/+lNs+7YQFMBIRpjgRBIWc5GE5fFu6RC9EG9k m4A3j598FJsGaCigKu7PPkymhVoROdhlrwEu3Ug2/44bgbSnnADhNwRtGYjvdfB01vu8 flYwXyMU64kQv9unrHVlFj4+KGPFqIHWR3kAJsl0O8CSxhRXU4/jPDE4IA6hIN0REUvd y9Vtz83gghNTR/r0bl7Tin0b8wV2BVvEcTQtomFcbvhIQydH5BWMlY3NDl7P5umj0Hod +MBjvKJEYAkgs/E/yfV4ZWf+QpYARkLJIUwKmCm1J0kA5xJQoyP/OjjYVJgBkI/58xPs eJeg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=5FrumbcAeu54idbHYrGk3eIL/4JmYNsuV6pzKeioD/A=; b=SUrjOBOkycMvvg84hF2e/d65Z9AHNJrkJ46XNEYOUYfqqRrAA3AQEyweEXKGXhm2Tu zveM2sDz30+YEvdXSrTkWBc6rsH5nKkBR0HaDerBi0z7wCJKMPrXGjEZ+mZ3uzTktZgs qPhqN8zK0LhaSD8W2l9fInyqx6TztN3yVFmVpvI5gLZDXIBg4h8dd+E/X156Imm+BZRl Uq5hFpSr6zug/QxmHsLDhkMoUF1qZsyXaKuGquBijZGBrTlsY0Wj1tM2KWhlqZy3KXkV jZEaFYPVusiZODvH8WMXvC/2LP1OdRhLsjKlKCgs9dX+fjvCo71F9k2rCM7BcU2+LIAt kfEw== X-Gm-Message-State: AOAM532VI7vRpgWgpv2Nnf/a0gN0vyVhxwgkbbgASqLI1LNtqL1BOLws xeSGwCtIXQGmRfENtA86Kq4IxJKLgE8= X-Google-Smtp-Source: ABdhPJyywnIiDx/8snJDlo4oLbprY1kUapZltGvSNvHTc/9eF/ckRq07b7AMs57MSoSBQqlTFWXNIOPHmcU= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a0c:ee86:: with SMTP id u6mr1826182qvr.56.1600718172071; Mon, 21 Sep 2020 12:56:12 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:49 -0700 In-Reply-To: <20200921195555.1050731-1-badhri@google.com> Message-Id: <20200921195555.1050731-5-badhri@google.com> Mime-Version: 1.0 References: <20200921195555.1050731-1-badhri@google.com> X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 05/11] dt-bindings: connector: Add property to set initial current cap for FRS From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org This change adds frs-typec-current which allows setting the initial current capability of the new source when vSafe5V is applied during PD3.0 sink Fast Role Swap. Signed-off-by: Badhri Jagan Sridharan --- Changes since v1: - Changing patch version to v6 to fix version number confusion. Changes since v6: - Removed the redundant usb-connector.txt that I created by mistake. - Moved to yaml. Changes since v7: - Rebase --- .../devicetree/bindings/connector/usb-connector.yaml | 8 ++++++++ include/dt-bindings/usb/pd.h | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml index 9bd52e63c935..1ca8e6a337e5 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.yaml +++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml @@ -142,6 +142,14 @@ properties: required: - port@0 + frs-typec-current: + description: Initial current capability of the new source when vSafe5V + is applied during PD3.0 Fast Role Swap. "Table 6-14 Fixed Supply PDO - Sink" + of "USB Power Delivery Specification Revision 3.0, Version 1.2" provides the + different power levels and "6.4.1.3.1.6 Fast Role Swap USB Type-C Current" + provides a detailed description of the field. + $ref: /schemas/types.yaml#/definitions/uint32 + required: - compatible diff --git a/include/dt-bindings/usb/pd.h b/include/dt-bindings/usb/pd.h index 985f2bbd4d24..db1ad4532197 100644 --- a/include/dt-bindings/usb/pd.h +++ b/include/dt-bindings/usb/pd.h @@ -35,6 +35,16 @@ #define VSAFE5V 5000 /* mv units */ +/* + * Based on "Table 6-14 Fixed Supply PDO - Sink" of "USB Power Delivery Specification Revision 3.0, + * Version 1.2" + * Initial current capability of the new source when vSafe5V is applied. + */ +#define FRS_NOT_SUPPORTED 0 +#define FRS_DEFAULT_POWER 1 +#define FRS_5V_1P5A 2 +#define FRS_5V_3A 3 + #define PDO_BATT_MAX_VOLT_SHIFT 20 /* 50mV units */ #define PDO_BATT_MIN_VOLT_SHIFT 10 /* 50mV units */ #define PDO_BATT_MAX_PWR_SHIFT 0 /* 250mW units */ From patchwork Mon Sep 21 19:55:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790825 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A92ED139A for ; Mon, 21 Sep 2020 19:56:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8030B22262 for ; Mon, 21 Sep 2020 19:56:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="M3hp9y82" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728413AbgIUT4o (ORCPT ); Mon, 21 Sep 2020 15:56:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35548 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728113AbgIUT4P (ORCPT ); Mon, 21 Sep 2020 15:56:15 -0400 Received: from mail-qv1-xf49.google.com (mail-qv1-xf49.google.com [IPv6:2607:f8b0:4864:20::f49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 25B93C0613CF for ; Mon, 21 Sep 2020 12:56:15 -0700 (PDT) Received: by mail-qv1-xf49.google.com with SMTP id p20so9801841qvl.4 for ; Mon, 21 Sep 2020 12:56:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=5omKMHGrqT1FMvI/mN9PGdF8I/6+6W4daRXYUBtnBhs=; b=M3hp9y82v5/uCa0TLYspv5gN8Pc/jGsNGiVpnv4E1dPkhCJYjHy42Zem+5cHEZCq9F w2WCU/rVKubzqIXZsVNOUzTwq7oAO3EL2Nk/oXfIXV42BtReX37BnfHCWpS6t80bsViL 7cPNzfsVWwOh3NtneUPF7FWOMo8OIGCx/QCVg63L3hcNjpc3KVuldt1Q8Gn9ggPLQU6R Jt/94o9AlwUgs3+Kqo8rc9zGgiYOY+Yg2lwHMB5e1JR94ZQOCr32gtDf6Xpd02GaPVSm Z6s0QJQPkAOX/onCG2Ib7+ajHyeV+9fY0Qs3OwW5lrYYiyDBdpdfYJz2+vz2z5a0pHAg ieNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=5omKMHGrqT1FMvI/mN9PGdF8I/6+6W4daRXYUBtnBhs=; b=OOt91q4ju3efG6lkHmOI3d1UlOLeHEdXmClLhnIVPsTtSVsLwT8I0b/94Ed6pZKoPL dqL5pCOFNo0jhIryU5O6JQSwdWYHMyf7TEjDLRIjQw6yk2IaIEnJGEfchkJV6cBBR6jP ChOPXxaMpts6DvkcBdWTKhMSME7IfZP8W8yppsm1MD+Jxo8XTEN9vekMRA6H70cDD9HO ioarLKpw3G58d3IeUp5Qne3LDfhOTGiTr325sd8YYV40gFBIy8FixhFyPtBptMsIc/Cl xTsbvb75g1uUk5rysC1NXUnaM1lMO8uGSX5lSf4grjUoHU+ECahHTOOEw3I2RPYt5nzd /ycg== X-Gm-Message-State: AOAM532vK9MDmRk2V0Dmf/Fh9laK9VdUzOUCVprJrUeeDIEJFUekHzez 39vyANWovOY19wauVs4rhqhni9WiSPE= X-Google-Smtp-Source: ABdhPJz3fDVqtn4McvHIQysiiXVccrbhSx9UghFfQiFWNFDhT8HJvQ0pFFULE/HL3kttdmqDWoGAsQFAx/c= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a0c:b60c:: with SMTP id f12mr1950331qve.2.1600718174118; Mon, 21 Sep 2020 12:56:14 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:50 -0700 In-Reply-To: <20200921195555.1050731-1-badhri@google.com> Message-Id: <20200921195555.1050731-6-badhri@google.com> Mime-Version: 1.0 References: <20200921195555.1050731-1-badhri@google.com> X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 06/11] usb: typec: tcpm: Add support for Sink Fast Role SWAP(FRS) From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org PD 3.0 spec defines a new mechanism for power role swap called Fast role swap. This change enables TCPM to support FRS when acting as sink. Once the explicit contract is negotiated, sink port is expected to query the source port for sink caps to determine whether the source is FRS capable. Bits 23 & 24 of fixed pdo of the sink caps from the source, when set, indicates the current needed by the source when fast role swap is in progress(Implicit contract phasae). 0 indicates that the source does not support Fast Role Swap. Upon receiving the FRS signal from the source, TCPC(TCPM_FRS_EVENT) informs TCPM to start the Fast role swap sequence. 1. TCPM sends FRS PD message: FR_SWAP_SEND 2. If response is not received within the expiry of SenderResponseTimer, Error recovery is triggered.: FR_SWAP_SEND_TIMEOUT 3. Upon receipt of the accept message, TCPM waits for PSSourceOffTimer for PS_READY message from the partner: FR_SWAP_SNK_SRC_NEW_SINK_READY. TCPC is expected to autonomously turn on vbus once the FRS signal is received and vbus voltage falls below vsafe5v within tSrcFrSwap. This is different from traditional power role swap where the vbus sourcing is turned on by TCPM. 4. By this time, TCPC most likely would have started to source vbus, TCPM waits for tSrcFrSwap to see if the lower level TCPC driver signals TCPM_SOURCING_VBUS event: FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED. 5. When TCPC signals sourcing vbus, TCPM sends PS_READY msg and changes the CC pin from Rd to Rp. This is the end of fast role swap sequence and TCPM initiates the sequnce to negotiate explicit contract by transitioning into SRC_STARTUP after SwapSrcStart. The code is written based on the sequence described in "Figure 8-107: Dual-role Port in Sink to Source Fast Role Swap State Diagram" of USB Power Delivery Specification Revision 3.0, Version 1.2. Signed-off-by: Badhri Jagan Sridharan Reviewed-by: Heikki Krogerus --- Changes since v1: - Changing patch version to v6 to fix version number confusion. - Rebased on top of usb-next and resolved conflicts due to the below changes: 3ed8e1c2ac99 usb: typec: tcpm: Migrate workqueue to RT priority for processing events 6bbe2a90a0bb usb: typec: tcpm: During PR_SWAP, source caps should be sent only after tSwapSourceStart - enable_frs sequence is now run as part of the same kthread that runs the state machines. - Fixed the implicit fallthrough warning in the switch case for FR_SWAP_CANCEL case. Changes since v6: - Moved frs_current from caps to tcpm_port as Heikki suggested. Changes since v7: - Added Reviewed-by: Heikki --- drivers/usb/typec/tcpm/tcpm.c | 229 +++++++++++++++++++++++++++++++++- include/linux/usb/pd.h | 19 +-- include/linux/usb/tcpm.h | 8 +- 3 files changed, 244 insertions(+), 12 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 92806547f485..55535c4f66bf 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -106,6 +106,13 @@ S(VCONN_SWAP_TURN_ON_VCONN), \ S(VCONN_SWAP_TURN_OFF_VCONN), \ \ + S(FR_SWAP_SEND), \ + S(FR_SWAP_SEND_TIMEOUT), \ + S(FR_SWAP_SNK_SRC_TRANSITION_TO_OFF), \ + S(FR_SWAP_SNK_SRC_NEW_SINK_READY), \ + S(FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED), \ + S(FR_SWAP_CANCEL), \ + \ S(SNK_TRY), \ S(SNK_TRY_WAIT), \ S(SNK_TRY_WAIT_DEBOUNCE), \ @@ -127,6 +134,9 @@ S(GET_PPS_STATUS_SEND), \ S(GET_PPS_STATUS_SEND_TIMEOUT), \ \ + S(GET_SINK_CAP), \ + S(GET_SINK_CAP_TIMEOUT), \ + \ S(ERROR_RECOVERY), \ S(PORT_RESET), \ S(PORT_RESET_WAIT_OFF) @@ -170,11 +180,25 @@ enum adev_actions { ADEV_ATTENTION, }; +/* + * Initial current capability of the new source when vSafe5V is applied during PD3.0 Fast Role Swap. + * Based on "Table 6-14 Fixed Supply PDO - Sink" of "USB Power Delivery Specification Revision 3.0, + * Version 1.2" + */ +enum frs_typec_current { + FRS_NOT_SUPPORTED, + FRS_DEFAULT_POWER, + FRS_5V_1P5A, + FRS_5V_3A, +}; + /* Events from low level driver */ #define TCPM_CC_EVENT BIT(0) #define TCPM_VBUS_EVENT BIT(1) #define TCPM_RESET_EVENT BIT(2) +#define TCPM_FRS_EVENT BIT(3) +#define TCPM_SOURCING_VBUS BIT(4) #define LOG_BUFFER_ENTRIES 1024 #define LOG_BUFFER_ENTRY_SIZE 128 @@ -184,6 +208,8 @@ enum adev_actions { #define SVID_DISCOVERY_MAX 16 #define ALTMODE_DISCOVERY_MAX (SVID_DISCOVERY_MAX * MODE_DISCOVERY_MAX) +#define GET_SINK_CAP_RETRY_MS 100 + struct pd_mode_data { int svid_index; /* current SVID index */ int nsvids; @@ -261,6 +287,8 @@ struct tcpm_port { struct kthread_work state_machine; struct hrtimer vdm_state_machine_timer; struct kthread_work vdm_state_machine; + struct hrtimer enable_frs_timer; + struct kthread_work enable_frs; bool state_machine_running; struct completion tx_complete; @@ -335,6 +363,12 @@ struct tcpm_port { /* port belongs to a self powered device */ bool self_powered; + /* FRS */ + enum frs_typec_current frs_current; + + /* Sink caps have been queried */ + bool sink_cap_done; + #ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct mutex logbuffer_lock; /* log buffer access lock */ @@ -940,6 +974,16 @@ static void mod_vdm_delayed_work(struct tcpm_port *port, unsigned int delay_ms) } } +static void mod_enable_frs_delayed_work(struct tcpm_port *port, unsigned int delay_ms) +{ + if (delay_ms) { + hrtimer_start(&port->enable_frs_timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL); + } else { + hrtimer_cancel(&port->enable_frs_timer); + kthread_queue_work(port->wq, &port->enable_frs); + } +} + static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state, unsigned int delay_ms) { @@ -1669,6 +1713,9 @@ static void tcpm_pd_data_request(struct tcpm_port *port, unsigned int cnt = pd_header_cnt_le(msg->header); unsigned int rev = pd_header_rev_le(msg->header); unsigned int i; + enum frs_typec_current frs_current; + bool frs_enable; + int ret; switch (type) { case PD_DATA_SOURCE_CAP: @@ -1738,7 +1785,21 @@ static void tcpm_pd_data_request(struct tcpm_port *port, /* We don't do anything with this at the moment... */ for (i = 0; i < cnt; i++) port->sink_caps[i] = le32_to_cpu(msg->payload[i]); + + frs_current = (port->sink_caps[0] & PDO_FIXED_FRS_CURR_MASK) >> + PDO_FIXED_FRS_CURR_SHIFT; + frs_enable = frs_current && (frs_current <= port->frs_current); + tcpm_log(port, + "Port partner FRS capable partner_frs_current:%u port_frs_current:%u enable:%c", + frs_current, port->frs_current, frs_enable ? 'y' : 'n'); + if (frs_enable) { + ret = port->tcpc->enable_frs(port->tcpc, true); + tcpm_log(port, "Enable FRS %s, ret:%d\n", ret ? "fail" : "success", ret); + } + port->nr_sink_caps = cnt; + port->sink_cap_done = true; + tcpm_set_state(port, SNK_READY, 0); break; case PD_DATA_VENDOR_DEF: tcpm_handle_vdm_request(port, msg->payload, cnt); @@ -1833,6 +1894,9 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, case VCONN_SWAP_WAIT_FOR_VCONN: tcpm_set_state(port, VCONN_SWAP_TURN_OFF_VCONN, 0); break; + case FR_SWAP_SNK_SRC_TRANSITION_TO_OFF: + tcpm_set_state(port, FR_SWAP_SNK_SRC_NEW_SINK_READY, 0); + break; default: break; } @@ -1872,6 +1936,13 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, -EAGAIN : -EOPNOTSUPP); tcpm_set_state(port, VCONN_SWAP_CANCEL, 0); break; + case FR_SWAP_SEND: + tcpm_set_state(port, FR_SWAP_CANCEL, 0); + break; + case GET_SINK_CAP: + port->sink_cap_done = true; + tcpm_set_state(port, ready_state(port), 0); + break; default: break; } @@ -1906,6 +1977,9 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, case VCONN_SWAP_SEND: tcpm_set_state(port, VCONN_SWAP_START, 0); break; + case FR_SWAP_SEND: + tcpm_set_state(port, FR_SWAP_SNK_SRC_TRANSITION_TO_OFF, 0); + break; default: break; } @@ -2806,6 +2880,10 @@ static void tcpm_reset_port(struct tcpm_port *port) port->try_src_count = 0; port->try_snk_count = 0; port->usb_type = POWER_SUPPLY_USB_TYPE_C; + port->nr_sink_caps = 0; + port->sink_cap_done = false; + if (port->tcpc->enable_frs) + port->tcpc->enable_frs(port->tcpc, false); power_supply_changed(port->psy); } @@ -3356,10 +3434,9 @@ static void run_state_machine(struct tcpm_port *port) tcpm_swap_complete(port, 0); tcpm_typec_connect(port); tcpm_check_send_discover(port); + mod_enable_frs_delayed_work(port, 0); tcpm_pps_complete(port, port->pps_status); - power_supply_changed(port->psy); - break; /* Accessory states */ @@ -3383,9 +3460,13 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, HARD_RESET_START, 0); break; case HARD_RESET_START: + port->sink_cap_done = false; + if (port->tcpc->enable_frs) + port->tcpc->enable_frs(port->tcpc, false); port->hard_reset_count++; port->tcpc->set_pd_rx(port->tcpc, false); tcpm_unregister_altmodes(port); + port->nr_sink_caps = 0; port->send_discover = true; if (port->pwr_role == TYPEC_SOURCE) tcpm_set_state(port, SRC_HARD_RESET_VBUS_OFF, @@ -3517,6 +3598,35 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, ready_state(port), 0); break; + case FR_SWAP_SEND: + if (tcpm_pd_send_control(port, PD_CTRL_FR_SWAP)) { + tcpm_set_state(port, ERROR_RECOVERY, 0); + break; + } + tcpm_set_state_cond(port, FR_SWAP_SEND_TIMEOUT, PD_T_SENDER_RESPONSE); + break; + case FR_SWAP_SEND_TIMEOUT: + tcpm_set_state(port, ERROR_RECOVERY, 0); + break; + case FR_SWAP_SNK_SRC_TRANSITION_TO_OFF: + tcpm_set_state(port, ERROR_RECOVERY, PD_T_PS_SOURCE_OFF); + break; + case FR_SWAP_SNK_SRC_NEW_SINK_READY: + if (port->vbus_source) + tcpm_set_state(port, FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED, 0); + else + tcpm_set_state(port, ERROR_RECOVERY, PD_T_RECEIVER_RESPONSE); + break; + case FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED: + tcpm_set_pwr_role(port, TYPEC_SOURCE); + if (tcpm_pd_send_control(port, PD_CTRL_PS_RDY)) { + tcpm_set_state(port, ERROR_RECOVERY, 0); + break; + } + tcpm_set_cc(port, tcpm_rp_cc(port)); + tcpm_set_state(port, SRC_STARTUP, PD_T_SWAP_SRC_START); + break; + /* PR_Swap states */ case PR_SWAP_ACCEPT: tcpm_pd_send_control(port, PD_CTRL_ACCEPT); @@ -3640,6 +3750,12 @@ static void run_state_machine(struct tcpm_port *port) else tcpm_set_state(port, SNK_READY, 0); break; + case FR_SWAP_CANCEL: + if (port->pwr_role == TYPEC_SOURCE) + tcpm_set_state(port, SRC_READY, 0); + else + tcpm_set_state(port, SNK_READY, 0); + break; case BIST_RX: switch (BDO_MODE_MASK(port->bist_request)) { @@ -3674,6 +3790,14 @@ static void run_state_machine(struct tcpm_port *port) case GET_PPS_STATUS_SEND_TIMEOUT: tcpm_set_state(port, ready_state(port), 0); break; + case GET_SINK_CAP: + tcpm_pd_send_control(port, PD_CTRL_GET_SINK_CAP); + tcpm_set_state(port, GET_SINK_CAP_TIMEOUT, PD_T_SENDER_RESPONSE); + break; + case GET_SINK_CAP_TIMEOUT: + port->sink_cap_done = true; + tcpm_set_state(port, ready_state(port), 0); + break; case ERROR_RECOVERY: tcpm_swap_complete(port, -EPROTO); tcpm_pps_complete(port, -EPROTO); @@ -3889,6 +4013,13 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, * Ignore it. */ break; + case FR_SWAP_SEND: + case FR_SWAP_SEND_TIMEOUT: + case FR_SWAP_SNK_SRC_TRANSITION_TO_OFF: + case FR_SWAP_SNK_SRC_NEW_SINK_READY: + case FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED: + /* Do nothing, CC change expected */ + break; case PORT_RESET: case PORT_RESET_WAIT_OFF: @@ -3959,6 +4090,9 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port) case SRC_TRY_DEBOUNCE: /* Do nothing, waiting for sink detection */ break; + case FR_SWAP_SNK_SRC_NEW_SINK_READY: + tcpm_set_state(port, FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED, 0); + break; case PORT_RESET: case PORT_RESET_WAIT_OFF: @@ -4038,6 +4172,14 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port) */ break; + case FR_SWAP_SEND: + case FR_SWAP_SEND_TIMEOUT: + case FR_SWAP_SNK_SRC_TRANSITION_TO_OFF: + case FR_SWAP_SNK_SRC_NEW_SINK_READY: + case FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED: + /* Do nothing, vbus drop expected */ + break; + default: if (port->pwr_role == TYPEC_SINK && port->attached) @@ -4092,6 +4234,25 @@ static void tcpm_pd_event_handler(struct kthread_work *work) if (port->tcpc->get_cc(port->tcpc, &cc1, &cc2) == 0) _tcpm_cc_change(port, cc1, cc2); } + if (events & TCPM_FRS_EVENT) { + if (port->state == SNK_READY) + tcpm_set_state(port, FR_SWAP_SEND, 0); + else + tcpm_log(port, "Discarding FRS_SIGNAL! Not in sink ready"); + } + if (events & TCPM_SOURCING_VBUS) { + tcpm_log(port, "sourcing vbus"); + /* + * In fast role swap case TCPC autonomously sources vbus. Set vbus_source + * true as TCPM wouldn't have called tcpm_set_vbus. + * + * When vbus is sourced on the command on TCPM i.e. TCPM called + * tcpm_set_vbus to source vbus, vbus_source would already be true. + */ + port->vbus_source = true; + _tcpm_pd_vbus_on(port); + } + spin_lock(&port->pd_event_lock); } spin_unlock(&port->pd_event_lock); @@ -4125,6 +4286,50 @@ void tcpm_pd_hard_reset(struct tcpm_port *port) } EXPORT_SYMBOL_GPL(tcpm_pd_hard_reset); +void tcpm_sink_frs(struct tcpm_port *port) +{ + spin_lock(&port->pd_event_lock); + port->pd_events = TCPM_FRS_EVENT; + spin_unlock(&port->pd_event_lock); + kthread_queue_work(port->wq, &port->event_work); +} +EXPORT_SYMBOL_GPL(tcpm_sink_frs); + +void tcpm_sourcing_vbus(struct tcpm_port *port) +{ + spin_lock(&port->pd_event_lock); + port->pd_events = TCPM_SOURCING_VBUS; + spin_unlock(&port->pd_event_lock); + kthread_queue_work(port->wq, &port->event_work); +} +EXPORT_SYMBOL_GPL(tcpm_sourcing_vbus); + +static void tcpm_enable_frs_work(struct kthread_work *work) +{ + struct tcpm_port *port = container_of(work, struct tcpm_port, enable_frs); + + mutex_lock(&port->lock); + /* Not FRS capable */ + if (!port->connected || port->port_type != TYPEC_PORT_DRP || + port->pwr_opmode != TYPEC_PWR_MODE_PD || + !port->tcpc->enable_frs || + /* Sink caps queried */ + port->sink_cap_done || port->negotiated_rev < PD_REV30) + goto unlock; + + /* Send when the state machine is idle */ + if (port->state != SNK_READY || port->vdm_state != VDM_STATE_DONE || port->send_discover) + goto resched; + + tcpm_set_state(port, GET_SINK_CAP, 0); + port->sink_cap_done = true; + +resched: + mod_enable_frs_delayed_work(port, GET_SINK_CAP_RETRY_MS); +unlock: + mutex_unlock(&port->lock); +} + static int tcpm_dr_set(struct typec_port *p, enum typec_data_role data) { struct tcpm_port *port = typec_get_drvdata(p); @@ -4532,7 +4737,7 @@ static int tcpm_fw_get_caps(struct tcpm_port *port, { const char *cap_str; int ret; - u32 mw; + u32 mw, frs_current; if (!fwnode) return -EINVAL; @@ -4601,6 +4806,13 @@ static int tcpm_fw_get_caps(struct tcpm_port *port, port->self_powered = fwnode_property_read_bool(fwnode, "self-powered"); + /* FRS can only be supported byb DRP ports */ + if (port->port_type == TYPEC_PORT_DRP) { + ret = fwnode_property_read_u32(fwnode, "frs-typec-current", &frs_current); + if (ret >= 0 && frs_current <= FRS_5V_3A) + port->frs_current = frs_current; + } + return 0; } @@ -4845,6 +5057,14 @@ static enum hrtimer_restart vdm_state_machine_timer_handler(struct hrtimer *time return HRTIMER_NORESTART; } +static enum hrtimer_restart enable_frs_timer_handler(struct hrtimer *timer) +{ + struct tcpm_port *port = container_of(timer, struct tcpm_port, enable_frs_timer); + + kthread_queue_work(port->wq, &port->enable_frs); + return HRTIMER_NORESTART; +} + struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) { struct tcpm_port *port; @@ -4874,10 +5094,13 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) kthread_init_work(&port->state_machine, tcpm_state_machine_work); kthread_init_work(&port->vdm_state_machine, vdm_state_machine_work); kthread_init_work(&port->event_work, tcpm_pd_event_handler); + kthread_init_work(&port->enable_frs, tcpm_enable_frs_work); hrtimer_init(&port->state_machine_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); port->state_machine_timer.function = state_machine_timer_handler; hrtimer_init(&port->vdm_state_machine_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); port->vdm_state_machine_timer.function = vdm_state_machine_timer_handler; + hrtimer_init(&port->enable_frs_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + port->enable_frs_timer.function = enable_frs_timer_handler; spin_lock_init(&port->pd_event_lock); diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h index f842e4589bd2..3a805e2ecbc9 100644 --- a/include/linux/usb/pd.h +++ b/include/linux/usb/pd.h @@ -219,14 +219,16 @@ enum pd_pdo_type { #define PDO_CURR_MASK 0x3ff #define PDO_PWR_MASK 0x3ff -#define PDO_FIXED_DUAL_ROLE BIT(29) /* Power role swap supported */ -#define PDO_FIXED_SUSPEND BIT(28) /* USB Suspend supported (Source) */ -#define PDO_FIXED_HIGHER_CAP BIT(28) /* Requires more than vSafe5V (Sink) */ -#define PDO_FIXED_EXTPOWER BIT(27) /* Externally powered */ -#define PDO_FIXED_USB_COMM BIT(26) /* USB communications capable */ -#define PDO_FIXED_DATA_SWAP BIT(25) /* Data role swap supported */ -#define PDO_FIXED_VOLT_SHIFT 10 /* 50mV units */ -#define PDO_FIXED_CURR_SHIFT 0 /* 10mA units */ +#define PDO_FIXED_DUAL_ROLE BIT(29) /* Power role swap supported */ +#define PDO_FIXED_SUSPEND BIT(28) /* USB Suspend supported (Source) */ +#define PDO_FIXED_HIGHER_CAP BIT(28) /* Requires more than vSafe5V (Sink) */ +#define PDO_FIXED_EXTPOWER BIT(27) /* Externally powered */ +#define PDO_FIXED_USB_COMM BIT(26) /* USB communications capable */ +#define PDO_FIXED_DATA_SWAP BIT(25) /* Data role swap supported */ +#define PDO_FIXED_FRS_CURR_MASK (BIT(24) | BIT(23)) /* FR_Swap Current (Sink) */ +#define PDO_FIXED_FRS_CURR_SHIFT 23 +#define PDO_FIXED_VOLT_SHIFT 10 /* 50mV units */ +#define PDO_FIXED_CURR_SHIFT 0 /* 10mA units */ #define PDO_FIXED_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_FIXED_VOLT_SHIFT) #define PDO_FIXED_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_FIXED_CURR_SHIFT) @@ -454,6 +456,7 @@ static inline unsigned int rdo_max_power(u32 rdo) #define PD_T_DB_DETECT 10000 /* 10 - 15 seconds */ #define PD_T_SEND_SOURCE_CAP 150 /* 100 - 200 ms */ #define PD_T_SENDER_RESPONSE 60 /* 24 - 30 ms, relaxed */ +#define PD_T_RECEIVER_RESPONSE 15 /* 15ms max */ #define PD_T_SOURCE_ACTIVITY 45 #define PD_T_SINK_ACTIVITY 135 #define PD_T_SINK_WAIT_CAP 240 diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h index 89f58760cf48..09762d26fa0c 100644 --- a/include/linux/usb/tcpm.h +++ b/include/linux/usb/tcpm.h @@ -78,8 +78,11 @@ enum tcpm_transmit_type { * automatically if a connection is established. * @try_role: Optional; called to set a preferred role * @pd_transmit:Called to transmit PD message - * @mux: Pointer to multiplexer data * @set_bist_data: Turn on/off bist data mode for compliance testing + * @enable_frs: + * Optional; Called to enable/disable PD 3.0 fast role swap. + * Enabling frs is accessory dependent as not all PD3.0 + * accessories support fast role swap. */ struct tcpc_dev { struct fwnode_handle *fwnode; @@ -105,6 +108,7 @@ struct tcpc_dev { int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type, const struct pd_message *msg); int (*set_bist_data)(struct tcpc_dev *dev, bool on); + int (*enable_frs)(struct tcpc_dev *dev, bool enable); }; struct tcpm_port; @@ -114,6 +118,8 @@ void tcpm_unregister_port(struct tcpm_port *port); void tcpm_vbus_change(struct tcpm_port *port); void tcpm_cc_change(struct tcpm_port *port); +void tcpm_sink_frs(struct tcpm_port *port); +void tcpm_sourcing_vbus(struct tcpm_port *port); void tcpm_pd_receive(struct tcpm_port *port, const struct pd_message *msg); void tcpm_pd_transmit_complete(struct tcpm_port *port, From patchwork Mon Sep 21 19:55:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790821 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9BE58139A for ; Mon, 21 Sep 2020 19:56:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7A71F23447 for ; Mon, 21 Sep 2020 19:56:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="n+ZIG19/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728341AbgIUT4Y (ORCPT ); Mon, 21 Sep 2020 15:56:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35558 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728278AbgIUT4R (ORCPT ); Mon, 21 Sep 2020 15:56:17 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 43BF6C0613D1 for ; Mon, 21 Sep 2020 12:56:17 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id f185so13908362ybf.17 for ; Mon, 21 Sep 2020 12:56:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=bm2T+CrCpRo3vv+J+7TT/LPjfYta6ghVQoeicKU+M4k=; b=n+ZIG19/CrRbjvYH5MKj96POy8PjEe+b1pxFwzwz5ohqNcAkjQFC/wiyCLMFDauK5i 6qBQ50qbJ4Phb6YhXgRTpgDj3rW1e6qjQwK6/FS0TBRIrVD5qWTcCl9aMp+idI4j76EV 5+BjrE6V+FPGBFSLB+kahfzcLhSC/o+XiXs5r2hIKqfTMQ0ByMMBzqv4M8hOXp25wVC7 HupwBUauPOQh7pwWEI1ZRhimvyu7IywcDE9PfQKTxrDLECGgPI83R9PoBO5oqzO0hQLk 2dhDjdSOH6XtWhRuP0TQ6hsU6GYTEek0uyGTv8tk/xdVMw4gX1bMwevpz1OOvssgOC7x POjw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=bm2T+CrCpRo3vv+J+7TT/LPjfYta6ghVQoeicKU+M4k=; b=PS2PohqbQyYgN5uM4xrJHmTD9fQLvJXRRG+jnr2fgR8KpwbbLtbd1+56IUlLlR+mh1 AC0rv07Ovthh2Kmoimk82KNLKR39npdK+8ULibNBgrBcl7xvasOftX51mI2nhe+Ov67p rqw3dN3sDIEkIfxry8QNWYJMkFj1rG7tkkNWN64O6m9p4tzO2z5NdYOIgxjNOlLxqaTu MCVvEe0E+16feBjfPfCHWrXxOmiX/BQ3QuyDZAI6fQ/XcXUTgL0eDXcgJ/a0lDUEQObL bvMiy08YEY2fowdi/M+5RaYs2vEf37tc/Yaw+/lyVtW+hJ3c/tYLHwmXuh9S/OSBHcDo uSdA== X-Gm-Message-State: AOAM533UGSXsD6Mr45npnPVdWzf8yVm4w7RMKdHYyi/o4KKL85q9a6rS CzFphMTuf+IxDQ7O+gnwnnRvI6XX2J4= X-Google-Smtp-Source: ABdhPJwCgp50wVGLJdMUT75HsueAsOaD8yLJ6RjGJWNpyXbIT9EoLmTnoIe+EwvShpnEPpFiNhgwMUqTLxA= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a25:2f85:: with SMTP id v127mr2189523ybv.372.1600718176459; Mon, 21 Sep 2020 12:56:16 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:51 -0700 In-Reply-To: <20200921195555.1050731-1-badhri@google.com> Message-Id: <20200921195555.1050731-7-badhri@google.com> Mime-Version: 1.0 References: <20200921195555.1050731-1-badhri@google.com> X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 07/11] usb: typec: tcpci: Implement callbacks for FRS From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Implement tcpc.enable_frs to enable TCPC to receive Fast role swap signal. Additionally set the sink disconnect threshold to 4v to prevent disconnect during Fast Role swap. Signed-off-by: Badhri Jagan Sridharan Reviewed-by: Heikki Krogerus --- Changes since v1: - Changing patch version to v6 to fix version number confusion. Changes since v6: - Rebase on usb-next. - Fixed formatting error. - Added Reviewed-by: Heikki. Changes since v7: - Rebase on usb-next. --- drivers/usb/typec/tcpm/tcpci.c | 17 +++++++++++++++++ drivers/usb/typec/tcpm/tcpci.h | 8 ++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index d6a6fac82d48..f9f0af64da5f 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -268,6 +268,22 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable) enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0); } +static int tcpci_enable_frs(struct tcpc_dev *dev, bool enable) +{ + struct tcpci *tcpci = tcpc_to_tcpci(dev); + int ret; + + /* To prevent disconnect during FRS, set disconnect threshold to 3.5V */ + ret = tcpci_write16(tcpci, TCPC_VBUS_SINK_DISCONNECT_THRESH, enable ? 0 : 0x8c); + if (ret < 0) + return ret; + + ret = regmap_update_bits(tcpci->regmap, TCPC_POWER_CTRL, TCPC_FAST_ROLE_SWAP_EN, enable ? + TCPC_FAST_ROLE_SWAP_EN : 0); + + return ret; +} + static int tcpci_set_bist_data(struct tcpc_dev *tcpc, bool enable) { struct tcpci *tcpci = tcpc_to_tcpci(tcpc); @@ -611,6 +627,7 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data) tcpci->tcpc.set_roles = tcpci_set_roles; tcpci->tcpc.pd_transmit = tcpci_pd_transmit; tcpci->tcpc.set_bist_data = tcpci_set_bist_data; + tcpci->tcpc.enable_frs = tcpci_enable_frs; err = tcpci_parse_config(tcpci); if (err < 0) diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h index 82f021a82456..5ef07a56d67a 100644 --- a/drivers/usb/typec/tcpm/tcpci.h +++ b/drivers/usb/typec/tcpm/tcpci.h @@ -16,6 +16,7 @@ #define TCPC_PD_INT_REV 0xa #define TCPC_ALERT 0x10 +#define TCPC_ALERT_EXTND BIT(14) #define TCPC_ALERT_EXTENDED_STATUS BIT(13) #define TCPC_ALERT_VBUS_DISCNCT BIT(11) #define TCPC_ALERT_RX_BUF_OVF BIT(10) @@ -37,6 +38,9 @@ #define TCPC_EXTENDED_STATUS_MASK 0x16 #define TCPC_EXTENDED_STATUS_MASK_VSAFE0V BIT(0) +#define TCPC_ALERT_EXTENDED_MASK 0x17 +#define TCPC_SINK_FAST_ROLE_SWAP BIT(0) + #define TCPC_CONFIG_STD_OUTPUT 0x18 #define TCPC_TCPC_CTRL 0x19 @@ -63,6 +67,7 @@ #define TCPC_POWER_CTRL 0x1c #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0) +#define TCPC_FAST_ROLE_SWAP_EN BIT(7) #define TCPC_CC_STATUS 0x1d #define TCPC_CC_STATUS_TOGGLING BIT(5) @@ -74,11 +79,14 @@ #define TCPC_POWER_STATUS 0x1e #define TCPC_POWER_STATUS_UNINIT BIT(6) +#define TCPC_POWER_STATUS_SOURCING_VBUS BIT(4) #define TCPC_POWER_STATUS_VBUS_DET BIT(3) #define TCPC_POWER_STATUS_VBUS_PRES BIT(2) #define TCPC_FAULT_STATUS 0x1f +#define TCPC_ALERT_EXTENDED 0x21 + #define TCPC_COMMAND 0x23 #define TCPC_CMD_WAKE_I2C 0x11 #define TCPC_CMD_DISABLE_VBUS_DETECT 0x22 From patchwork Mon Sep 21 19:55:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790819 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AA92E139F for ; Mon, 21 Sep 2020 19:56:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8E0D1222BB for ; Mon, 21 Sep 2020 19:56:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="IuEAfWMb" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728357AbgIUT4Z (ORCPT ); Mon, 21 Sep 2020 15:56:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35584 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728274AbgIUT4Y (ORCPT ); Mon, 21 Sep 2020 15:56:24 -0400 Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3538CC0613D6 for ; Mon, 21 Sep 2020 12:56:19 -0700 (PDT) Received: by mail-qk1-x749.google.com with SMTP id 139so11804353qkl.11 for ; Mon, 21 Sep 2020 12:56:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=WnqoxyrnhnbLSjlAaHJroAag0WGYLddsMxxYzP4KpXk=; b=IuEAfWMb816wbj/U5cLCZcEF5wlL+VU3SvhkCDjQdshmqdZYUbcrAuKUqAT6Y2UmQh Q+lmlk2GQH3QClKT6Hlw11V70gS7PRestTQ1d22IuvZQ4pR4XQ3Bnh62EiF6KxsPEGCp QacwcJJpjPyNUDy6Pykym0Td1qAx7ORIW9md0wz1phtvN3xT5DrNm21gP0V28tp2ADpX 27uuGDc9EY5d6+rSNWX7exw52Efh6/lxxhp7pzRQy3ZeTGUKEJ1SZSDg84JnlzeaaBD6 HhdoaVpebIF0eBvH3nZL9gr24gHCF35s3ylnXmdNPy8OC1Tz1ennQ69S1zbuJEAu74Eg /9Xg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=WnqoxyrnhnbLSjlAaHJroAag0WGYLddsMxxYzP4KpXk=; b=nETF7vA4th8eldwv+H8T8HPYrp3WXU2FPxs/9Azi1QxknEkjRa8Dfpad+uPIbjPXRK geytayAx6yBUVeU+LIwWCryp1SDViKRjtdI5CFWVCOwcPsZ6gamC2Ey4FReF8v4xTn/j Weqa88kZwRvvcjx10q/1fhv7F1eC3ZUgThxYAvcOMHU1WsWE7rO1EqD4+JmVFlOhhxCe uh1RQk/t0bLhrk9P3Effk+4lzay9yP9xhXT2yBXH5wgO6/oHLpl/gwels9qdZoKWtxzG KJzsp3wGRDmeycS2+Hu/rKLC3io7TKT8A8OB1wzuCtnfIW2b4ye3uJx9XRDRiiTlbhs0 ObTA== X-Gm-Message-State: AOAM5335juLOvVdOSif+iShy4PAFycQdlWMLtnK0/0ap+fwowYy8HeAU rwdxxjCpwUbZo3RW8UOOsQ/HdSRfBE0= X-Google-Smtp-Source: ABdhPJxg4JxCZLbtomgqq/fu0Yf2KDRoNnvgOXJpL6EI9XyjQIhbCzy42EjF+TZihw38hdwP4sLezG9DxnQ= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a0c:abc5:: with SMTP id k5mr1918418qvb.40.1600718178413; Mon, 21 Sep 2020 12:56:18 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:52 -0700 In-Reply-To: <20200921195555.1050731-1-badhri@google.com> Message-Id: <20200921195555.1050731-8-badhri@google.com> Mime-Version: 1.0 References: <20200921195555.1050731-1-badhri@google.com> X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 08/11] usb: typec: tcpci_maxim: Add support for Sink FRS From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Upon receiving ALERT_EXTENDED.TCPC_SINK_FAST_ROLE_SWAP signal tcpm to start Sink fast role swap signal. Inform when TCPM is sourcing vbus. Signed-off-by: Badhri Jagan Sridharan Reviewed-by: Heikki Krogerus --- Changes since v1: - Changing patch version to v6 to fix version number confusion. Changes since v6: - rebase on usb-next - Added Reviewed-by: Heikki Changes since v7: - Rebase on usb-next --- drivers/usb/typec/tcpm/tcpci_maxim.c | 50 +++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.c b/drivers/usb/typec/tcpm/tcpci_maxim.c index 91337ddb4962..723d7dd38f75 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim.c +++ b/drivers/usb/typec/tcpm/tcpci_maxim.c @@ -106,13 +106,22 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip) return; } + ret = max_tcpci_write8(chip, TCPC_ALERT_EXTENDED, 0xff); + if (ret < 0) { + dev_err(chip->dev, "Unable to clear TCPC_ALERT_EXTENDED ret:%d\n", ret); + return; + } + alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED | TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS | - TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS; + TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS | + /* Enable Extended alert for detecting Fast Role Swap Signal */ + TCPC_ALERT_EXTND; ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask); if (ret < 0) { - dev_err(chip->dev, "Error writing to TCPC_ALERT_MASK ret:%d\n", ret); + dev_err(chip->dev, + "Error enabling TCPC_ALERT: TCPC_ALERT_MASK write failed ret:%d\n", ret); return; } @@ -122,6 +131,10 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip) dev_err(chip->dev, "Error writing to TCPC_POWER_CTRL ret:%d\n", ret); return; } + + ret = max_tcpci_write8(chip, TCPC_ALERT_EXTENDED_MASK, TCPC_SINK_FAST_ROLE_SWAP); + if (ret < 0) + return; } static void process_rx(struct max_tcpci_chip *chip, u16 status) @@ -225,10 +238,23 @@ static void process_power_status(struct max_tcpci_chip *chip) if (ret < 0) return; - if (pwr_status == 0xff) + if (pwr_status == 0xff) { max_tcpci_init_regs(chip); - else + } else if (pwr_status & TCPC_POWER_STATUS_SOURCING_VBUS) { + tcpm_sourcing_vbus(chip->port); + /* + * Alawys re-enable boost here. + * In normal case, when say an headset is attached, TCPM would + * have instructed to TCPC to enable boost, so the call is a + * no-op. + * But for Fast Role Swap case, Boost turns on autonomously without + * AP intervention, but, needs AP to enable source mode explicitly + * for AP to regain control. + */ + max_tcpci_set_vbus(chip->tcpci, &chip->data, true, false); + } else { tcpm_vbus_change(chip->port); + } } static void process_tx(struct max_tcpci_chip *chip, u16 status) @@ -249,6 +275,7 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status) { u16 mask; int ret; + u8 reg_status; /* * Clear alert status for everything except RX_STATUS, which shouldn't @@ -274,6 +301,21 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status) } } + if (status & TCPC_ALERT_EXTND) { + ret = max_tcpci_read8(chip, TCPC_ALERT_EXTENDED, ®_status); + if (ret < 0) + return ret; + + ret = max_tcpci_write8(chip, TCPC_ALERT_EXTENDED, reg_status); + if (ret < 0) + return ret; + + if (reg_status & TCPC_SINK_FAST_ROLE_SWAP) { + dev_info(chip->dev, "FRS Signal"); + tcpm_sink_frs(chip->port); + } + } + if (status & TCPC_ALERT_RX_STATUS) process_rx(chip, status); From patchwork Mon Sep 21 19:55:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790823 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2ACBA139F for ; Mon, 21 Sep 2020 19:56:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 06BC52193E for ; Mon, 21 Sep 2020 19:56:43 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="UpV3Hicb" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728393AbgIUT4g (ORCPT ); Mon, 21 Sep 2020 15:56:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35588 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728328AbgIUT4X (ORCPT ); Mon, 21 Sep 2020 15:56:23 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 30467C0613D8 for ; Mon, 21 Sep 2020 12:56:21 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id 140so12863990ybf.2 for ; Mon, 21 Sep 2020 12:56:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=PpfXbwP5h561OnIXDrzldax9t/sUHIL5wMhDCaaaIt8=; b=UpV3Hicb3hTUuqUhuf+XEZX4SNcRpCJLpT0XnZc6eMzGRt6lOz8zyAPmKCeye2TOOn t7mDyGPGlBkjWpQSTz81abNXTim4uFIDf9SetTi9i39jnuCR14bWaBBzxO01/6hQH297 kBqRlxGWPi0CDmpi8nbrcjBcQcJDOzS0B3+tpYYqx070dKnb9D8TDYOXGyrD96Xz6yQp Yzt4cPn9KgSnsOXYv13hKIyprBBPkZ8v+D2/JPmXLWlDOm3uGwzkMZbqBNcbnk2a8r6t LKu2y58wMRG44TtHyYuBdeDMT/vJCyW8mFkZJx81DfF7sK2EeFhBkQLkupFbumP7I/6D 4Kfw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=PpfXbwP5h561OnIXDrzldax9t/sUHIL5wMhDCaaaIt8=; b=SL7VK8RpADu0gwYuzw5+wb/6C/UiygX3PENkQuWmzHYX/NYUEA84UJ8s2m2T0QONC8 KUUe/gzFlkxO1ixIEC52GqqGIA4Gvse0E/8o288KbtI48hnzrHKCQ4fMY8umYV4tvobP 9EAU4osnGDqErV7+O3Xr0LnVYfWMExR3vuJsqaw0KxCrSAftjrIsVD9qmGt6xhzskwyv HC6r9hSiAvzS3IBoqv+nrhjqUD4mpBNzROkNEKJkZjyxqSf5FhJziGKmm67dCnRXHq4m vYZaP/e49C1CNVeqqZtgEmQTXBcbVffBSjtSsuclD71XUJsrA9LHCeR3M/H/6mOZRHdw kfeg== X-Gm-Message-State: AOAM530I62GtpAwjXhHKsCbfHo5Dp4PZYHfL79gYrXQLZrUCp5dMs1RV 4KFUIpVX0fCRFWCISSDxqoiLQ1wE8Xw= X-Google-Smtp-Source: ABdhPJyyHgl5vZ2F2DjF/eQZyiOiGSCC2TgiZ3KwSfW+7TuMzC+cnMAo8DZM/Z7aLGtBvV8wdzuD+sZguSQ= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a25:d950:: with SMTP id q77mr2161784ybg.402.1600718180389; Mon, 21 Sep 2020 12:56:20 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:53 -0700 In-Reply-To: <20200921195555.1050731-1-badhri@google.com> Message-Id: <20200921195555.1050731-9-badhri@google.com> Mime-Version: 1.0 References: <20200921195555.1050731-1-badhri@google.com> X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 09/11] usb: typec: tcpm: Implement enabling Auto Discharge disconnect support From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org TCPCI spec allows TCPC hardware to autonomously discharge the vbus capacitance upon disconnect. The expectation is that the TCPM enables AutoDischargeDisconnect while entering SNK/SRC_ATTACHED states. Hardware then automously discharges vbus when the vbus falls below a certain threshold i.e. VBUS_SINK_DISCONNECT_THRESHOLD. Apart from enabling the vbus discharge circuit, AutoDischargeDisconnect is also used a flag to move TCPCI based TCPC implementations into Attached.Snk/Attached.Src state as mentioned in Figure 4-15. TCPC State Diagram before a Connection of the USB Type-C Port Controller Interface Specification. In such TCPC implementations, setting AutoDischargeDisconnect would prevent TCPC into entering "Connection_Invalid" state as well. Signed-off-by: Badhri Jagan Sridharan --- Changes since v1: - Changing patch version to v6 to fix version number confusion. Changes since v6: - Fixed incorrect data_role error that I introduced by mistake in the previous version. Changes since v7: - Rebase on usb-next --- drivers/usb/typec/tcpm/tcpm.c | 74 +++++++++++++++++++++++++++++++++-- include/linux/usb/tcpm.h | 16 ++++++++ 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 55535c4f66bf..d6b2a757a564 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -1706,6 +1706,25 @@ static void tcpm_handle_alert(struct tcpm_port *port, const __le32 *payload, } } +static int tcpm_set_auto_vbus_discharge_threshold(struct tcpm_port *port, enum typec_role port_role, + enum typec_pwr_opmode mode, bool pps_active, + u32 requested_vbus_voltage) +{ + int ret; + + if (!port->tcpc->set_auto_vbus_discharge_threshold) + return 0; + + ret = port->tcpc->set_auto_vbus_discharge_threshold(port->tcpc, port_role, mode, pps_active, + requested_vbus_voltage); + tcpm_log_force(port, + "set_auto_vbus_discharge_threshold pwr_role:%s mode:%d pps_active:%c vbus:%u ret:%d", + port_role == TYPEC_SINK ? "sink" : "source", mode, pps_active ? 'y' : 'n', + requested_vbus_voltage, ret); + + return ret; +} + static void tcpm_pd_data_request(struct tcpm_port *port, const struct pd_message *msg) { @@ -1875,6 +1894,10 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, port->current_limit, port->supply_voltage); port->explicit_contract = true; + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SINK, + TYPEC_PWR_MODE_PD, + port->pps_data.active, + port->supply_voltage); tcpm_set_state(port, SNK_READY, 0); } else { /* @@ -2789,8 +2812,14 @@ static int tcpm_src_attach(struct tcpm_port *port) if (ret < 0) return ret; - ret = tcpm_set_roles(port, true, TYPEC_SOURCE, - tcpm_data_role_for_source(port)); + if (port->tcpc->enable_auto_vbus_discharge) { + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SOURCE, 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); + } + + ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port)); if (ret < 0) return ret; @@ -2857,6 +2886,12 @@ static void tcpm_unregister_altmodes(struct tcpm_port *port) static void tcpm_reset_port(struct tcpm_port *port) { + int ret; + + 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); + } tcpm_unregister_altmodes(port); tcpm_typec_disconnect(port); port->attached = false; @@ -2921,8 +2956,14 @@ static int tcpm_snk_attach(struct tcpm_port *port) if (ret < 0) return ret; - ret = tcpm_set_roles(port, true, TYPEC_SINK, - tcpm_data_role_for_sink(port)); + if (port->tcpc->enable_auto_vbus_discharge) { + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SINK, 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); + } + + ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port)); if (ret < 0) return ret; @@ -3482,6 +3523,8 @@ static void run_state_machine(struct tcpm_port *port) * drive VBUS to vSafe0V as shown in Figure 7-9. */ tcpm_set_vconn(port, false); + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SOURCE, TYPEC_PWR_MODE_USB, + false, 0); tcpm_set_vbus(port, false); tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE, tcpm_data_role_for_source(port)); @@ -3503,9 +3546,13 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_vbus(port, true); port->tcpc->set_pd_rx(port->tcpc, true); tcpm_set_attached_state(port, true); + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SOURCE, TYPEC_PWR_MODE_USB, + false, VSAFE5V); tcpm_set_state(port, SRC_UNATTACHED, PD_T_PS_SOURCE_ON); break; case SNK_HARD_RESET_SINK_OFF: + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SINK, TYPEC_PWR_MODE_USB, false, + 0); memset(&port->pps_data, 0, sizeof(port->pps_data)); tcpm_set_vconn(port, false); if (port->pd_capable) @@ -3548,6 +3595,8 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_charge(port, true); } tcpm_set_attached_state(port, true); + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SINK, TYPEC_PWR_MODE_USB, false, + VSAFE5V); tcpm_set_state(port, SNK_STARTUP, 0); break; @@ -3649,6 +3698,12 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, PR_SWAP_SNK_SRC_SINK_OFF, 0); break; case PR_SWAP_SRC_SNK_TRANSITION_OFF: + /* + * Prevent vbus discharge circuit from turning on during PR_SWAP + * as this is not a disconnect. + */ + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SOURCE, TYPEC_PWR_MODE_USB, + port->pps_data.active, 0); tcpm_set_vbus(port, false); port->explicit_contract = false; /* allow time for Vbus discharge, must be < tSrcSwapStdby */ @@ -3677,9 +3732,18 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state_cond(port, SNK_UNATTACHED, PD_T_PS_SOURCE_ON); break; case PR_SWAP_SRC_SNK_SINK_ON: + /* Set the vbus disconnect threshold for implicit contract */ + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SINK, TYPEC_PWR_MODE_USB, false, + VSAFE5V); tcpm_set_state(port, SNK_STARTUP, 0); break; case PR_SWAP_SNK_SRC_SINK_OFF: + /* + * Prevent vbus discharge circuit from turning on during PR_SWAP + * as this is not a disconnect. + */ + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SINK, TYPEC_PWR_MODE_USB, + port->pps_data.active, 0); tcpm_set_charge(port, false); tcpm_set_state(port, hard_reset_state(port), PD_T_PS_SOURCE_OFF); @@ -3705,6 +3769,8 @@ static void run_state_machine(struct tcpm_port *port) */ tcpm_set_pwr_role(port, TYPEC_SOURCE); tcpm_pd_send_control(port, PD_CTRL_PS_RDY); + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_SOURCE, TYPEC_PWR_MODE_USB, + false, VSAFE5V); tcpm_set_state(port, SRC_STARTUP, PD_T_SWAP_SRC_START); break; diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h index 09762d26fa0c..a1707def51c3 100644 --- a/include/linux/usb/tcpm.h +++ b/include/linux/usb/tcpm.h @@ -83,6 +83,18 @@ enum tcpm_transmit_type { * Optional; Called to enable/disable PD 3.0 fast role swap. * Enabling frs is accessory dependent as not all PD3.0 * accessories support fast role swap. + * @enable_auto_vbus_discharge: + * Optional; TCPCI spec based TCPC implementations can optionally + * support hardware to autonomously dischrge vbus upon disconnecting + * as sink or source. TCPM signals TCPC to enable the mechanism upon + * entering connected state and signals disabling upon disconnect. + * @set_auto_vbus_discharge_threshold: + * Mandatory when enable_auto_vbus_discharge is implemented. TCPM + * calls this function to allow lower levels drivers to program the + * vbus threshold voltage below which the vbus discharge circuit + * will be turned on. requested_vbus_voltage is set to 0 when vbus + * is going to disappear knowingly i.e. during PR_SWAP and + * HARD_RESET etc. */ struct tcpc_dev { struct fwnode_handle *fwnode; @@ -109,6 +121,10 @@ struct tcpc_dev { const struct pd_message *msg); int (*set_bist_data)(struct tcpc_dev *dev, bool on); int (*enable_frs)(struct tcpc_dev *dev, bool enable); + int (*enable_auto_vbus_discharge)(struct tcpc_dev *dev, bool enable); + int (*set_auto_vbus_discharge_threshold)(struct tcpc_dev *dev, enum typec_role port_role, + enum typec_pwr_opmode mode, bool pps_active, + u32 requested_vbus_voltage); }; struct tcpm_port; From patchwork Mon Sep 21 19:55:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790815 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8BD83139F for ; Mon, 21 Sep 2020 19:56:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6C01822262 for ; Mon, 21 Sep 2020 19:56:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Vww2+/C0" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728347AbgIUT4Y (ORCPT ); Mon, 21 Sep 2020 15:56:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35592 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728334AbgIUT4X (ORCPT ); Mon, 21 Sep 2020 15:56:23 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8D961C0613DA for ; Mon, 21 Sep 2020 12:56:23 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id i23so492864pju.7 for ; Mon, 21 Sep 2020 12:56:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=Od9yElV1P9nOtF+n66V3yXmKIpojTRtnzHLfBefsfwo=; b=Vww2+/C0IkDqNnyGXH1GAHujyibguHDsm4lLK8VjE+c7UnUjUtzOq5UB30F70tFphG swKndRU0R/ZbhLJHAckgcicxC+lZAANZ8JZXwsxBity7k6JIQInaWDzKnqmgTZnjuBKU 1ySuxz9fNDJ+PPq5NuaQMvmyL0zBeXXDV/JnS1nd+a3TJli3bA6N/sdrH/rJAsdrlzLo YryjCvvn/B5WXJ8HXaPfvpjlImSzkjYiV8DtZRlXbz0L4fZ57taDPn4VZmWV8LE36uyz zhJpPPo7/tm5womydtGBB0XQ5tWQxu7WYOJSLoKxaNvAt9d2SkUV+U6eNEzYT0pN9j3P VVFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=Od9yElV1P9nOtF+n66V3yXmKIpojTRtnzHLfBefsfwo=; b=ph/60ZAtuW4+fRbJTa5XQbDNo37FuFyQIm8HuxXxTWcCrszmUhOLYxPAt4A+bGfF7j 6tWv4hMggZe0gDvJcw9mSmteudNISsd8jJ9YVi8/KnQd+ikDB06m+Eed8iwc/1YKfSvN XAR/bata0hIfl/dlTlosJ0KK0KC2ojU9mi/rM46zHOZdHK/PjxZmfMQchoekOl8ezLNh tn2PKrujETYEz4vRvXLhZ+Jt28n1c2YUeLLhezFu3sBZyiw1sSihqhbfyXBg6oqds4+n yKxzQUEkr4nf9JM9HwBwxWaAimTp8QxLaxYIRkJ2Q7ePL2zTA3NjpowtJJ6CI9+gzBtE DEyQ== X-Gm-Message-State: AOAM530eMfJ383Dn+gLsbD5IdzNnvPLBpmCwc7wEEtXjFp4ljbkumcNP eNmzEykG/Pscp8y2bEr+KU6/pzQXeRg= X-Google-Smtp-Source: ABdhPJyRKWIhRYoXSiKYNl0C/5q5JrF4gGPkiq+w/miU7Llsu5J9c/kNjGVyXw2U2OY39CC+V4PdLBwJf1I= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a17:902:6b05:b029:d0:a100:8365 with SMTP id o5-20020a1709026b05b02900d0a1008365mr1457888plk.11.1600718182548; Mon, 21 Sep 2020 12:56:22 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:54 -0700 In-Reply-To: <20200921195555.1050731-1-badhri@google.com> Message-Id: <20200921195555.1050731-10-badhri@google.com> Mime-Version: 1.0 References: <20200921195555.1050731-1-badhri@google.com> X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 10/11] usb: typec: tcpci: Implement Auto discharge disconnect callbacks From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Implement callbacks for enabling/disabling POWER_CONTROL.AutoDischargeDisconnect. TCPCI spec allows TCPC hardware to autonomously discharge the vbus capacitance upon disconnect. The expectation is that the TCPM enables AutoDischargeDisconnect while entering SNK/SRC_ATTACHED states. Hardware then automously discharges vbus when the vbus falls below a certain threshold i.e. VBUS_SINK_DISCONNECT_THRESHOLD. Apart from enabling the vbus discharge circuit, AutoDischargeDisconnect is also used a flag to move TCPCI based TCPC implementations into Attached.Snk/Attached.Src state as mentioned in Figure 4-15. TCPC State Diagram before a Connection of the USB Type-C Port Controller Interface Specification. In such TCPC implementations, setting AutoDischargeDisconnect would prevent TCPC into entering "Connection_Invalid" state as well. Signed-off-by: Badhri Jagan Sridharan --- Changes since v1: - Changing patch version to v6 to fix version number confusion. Changes since v6: - Rebase on usb-next. Changes since v7: Heikki's suggestion: - Moved the actual write to TCPC_VBUS_SINK_DISCONNECT_THRESH as it's common to all chip drivers. - Renaming the tcpci_data callback as get_auto_vbus_discharge_threshold --- drivers/usb/typec/tcpm/tcpci.c | 48 ++++++++++++++++++++++++++++++++++ drivers/usb/typec/tcpm/tcpci.h | 22 ++++++++++++++-- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index f9f0af64da5f..dca21cd5873e 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -268,6 +268,48 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable) enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0); } +static int tcpci_enable_auto_vbus_discharge(struct tcpc_dev *dev, bool enable) +{ + struct tcpci *tcpci = tcpc_to_tcpci(dev); + int ret; + + ret = regmap_update_bits(tcpci->regmap, TCPC_POWER_CTRL, TCPC_POWER_CTRL_AUTO_DISCHARGE, + enable ? TCPC_POWER_CTRL_AUTO_DISCHARGE : 0); + return ret; +} + +static int tcpci_set_auto_vbus_discharge_threshold(struct tcpc_dev *dev, enum typec_role port_role, + enum typec_pwr_opmode mode, bool pps_active, + u32 requested_vbus_voltage_mv) +{ + struct tcpci *tcpci = tcpc_to_tcpci(dev); + u32 (*get_auto_vbus_threshold)(struct tcpci *tcpci, struct tcpci_data *data, + enum typec_role port_role, enum typec_pwr_opmode mode, + bool pps_active, u32 requested_vbus_voltage_mv); + + get_auto_vbus_threshold = tcpci->data->get_auto_vbus_discharge_threshold; + if (get_auto_vbus_threshold) { + u32 threshold; + u16 val; + + /* + * Indicates that vbus is going to go away due PR_SWAP, hard reset etc. + * Do not discharge vbus here. + */ + threshold = requested_vbus_voltage_mv ? + get_auto_vbus_threshold(tcpci, tcpci->data, port_role, mode, pps_active, + requested_vbus_voltage_mv) : 0; + + val = threshold / TCPC_VBUS_SINK_DISCONNECT_THRESH_LSB_MV; + if (val > TCPC_VBUS_SINK_DISCONNECT_THRESH_MAX) + return -EINVAL; + + return tcpci_write16(tcpci, TCPC_VBUS_SINK_DISCONNECT_THRESH, val); + } + + return 0; +} + static int tcpci_enable_frs(struct tcpc_dev *dev, bool enable) { struct tcpci *tcpci = tcpc_to_tcpci(dev); @@ -629,6 +671,12 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data) tcpci->tcpc.set_bist_data = tcpci_set_bist_data; tcpci->tcpc.enable_frs = tcpci_enable_frs; + if (tcpci->data->auto_discharge_disconnect) { + tcpci->tcpc.enable_auto_vbus_discharge = tcpci_enable_auto_vbus_discharge; + tcpci->tcpc.set_auto_vbus_discharge_threshold = + tcpci_set_auto_vbus_discharge_threshold; + } + err = tcpci_parse_config(tcpci); if (err < 0) return ERR_PTR(err); diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h index 5ef07a56d67a..406dfb53f492 100644 --- a/drivers/usb/typec/tcpm/tcpci.h +++ b/drivers/usb/typec/tcpm/tcpci.h @@ -8,6 +8,8 @@ #ifndef __LINUX_USB_TCPCI_H #define __LINUX_USB_TCPCI_H +#include + #define TCPC_VENDOR_ID 0x0 #define TCPC_PRODUCT_ID 0x2 #define TCPC_BCD_DEV 0x4 @@ -67,6 +69,7 @@ #define TCPC_POWER_CTRL 0x1c #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0) +#define TCPC_POWER_CTRL_AUTO_DISCHARGE BIT(4) #define TCPC_FAST_ROLE_SWAP_EN BIT(7) #define TCPC_CC_STATUS 0x1d @@ -133,6 +136,8 @@ #define TCPC_VBUS_VOLTAGE 0x70 #define TCPC_VBUS_SINK_DISCONNECT_THRESH 0x72 +#define TCPC_VBUS_SINK_DISCONNECT_THRESH_LSB_MV 25 +#define TCPC_VBUS_SINK_DISCONNECT_THRESH_MAX 0x3ff #define TCPC_VBUS_STOP_DISCHARGE_THRESH 0x74 #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76 #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78 @@ -140,20 +145,33 @@ /* I2C_WRITE_BYTE_COUNT + 1 when TX_BUF_BYTE_x is only accessible I2C_WRITE_BYTE_COUNT */ #define TCPC_TRANSMIT_BUFFER_MAX_LEN 31 +struct tcpci; + /* - * @TX_BUF_BYTE_x_hidden + * @TX_BUF_BYTE_x_hidden: * optional; Set when TX_BUF_BYTE_x can only be accessed through I2C_WRITE_BYTE_COUNT. + * @auto_discharge_disconnect: + * Optional; Enables TCPC to autonously discharge vbus on disconnect. + * @set_auto_vbus_discharge_threshold: + * Mandatory when @auto_discharge_disconnect is sets. Allows + * programming the voltage threshold of vbus below which TCPC + * enables the vbus discharge circuit. */ -struct tcpci; struct tcpci_data { struct regmap *regmap; unsigned char TX_BUF_BYTE_x_hidden:1; + unsigned char auto_discharge_disconnect:1; + int (*init)(struct tcpci *tcpci, struct tcpci_data *data); int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data, bool enable); int (*start_drp_toggling)(struct tcpci *tcpci, struct tcpci_data *data, enum typec_cc_status cc); int (*set_vbus)(struct tcpci *tcpci, struct tcpci_data *data, bool source, bool sink); + u32 (*get_auto_vbus_discharge_threshold)(struct tcpci *tcpci, struct tcpci_data *data, + enum typec_role port_role, + enum typec_pwr_opmode mode, bool pps_active, + u32 requested_vbus_voltage); }; struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data); From patchwork Mon Sep 21 19:55:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Badhri Jagan Sridharan X-Patchwork-Id: 11790817 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 482D4139A for ; Mon, 21 Sep 2020 19:56:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2F71A2193E for ; Mon, 21 Sep 2020 19:56:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="t+GNICct" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728373AbgIUT42 (ORCPT ); Mon, 21 Sep 2020 15:56:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35602 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728281AbgIUT4Z (ORCPT ); Mon, 21 Sep 2020 15:56:25 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 36058C0613D0 for ; Mon, 21 Sep 2020 12:56:25 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id t201so9492111pfc.13 for ; Mon, 21 Sep 2020 12:56:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=AWunavfjR2h7DGqJnJiiTrYCviYOJo4UjdEoDLbILJA=; b=t+GNICctCeMjWN/pUlO1D6VvqfujACAsEcklfpybyR5nZwW6Sdy0QnYyrhBPaIC5t6 H14TSCQ9hvaKthS+0J7iv7W3S124LYUJjIn8tSybY1iBuhwhcstsGAGXxx+MKSl2D5rV x1qT8rzCzrzUfHdbRpVEMzO2Qsz4WKJ9sZmwktYdUXjte3x4jHDV1Q0DmCa6LCZP+WRU R7RJapDAJZCi5xkL+gOGg/vHjK0TzMA/4Ts41bi+x6kJuPbS8cgPiaZYtFuBwKSTQME5 AJaWthUeIzVlaBTWgTi0277fp+iOysN3yPiFmUvkI2KLp+ByLyegHYOBacsvUPov1VNU vNXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=AWunavfjR2h7DGqJnJiiTrYCviYOJo4UjdEoDLbILJA=; b=EDGTKI+a6aX7DwXKCN7lWQbyfpe/4S+BDPSg6pDdcd9piJfiEfBw5FwigjpH8g6QBT JvA7VNH+mRAjmiR4ndYQzzFoOEeItUmFyx7bt2L8MHCipth8uyM7YWlsOXr5PKLwdNst 9xjCbb/QqWRMt6QsK/pX65YnODXruDBgltssMvJcYpXpft+G6/dFyFa1wagrL6SYORWC n0SgCfgbCfbCF2IfGfO8uCDo3/ij3VogCZeWYt02G1AMf93VnQDhVMBldaL3ArEfqCyy apGCNt0VdWVTQh3g50q8AJFzw8W01Wp+pGQ+0sWTFVtXbTMT8vDeZm6RA1Ls/qwWF5BB hugw== X-Gm-Message-State: AOAM533aykjpWz6b1NF/+GW5NWwypVmNqumwvQ3Dm0BId+y4ESUdaIsI l0NJfES3agYdQCVL5da1lWH6Dn68KkE= X-Google-Smtp-Source: ABdhPJw68r3Flh7t8b0dWbxHTV0lK3ldYw/oSD30QlZuU6Hf9NnbdqD72KDkJsC1TlfmPRXRzX3WdKSiQew= Sender: "badhri via sendgmr" X-Received: from badhri.mtv.corp.google.com ([2620:15c:211:1:f292:1cff:fee0:66cf]) (user=badhri job=sendgmr) by 2002:a17:902:d68c:b029:d2:23a6:f6d7 with SMTP id v12-20020a170902d68cb02900d223a6f6d7mr1462202ply.45.1600718184724; Mon, 21 Sep 2020 12:56:24 -0700 (PDT) Date: Mon, 21 Sep 2020 12:55:55 -0700 In-Reply-To: <20200921195555.1050731-1-badhri@google.com> Message-Id: <20200921195555.1050731-11-badhri@google.com> Mime-Version: 1.0 References: <20200921195555.1050731-1-badhri@google.com> X-Mailer: git-send-email 2.28.0.681.g6f77f65b4e-goog Subject: [PATCH v8 11/11] usb: typec: tcpci_maxim: Implemnent set_auto_vbus_discharge_threshold From: Badhri Jagan Sridharan To: Guenter Roeck , Heikki Krogerus , Greg Kroah-Hartman , Rob Herring , Lee Jones , Mark Brown , Maxime Ripard , Alexandre Belloni , Thierry Reding , Prashant Malani , Badhri Jagan Sridharan Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Programs VBUS_SINK_DISCONNECT_THRESHOLD based on the power_role, voltage requested as sink, mode of operation. The programmed threshold is based on vSinkDisconnect and vSinkDisconnectPD values. Signed-off-by: Badhri Jagan Sridharan --- Changes since v1: - Changing patch version to v6 to fix version number confusion. Changes since v6: - Rebase on usb-next. Changes since v7: - Heikki's suggestion: Moved the actual write of TCPC_VBUS_SINK_DISCONNECT_THRES register to tcpci code. --- drivers/usb/typec/tcpm/tcpci_maxim.c | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.c b/drivers/usb/typec/tcpm/tcpci_maxim.c index 723d7dd38f75..329138622cc9 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim.c +++ b/drivers/usb/typec/tcpm/tcpci_maxim.c @@ -137,6 +137,37 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip) return; } +u32 max_tcpci_get_auto_vbus_discharge_threshold(struct tcpci *tcpci, struct tcpci_data *data, + enum typec_role port_role, + enum typec_pwr_opmode mode, bool pps_active, + u32 requested_vbus_voltage_mv) +{ + struct max_tcpci_chip *chip = tdata_to_max_tcpci(data); + u32 threshold = 0; + u8 pwr_ctrl; + + if (port_role == TYPEC_SINK) { + max_tcpci_read8(chip, TCPC_POWER_CTRL, &pwr_ctrl); + if (pwr_ctrl & TCPC_FAST_ROLE_SWAP_EN) { + /* To prevent disconnect when the source is fast role swap is capable. */ + threshold = 3500; + } else if (mode == TYPEC_PWR_MODE_PD) { + if (pps_active) + threshold = (95 * requested_vbus_voltage_mv / 100) - 850; + else + threshold = (95 * requested_vbus_voltage_mv / 100) - 1250; + } else { + /* 3.5V for non-pd sink */ + threshold = 3500; + } + } else { + /* 4V for source */ + threshold = 4000; + } + + return threshold; +} + static void process_rx(struct max_tcpci_chip *chip, u16 status) { struct pd_message msg; @@ -441,6 +472,8 @@ static int max_tcpci_probe(struct i2c_client *client, const struct i2c_device_id chip->data.start_drp_toggling = max_tcpci_start_toggling; chip->data.TX_BUF_BYTE_x_hidden = true; chip->data.init = tcpci_init; + chip->data.get_auto_vbus_discharge_threshold = max_tcpci_get_auto_vbus_discharge_threshold; + chip->data.auto_discharge_disconnect = true; max_tcpci_init_regs(chip); chip->tcpci = tcpci_register_port(chip->dev, &chip->data);