usb: roles: Link the switch to its connector
authorHeikki Krogerus <heikki.krogerus@linux.intel.com>
Tue, 13 Feb 2024 13:00:17 +0000 (15:00 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 17 Feb 2024 16:02:42 +0000 (17:02 +0100)
This is probable useful information to have in user space in
general, but it's primarily needed for the xHCI DbC (Debug
Capability). When xHCI DbC is being used, the USB port needs
to be muxed to the xHCI even in device role. In xHCI DbC mode,
the xHCI is the USB device controller.

Tested-by: Uday Bhat <uday.m.bhat@intel.com>
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Prashant Malani <pmalani@chromium.org>
Link: https://lore.kernel.org/r/20240213130018.3029991-2-heikki.krogerus@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/sysfs-class-usb_role
drivers/usb/roles/class.c

index 3b810a425a52c8c0d1d30b5af84140779fa3622c..9fab3f06679e297cd334dce5d238d6df2522dc3f 100644 (file)
@@ -19,3 +19,9 @@ Description:
                - none
                - host
                - device
+
+What:          /sys/class/usb_role/<switch>/connector
+Date:          Feb 2024
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               Optional symlink to the USB Type-C connector.
index ae41578bd0149900b0a867f71a0cf6080e238566..4ad03c93c17f17c3f3c7d3877f25af16052bf6d2 100644 (file)
@@ -7,6 +7,7 @@
  *         Hans de Goede <hdegoede@redhat.com>
  */
 
+#include <linux/component.h>
 #include <linux/usb/role.h>
 #include <linux/property.h>
 #include <linux/device.h>
@@ -34,6 +35,32 @@ struct usb_role_switch {
 
 #define to_role_switch(d)      container_of(d, struct usb_role_switch, dev)
 
+static int connector_bind(struct device *dev, struct device *connector, void *data)
+{
+       int ret;
+
+       ret = sysfs_create_link(&dev->kobj, &connector->kobj, "connector");
+       if (ret)
+               return ret;
+
+       ret = sysfs_create_link(&connector->kobj, &dev->kobj, "usb-role-switch");
+       if (ret)
+               sysfs_remove_link(&dev->kobj, "connector");
+
+       return ret;
+}
+
+static void connector_unbind(struct device *dev, struct device *connector, void *data)
+{
+       sysfs_remove_link(&connector->kobj, "usb-role-switch");
+       sysfs_remove_link(&dev->kobj, "connector");
+}
+
+static const struct component_ops connector_ops = {
+       .bind = connector_bind,
+       .unbind = connector_unbind,
+};
+
 /**
  * usb_role_switch_set_role - Set USB role for a switch
  * @sw: USB role switch
@@ -352,6 +379,12 @@ usb_role_switch_register(struct device *parent,
                return ERR_PTR(ret);
        }
 
+       if (dev_fwnode(&sw->dev)) {
+               ret = component_add(&sw->dev, &connector_ops);
+               if (ret)
+                       dev_warn(&sw->dev, "failed to add component\n");
+       }
+
        /* TODO: Symlinks for the host port and the device controller. */
 
        return sw;
@@ -366,8 +399,11 @@ EXPORT_SYMBOL_GPL(usb_role_switch_register);
  */
 void usb_role_switch_unregister(struct usb_role_switch *sw)
 {
-       if (!IS_ERR_OR_NULL(sw))
-               device_unregister(&sw->dev);
+       if (IS_ERR_OR_NULL(sw))
+               return;
+       if (dev_fwnode(&sw->dev))
+               component_del(&sw->dev, &connector_ops);
+       device_unregister(&sw->dev);
 }
 EXPORT_SYMBOL_GPL(usb_role_switch_unregister);