usb: typec: Manage SVDM version
authorKyle Tso <kyletso@google.com>
Fri, 5 Feb 2021 03:34:09 +0000 (11:34 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Feb 2021 10:48:54 +0000 (11:48 +0100)
PD Spec Revision 3.0 Version 2.0 + ECNs 2020-12-10
  6.4.4.2.3 Structured VDM Version
  "The Structured VDM Version field of the Discover Identity Command
  sent and received during VDM discovery Shall be used to determine the
  lowest common Structured VDM Version supported by the Port Partners or
  Cable Plug and Shall continue to operate using this Specification
  Revision until they are Detached."

Add a variable in typec_capability to specify the highest SVDM version
supported by the port and another variable in typec_partner to cache the
negotiated SVDM version between the port and the partner.

Also add setter/getter functions for the negotiated SVDM version.

Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Kyle Tso <kyletso@google.com>
Link: https://lore.kernel.org/r/20210205033415.3320439-2-kyletso@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/class.c
include/linux/usb/typec.h
include/linux/usb/typec_altmode.h

index b4a5d9d..45f0bf6 100644 (file)
@@ -38,6 +38,7 @@ struct typec_partner {
        struct ida                      mode_ids;
        int                             num_altmodes;
        u16                             pd_revision; /* 0300H = "3.0" */
+       enum usb_pd_svdm_ver            svdm_version;
 };
 
 struct typec_port {
@@ -825,6 +826,20 @@ typec_partner_register_altmode(struct typec_partner *partner,
 EXPORT_SYMBOL_GPL(typec_partner_register_altmode);
 
 /**
+ * typec_partner_set_svdm_version - Set negotiated Structured VDM (SVDM) Version
+ * @partner: USB Type-C Partner that supports SVDM
+ * @svdm_version: Negotiated SVDM Version
+ *
+ * This routine is used to save the negotiated SVDM Version.
+ */
+void typec_partner_set_svdm_version(struct typec_partner *partner,
+                                  enum usb_pd_svdm_ver svdm_version)
+{
+       partner->svdm_version = svdm_version;
+}
+EXPORT_SYMBOL_GPL(typec_partner_set_svdm_version);
+
+/**
  * typec_register_partner - Register a USB Type-C Partner
  * @port: The USB Type-C Port the partner is connected to
  * @desc: Description of the partner
@@ -848,6 +863,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port,
        partner->accessory = desc->accessory;
        partner->num_altmodes = -1;
        partner->pd_revision = desc->pd_revision;
+       partner->svdm_version = port->cap->svdm_version;
 
        if (desc->identity) {
                /*
@@ -1895,6 +1911,33 @@ EXPORT_SYMBOL_GPL(typec_set_mode);
 /* --------------------------------------- */
 
 /**
+ * typec_get_negotiated_svdm_version - Get negotiated SVDM Version
+ * @port: USB Type-C Port.
+ *
+ * Get the negotiated SVDM Version. The Version is set to the port default
+ * value stored in typec_capability on partner registration, and updated after
+ * a successful Discover Identity if the negotiated value is less than the
+ * default value.
+ *
+ * Returns usb_pd_svdm_ver if the partner has been registered otherwise -ENODEV.
+ */
+int typec_get_negotiated_svdm_version(struct typec_port *port)
+{
+       enum usb_pd_svdm_ver svdm_version;
+       struct device *partner_dev;
+
+       partner_dev = device_find_child(&port->dev, NULL, partner_match);
+       if (!partner_dev)
+               return -ENODEV;
+
+       svdm_version = to_typec_partner(partner_dev)->svdm_version;
+       put_device(partner_dev);
+
+       return svdm_version;
+}
+EXPORT_SYMBOL_GPL(typec_get_negotiated_svdm_version);
+
+/**
  * typec_get_drvdata - Return private driver data pointer
  * @port: USB Type-C port
  */
index a94df82..91b4303 100644 (file)
@@ -217,12 +217,19 @@ struct typec_operations {
                             enum typec_port_type type);
 };
 
+enum usb_pd_svdm_ver {
+       SVDM_VER_1_0 = 0,
+       SVDM_VER_2_0 = 1,
+       SVDM_VER_MAX = SVDM_VER_2_0,
+};
+
 /*
  * struct typec_capability - USB Type-C Port Capabilities
  * @type: Supported power role of the port
  * @data: Supported data role of the port
  * @revision: USB Type-C Specification release. Binary coded decimal
  * @pd_revision: USB Power Delivery Specification revision if supported
+ * @svdm_version: USB PD Structured VDM version if supported
  * @prefer_role: Initial role preference (DRP ports).
  * @accessory: Supported Accessory Modes
  * @fwnode: Optional fwnode of the port
@@ -236,6 +243,7 @@ struct typec_capability {
        enum typec_port_data    data;
        u16                     revision; /* 0120H = "1.2" */
        u16                     pd_revision; /* 0300H = "3.0" */
+       enum usb_pd_svdm_ver    svdm_version;
        int                     prefer_role;
        enum typec_accessory    accessory[TYPEC_MAX_ACCESSORY];
        unsigned int            orientation_aware:1;
@@ -286,4 +294,8 @@ int typec_find_orientation(const char *name);
 int typec_find_port_power_role(const char *name);
 int typec_find_power_role(const char *name);
 int typec_find_port_data_role(const char *name);
+
+void typec_partner_set_svdm_version(struct typec_partner *partner,
+                                   enum usb_pd_svdm_ver svdm_version);
+int typec_get_negotiated_svdm_version(struct typec_port *port);
 #endif /* __LINUX_USB_TYPEC_H */
index 5e0a7b7..65933cb 100644 (file)
@@ -133,6 +133,16 @@ typec_altmode_get_orientation(struct typec_altmode *altmode)
 }
 
 /**
+ * typec_altmode_get_svdm_version - Get negotiated SVDM version
+ * @altmode: Handle to the alternate mode
+ */
+static inline int
+typec_altmode_get_svdm_version(struct typec_altmode *altmode)
+{
+       return typec_get_negotiated_svdm_version(typec_altmode2port(altmode));
+}
+
+/**
  * struct typec_altmode_driver - USB Type-C alternate mode device driver
  * @id_table: Null terminated array of SVIDs
  * @probe: Callback for device binding