diff options
Diffstat (limited to 'drivers/usb/host/ohci-pci.c')
-rw-r--r-- | drivers/usb/host/ohci-pci.c | 57 |
1 files changed, 56 insertions, 1 deletions
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index ca62cb583221..a5e2eb85d073 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c | |||
@@ -111,6 +111,18 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd) | |||
111 | #endif | 111 | #endif |
112 | } | 112 | } |
113 | 113 | ||
114 | /* Check for NEC chip and apply quirk for allegedly lost interrupts. | ||
115 | */ | ||
116 | static int ohci_quirk_nec(struct usb_hcd *hcd) | ||
117 | { | ||
118 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | ||
119 | |||
120 | ohci->flags |= OHCI_QUIRK_NEC; | ||
121 | ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n"); | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
114 | /* List of quirks for OHCI */ | 126 | /* List of quirks for OHCI */ |
115 | static const struct pci_device_id ohci_pci_quirks[] = { | 127 | static const struct pci_device_id ohci_pci_quirks[] = { |
116 | { | 128 | { |
@@ -134,6 +146,10 @@ static const struct pci_device_id ohci_pci_quirks[] = { | |||
134 | .driver_data = (unsigned long)ohci_quirk_toshiba_scc, | 146 | .driver_data = (unsigned long)ohci_quirk_toshiba_scc, |
135 | }, | 147 | }, |
136 | { | 148 | { |
149 | PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB), | ||
150 | .driver_data = (unsigned long)ohci_quirk_nec, | ||
151 | }, | ||
152 | { | ||
137 | /* Toshiba portege 4000 */ | 153 | /* Toshiba portege 4000 */ |
138 | .vendor = PCI_VENDOR_ID_AL, | 154 | .vendor = PCI_VENDOR_ID_AL, |
139 | .device = 0x5237, | 155 | .device = 0x5237, |
@@ -202,6 +218,42 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd) | |||
202 | return ret; | 218 | return ret; |
203 | } | 219 | } |
204 | 220 | ||
221 | #if defined(CONFIG_USB_PERSIST) && (defined(CONFIG_USB_EHCI_HCD) || \ | ||
222 | defined(CONFIG_USB_EHCI_HCD_MODULE)) | ||
223 | |||
224 | /* Following a power loss, we must prepare to regain control of the ports | ||
225 | * we used to own. This means turning on the port power before ehci-hcd | ||
226 | * tries to switch ownership. | ||
227 | * | ||
228 | * This isn't a 100% perfect solution. On most systems the OHCI controllers | ||
229 | * lie at lower PCI addresses than the EHCI controller, so they will be | ||
230 | * discovered (and hence resumed) first. But there is no guarantee things | ||
231 | * will always work this way. If the EHCI controller is resumed first and | ||
232 | * the OHCI ports are unpowered, then the handover will fail. | ||
233 | */ | ||
234 | static void prepare_for_handover(struct usb_hcd *hcd) | ||
235 | { | ||
236 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | ||
237 | int port; | ||
238 | |||
239 | /* Here we "know" root ports should always stay powered */ | ||
240 | ohci_dbg(ohci, "powerup ports\n"); | ||
241 | for (port = 0; port < ohci->num_ports; port++) | ||
242 | ohci_writel(ohci, RH_PS_PPS, | ||
243 | &ohci->regs->roothub.portstatus[port]); | ||
244 | |||
245 | /* Flush those writes */ | ||
246 | ohci_readl(ohci, &ohci->regs->control); | ||
247 | msleep(20); | ||
248 | } | ||
249 | |||
250 | #else | ||
251 | |||
252 | static inline void prepare_for_handover(struct usb_hcd *hcd) | ||
253 | { } | ||
254 | |||
255 | #endif /* CONFIG_USB_PERSIST etc. */ | ||
256 | |||
205 | #ifdef CONFIG_PM | 257 | #ifdef CONFIG_PM |
206 | 258 | ||
207 | static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) | 259 | static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) |
@@ -241,7 +293,10 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) | |||
241 | static int ohci_pci_resume (struct usb_hcd *hcd) | 293 | static int ohci_pci_resume (struct usb_hcd *hcd) |
242 | { | 294 | { |
243 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 295 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
244 | usb_hcd_resume_root_hub(hcd); | 296 | |
297 | /* FIXME: we should try to detect loss of VBUS power here */ | ||
298 | prepare_for_handover(hcd); | ||
299 | |||
245 | return 0; | 300 | return 0; |
246 | } | 301 | } |
247 | 302 | ||