[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251201122604.1268071-6-akuchynski@chromium.org>
Date: Mon, 1 Dec 2025 12:26:01 +0000
From: Andrei Kuchynski <akuchynski@...omium.org>
To: Heikki Krogerus <heikki.krogerus@...ux.intel.com>,
Abhishek Pandit-Subedi <abhishekpandit@...omium.org>,
Benson Leung <bleung@...omium.org>,
Jameson Thies <jthies@...gle.com>,
Tzung-Bi Shih <tzungbi@...nel.org>,
linux-usb@...r.kernel.org,
chrome-platform@...ts.linux.dev
Cc: Guenter Roeck <groeck@...omium.org>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Dmitry Baryshkov <dmitry.baryshkov@....qualcomm.com>,
"Christian A. Ehrhardt" <lk@...e.de>,
Abel Vesa <abel.vesa@...aro.org>,
Pooja Katiyar <pooja.katiyar@...el.com>,
Pavan Holla <pholla@...omium.org>,
Madhu M <madhu.m@...el.com>,
Venkat Jayaraman <venkat.jayaraman@...el.com>,
linux-kernel@...r.kernel.org,
Andrei Kuchynski <akuchynski@...omium.org>
Subject: [PATCH RFC 5/8] usb: typec: ucsi: Enforce mode selection for cros_ec_ucsi
The mode selection sequence is initiated by the driver after all partner
alternate modes have been successfully registered.
To prevent the Power Delivery Controller (PDC) from activating alternate
modes, the driver disables all alternate modes on the connector:
- During the connector registration
- Upon partner disconnection
When a partner is disconnected, the driver also stops the mode selection
process and releases resources via `typec_mode_selection_delete`.
Signed-off-by: Andrei Kuchynski <akuchynski@...omium.org>
---
drivers/usb/typec/ucsi/cros_ec_ucsi.c | 44 +++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/drivers/usb/typec/ucsi/cros_ec_ucsi.c b/drivers/usb/typec/ucsi/cros_ec_ucsi.c
index d753f2188e25..988a159ed778 100644
--- a/drivers/usb/typec/ucsi/cros_ec_ucsi.c
+++ b/drivers/usb/typec/ucsi/cros_ec_ucsi.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/wait.h>
+#include <linux/usb/typec_altmode.h>
#include "ucsi.h"
@@ -33,6 +34,11 @@
/* Number of times to attempt recovery from a write timeout before giving up. */
#define WRITE_TMO_CTR_MAX 5
+/* Delay between mode entry/exit attempts, ms */
+static const unsigned int mode_selection_delay = 1000;
+/* Timeout for a mode entry attempt, ms */
+static const unsigned int mode_selection_timeout = 4000;
+
struct cros_ucsi_data {
struct device *dev;
struct ucsi *ucsi;
@@ -133,6 +139,41 @@ static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci)
return ret;
}
+static void cros_ucsi_disable_altmodes(struct ucsi_connector *con)
+{
+ struct cros_ucsi_data *udata = ucsi_get_drvdata(con->ucsi);
+ u64 command = UCSI_SET_NEW_CAM | UCSI_CONNECTOR_NUMBER(con->num) |
+ UCSI_SET_NEW_CAM_SET_AM((u64)0xFF);
+ int ret;
+
+ con->ucsi->message_in_size = 0;
+ ret = ucsi_send_command(con->ucsi, command);
+ if (ret < 0)
+ dev_err(udata->dev,
+ "Unable to disable alt-modes on port %d\n", con->num);
+}
+
+static void cros_ucsi_update_connector(struct ucsi_connector *con)
+{
+ if (con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE)
+ cros_ucsi_disable_altmodes(con);
+}
+
+static void cros_ucsi_add_partner_altmodes(struct ucsi_connector *con)
+{
+ if (con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE)
+ typec_mode_selection_start(con->partner,
+ mode_selection_delay, mode_selection_timeout);
+}
+
+static void cros_ucsi_remove_partner_altmodes(struct ucsi_connector *con)
+{
+ if (con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE) {
+ typec_mode_selection_delete(con->partner);
+ cros_ucsi_disable_altmodes(con);
+ }
+}
+
static const struct ucsi_operations cros_ucsi_ops = {
.read_version = cros_ucsi_read_version,
.read_cci = cros_ucsi_read_cci,
@@ -140,6 +181,9 @@ static const struct ucsi_operations cros_ucsi_ops = {
.read_message_in = cros_ucsi_read_message_in,
.async_control = cros_ucsi_async_control,
.sync_control = cros_ucsi_sync_control,
+ .update_connector = cros_ucsi_update_connector,
+ .add_partner_altmodes = cros_ucsi_add_partner_altmodes,
+ .remove_partner_altmodes = cros_ucsi_remove_partner_altmodes,
};
static void cros_ucsi_work(struct work_struct *work)
--
2.52.0.158.g65b55ccf14-goog
Powered by blists - more mailing lists