I've got a patch that adds OHCI support for a new SoC. I'd say it is all good except that it requires a work-around for accessing OHCI registers. The code needs to hijack readl() so that it can perform the read twice.
What it does is define OHCI_readl() and then replace uses of readl() with that macro. For all other implementations the OHCI_readl() call translates to readl (). I did it this way so that there would be no doubt that OHCI_readl () might not be the standard macro. The questions are these. Is the applied method acceptable? Is there another way you'd prefer? Cheers.
Index: drivers/usb/Kconfig =================================================================== --- a/drivers/usb/Kconfig (.../2.6.4) (revision 73) +++ b/drivers/usb/Kconfig (.../lh7a40x-2.6.4-ms8) (revision 73) @@ -7,7 +7,7 @@ # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. config USB tristate "Support for USB" - depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610 + depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610 || ARCH_LH7A404 ---help--- Universal Serial Bus (USB) is a specification for a serial bus subsystem which offers higher speeds and more features than the Index: drivers/usb/host/ohci-hub.c =================================================================== --- a/drivers/usb/host/ohci-hub.c (.../2.6.4) (revision 73) +++ b/drivers/usb/host/ohci-hub.c (.../lh7a40x-2.6.4-ms8) (revision 73) @@ -20,20 +20,20 @@ * till some bits (mostly reserved) are clear; ok for all revs. */ #define read_roothub(hc, register, mask) ({ \ - u32 temp = readl (&hc->regs->roothub.register); \ + u32 temp = OHCI_readl (&hc->regs->roothub.register); \ if (temp == -1) \ disable (hc); \ else if (hc->flags & OHCI_QUIRK_AMD756) \ while (temp & mask) \ - temp = readl (&hc->regs->roothub.register); \ + temp = OHCI_readl (&hc->regs->roothub.register); \ temp; }) static u32 roothub_a (struct ohci_hcd *hc) { return read_roothub (hc, a, 0xfc0fe000); } static inline u32 roothub_b (struct ohci_hcd *hc) - { return readl (&hc->regs->roothub.b); } + { return OHCI_readl (&hc->regs->roothub.b); } static inline u32 roothub_status (struct ohci_hcd *hc) - { return readl (&hc->regs->roothub.status); } + { return OHCI_readl (&hc->regs->roothub.status); } static u32 roothub_portstatus (struct ohci_hcd *hc, int i) { return read_roothub (hc, portstatus [i], 0xffe0fce0); } @@ -76,7 +76,7 @@ if (!HCD_IS_RUNNING(ohci->hcd.state)) return -ESHUTDOWN; ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", - ports, readl (&ohci->regs->roothub.a) & RH_A_NDP); + ports, OHCI_readl (&ohci->regs->roothub.a) & RH_A_NDP); /* retry later; "should not happen" */ return 0; } @@ -208,7 +208,7 @@ goto error; } writel (temp, &ohci->regs->roothub.portstatus [wIndex]); - // readl (&ohci->regs->roothub.portstatus [wIndex]); + // OHCI_readl (&ohci->regs->roothub.portstatus [wIndex]); break; case GetHubDescriptor: ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf); @@ -253,7 +253,7 @@ &ohci->regs->roothub.portstatus [wIndex]); break; case USB_PORT_FEAT_RESET: - temp = readl (&ohci->regs->roothub.portstatus [wIndex]); + temp = OHCI_readl (&ohci->regs->roothub.portstatus [wIndex]); if (temp & RH_PS_CCS) writel (RH_PS_PRS, &ohci->regs->roothub.portstatus [wIndex]); Index: drivers/usb/host/ohci-lh7a404.c =================================================================== --- a/drivers/usb/host/ohci-lh7a404.c (revision 0) +++ b/drivers/usb/host/ohci-lh7a404.c (revision 73) @@ -0,0 +1,388 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber <[EMAIL PROTECTED]> + * (C) Copyright 2000-2002 David Brownell <[EMAIL PROTECTED]> + * (C) Copyright 2002 Hewlett-Packard Company + * + * Bus Glue for Sharp LH7A404 + * + * Written by Christopher Hoover <[EMAIL PROTECTED]> + * Based on fragments of previous driver by Rusell King et al. + * + * Modified for LH7A404 from ohci-sa1111.c + * by Durgesh Pattamatta <[EMAIL PROTECTED]> + * + * This file is licenced under the GPL. + */ + +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/arch/hardware.h> + + +extern int usb_disabled(void); + +/*-------------------------------------------------------------------------*/ + +static void lh7a404_start_hc(struct platform_device *dev) +{ + printk(KERN_DEBUG __FILE__ + ": starting LH7A404 OHCI USB Controller\n"); + + /* + * Now, carefully enable the USB clock, and take + * the USB host controller out of reset. + */ + CSC_PWRCNT |= CSC_PWRCNT_USBH_EN; /* Enable clock */ + udelay(1000); + USBH_CMDSTATUS = OHCI_HCR; + + printk(KERN_DEBUG __FILE__ + ": Clock to USB host has been enabled \n"); +} + +static void lh7a404_stop_hc(struct platform_device *dev) +{ + printk(KERN_DEBUG __FILE__ + ": stopping LH7A404 OHCI USB Controller\n"); + + CSC_PWRCNT &= ~CSC_PWRCNT_USBH_EN; /* Disable clock */ +} + + +/*-------------------------------------------------------------------------*/ + + +static irqreturn_t usb_hcd_lh7a404_hcim_irq (int irq, void *__hcd, + struct pt_regs * r) +{ + struct usb_hcd *hcd = __hcd; + + return usb_hcd_irq(irq, hcd, r); +} + +/*-------------------------------------------------------------------------*/ + +void usb_hcd_lh7a404_remove (struct usb_hcd *, struct platform_device *); + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + + +/** + * usb_hcd_lh7a404_probe - initialize LH7A404-based HCDs + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + * Store this function in the HCD's struct pci_driver as probe(). + */ +int usb_hcd_lh7a404_probe (const struct hc_driver *driver, + struct usb_hcd **hcd_out, + struct platform_device *dev) +{ + int retval; + struct usb_hcd *hcd = 0; + + unsigned int *addr = NULL; + + if (!request_mem_region(dev->resource[0].start, + dev->resource[0].end + - dev->resource[0].start + 1, hcd_name)) { + dbg("request_mem_region failed"); + return -EBUSY; + } + + + lh7a404_start_hc(dev); + + addr = ioremap(dev->resource[0].start, + dev->resource[0].end + - dev->resource[0].start + 1); + if (!addr) { + dbg("ioremap failed"); + retval = -ENOMEM; + goto err1; + } + + + hcd = driver->hcd_alloc (); + if (hcd == NULL){ + dbg ("hcd_alloc failed"); + retval = -ENOMEM; + goto err1; + } + + if(dev->resource[1].flags != IORESOURCE_IRQ){ + dbg ("resource[1] is not IORESOURCE_IRQ"); + retval = -ENOMEM; + goto err1; + } + + hcd->driver = (struct hc_driver *) driver; + hcd->description = driver->description; + hcd->irq = dev->resource[1].start; + hcd->regs = addr; + hcd->self.controller = &dev->dev; + + retval = hcd_buffer_create (hcd); + if (retval != 0) { + dbg ("pool alloc fail"); + goto err1; + } + + retval = request_irq (hcd->irq, usb_hcd_lh7a404_hcim_irq, SA_INTERRUPT, + hcd->description, hcd); + if (retval != 0) { + dbg("request_irq failed"); + retval = -EBUSY; + goto err2; + } + + dbg ("%s (LH7A404) at 0x%p, irq %d", + hcd->description, hcd->regs, hcd->irq); + + usb_bus_init (&hcd->self); + hcd->self.op = &usb_hcd_operations; + hcd->self.hcpriv = (void *) hcd; + hcd->self.bus_name = "lh7a404"; + hcd->product_desc = "LH7A404 OHCI"; + + INIT_LIST_HEAD (&hcd->dev_list); + + usb_register_bus (&hcd->self); + + if ((retval = driver->start (hcd)) < 0) + { + usb_hcd_lh7a404_remove(hcd, dev); + return retval; + } + + *hcd_out = hcd; + return 0; + + err2: + hcd_buffer_destroy (hcd); + if (hcd) + driver->hcd_free(hcd); + err1: + lh7a404_stop_hc(dev); + release_mem_region(dev->resource[0].start, + dev->resource[0].end + - dev->resource[0].start + 1); + return retval; +} + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_lh7a404_remove - shutdown processing for LH7A404-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_lh7a404_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + */ +void usb_hcd_lh7a404_remove (struct usb_hcd *hcd, struct platform_device *dev) +{ + struct usb_device *hub; + void *base; + + dbg ("remove: %s, state %x", hcd->self.bus_name, hcd->state); + + if (in_interrupt ()) + BUG (); + + hub = hcd->self.root_hub; + hcd->state = USB_STATE_QUIESCING; + + dbg ("%s: roothub graceful disconnect", hcd->self.bus_name); + usb_disconnect (&hub); + + hcd->driver->stop (hcd); + hcd->state = USB_STATE_HALT; + + free_irq (hcd->irq, hcd); + hcd_buffer_destroy (hcd); + + usb_deregister_bus (&hcd->self); + + base = hcd->regs; + hcd->driver->hcd_free (hcd); + + lh7a404_stop_hc(dev); + release_mem_region(dev->resource[0].start, + dev->resource[0].end + - dev->resource[0].start + 1); +} + +/*-------------------------------------------------------------------------*/ + +static int __devinit +ohci_lh7a404_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + dbg ("ohci_lh7a404_start, ohci:%p", ohci); + + ohci->hcca = dma_alloc_coherent (hcd->self.controller, + sizeof *ohci->hcca, &ohci->hcca_dma, 0); + if (!ohci->hcca) + return -ENOMEM; + + dbg ("ohci_lh7a404_start, ohci->hcca:%p", + ohci->hcca); + + memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); + + if ((ret = ohci_mem_init (ohci)) < 0) { + ohci_stop (hcd); + return ret; + } + ohci->regs = hcd->regs; + + if (hc_reset (ohci) < 0) { + ohci_stop (hcd); + return -ENODEV; + } + + if (hc_start (ohci) < 0) { + err ("can't start %s", ohci->hcd.self.bus_name); + ohci_stop (hcd); + return -EBUSY; + } + create_debug_files (ohci); + +#ifdef DEBUG + ohci_dump (ohci, 1); +#endif /*DEBUG*/ + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_lh7a404_hc_driver = { + .description = hcd_name, + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11, + + /* + * basic lifecycle operations + */ + .start = ohci_lh7a404_start, +#ifdef CONFIG_PM + /* suspend: ohci_lh7a404_suspend, -- tbd */ + /* resume: ohci_lh7a404_resume, -- tbd */ +#endif /*CONFIG_PM*/ + .stop = ohci_stop, + + /* + * memory lifecycle (except per-request) + */ + .hcd_alloc = ohci_hcd_alloc, + .hcd_free = ohci_hcd_free, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +}; + +/*-------------------------------------------------------------------------*/ + +static int ohci_hcd_lh7a404_drv_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = NULL; + int ret; + + dbg ("In ohci_hcd_lh7a404_drv_probe"); + + if (usb_disabled()) + return -ENODEV; + + ret = usb_hcd_lh7a404_probe(&ohci_lh7a404_hc_driver, &hcd, pdev); + + if (ret == 0) + dev_set_drvdata(dev, hcd); + + return ret; +} + +static int ohci_hcd_lh7a404_drv_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + usb_hcd_lh7a404_remove(hcd, pdev); + dev_set_drvdata(dev, NULL); + return 0; +} + /*TBD*/ +/*static int ohci_hcd_lh7a404_drv_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return 0; +} +static int ohci_hcd_lh7a404_drv_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + + return 0; +} +*/ + +static struct device_driver ohci_hcd_lh7a404_driver = { + .name = "lh7a404-ohci", + .bus = &platform_bus_type, + .probe = ohci_hcd_lh7a404_drv_probe, + .remove = ohci_hcd_lh7a404_drv_remove, + /*.suspend = ohci_hcd_lh7a404_drv_suspend, */ + /*.resume = ohci_hcd_lh7a404_drv_resume, */ +}; + +static int __init ohci_hcd_lh7a404_init (void) +{ + dbg (DRIVER_INFO " (LH7A404)"); + dbg ("block sizes: ed %d td %d\n", + sizeof (struct ed), sizeof (struct td)); + + return driver_register(&ohci_hcd_lh7a404_driver); +} + +static void __exit ohci_hcd_lh7a404_cleanup (void) +{ + driver_unregister(&ohci_hcd_lh7a404_driver); +} + +module_init (ohci_hcd_lh7a404_init); +module_exit (ohci_hcd_lh7a404_cleanup); Index: drivers/usb/host/ohci-dbg.c =================================================================== --- a/drivers/usb/host/ohci-dbg.c (.../2.6.4) (revision 73) +++ b/drivers/usb/host/ohci-dbg.c (.../lh7a40x-2.6.4-ms8) (revision 73) @@ -134,13 +134,13 @@ struct ohci_regs *regs = controller->regs; u32 temp; - temp = readl (®s->revision) & 0xff; + temp = OHCI_readl (®s->revision) & 0xff; ohci_dbg_sw (controller, next, size, "OHCI %d.%d, %s legacy support registers\n", 0x03 & (temp >> 4), (temp & 0x0f), (temp & 0x10) ? "with" : "NO"); - temp = readl (®s->control); + temp = OHCI_readl (®s->control); ohci_dbg_sw (controller, next, size, "control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n", temp, @@ -155,7 +155,7 @@ temp & OHCI_CTRL_CBSR ); - temp = readl (®s->cmdstatus); + temp = OHCI_readl (®s->cmdstatus); ohci_dbg_sw (controller, next, size, "cmdstatus 0x%05x SOC=%d%s%s%s%s\n", temp, (temp & OHCI_SOC) >> 16, @@ -166,26 +166,26 @@ ); ohci_dump_intr_mask (controller, "intrstatus", - readl (®s->intrstatus), next, size); + OHCI_readl (®s->intrstatus), next, size); ohci_dump_intr_mask (controller, "intrenable", - readl (®s->intrenable), next, size); + OHCI_readl (®s->intrenable), next, size); // intrdisable always same as intrenable maybe_print_eds (controller, "ed_periodcurrent", - readl (®s->ed_periodcurrent), next, size); + OHCI_readl (®s->ed_periodcurrent), next, size); maybe_print_eds (controller, "ed_controlhead", - readl (®s->ed_controlhead), next, size); + OHCI_readl (®s->ed_controlhead), next, size); maybe_print_eds (controller, "ed_controlcurrent", - readl (®s->ed_controlcurrent), next, size); + OHCI_readl (®s->ed_controlcurrent), next, size); maybe_print_eds (controller, "ed_bulkhead", - readl (®s->ed_bulkhead), next, size); + OHCI_readl (®s->ed_bulkhead), next, size); maybe_print_eds (controller, "ed_bulkcurrent", - readl (®s->ed_bulkcurrent), next, size); + OHCI_readl (®s->ed_bulkcurrent), next, size); maybe_print_eds (controller, "donehead", - readl (®s->donehead), next, size); + OHCI_readl (®s->donehead), next, size); } #define dbg_port_sw(hc,num,value,next,size) \ @@ -627,7 +627,7 @@ "hcca frame 0x%04x\n", OHCI_FRAME_NO(ohci->hcca)); /* other registers mostly affect frame timings */ - rdata = readl (®s->fminterval); + rdata = OHCI_readl (®s->fminterval); temp = scnprintf (next, size, "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n", rdata, (rdata >> 31) ? " FIT" : "", @@ -635,20 +635,20 @@ size -= temp; next += temp; - rdata = readl (®s->fmremaining); + rdata = OHCI_readl (®s->fmremaining); temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n", rdata, (rdata >> 31) ? " FRT" : "", rdata & 0x3fff); size -= temp; next += temp; - rdata = readl (®s->periodicstart); + rdata = OHCI_readl (®s->periodicstart); temp = scnprintf (next, size, "periodicstart 0x%04x\n", rdata & 0x3fff); size -= temp; next += temp; - rdata = readl (®s->lsthresh); + rdata = OHCI_readl (®s->lsthresh); temp = scnprintf (next, size, "lsthresh 0x%04x\n", rdata & 0x3fff); size -= temp; Index: drivers/usb/host/ohci-hcd.c =================================================================== --- a/drivers/usb/host/ohci-hcd.c (.../2.6.4) (revision 73) +++ b/drivers/usb/host/ohci-hcd.c (.../lh7a40x-2.6.4-ms8) (revision 73) @@ -17,6 +17,7 @@ * * History: * + * 2004/03/24 LH7A404 support (Durgesh Pattamatta & Marc Singer) * 2004/02/04 use generic dma_* functions instead of pci_* ([EMAIL PROTECTED]) * 2003/02/24 show registers in sysfs (Kevin Brosius) * @@ -131,6 +132,26 @@ ohci->hcd.state = USB_STATE_HALT; } +#ifdef CONFIG_ARCH_LH7A404 + /* Marc Singer: at the time this code was written, the LH7A404 + * had a problem reading the USB host registers. This + * implementation of the OHCI_readl function performs the read + * twice as a work-around. + */ +static inline unsigned int OHCI_readl (void* regs) +{ + *(volatile unsigned int*) regs; + return *(volatile unsigned int*) regs; +} +#else + /* Standard version of OHCI_readl uses normal, platform + * specific implementation. */ +static inline unsigned int OHCI_readl (void* regs) +{ + return readl (regs); +} +#endif + #include "ohci-hub.c" #include "ohci-dbg.c" #include "ohci-mem.c" @@ -398,7 +419,7 @@ * On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ #ifndef __hppa__ - if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { + if (OHCI_readl (&ohci->regs->control) & OHCI_CTRL_IR) { ohci_dbg (ohci, "USB HC TakeOver from BIOS/SMM\n"); /* this timeout is arbitrary. we make it long, so systems @@ -409,7 +430,7 @@ writel (OHCI_INTR_OC, &ohci->regs->intrenable); writel (OHCI_OCR, &ohci->regs->cmdstatus); - while (readl (&ohci->regs->control) & OHCI_CTRL_IR) { + while (OHCI_readl (&ohci->regs->control) & OHCI_CTRL_IR) { wait_ms (10); if (--temp == 0) { ohci_err (ohci, "USB HC TakeOver failed!\n"); @@ -423,12 +444,12 @@ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); ohci_dbg (ohci, "reset, control = 0x%x\n", - readl (&ohci->regs->control)); + OHCI_readl (&ohci->regs->control)); /* Reset USB (needed by some controllers); RemoteWakeupConnected * saved if boot firmware (BIOS/SMM/...) told us it's connected */ - ohci->hc_control = readl (&ohci->regs->control); + ohci->hc_control = OHCI_readl (&ohci->regs->control); ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */ writel (ohci->hc_control, &ohci->regs->control); if (power_switching) { @@ -440,13 +461,13 @@ &ohci->regs->roothub.portstatus [temp]); } // flush those pci writes - (void) readl (&ohci->regs->control); + (void) OHCI_readl (&ohci->regs->control); wait_ms (50); /* HC Reset requires max 10 us delay */ writel (OHCI_HCR, &ohci->regs->cmdstatus); temp = 30; /* ... allow extra time */ - while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { + while ((OHCI_readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { if (--temp == 0) { ohci_err (ohci, "USB HC reset timed out!\n"); return -1; @@ -463,7 +484,7 @@ */ writel (ohci->hc_control, &ohci->regs->control); // flush those pci writes - (void) readl (&ohci->regs->control); + (void) OHCI_readl (&ohci->regs->control); return 0; } @@ -504,8 +525,8 @@ /* some OHCI implementations are finicky about how they init. * bogus values here mean not even enumeration could work. */ - if ((readl (&ohci->regs->fminterval) & 0x3fff0000) == 0 - || !readl (&ohci->regs->periodicstart)) { + if ((OHCI_readl (&ohci->regs->fminterval) & 0x3fff0000) == 0 + || !OHCI_readl (&ohci->regs->periodicstart)) { ohci_err (ohci, "init err\n"); return -EOVERFLOW; } @@ -544,7 +565,7 @@ writel (RH_HS_LPSC, &ohci->regs->roothub.status); writel (power_switching ? RH_B_PPCM : 0, &ohci->regs->roothub.b); // flush those pci writes - (void) readl (&ohci->regs->control); + (void) OHCI_readl (&ohci->regs->control); // POTPGT delay is bits 24-31, in 2 ms units. mdelay ((roothub_a (ohci) >> 23) & 0x1fe); @@ -583,19 +604,20 @@ struct ohci_regs *regs = ohci->regs; int ints; - /* we can eliminate a (slow) readl() if _only_ WDH caused this irq */ + /* we can eliminate a (slow) OHCI_readl() + if _only_ WDH caused this irq */ if ((ohci->hcca->done_head != 0) && ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) { ints = OHCI_INTR_WDH; /* cardbus/... hardware gone before remove() */ - } else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { + } else if ((ints = OHCI_readl (®s->intrstatus)) == ~(u32)0) { disable (ohci); ohci_dbg (ohci, "device removed!\n"); return IRQ_HANDLED; /* interrupt for some other device? */ - } else if ((ints &= readl (®s->intrenable)) == 0) { + } else if ((ints &= OHCI_readl (®s->intrenable)) == 0) { return IRQ_NONE; } @@ -634,7 +656,7 @@ writel (ints, ®s->intrstatus); writel (OHCI_INTR_MIE, ®s->intrenable); // flush those pci writes - (void) readl (&ohci->regs->control); + (void) OHCI_readl (&ohci->regs->control); } return IRQ_HANDLED; @@ -723,6 +745,14 @@ #include "ohci-omap.c" #endif -#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111) || defined(CONFIG_ARCH_OMAP)) +#ifdef CONFIG_ARCH_LH7A404 +#include "ohci-lh7a404.c" +#endif + +#if !(defined(CONFIG_PCI) \ + || defined(CONFIG_SA1111) \ + || defined(CONFIG_ARCH_OMAP) \ + || defined (CONFIG_ARCH_LH7A404) \ + ) #error "missing bus glue for ohci-hcd" #endif Index: drivers/usb/host/ohci-q.c =================================================================== --- a/drivers/usb/host/ohci-q.c (.../2.6.4) (revision 73) +++ b/drivers/usb/host/ohci-q.c (.../lh7a40x-2.6.4-ms8) (revision 73) @@ -314,7 +314,7 @@ if (!ed->hwNextED) { ohci->hc_control &= ~OHCI_CTRL_CLE; writel (ohci->hc_control, &ohci->regs->control); - // a readl() later syncs CLE with the HC + // a OHCI_readl() later syncs CLE with the HC } else writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead); @@ -338,7 +338,7 @@ if (!ed->hwNextED) { ohci->hc_control &= ~OHCI_CTRL_BLE; writel (ohci->hc_control, &ohci->regs->control); - // a readl() later syncs BLE with the HC + // a OHCI_readl() later syncs BLE with the HC } else writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead); @@ -474,7 +474,7 @@ writel (OHCI_INTR_SF, &ohci->regs->intrstatus); writel (OHCI_INTR_SF, &ohci->regs->intrenable); // flush those writes, and get latest HCCA contents - (void) readl (&ohci->regs->control); + (void) OHCI_readl (&ohci->regs->control); /* SF interrupt might get delayed; record the frame counter value that * indicates when the HC isn't looking at it, so concurrent unlinks