summaryrefslogtreecommitdiff
path: root/drivers/usb/typec/class.c
diff options
context:
space:
mode:
authorBenson Leung <bleung@chromium.org>2021-01-28 22:14:02 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-02-01 15:31:34 +0100
commitf5030e252687be6e999bd52feb1f79d515b2f684 (patch)
treedbc11ca2a1b8af2a2a9611afc6d6306f9205f5eb /drivers/usb/typec/class.c
parent1ed8459d8f1060c87c7d66fe2d3cbbe4bc9cdd24 (diff)
usb: typec: Provide PD Specification Revision for cable and partner
The USB Power Delivery specification Section 6.2.1.1.5 outlines revision backward compatibility requirements starting from Revision 3.0. The Port, the Cable Plug, and the Port Partner may support either revision 2 or revision 3 independently, and communication between ports, partners, and cables of different revisions are allowed under rules that the parties agree to communicate between each other using the lowest common operating revision. This may mean that Port-to-Partner operating revision comms may be different than Port-to-CablePlug operating revision comms. For example, it is possible for a R3.0 port to communicate with a R3.0 partner using R3.0 messages, while the R3.0 port (in the same session) must communicate with the R2.0 cable using R2.0 messages only. Introduce individual revision number properties for cable and port partner so that the port can track them independently. Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Signed-off-by: Benson Leung <bleung@chromium.org> Link: https://lore.kernel.org/r/20210129061406.2680146-3-bleung@chromium.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/typec/class.c')
-rw-r--r--drivers/usb/typec/class.c30
1 files changed, 26 insertions, 4 deletions
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 4f60ee7ba76a..b5241f4756c2 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -27,6 +27,7 @@ struct typec_cable {
enum typec_plug_type type;
struct usb_pd_identity *identity;
unsigned int active:1;
+ u16 pd_revision; /* 0300H = "3.0" */
};
struct typec_partner {
@@ -36,6 +37,7 @@ struct typec_partner {
enum typec_accessory accessory;
struct ida mode_ids;
int num_altmodes;
+ u16 pd_revision; /* 0300H = "3.0" */
};
struct typec_port {
@@ -264,6 +266,11 @@ type_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR_RO(type);
+static ssize_t usb_power_delivery_revision_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+static DEVICE_ATTR_RO(usb_power_delivery_revision);
+
/* ------------------------------------------------------------------------- */
/* Alternate Modes */
@@ -680,6 +687,7 @@ static struct attribute *typec_partner_attrs[] = {
&dev_attr_supports_usb_power_delivery.attr,
&dev_attr_number_of_alternate_modes.attr,
&dev_attr_type.attr,
+ &dev_attr_usb_power_delivery_revision.attr,
NULL
};
@@ -815,6 +823,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port,
partner->usb_pd = desc->usb_pd;
partner->accessory = desc->accessory;
partner->num_altmodes = -1;
+ partner->pd_revision = desc->pd_revision;
if (desc->identity) {
/*
@@ -1028,6 +1037,7 @@ static DEVICE_ATTR_RO(plug_type);
static struct attribute *typec_cable_attrs[] = {
&dev_attr_type.attr,
&dev_attr_plug_type.attr,
+ &dev_attr_usb_power_delivery_revision.attr,
NULL
};
ATTRIBUTE_GROUPS(typec_cable);
@@ -1130,6 +1140,7 @@ struct typec_cable *typec_register_cable(struct typec_port *port,
cable->type = desc->type;
cable->active = desc->active;
+ cable->pd_revision = desc->pd_revision;
if (desc->identity) {
/*
@@ -1499,12 +1510,23 @@ static ssize_t usb_power_delivery_revision_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct typec_port *p = to_typec_port(dev);
- u16 rev = p->cap->pd_revision;
+ u16 rev = 0;
- return sprintf(buf, "%d.%d\n", (rev >> 8) & 0xff, (rev >> 4) & 0xf);
+ if (is_typec_partner(dev)) {
+ struct typec_partner *partner = to_typec_partner(dev);
+
+ rev = partner->pd_revision;
+ } else if (is_typec_cable(dev)) {
+ struct typec_cable *cable = to_typec_cable(dev);
+
+ rev = cable->pd_revision;
+ } else if (is_typec_port(dev)) {
+ struct typec_port *p = to_typec_port(dev);
+
+ rev = p->cap->pd_revision;
+ }
+ return sysfs_emit(buf, "%d.%d\n", (rev >> 8) & 0xff, (rev >> 4) & 0xf);
}
-static DEVICE_ATTR_RO(usb_power_delivery_revision);
static ssize_t orientation_show(struct device *dev,
struct device_attribute *attr,