diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 82f64986bc2269c2a185bfb1d05169ff9479d0a4..5f56c4a42f528e487f33bbcf401b68cbd79fc78f 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1201,11 +1201,14 @@ static int isp116x_bus_suspend(struct usb_hcd *hcd) return ret; } +/* Get rid of these declarations later in cleanup */ +static int isp116x_reset(struct usb_hcd *hcd); +static int isp116x_start(struct usb_hcd *hcd); + static int isp116x_bus_resume(struct usb_hcd *hcd) { struct isp116x *isp116x = hcd_to_isp116x(hcd); u32 val; - int ret = -EINPROGRESS; msleep(5); spin_lock_irq(&isp116x->lock); @@ -1219,20 +1222,27 @@ static int isp116x_bus_resume(struct usb_hcd *hcd) case HCCONTROL_USB_RESUME: break; case HCCONTROL_USB_OPER: + spin_unlock_irq(&isp116x->lock); /* Without setting power_state here the SUSPENDED state won't be removed from sysfs/usbN/power.state as a response to remote wakeup. Maybe in the future. */ hcd->self.root_hub->dev.power.power_state = PMSG_ON; - ret = 0; - break; + return 0; default: - ret = -EBUSY; - } - - if (ret != -EINPROGRESS) { + /* HCCONTROL_USB_RESET: this may happen, when during + suspension the HC lost power. Reinitialize completely */ spin_unlock_irq(&isp116x->lock); - return ret; + DBG("Chip has been reset while suspended. Reinit from scratch.\n"); + isp116x_reset(hcd); + isp116x_start(hcd); + isp116x_hub_control(hcd, SetPortFeature, + USB_PORT_FEAT_POWER, 1, NULL, 0); + if ((isp116x->rhdesca & RH_A_NDP) == 2) + isp116x_hub_control(hcd, SetPortFeature, + USB_PORT_FEAT_POWER, 2, NULL, 0); + hcd->self.root_hub->dev.power.power_state = PMSG_ON; + return 0; } val = isp116x->rhdesca & RH_A_NDP;