Commit 8060bcb1 authored by Heikki Krogerus's avatar Heikki Krogerus Committed by Greg Kroah-Hartman
Browse files

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: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20241016131834.898599-2-heikki.krogerus@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0990e5c6
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -149,6 +149,19 @@ Description:
		advertise to the partner. The currently used capabilities are in
		brackets. Selection happens by writing to the file.

What:		/sys/class/typec/<port>/usb_capability
Date:		November 2024
Contact:	Heikki Krogerus <heikki.krogerus@linux.intel.com>
Description:	Lists the supported USB Modes. The default USB mode that is used
		next time with the Enter_USB Message is in brackets. The default
		mode can be changed by writing to the file when supported by the
		driver.

		Valid values:
		- usb2 (USB 2.0)
		- usb3 (USB 3.2)
		- usb4 (USB4)

USB Type-C partner devices (eg. /sys/class/typec/port0-partner/)

What:		/sys/class/typec/<port>-partner/accessory_mode
+81 −0
Original line number Diff line number Diff line
@@ -219,6 +219,13 @@ static ssize_t usb_power_delivery_revision_show(struct device *dev,
						char *buf);
static DEVICE_ATTR_RO(usb_power_delivery_revision);

static const char * const usb_modes[] = {
	[USB_MODE_NONE] = "none",
	[USB_MODE_USB2] = "usb2",
	[USB_MODE_USB3] = "usb3",
	[USB_MODE_USB4] = "usb4"
};

/* ------------------------------------------------------------------------- */
/* Alternate Modes */

@@ -1289,6 +1296,67 @@ EXPORT_SYMBOL_GPL(typec_unregister_cable);
/* ------------------------------------------------------------------------- */
/* USB Type-C ports */

/**
 * typec_port_set_usb_mode - Set the operational USB mode for the port
 * @port: USB Type-C port
 * @mode: USB Mode (USB2, USB3 or USB4)
 *
 * @mode will be used with the next Enter_USB message. Existing connections are
 * not affected.
 */
void typec_port_set_usb_mode(struct typec_port *port, enum usb_mode mode)
{
	port->usb_mode = mode;
}
EXPORT_SYMBOL_GPL(typec_port_set_usb_mode);

static ssize_t
usb_capability_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct typec_port *port = to_typec_port(dev);
	int len = 0;
	int i;

	for (i = USB_MODE_USB2; i < USB_MODE_USB4 + 1; i++) {
		if (!(BIT(i - 1) & port->cap->usb_capability))
			continue;

		if (i == port->usb_mode)
			len += sysfs_emit_at(buf, len, "[%s] ", usb_modes[i]);
		else
			len += sysfs_emit_at(buf, len, "%s ", usb_modes[i]);
	}

	sysfs_emit_at(buf, len - 1, "\n");

	return len;
}

static ssize_t
usb_capability_store(struct device *dev, struct device_attribute *attr,
		     const char *buf, size_t size)
{
	struct typec_port *port = to_typec_port(dev);
	int ret = 0;
	int mode;

	if (!port->ops || !port->ops->default_usb_mode_set)
		return -EOPNOTSUPP;

	mode = sysfs_match_string(usb_modes, buf);
	if (mode < 0)
		return mode;

	ret = port->ops->default_usb_mode_set(port, mode);
	if (ret)
		return ret;

	port->usb_mode = mode;

	return size;
}
static DEVICE_ATTR_RW(usb_capability);

/**
 * typec_port_set_usb_power_delivery - Assign USB PD for port.
 * @port: USB Type-C port.
@@ -1757,6 +1825,7 @@ static struct attribute *typec_attrs[] = {
	&dev_attr_vconn_source.attr,
	&dev_attr_port_type.attr,
	&dev_attr_orientation.attr,
	&dev_attr_usb_capability.attr,
	NULL,
};

@@ -1790,6 +1859,11 @@ static umode_t typec_attr_is_visible(struct kobject *kobj,
		if (port->cap->orientation_aware)
			return 0444;
		return 0;
	} else if (attr == &dev_attr_usb_capability.attr) {
		if (!port->cap->usb_capability)
			return 0;
		if (!port->ops || !port->ops->default_usb_mode_set)
			return 0444;
	}

	return attr->mode;
@@ -2428,6 +2502,13 @@ struct typec_port *typec_register_port(struct device *parent,
	port->con.attach = typec_partner_attach;
	port->con.deattach = typec_partner_deattach;

	if (cap->usb_capability & USB_CAPABILITY_USB4)
		port->usb_mode = USB_MODE_USB4;
	else if (cap->usb_capability & USB_CAPABILITY_USB3)
		port->usb_mode = USB_MODE_USB3;
	else if (cap->usb_capability & USB_CAPABILITY_USB2)
		port->usb_mode = USB_MODE_USB2;

	device_initialize(&port->dev);
	port->dev.class = &typec_class;
	port->dev.parent = parent;
+1 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ struct typec_port {
	enum typec_role			vconn_role;
	enum typec_pwr_opmode		pwr_opmode;
	enum typec_port_type		port_type;
	enum usb_mode			usb_mode;
	struct mutex			port_type_lock;

	enum typec_orientation		orientation;
+17 −0
Original line number Diff line number Diff line
@@ -87,6 +87,17 @@ enum typec_orientation {
	TYPEC_ORIENTATION_REVERSE,
};

enum usb_mode {
	USB_MODE_NONE,
	USB_MODE_USB2,
	USB_MODE_USB3,
	USB_MODE_USB4
};

#define USB_CAPABILITY_USB2	BIT(0)
#define USB_CAPABILITY_USB3	BIT(1)
#define USB_CAPABILITY_USB4	BIT(2)

/*
 * struct enter_usb_data - Enter_USB Message details
 * @eudo: Enter_USB Data Object
@@ -240,6 +251,7 @@ struct typec_partner_desc {
 * @port_type_set: Set port type
 * @pd_get: Get available USB Power Delivery Capabilities.
 * @pd_set: Set USB Power Delivery Capabilities.
 * @default_usb_mode_set: USB Mode to be used by default with Enter_USB Message
 */
struct typec_operations {
	int (*try_role)(struct typec_port *port, int role);
@@ -250,6 +262,7 @@ struct typec_operations {
			     enum typec_port_type type);
	struct usb_power_delivery **(*pd_get)(struct typec_port *port);
	int (*pd_set)(struct typec_port *port, struct usb_power_delivery *pd);
	int (*default_usb_mode_set)(struct typec_port *port, enum usb_mode mode);
};

enum usb_pd_svdm_ver {
@@ -267,6 +280,7 @@ enum usb_pd_svdm_ver {
 * @svdm_version: USB PD Structured VDM version if supported
 * @prefer_role: Initial role preference (DRP ports).
 * @accessory: Supported Accessory Modes
 * @usb_capability: Supported USB Modes
 * @fwnode: Optional fwnode of the port
 * @driver_data: Private pointer for driver specific info
 * @pd: Optional USB Power Delivery Support
@@ -283,6 +297,7 @@ struct typec_capability {
	int			prefer_role;
	enum typec_accessory	accessory[TYPEC_MAX_ACCESSORY];
	unsigned int		orientation_aware:1;
	u8			usb_capability;

	struct fwnode_handle	*fwnode;
	void			*driver_data;
@@ -350,6 +365,8 @@ int typec_port_set_usb_power_delivery(struct typec_port *port, struct usb_power_
int typec_partner_set_usb_power_delivery(struct typec_partner *partner,
					 struct usb_power_delivery *pd);

void typec_port_set_usb_mode(struct typec_port *port, enum usb_mode mode);

/**
 * struct typec_connector - Representation of Type-C port for external drivers
 * @attach: notification about device removal