#include <linux/usb/pd_vdo.h>
 #include <linux/usb/typec_mux.h>
 #include <linux/usb/typec_retimer.h>
+#include <linux/usb.h>
 
 #include "bus.h"
 #include "class.h"
        .release = typec_partner_release,
 };
 
+static void typec_partner_link_device(struct typec_partner *partner, struct device *dev)
+{
+       int ret;
+
+       ret = sysfs_create_link(&dev->kobj, &partner->dev.kobj, "typec");
+       if (ret)
+               return;
+
+       ret = sysfs_create_link(&partner->dev.kobj, &dev->kobj, dev_name(dev));
+       if (ret) {
+               sysfs_remove_link(&dev->kobj, "typec");
+               return;
+       }
+
+       if (partner->attach)
+               partner->attach(partner, dev);
+}
+
+static void typec_partner_unlink_device(struct typec_partner *partner, struct device *dev)
+{
+       sysfs_remove_link(&partner->dev.kobj, dev_name(dev));
+       sysfs_remove_link(&dev->kobj, "typec");
+
+       if (partner->deattach)
+               partner->deattach(partner, dev);
+}
+
 /**
  * typec_partner_set_identity - Report result from Discover Identity command
  * @partner: The partner updated identity values
        partner->num_altmodes = -1;
        partner->pd_revision = desc->pd_revision;
        partner->svdm_version = port->cap->svdm_version;
+       partner->attach = desc->attach;
+       partner->deattach = desc->deattach;
 
        if (desc->identity) {
                /*
                return ERR_PTR(ret);
        }
 
+       if (port->usb2_dev)
+               typec_partner_link_device(partner, port->usb2_dev);
+       if (port->usb3_dev)
+               typec_partner_link_device(partner, port->usb3_dev);
+
        return partner;
 }
 EXPORT_SYMBOL_GPL(typec_register_partner);
  */
 void typec_unregister_partner(struct typec_partner *partner)
 {
-       if (!IS_ERR_OR_NULL(partner))
-               device_unregister(&partner->dev);
+       struct typec_port *port;
+
+       if (IS_ERR_OR_NULL(partner))
+               return;
+
+       port = to_typec_port(partner->dev.parent);
+
+       if (port->usb2_dev)
+               typec_partner_unlink_device(partner, port->usb2_dev);
+       if (port->usb3_dev)
+               typec_partner_unlink_device(partner, port->usb3_dev);
+
+       device_unregister(&partner->dev);
 }
 EXPORT_SYMBOL_GPL(typec_unregister_partner);
 
        return is_typec_partner(dev);
 }
 
+static struct typec_partner *typec_get_partner(struct typec_port *port)
+{
+       struct device *dev;
+
+       dev = device_find_child(&port->dev, NULL, partner_match);
+       if (!dev)
+               return NULL;
+
+       return to_typec_partner(dev);
+}
+
+static void typec_partner_attach(struct typec_connector *con, struct device *dev)
+{
+       struct typec_port *port = container_of(con, struct typec_port, con);
+       struct typec_partner *partner = typec_get_partner(port);
+       struct usb_device *udev = to_usb_device(dev);
+
+       if (udev->speed < USB_SPEED_SUPER)
+               port->usb2_dev = dev;
+       else
+               port->usb3_dev = dev;
+
+       if (partner) {
+               typec_partner_link_device(partner, dev);
+               put_device(&partner->dev);
+       }
+}
+
+static void typec_partner_deattach(struct typec_connector *con, struct device *dev)
+{
+       struct typec_port *port = container_of(con, struct typec_port, con);
+       struct typec_partner *partner = typec_get_partner(port);
+
+       if (partner) {
+               typec_partner_unlink_device(partner, dev);
+               put_device(&partner->dev);
+       }
+
+       if (port->usb2_dev == dev)
+               port->usb2_dev = NULL;
+       else if (port->usb3_dev == dev)
+               port->usb3_dev = NULL;
+}
+
 /**
  * typec_set_data_role - Report data role change
  * @port: The USB Type-C Port where the role was changed
  */
 void typec_set_data_role(struct typec_port *port, enum typec_data_role role)
 {
-       struct device *partner_dev;
+       struct typec_partner *partner;
 
        if (port->data_role == role)
                return;
        sysfs_notify(&port->dev.kobj, NULL, "data_role");
        kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
 
-       partner_dev = device_find_child(&port->dev, NULL, partner_match);
-       if (!partner_dev)
+       partner = typec_get_partner(port);
+       if (!partner)
                return;
 
-       if (to_typec_partner(partner_dev)->identity)
-               typec_product_type_notify(partner_dev);
+       if (partner->identity)
+               typec_product_type_notify(&partner->dev);
 
-       put_device(partner_dev);
+       put_device(&partner->dev);
 }
 EXPORT_SYMBOL_GPL(typec_set_data_role);
 
        port->ops = cap->ops;
        port->port_type = cap->type;
        port->prefer_role = cap->prefer_role;
+       port->con.attach = typec_partner_attach;
+       port->con.deattach = typec_partner_deattach;
 
        device_initialize(&port->dev);
        port->dev.class = &typec_class;
 
 
 struct typec_mux;
 struct typec_switch;
+struct usb_device;
 
 struct typec_plug {
        struct device                   dev;
        enum usb_pd_svdm_ver            svdm_version;
 
        struct usb_power_delivery       *pd;
+
+       void (*attach)(struct typec_partner *partner, struct device *dev);
+       void (*deattach)(struct typec_partner *partner, struct device *dev);
 };
 
 struct typec_port {
 
        const struct typec_capability   *cap;
        const struct typec_operations   *ops;
+
+       struct typec_connector          con;
+
+       /*
+        * REVISIT: Only USB devices for now. If there are others, these need to
+        * be converted into a list.
+        *
+        * NOTE: These may be registered first before the typec_partner, so they
+        * will always have to be kept here instead of struct typec_partner.
+        */
+       struct device                   *usb2_dev;
+       struct device                   *usb3_dev;
 };
 
 #define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev)
 
  * @accessory: Audio, Debug or none.
  * @identity: Discover Identity command data
  * @pd_revision: USB Power Delivery Specification Revision if supported
+ * @attach: Notification about attached USB device
+ * @deattach: Notification about removed USB device
  *
  * Details about a partner that is attached to USB Type-C port. If @identity
  * member exists when partner is registered, a directory named "identity" is
        enum typec_accessory    accessory;
        struct usb_pd_identity  *identity;
        u16                     pd_revision; /* 0300H = "3.0" */
+
+       void (*attach)(struct typec_partner *partner, struct device *dev);
+       void (*deattach)(struct typec_partner *partner, struct device *dev);
 };
 
 /**
 int typec_partner_set_usb_power_delivery(struct typec_partner *partner,
                                         struct usb_power_delivery *pd);
 
+/**
+ * struct typec_connector - Representation of Type-C port for external drivers
+ * @attach: notification about device removal
+ * @deattach: notification about device removal
+ *
+ * Drivers that control the USB and other ports (DisplayPorts, etc.), that are
+ * connected to the Type-C connectors, can use these callbacks to inform the
+ * Type-C connector class about connections and disconnections. That information
+ * can then be used by the typec-port drivers to power on or off parts that are
+ * needed or not needed - as an example, in USB mode if USB2 device is
+ * enumerated, USB3 components (retimers, phys, and what have you) do not need
+ * to be powered on.
+ *
+ * The attached (enumerated) devices will be liked with the typec-partner device.
+ */
+struct typec_connector {
+       void (*attach)(struct typec_connector *con, struct device *dev);
+       void (*deattach)(struct typec_connector *con, struct device *dev);
+};
+
+static inline void typec_attach(struct typec_connector *con, struct device *dev)
+{
+       if (con && con->attach)
+               con->attach(con, dev);
+}
+
+static inline void typec_deattach(struct typec_connector *con, struct device *dev)
+{
+       if (con && con->deattach)
+               con->deattach(con, dev);
+}
+
 #endif /* __LINUX_USB_TYPEC_H */