From patchwork Fri Mar 17 10:42:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Alvin_=C5=A0ipraga?= X-Patchwork-Id: 664970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AB48CC6FD1D for ; Fri, 17 Mar 2023 10:42:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229539AbjCQKm5 (ORCPT ); Fri, 17 Mar 2023 06:42:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33590 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230089AbjCQKmv (ORCPT ); Fri, 17 Mar 2023 06:42:51 -0400 Received: from mail-ed1-x52c.google.com (mail-ed1-x52c.google.com [IPv6:2a00:1450:4864:20::52c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6F90BB4217 for ; Fri, 17 Mar 2023 03:42:46 -0700 (PDT) Received: by mail-ed1-x52c.google.com with SMTP id x13so18656537edd.1 for ; Fri, 17 Mar 2023 03:42:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pqrs.dk; s=google; t=1679049765; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=4mzN/37UoYXUZaB9D3Kvm+oDNKKugvTJRDf02rBTRys=; b=mbOx0ApqHiRq7wPARubyIPBIX+wNc6krXZwwVEumSxZJMbtTu7p6cgaitvyO6C+SMb E0pjhB6uenC5fFMCQr0d3vw5ml2WQ1A08n2ba0WAF1QJ7h2wlgnVilM0xOBC8a08dFSH 83A/pM2xDe/8im3WqN9Cs9UHF4/zFemO9PZ/c= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1679049765; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=4mzN/37UoYXUZaB9D3Kvm+oDNKKugvTJRDf02rBTRys=; b=QJjisV319AekZ1M4oBll+cHx8Ciz/8bEW/bJuE0YiUAo48Ryk0xVgmfOU005hY48qs 8nIkn7Wq9TP4yecLbm4wN66bThJQrwFSx9OqqvhcPx/ZrVUIyOmNZliBMPyzn3c+fyur k00zv7kuaQoLXTHJl8b5WsxaIBjt3b13bxPIyK0YwxgZ17R3b7AK44rxHKai9DCGuKKj AiyBtNj+EULwNNibZ3tmVKu9AqW6oqFje0jMjgMOaJmUvQSAYDyUdvbg5Jl9AbKrYfl0 49bu9HazHSZNIKyl3omVHeQtv8OfuQQPKIfWKEftCQKxJFmGFZK/Y7/1aOrnWJthZdf6 DUBw== X-Gm-Message-State: AO0yUKUTXDEU7enwmgTqZfyZLEvj4uQvdBXug56NSW34V/wRunESS5tP h/K2E6JCr2DsLkM6wJr2NXbiyw== X-Google-Smtp-Source: AK7set/A3JcjdNLJx52qZo3Imzp237XXegZMjJzgTtom2W6zEiWpF7C0hM0xWzAEz4eM3T79GXx01g== X-Received: by 2002:a17:906:4e92:b0:878:72d0:2817 with SMTP id v18-20020a1709064e9200b0087872d02817mr13248540eju.29.1679049764924; Fri, 17 Mar 2023 03:42:44 -0700 (PDT) Received: from localhost.localdomain ([193.89.194.60]) by smtp.gmail.com with ESMTPSA id e5-20020a170906314500b009236ae669ecsm816144eje.191.2023.03.17.03.42.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Mar 2023 03:42:44 -0700 (PDT) From: =?utf-8?q?Alvin_=C5=A0ipraga?= To: Heikki Krogerus , Greg Kroah-Hartman , MyungJoo Ham , Chanwoo Choi Cc: linux-usb@vger.kernel.org, =?utf-8?q?Alvin_=C5=A0ipraga?= , linux-kernel@vger.kernel.org Subject: [PATCH 1/2] extcon: usbc-tusb320: add accessory detection support Date: Fri, 17 Mar 2023 11:42:27 +0100 Message-Id: <20230317104229.1392742-1-alvin@pqrs.dk> X-Mailer: git-send-email 2.39.2 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Alvin Šipraga The TUSB320 can detect the following types of accessory: - Audio Accessory - Audio Accessory with charge-thru - Debug Accessory (DFP) - Debug Accessory (UFP) Moreover, the typec subsystem can be informed of this through the typec_set_mode() function. The information will be propagated to any linked typec muxes. Add the necessary support to the driver. Note that for the Debug Accessory modes, an educated guess was made that for the USB data role, DFP implies HOST and UFP implies DEVICE. But this might want to be made configurable at a later date. Signed-off-by: Alvin Šipraga --- v2: no change --- drivers/extcon/extcon-usbc-tusb320.c | 90 +++++++++++++++++++++------- 1 file changed, 68 insertions(+), 22 deletions(-) diff --git a/drivers/extcon/extcon-usbc-tusb320.c b/drivers/extcon/extcon-usbc-tusb320.c index 10dff1c512c4..882d1f48495e 100644 --- a/drivers/extcon/extcon-usbc-tusb320.c +++ b/drivers/extcon/extcon-usbc-tusb320.c @@ -15,6 +15,7 @@ #include #include #include +#include #define TUSB320_REG8 0x8 #define TUSB320_REG8_CURRENT_MODE_ADVERTISE GENMASK(7, 6) @@ -26,16 +27,16 @@ #define TUSB320_REG8_CURRENT_MODE_DETECT_MED 0x1 #define TUSB320_REG8_CURRENT_MODE_DETECT_ACC 0x2 #define TUSB320_REG8_CURRENT_MODE_DETECT_HI 0x3 -#define TUSB320_REG8_ACCESSORY_CONNECTED GENMASK(3, 2) +#define TUSB320_REG8_ACCESSORY_CONNECTED GENMASK(3, 1) #define TUSB320_REG8_ACCESSORY_CONNECTED_NONE 0x0 #define TUSB320_REG8_ACCESSORY_CONNECTED_AUDIO 0x4 -#define TUSB320_REG8_ACCESSORY_CONNECTED_ACC 0x5 -#define TUSB320_REG8_ACCESSORY_CONNECTED_DEBUG 0x6 +#define TUSB320_REG8_ACCESSORY_CONNECTED_ACHRG 0x5 +#define TUSB320_REG8_ACCESSORY_CONNECTED_DBGDFP 0x6 +#define TUSB320_REG8_ACCESSORY_CONNECTED_DBGUFP 0x7 #define TUSB320_REG8_ACTIVE_CABLE_DETECTION BIT(0) #define TUSB320_REG9 0x9 -#define TUSB320_REG9_ATTACHED_STATE_SHIFT 6 -#define TUSB320_REG9_ATTACHED_STATE_MASK 0x3 +#define TUSB320_REG9_ATTACHED_STATE GENMASK(7, 6) #define TUSB320_REG9_CABLE_DIRECTION BIT(5) #define TUSB320_REG9_INTERRUPT_STATUS BIT(4) @@ -250,8 +251,7 @@ static void tusb320_extcon_irq_handler(struct tusb320_priv *priv, u8 reg) { int state, polarity; - state = (reg >> TUSB320_REG9_ATTACHED_STATE_SHIFT) & - TUSB320_REG9_ATTACHED_STATE_MASK; + state = FIELD_GET(TUSB320_REG9_ATTACHED_STATE, reg); polarity = !!(reg & TUSB320_REG9_CABLE_DIRECTION); dev_dbg(priv->dev, "attached state: %s, polarity: %d\n", @@ -277,32 +277,78 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9) { struct typec_port *port = priv->port; struct device *dev = priv->dev; - u8 mode, role, state; + int typec_mode; + enum typec_role pwr_role; + enum typec_data_role data_role; + u8 state, mode, accessory; int ret, reg8; bool ori; + ret = regmap_read(priv->regmap, TUSB320_REG8, ®8); + if (ret) { + dev_err(dev, "error during reg8 i2c read, ret=%d!\n", ret); + return; + } + ori = reg9 & TUSB320_REG9_CABLE_DIRECTION; typec_set_orientation(port, ori ? TYPEC_ORIENTATION_REVERSE : TYPEC_ORIENTATION_NORMAL); - state = (reg9 >> TUSB320_REG9_ATTACHED_STATE_SHIFT) & - TUSB320_REG9_ATTACHED_STATE_MASK; - if (state == TUSB320_ATTACHED_STATE_DFP) - role = TYPEC_SOURCE; - else - role = TYPEC_SINK; + state = FIELD_GET(TUSB320_REG9_ATTACHED_STATE, reg9); + accessory = FIELD_GET(TUSB320_REG8_ACCESSORY_CONNECTED, reg8); + + switch (state) { + case TUSB320_ATTACHED_STATE_DFP: + typec_mode = TYPEC_MODE_USB2; + pwr_role = TYPEC_SOURCE; + data_role = TYPEC_HOST; + break; + case TUSB320_ATTACHED_STATE_UFP: + typec_mode = TYPEC_MODE_USB2; + pwr_role = TYPEC_SINK; + data_role = TYPEC_DEVICE; + break; + case TUSB320_ATTACHED_STATE_ACC: + /* + * Accessory detected. For debug accessories, just make some + * qualified guesses as to the role for lack of a better option. + */ + if (accessory == TUSB320_REG8_ACCESSORY_CONNECTED_AUDIO || + accessory == TUSB320_REG8_ACCESSORY_CONNECTED_ACHRG) { + typec_mode = TYPEC_MODE_AUDIO; + pwr_role = TYPEC_SINK; + data_role = TYPEC_DEVICE; + break; + } else if (accessory == + TUSB320_REG8_ACCESSORY_CONNECTED_DBGDFP) { + typec_mode = TYPEC_MODE_DEBUG; + pwr_role = TYPEC_SOURCE; + data_role = TYPEC_HOST; + break; + } else if (accessory == + TUSB320_REG8_ACCESSORY_CONNECTED_DBGUFP) { + typec_mode = TYPEC_MODE_DEBUG; + pwr_role = TYPEC_SINK; + data_role = TYPEC_DEVICE; + break; + } - typec_set_vconn_role(port, role); - typec_set_pwr_role(port, role); - typec_set_data_role(port, role == TYPEC_SOURCE ? - TYPEC_HOST : TYPEC_DEVICE); + dev_warn(priv->dev, "unexpected ACCESSORY_CONNECTED state %d\n", + accessory); - ret = regmap_read(priv->regmap, TUSB320_REG8, ®8); - if (ret) { - dev_err(dev, "error during reg8 i2c read, ret=%d!\n", ret); - return; + fallthrough; + default: + typec_mode = TYPEC_MODE_USB2; + pwr_role = TYPEC_SINK; + data_role = TYPEC_DEVICE; + break; } + typec_set_vconn_role(port, pwr_role); + typec_set_pwr_role(port, pwr_role); + typec_set_data_role(port, data_role); + typec_set_mode(port, typec_mode); + mode = FIELD_GET(TUSB320_REG8_CURRENT_MODE_DETECT, reg8); if (mode == TUSB320_REG8_CURRENT_MODE_DETECT_DEF) typec_set_pwr_opmode(port, TYPEC_PWR_MODE_USB);