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.
Unified · Split
| @@ -149,6 +149,19 @@ Description: · 148 unmodified lines | |||
| 149 | advertise to the partner. The currently used capabilities are in | 149 | advertise to the partner. The currently used capabilities are in |
| 150 | brackets. Selection happens by writing to the file. | 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 | USB Type-C partner devices (eg. /sys/class/typec/port0-partner/) | 165 | USB Type-C partner devices (eg. /sys/class/typec/port0-partner/) |
| 153 | 166 | ||
| 154 | What: /sys/class/typec/<port>-partner/accessory_mode | 167 | What: /sys/class/typec/<port>-partner/accessory_mode |
| @@ -219,6 +219,13 @@ static ssize_t usb_power_delivery_revision_show(struct device *dev, · 218 unmodified lines | |||
| 219 | char *buf); | 219 | char *buf); |
| 220 | static DEVICE_ATTR_RO(usb_power_delivery_revision); | 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 | /* Alternate Modes */ | 230 | /* Alternate Modes */ |
| 224 | 231 | ||
| @@ -1289,6 +1296,67 @@ EXPORT_SYMBOL_GPL(typec_unregister_cable); · 1064 unmodified lines | |||
| 1289 | /* ------------------------------------------------------------------------- */ | 1296 | /* ------------------------------------------------------------------------- */ |
| 1290 | /* USB Type-C ports */ | 1297 | /* USB Type-C ports */ |
| 1291 | 1298 | ||
| 1299 | /** | ||
| 1300 | * typec_port_set_usb_mode - Set the operational USB mode for the port | ||
| 1301 | * @port: USB Type-C port | ||
| 1302 | * @mode: USB Mode (USB2, USB3 or USB4) | ||
| 1303 | * | ||
| 1304 | * @mode will be used with the next Enter_USB message. Existing connections are | ||
| 1305 | * not affected. | ||
| 1306 | */ | ||
| 1307 | void typec_port_set_usb_mode(struct typec_port *port, enum usb_mode mode) | ||
| 1308 | { | ||
| 1309 | port->usb_mode = mode; | ||
| 1310 | } | ||
| 1311 | EXPORT_SYMBOL_GPL(typec_port_set_usb_mode); | ||
| 1312 | |||
| 1313 | static ssize_t | ||
| 1314 | usb_capability_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
| 1315 | { | ||
| 1316 | struct typec_port *port = to_typec_port(dev); | ||
| 1317 | int len = 0; | ||
| 1318 | int i; | ||
| 1319 | |||
| 1320 | for (i = USB_MODE_USB2; i < USB_MODE_USB4 + 1; i++) { | ||
| 1321 | if (!(BIT(i - 1) & port->cap->usb_capability)) | ||
| 1322 | continue; | ||
| 1323 | |||
| 1324 | if (i == port->usb_mode) | ||
| 1325 | len += sysfs_emit_at(buf, len, "[%s] ", usb_modes[i]); | ||
| 1326 | else | ||
| 1327 | len += sysfs_emit_at(buf, len, "%s ", usb_modes[i]); | ||
| 1328 | } | ||
| 1329 | |||
| 1330 | sysfs_emit_at(buf, len - 1, "\n"); | ||
| 1331 | |||
| 1332 | return len; | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | static ssize_t | ||
| 1336 | usb_capability_store(struct device *dev, struct device_attribute *attr, | ||
| 1337 | const char *buf, size_t size) | ||
| 1338 | { | ||
| 1339 | struct typec_port *port = to_typec_port(dev); | ||
| 1340 | int ret = 0; | ||
| 1341 | int mode; | ||
| 1342 | |||
| 1343 | if (!port->ops || !port->ops->default_usb_mode_set) | ||
| 1344 | return -EOPNOTSUPP; | ||
| 1345 | |||
| 1346 | mode = sysfs_match_string(usb_modes, buf); | ||
| 1347 | if (mode < 0) | ||
| 1348 | return mode; | ||
| 1349 | |||
| 1350 | ret = port->ops->default_usb_mode_set(port, mode); | ||
| 1351 | if (ret) | ||
| 1352 | return ret; | ||
| 1353 | |||
| 1354 | port->usb_mode = mode; | ||
| 1355 | |||
| 1356 | return size; | ||
| 1357 | } | ||
| 1358 | static DEVICE_ATTR_RW(usb_capability); | ||
| 1359 | |||
| 1292 | /** | 1360 | /** |
| 1293 | * typec_port_set_usb_power_delivery - Assign USB PD for port. | 1361 | * typec_port_set_usb_power_delivery - Assign USB PD for port. |
| 1294 | * @port: USB Type-C port. | 1362 | * @port: USB Type-C port. |
| @@ -1757,6 +1825,7 @@ static struct attribute *typec_attrs[] = { · 462 unmodified lines | |||
| 1757 | &dev_attr_vconn_source.attr, | 1825 | &dev_attr_vconn_source.attr, |
| 1758 | &dev_attr_port_type.attr, | 1826 | &dev_attr_port_type.attr, |
| 1759 | &dev_attr_orientation.attr, | 1827 | &dev_attr_orientation.attr, |
| 1828 | &dev_attr_usb_capability.attr, | ||
| 1760 | NULL, | 1829 | NULL, |
| 1761 | }; | 1830 | }; |
| 1762 | 1831 | ||
| @@ -1790,6 +1859,11 @@ static umode_t typec_attr_is_visible(struct kobject *kobj, · 27 unmodified lines | |||
| 1790 | if (port->cap->orientation_aware) | 1859 | if (port->cap->orientation_aware) |
| 1791 | return 0444; | 1860 | return 0444; |
| 1792 | return 0; | 1861 | return 0; |
| 1862 | } else if (attr == &dev_attr_usb_capability.attr) { | ||
| 1863 | if (!port->cap->usb_capability) | ||
| 1864 | return 0; | ||
| 1865 | if (!port->ops || !port->ops->default_usb_mode_set) | ||
| 1866 | return 0444; | ||
| 1793 | } | 1867 | } |
| 1794 | 1868 | ||
| 1795 | return attr->mode; | 1869 | return attr->mode; |
| @@ -2428,6 +2502,13 @@ struct typec_port *typec_register_port(struct device *parent, · 632 unmodified lines | |||
| 2428 | port->con.attach = typec_partner_attach; | 2502 | port->con.attach = typec_partner_attach; |
| 2429 | port->con.deattach = typec_partner_deattach; | 2503 | port->con.deattach = typec_partner_deattach; |
| 2430 | 2504 | ||
| 2505 | if (cap->usb_capability & USB_CAPABILITY_USB4) | ||
| 2506 | port->usb_mode = USB_MODE_USB4; | ||
| 2507 | else if (cap->usb_capability & USB_CAPABILITY_USB3) | ||
| 2508 | port->usb_mode = USB_MODE_USB3; | ||
| 2509 | else if (cap->usb_capability & USB_CAPABILITY_USB2) | ||
| 2510 | port->usb_mode = USB_MODE_USB2; | ||
| 2511 | |||
| 2431 | device_initialize(&port->dev); | 2512 | device_initialize(&port->dev); |
| 2432 | port->dev.class = &typec_class; | 2513 | port->dev.class = &typec_class; |
| 2433 | port->dev.parent = parent; | 2514 | port->dev.parent = parent; |
| @@ -55,6 +55,7 @@ struct typec_port { · 54 unmodified lines | |||
| 55 | enum typec_role vconn_role; | 55 | enum typec_role vconn_role; |
| 56 | enum typec_pwr_opmode pwr_opmode; | 56 | enum typec_pwr_opmode pwr_opmode; |
| 57 | enum typec_port_type port_type; | 57 | enum typec_port_type port_type; |
| 58 | enum usb_mode usb_mode; | ||
| 58 | struct mutex port_type_lock; | 59 | struct mutex port_type_lock; |
| 59 | 60 | ||
| 60 | enum typec_orientation orientation; | 61 | enum typec_orientation orientation; |
| @@ -87,6 +87,17 @@ enum typec_orientation { · 86 unmodified lines | |||
| 87 | TYPEC_ORIENTATION_REVERSE, | 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 | * struct enter_usb_data - Enter_USB Message details | 102 | * struct enter_usb_data - Enter_USB Message details |
| 92 | * @eudo: Enter_USB Data Object | 103 | * @eudo: Enter_USB Data Object |
| @@ -240,6 +251,7 @@ struct typec_partner_desc { · 147 unmodified lines | |||
| 240 | * @port_type_set: Set port type | 251 | * @port_type_set: Set port type |
| 241 | * @pd_get: Get available USB Power Delivery Capabilities. | 252 | * @pd_get: Get available USB Power Delivery Capabilities. |
| 242 | * @pd_set: Set USB Power Delivery Capabilities. | 253 | * @pd_set: Set USB Power Delivery Capabilities. |
| 254 | * @default_usb_mode_set: USB Mode to be used by default with Enter_USB Message | ||
| 243 | */ | 255 | */ |
| 244 | struct typec_operations { | 256 | struct typec_operations { |
| 245 | int (*try_role)(struct typec_port *port, int role); | 257 | int (*try_role)(struct typec_port *port, int role); |
| @@ -250,6 +262,7 @@ struct typec_operations { · 4 unmodified lines | |||
| 250 | enum typec_port_type type); | 262 | enum typec_port_type type); |
| 251 | struct usb_power_delivery **(*pd_get)(struct typec_port *port); | 263 | struct usb_power_delivery **(*pd_get)(struct typec_port *port); |
| 252 | int (*pd_set)(struct typec_port *port, struct usb_power_delivery *pd); | 264 | int (*pd_set)(struct typec_port *port, struct usb_power_delivery *pd); |
| 265 | int (*default_usb_mode_set)(struct typec_port *port, enum usb_mode mode); | ||
| 253 | }; | 266 | }; |
| 254 | 267 | ||
| 255 | enum usb_pd_svdm_ver { | 268 | enum usb_pd_svdm_ver { |
| @@ -267,6 +280,7 @@ enum usb_pd_svdm_ver { · 11 unmodified lines | |||
| 267 | * @svdm_version: USB PD Structured VDM version if supported | 280 | * @svdm_version: USB PD Structured VDM version if supported |
| 268 | * @prefer_role: Initial role preference (DRP ports). | 281 | * @prefer_role: Initial role preference (DRP ports). |
| 269 | * @accessory: Supported Accessory Modes | 282 | * @accessory: Supported Accessory Modes |
| 283 | * @usb_capability: Supported USB Modes | ||
| 270 | * @fwnode: Optional fwnode of the port | 284 | * @fwnode: Optional fwnode of the port |
| 271 | * @driver_data: Private pointer for driver specific info | 285 | * @driver_data: Private pointer for driver specific info |
| 272 | * @pd: Optional USB Power Delivery Support | 286 | * @pd: Optional USB Power Delivery Support |
| @@ -283,6 +297,7 @@ struct typec_capability { · 10 unmodified lines | |||
| 283 | int prefer_role; | 297 | int prefer_role; |
| 284 | enum typec_accessory accessory[TYPEC_MAX_ACCESSORY]; | 298 | enum typec_accessory accessory[TYPEC_MAX_ACCESSORY]; |
| 285 | unsigned int orientation_aware:1; | 299 | unsigned int orientation_aware:1; |
| 300 | u8 usb_capability; | ||
| 286 | 301 | ||
| 287 | struct fwnode_handle *fwnode; | 302 | struct fwnode_handle *fwnode; |
| 288 | void *driver_data; | 303 | void *driver_data; |
| @@ -350,6 +365,8 @@ int typec_port_set_usb_power_delivery(struct typec_port *port, struct usb_power_ · 61 unmodified lines | |||
| 350 | int typec_partner_set_usb_power_delivery(struct typec_partner *partner, | 365 | int typec_partner_set_usb_power_delivery(struct typec_partner *partner, |
| 351 | struct usb_power_delivery *pd); | 366 | struct usb_power_delivery *pd); |
| 352 | 367 | ||
| 368 | void typec_port_set_usb_mode(struct typec_port *port, enum usb_mode mode); | ||
| 369 | |||
| 353 | /** | 370 | /** |
| 354 | * struct typec_connector - Representation of Type-C port for external drivers | 371 | * struct typec_connector - Representation of Type-C port for external drivers |
| 355 | * @attach: notification about device removal | 372 | * @attach: notification about device removal |