[PATCH v1 1/3] usb: typec: Add helper to check cable altmode support
From: Andrei Kuchynski
Date: Thu Jun 11 2026 - 08:22:41 EST
Introduce typec_cable_altmode_unsupported function to evaluate whether an
alternate mode is restricted based on the connected cable's properties.
Implement validation logic that parses the cable's identity to catch
incompatible setups early. Alternate modes are restricted over:
- cables lacking an identity header
- passive cables with USB 2.0 speed
- active cables unless they have corresponding plugs
The function returns false if the cable is not registered or the identifier
is not set.
Signed-off-by: Andrei Kuchynski <akuchynski@xxxxxxxxxxxx>
---
drivers/usb/typec/class.c | 35 +++++++++++++++++++++++++++++++++++
include/linux/usb/typec.h | 1 +
2 files changed, 36 insertions(+)
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 0977581ad1b6e..f7f1adbaab7e6 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -1429,6 +1429,41 @@ int typec_cable_is_active(struct typec_cable *cable)
}
EXPORT_SYMBOL_GPL(typec_cable_is_active);
+/**
+ * typec_cable_altmode_unsupported - Check if a cable restricts altmode
+ * @alt: The Alternate Mode to evaluate
+ *
+ * Returns true if the connected cable is incapable of handling the altmode.
+ */
+bool typec_cable_altmode_unsupported(struct typec_altmode *alt)
+{
+ struct typec_altmode *plug;
+ struct typec_cable *cable;
+ bool unsupported = false;
+
+ plug = typec_altmode_get_plug(alt, TYPEC_PLUG_SOP_P);
+ if (plug) {
+ typec_altmode_put_plug(plug);
+ return false;
+ }
+
+ cable = typec_cable_get(typec_altmode2port(alt));
+ if (cable && cable->identity) {
+ const u32 id_header = cable->identity->id_header;
+ const u32 speed = VDO_TYPEC_CABLE_SPEED(cable->identity->vdo[0]);
+
+ if (!id_header || PD_IDH_PTYPE(id_header) == IDH_PTYPE_ACABLE)
+ unsupported = true;
+ else if (PD_IDH_PTYPE(id_header) == IDH_PTYPE_PCABLE)
+ unsupported = (speed == CABLE_USB2_ONLY);
+ }
+ if (cable)
+ typec_cable_put(cable);
+
+ return unsupported;
+}
+EXPORT_SYMBOL_GPL(typec_cable_altmode_unsupported);
+
/**
* typec_cable_set_identity - Report result from Discover Identity command
* @cable: The cable updated identity values
diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h
index d61ec38216fa9..10a783b738efd 100644
--- a/include/linux/usb/typec.h
+++ b/include/linux/usb/typec.h
@@ -337,6 +337,7 @@ void typec_unregister_cable(struct typec_cable *cable);
struct typec_cable *typec_cable_get(struct typec_port *port);
void typec_cable_put(struct typec_cable *cable);
int typec_cable_is_active(struct typec_cable *cable);
+bool typec_cable_altmode_unsupported(struct typec_altmode *alt);
struct typec_plug *typec_register_plug(struct typec_cable *cable,
struct typec_plug_desc *desc);
--
2.54.0.1099.g489fc7bff1-goog