]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
usb: typec: ucsi: Enforce mode selection for cros_ec_ucsi
authorAndrei Kuchynski <akuchynski@chromium.org>
Mon, 19 Jan 2026 13:18:24 +0000 (13:18 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 Jan 2026 16:18:01 +0000 (17:18 +0100)
The mode selection sequence is initiated by the driver after all partner
alternate modes have been successfully registered.
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@chromium.org>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://patch.msgid.link/20260119131824.2529334-8-akuchynski@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/ucsi/cros_ec_ucsi.c

index eed2a7d0ebc634723d05004f6a5ea378a75b25d1..6bca2dce211cd003460777414f579c63e3f74757 100644 (file)
@@ -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"
 
 /* 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;
@@ -134,6 +140,20 @@ static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci,
        return ret;
 }
 
+static void cros_ucsi_add_partner_altmodes(struct ucsi_connector *con)
+{
+       if (!con->typec_cap.no_mode_control)
+               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->typec_cap.no_mode_control)
+               typec_mode_selection_delete(con->partner);
+}
+
 static const struct ucsi_operations cros_ucsi_ops = {
        .read_version = cros_ucsi_read_version,
        .read_cci = cros_ucsi_read_cci,
@@ -141,6 +161,8 @@ 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,
+       .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)