summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/isp116x-hcd.c26
1 files changed, 18 insertions, 8 deletions
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 82f64986bc22..5f56c4a42f52 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;