dm: usb: Do not scan companion buses if no devices where handed over
[platform/kernel/u-boot.git] / drivers / usb / host / usb-uclass.c
index 749257c..963464c 100644 (file)
@@ -21,6 +21,10 @@ DECLARE_GLOBAL_DATA_PTR;
 extern bool usb_started; /* flag for the started/stopped USB status */
 static bool asynch_allowed;
 
+struct usb_uclass_priv {
+       int companion_device_count;
+};
+
 int usb_disable_asynch(int disable)
 {
        int old_value = asynch_allowed;
@@ -46,11 +50,22 @@ int submit_control_msg(struct usb_device *udev, unsigned long pipe,
 {
        struct udevice *bus = udev->controller_dev;
        struct dm_usb_ops *ops = usb_get_ops(bus);
+       struct usb_uclass_priv *uc_priv = bus->uclass->priv;
+       int err;
 
        if (!ops->control)
                return -ENOSYS;
 
-       return ops->control(bus, udev, pipe, buffer, length, setup);
+       err = ops->control(bus, udev, pipe, buffer, length, setup);
+       if (setup->request == USB_REQ_SET_FEATURE &&
+           setup->requesttype == USB_RT_PORT &&
+           setup->value == cpu_to_le16(USB_PORT_FEAT_RESET) &&
+           err == -ENXIO) {
+               /* Device handed over to companion after port reset */
+               uc_priv->companion_device_count++;
+       }
+
+       return err;
 }
 
 int submit_bulk_msg(struct usb_device *udev, unsigned long pipe, void *buffer,
@@ -117,12 +132,16 @@ int usb_stop(void)
 {
        struct udevice *bus;
        struct uclass *uc;
+       struct usb_uclass_priv *uc_priv;
        int err = 0, ret;
 
        /* De-activate any devices that have been activated */
        ret = uclass_get(UCLASS_USB, &uc);
        if (ret)
                return ret;
+
+       uc_priv = uc->priv;
+
        uclass_foreach_dev(bus, uc) {
                ret = device_remove(bus);
                if (ret && !err)
@@ -142,6 +161,7 @@ int usb_stop(void)
 #endif
        usb_stor_reset();
        usb_hub_reset();
+       uc_priv->companion_device_count = 0;
        usb_started = 0;
 
        return err;
@@ -171,6 +191,7 @@ static void usb_scan_bus(struct udevice *bus, bool recurse)
 int usb_init(void)
 {
        int controllers_initialized = 0;
+       struct usb_uclass_priv *uc_priv;
        struct usb_bus_priv *priv;
        struct udevice *bus;
        struct uclass *uc;
@@ -184,6 +205,8 @@ int usb_init(void)
        if (ret)
                return ret;
 
+       uc_priv = uc->priv;
+
        uclass_foreach_dev(bus, uc) {
                /* init low_level USB */
                printf("USB%d:   ", count);
@@ -219,15 +242,17 @@ int usb_init(void)
        /*
         * Now that the primary controllers have been scanned and have handed
         * over any devices they do not understand to their companions, scan
-        * the companions.
+        * the companions if necessary.
         */
-       uclass_foreach_dev(bus, uc) {
-               if (!device_active(bus))
-                       continue;
+       if (uc_priv->companion_device_count) {
+               uclass_foreach_dev(bus, uc) {
+                       if (!device_active(bus))
+                               continue;
 
-               priv = dev_get_uclass_priv(bus);
-               if (priv->companion)
-                       usb_scan_bus(bus, true);
+                       priv = dev_get_uclass_priv(bus);
+                       if (priv->companion)
+                               usb_scan_bus(bus, true);
+               }
        }
 
        debug("scan end\n");
@@ -685,6 +710,7 @@ UCLASS_DRIVER(usb) = {
        .name           = "usb",
        .flags          = DM_UC_FLAG_SEQ_ALIAS,
        .post_bind      = usb_post_bind,
+       .priv_auto_alloc_size = sizeof(struct usb_uclass_priv),
        .per_child_auto_alloc_size = sizeof(struct usb_device),
        .per_device_auto_alloc_size = sizeof(struct usb_bus_priv),
        .child_post_bind = usb_child_post_bind,