diff options
-rw-r--r-- | drivers/usb/host/Kconfig | 4 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 73 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.h | 65 |
3 files changed, 142 insertions, 0 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 7dd4c44fabb..8045988f57a 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -410,6 +410,10 @@ config USB_UHCI_HCD | |||
410 | To compile this driver as a module, choose M here: the | 410 | To compile this driver as a module, choose M here: the |
411 | module will be called uhci-hcd. | 411 | module will be called uhci-hcd. |
412 | 412 | ||
413 | config USB_UHCI_SUPPORT_NON_PCI_HC | ||
414 | bool | ||
415 | depends on USB_UHCI_HCD | ||
416 | |||
413 | config USB_FHCI_HCD | 417 | config USB_FHCI_HCD |
414 | tristate "Freescale QE USB Host Controller support" | 418 | tristate "Freescale QE USB Host Controller support" |
415 | depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE | 419 | depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE |
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 5176c537b95..cd482fcc05d 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -167,6 +167,79 @@ static void check_and_reset_hc(struct uhci_hcd *uhci) | |||
167 | finish_reset(uhci); | 167 | finish_reset(uhci); |
168 | } | 168 | } |
169 | 169 | ||
170 | #if defined(CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC) | ||
171 | /* | ||
172 | * The two functions below are generic reset functions that are used on systems | ||
173 | * that do not have keyboard and mouse legacy support. We assume that we are | ||
174 | * running on such a system if CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC is defined. | ||
175 | */ | ||
176 | |||
177 | /* | ||
178 | * Make sure the controller is completely inactive, unable to | ||
179 | * generate interrupts or do DMA. | ||
180 | */ | ||
181 | static void uhci_generic_reset_hc(struct uhci_hcd *uhci) | ||
182 | { | ||
183 | /* Reset the HC - this will force us to get a | ||
184 | * new notification of any already connected | ||
185 | * ports due to the virtual disconnect that it | ||
186 | * implies. | ||
187 | */ | ||
188 | uhci_writew(uhci, USBCMD_HCRESET, USBCMD); | ||
189 | mb(); | ||
190 | udelay(5); | ||
191 | if (uhci_readw(uhci, USBCMD) & USBCMD_HCRESET) | ||
192 | dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n"); | ||
193 | |||
194 | /* Just to be safe, disable interrupt requests and | ||
195 | * make sure the controller is stopped. | ||
196 | */ | ||
197 | uhci_writew(uhci, 0, USBINTR); | ||
198 | uhci_writew(uhci, 0, USBCMD); | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Initialize a controller that was newly discovered or has just been | ||
203 | * resumed. In either case we can't be sure of its previous state. | ||
204 | * | ||
205 | * Returns: 1 if the controller was reset, 0 otherwise. | ||
206 | */ | ||
207 | static int uhci_generic_check_and_reset_hc(struct uhci_hcd *uhci) | ||
208 | { | ||
209 | unsigned int cmd, intr; | ||
210 | |||
211 | /* | ||
212 | * When restarting a suspended controller, we expect all the | ||
213 | * settings to be the same as we left them: | ||
214 | * | ||
215 | * Controller is stopped and configured with EGSM set; | ||
216 | * No interrupts enabled except possibly Resume Detect. | ||
217 | * | ||
218 | * If any of these conditions are violated we do a complete reset. | ||
219 | */ | ||
220 | |||
221 | cmd = uhci_readw(uhci, USBCMD); | ||
222 | if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) { | ||
223 | dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n", | ||
224 | __func__, cmd); | ||
225 | goto reset_needed; | ||
226 | } | ||
227 | |||
228 | intr = uhci_readw(uhci, USBINTR); | ||
229 | if (intr & (~USBINTR_RESUME)) { | ||
230 | dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n", | ||
231 | __func__, intr); | ||
232 | goto reset_needed; | ||
233 | } | ||
234 | return 0; | ||
235 | |||
236 | reset_needed: | ||
237 | dev_dbg(uhci_dev(uhci), "Performing full reset\n"); | ||
238 | uhci_generic_reset_hc(uhci); | ||
239 | return 1; | ||
240 | } | ||
241 | #endif /* CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC */ | ||
242 | |||
170 | /* | 243 | /* |
171 | * Store the basic register settings needed by the controller. | 244 | * Store the basic register settings needed by the controller. |
172 | */ | 245 | */ |
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index a6de241bf96..a4e64d08f02 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h | |||
@@ -380,6 +380,9 @@ struct uhci_hcd { | |||
380 | /* Grabbed from PCI */ | 380 | /* Grabbed from PCI */ |
381 | unsigned long io_addr; | 381 | unsigned long io_addr; |
382 | 382 | ||
383 | /* Used when registers are memory mapped */ | ||
384 | void __iomem *regs; | ||
385 | |||
383 | struct dma_pool *qh_pool; | 386 | struct dma_pool *qh_pool; |
384 | struct dma_pool *td_pool; | 387 | struct dma_pool *td_pool; |
385 | 388 | ||
@@ -481,6 +484,14 @@ struct urb_priv { | |||
481 | #define PCI_VENDOR_ID_GENESYS 0x17a0 | 484 | #define PCI_VENDOR_ID_GENESYS 0x17a0 |
482 | #define PCI_DEVICE_ID_GL880S_UHCI 0x8083 | 485 | #define PCI_DEVICE_ID_GL880S_UHCI 0x8083 |
483 | 486 | ||
487 | /* | ||
488 | * Functions used to access controller registers. The UCHI spec says that host | ||
489 | * controller I/O registers are mapped into PCI I/O space. For non-PCI hosts | ||
490 | * we use memory mapped registers. | ||
491 | */ | ||
492 | |||
493 | #if !defined(CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC) | ||
494 | /* Support PCI only */ | ||
484 | static inline u32 uhci_readl(struct uhci_hcd *uhci, int reg) | 495 | static inline u32 uhci_readl(struct uhci_hcd *uhci, int reg) |
485 | { | 496 | { |
486 | return inl(uhci->io_addr + reg); | 497 | return inl(uhci->io_addr + reg); |
@@ -511,4 +522,58 @@ static inline void uhci_writeb(struct uhci_hcd *uhci, u8 val, int reg) | |||
511 | outb(val, uhci->io_addr + reg); | 522 | outb(val, uhci->io_addr + reg); |
512 | } | 523 | } |
513 | 524 | ||
525 | #else | ||
526 | /* Support PCI and non-PCI host controllers */ | ||
527 | |||
528 | #define uhci_has_pci_registers(u) ((u)->io_addr != 0) | ||
529 | |||
530 | static inline u32 uhci_readl(struct uhci_hcd *uhci, int reg) | ||
531 | { | ||
532 | if (uhci_has_pci_registers(uhci)) | ||
533 | return inl(uhci->io_addr + reg); | ||
534 | else | ||
535 | return readl(uhci->regs + reg); | ||
536 | } | ||
537 | |||
538 | static inline void uhci_writel(struct uhci_hcd *uhci, u32 val, int reg) | ||
539 | { | ||
540 | if (uhci_has_pci_registers(uhci)) | ||
541 | outl(val, uhci->io_addr + reg); | ||
542 | else | ||
543 | writel(val, uhci->regs + reg); | ||
544 | } | ||
545 | |||
546 | static inline u16 uhci_readw(struct uhci_hcd *uhci, int reg) | ||
547 | { | ||
548 | if (uhci_has_pci_registers(uhci)) | ||
549 | return inw(uhci->io_addr + reg); | ||
550 | else | ||
551 | return readw(uhci->regs + reg); | ||
552 | } | ||
553 | |||
554 | static inline void uhci_writew(struct uhci_hcd *uhci, u16 val, int reg) | ||
555 | { | ||
556 | if (uhci_has_pci_registers(uhci)) | ||
557 | outw(val, uhci->io_addr + reg); | ||
558 | else | ||
559 | writew(val, uhci->regs + reg); | ||
560 | } | ||
561 | |||
562 | static inline u8 uhci_readb(struct uhci_hcd *uhci, int reg) | ||
563 | { | ||
564 | if (uhci_has_pci_registers(uhci)) | ||
565 | return inb(uhci->io_addr + reg); | ||
566 | else | ||
567 | return readb(uhci->regs + reg); | ||
568 | } | ||
569 | |||
570 | static inline void uhci_writeb(struct uhci_hcd *uhci, u8 val, int reg) | ||
571 | { | ||
572 | if (uhci_has_pci_registers(uhci)) | ||
573 | outb(val, uhci->io_addr + reg); | ||
574 | else | ||
575 | writeb(val, uhci->regs + reg); | ||
576 | } | ||
577 | #endif /* !defined(CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC) */ | ||
578 | |||
514 | #endif | 579 | #endif |