Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: typec: Add attribute file showing the supported USB modes of the port

This attribute file, named "usb_capability", will show the
supported USB modes, which are USB 2.0, USB 3.2 and USB4.
These modes are defined in the USB Type-C (R2.0) and USB
Power Delivery (R3.0 V2.0) Specifications.

Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20241016131834.898599-2-heikki.krogerus@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Heikki Krogerus and committed by
Greg Kroah-Hartman
8060bcb1 0990e5c6

+112
+13
Documentation/ABI/testing/sysfs-class-typec
··· 149 149 advertise to the partner. The currently used capabilities are in 150 150 brackets. Selection happens by writing to the file. 151 151 152 + What: /sys/class/typec/<port>/usb_capability 153 + Date: November 2024 154 + Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> 155 + Description: Lists the supported USB Modes. The default USB mode that is used 156 + next time with the Enter_USB Message is in brackets. The default 157 + mode can be changed by writing to the file when supported by the 158 + driver. 159 + 160 + Valid values: 161 + - usb2 (USB 2.0) 162 + - usb3 (USB 3.2) 163 + - usb4 (USB4) 164 + 152 165 USB Type-C partner devices (eg. /sys/class/typec/port0-partner/) 153 166 154 167 What: /sys/class/typec/<port>-partner/accessory_mode
+81
drivers/usb/typec/class.c
··· 219 219 char *buf); 220 220 static DEVICE_ATTR_RO(usb_power_delivery_revision); 221 221 222 + static const char * const usb_modes[] = { 223 + [USB_MODE_NONE] = "none", 224 + [USB_MODE_USB2] = "usb2", 225 + [USB_MODE_USB3] = "usb3", 226 + [USB_MODE_USB4] = "usb4" 227 + }; 228 + 222 229 /* ------------------------------------------------------------------------- */ 223 230 /* Alternate Modes */ 224 231 ··· 1297 1290 /* USB Type-C ports */ 1298 1291 1299 1292 /** 1293 + * typec_port_set_usb_mode - Set the operational USB mode for the port 1294 + * @port: USB Type-C port 1295 + * @mode: USB Mode (USB2, USB3 or USB4) 1296 + * 1297 + * @mode will be used with the next Enter_USB message. Existing connections are 1298 + * not affected. 1299 + */ 1300 + void typec_port_set_usb_mode(struct typec_port *port, enum usb_mode mode) 1301 + { 1302 + port->usb_mode = mode; 1303 + } 1304 + EXPORT_SYMBOL_GPL(typec_port_set_usb_mode); 1305 + 1306 + static ssize_t 1307 + usb_capability_show(struct device *dev, struct device_attribute *attr, char *buf) 1308 + { 1309 + struct typec_port *port = to_typec_port(dev); 1310 + int len = 0; 1311 + int i; 1312 + 1313 + for (i = USB_MODE_USB2; i < USB_MODE_USB4 + 1; i++) { 1314 + if (!(BIT(i - 1) & port->cap->usb_capability)) 1315 + continue; 1316 + 1317 + if (i == port->usb_mode) 1318 + len += sysfs_emit_at(buf, len, "[%s] ", usb_modes[i]); 1319 + else 1320 + len += sysfs_emit_at(buf, len, "%s ", usb_modes[i]); 1321 + } 1322 + 1323 + sysfs_emit_at(buf, len - 1, "\n"); 1324 + 1325 + return len; 1326 + } 1327 + 1328 + static ssize_t 1329 + usb_capability_store(struct device *dev, struct device_attribute *attr, 1330 + const char *buf, size_t size) 1331 + { 1332 + struct typec_port *port = to_typec_port(dev); 1333 + int ret = 0; 1334 + int mode; 1335 + 1336 + if (!port->ops || !port->ops->default_usb_mode_set) 1337 + return -EOPNOTSUPP; 1338 + 1339 + mode = sysfs_match_string(usb_modes, buf); 1340 + if (mode < 0) 1341 + return mode; 1342 + 1343 + ret = port->ops->default_usb_mode_set(port, mode); 1344 + if (ret) 1345 + return ret; 1346 + 1347 + port->usb_mode = mode; 1348 + 1349 + return size; 1350 + } 1351 + static DEVICE_ATTR_RW(usb_capability); 1352 + 1353 + /** 1300 1354 * typec_port_set_usb_power_delivery - Assign USB PD for port. 1301 1355 * @port: USB Type-C port. 1302 1356 * @pd: USB PD instance. ··· 1825 1757 &dev_attr_vconn_source.attr, 1826 1758 &dev_attr_port_type.attr, 1827 1759 &dev_attr_orientation.attr, 1760 + &dev_attr_usb_capability.attr, 1828 1761 NULL, 1829 1762 }; 1830 1763 ··· 1859 1790 if (port->cap->orientation_aware) 1860 1791 return 0444; 1861 1792 return 0; 1793 + } else if (attr == &dev_attr_usb_capability.attr) { 1794 + if (!port->cap->usb_capability) 1795 + return 0; 1796 + if (!port->ops || !port->ops->default_usb_mode_set) 1797 + return 0444; 1862 1798 } 1863 1799 1864 1800 return attr->mode; ··· 2501 2427 port->prefer_role = cap->prefer_role; 2502 2428 port->con.attach = typec_partner_attach; 2503 2429 port->con.deattach = typec_partner_deattach; 2430 + 2431 + if (cap->usb_capability & USB_CAPABILITY_USB4) 2432 + port->usb_mode = USB_MODE_USB4; 2433 + else if (cap->usb_capability & USB_CAPABILITY_USB3) 2434 + port->usb_mode = USB_MODE_USB3; 2435 + else if (cap->usb_capability & USB_CAPABILITY_USB2) 2436 + port->usb_mode = USB_MODE_USB2; 2504 2437 2505 2438 device_initialize(&port->dev); 2506 2439 port->dev.class = &typec_class;
+1
drivers/usb/typec/class.h
··· 55 55 enum typec_role vconn_role; 56 56 enum typec_pwr_opmode pwr_opmode; 57 57 enum typec_port_type port_type; 58 + enum usb_mode usb_mode; 58 59 struct mutex port_type_lock; 59 60 60 61 enum typec_orientation orientation;
+17
include/linux/usb/typec.h
··· 87 87 TYPEC_ORIENTATION_REVERSE, 88 88 }; 89 89 90 + enum usb_mode { 91 + USB_MODE_NONE, 92 + USB_MODE_USB2, 93 + USB_MODE_USB3, 94 + USB_MODE_USB4 95 + }; 96 + 97 + #define USB_CAPABILITY_USB2 BIT(0) 98 + #define USB_CAPABILITY_USB3 BIT(1) 99 + #define USB_CAPABILITY_USB4 BIT(2) 100 + 90 101 /* 91 102 * struct enter_usb_data - Enter_USB Message details 92 103 * @eudo: Enter_USB Data Object ··· 251 240 * @port_type_set: Set port type 252 241 * @pd_get: Get available USB Power Delivery Capabilities. 253 242 * @pd_set: Set USB Power Delivery Capabilities. 243 + * @default_usb_mode_set: USB Mode to be used by default with Enter_USB Message 254 244 */ 255 245 struct typec_operations { 256 246 int (*try_role)(struct typec_port *port, int role); ··· 262 250 enum typec_port_type type); 263 251 struct usb_power_delivery **(*pd_get)(struct typec_port *port); 264 252 int (*pd_set)(struct typec_port *port, struct usb_power_delivery *pd); 253 + int (*default_usb_mode_set)(struct typec_port *port, enum usb_mode mode); 265 254 }; 266 255 267 256 enum usb_pd_svdm_ver { ··· 280 267 * @svdm_version: USB PD Structured VDM version if supported 281 268 * @prefer_role: Initial role preference (DRP ports). 282 269 * @accessory: Supported Accessory Modes 270 + * @usb_capability: Supported USB Modes 283 271 * @fwnode: Optional fwnode of the port 284 272 * @driver_data: Private pointer for driver specific info 285 273 * @pd: Optional USB Power Delivery Support ··· 297 283 int prefer_role; 298 284 enum typec_accessory accessory[TYPEC_MAX_ACCESSORY]; 299 285 unsigned int orientation_aware:1; 286 + u8 usb_capability; 300 287 301 288 struct fwnode_handle *fwnode; 302 289 void *driver_data; ··· 364 349 int typec_port_set_usb_power_delivery(struct typec_port *port, struct usb_power_delivery *pd); 365 350 int typec_partner_set_usb_power_delivery(struct typec_partner *partner, 366 351 struct usb_power_delivery *pd); 352 + 353 + void typec_port_set_usb_mode(struct typec_port *port, enum usb_mode mode); 367 354 368 355 /** 369 356 * struct typec_connector - Representation of Type-C port for external drivers