--- a/drivers/usb/host/ohci-ssb.c +++ b/drivers/usb/host/ohci-ssb.c @@ -17,6 +17,8 @@ */ #include <linux/ssb/ssb.h> +extern int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **hcd); +extern void ssb_ehci_detach(struct ssb_device *dev, struct usb_hcd *hcd); #define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) @@ -24,6 +26,9 @@ struct ssb_ohci_device { struct ohci_hcd ohci; /* _must_ be at the beginning. */ u32 enable_flags; +#ifdef CONFIG_USB_EHCI_HCD_SSB + struct usb_hcd *ehci_hcd; +#endif }; static inline @@ -92,6 +97,9 @@ static const struct hc_driver ssb_ohci_h static void ssb_ohci_detach(struct ssb_device *dev) { struct usb_hcd *hcd = ssb_get_drvdata(dev); +#ifdef CONFIG_USB_EHCI_HCD_SSB + struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); +#endif if (hcd->driver->shutdown) hcd->driver->shutdown(hcd); @@ -99,6 +107,14 @@ static void ssb_ohci_detach(struct ssb_d iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); + +#ifdef CONFIG_USB_EHCI_HCD_SSB + /* + * Also detach ehci function + */ + if (dev->id.coreid == SSB_DEV_USB20_HOST) + ssb_ehci_detach(dev, ohcidev->ehci_hcd); +#endif ssb_device_disable(dev, 0); } @@ -121,6 +137,9 @@ static int ssb_ohci_attach(struct ssb_de /* * USB 2.0 special considerations: * + * Since the core supports both OHCI and EHCI functions, + * it must only be reset once. + * * In addition to the standard SSB reset sequence, the Host * Control Register must be programmed to bring the USB core * and various phy components out of reset. @@ -175,6 +194,14 @@ static int ssb_ohci_attach(struct ssb_de ssb_set_drvdata(dev, hcd); +#ifdef CONFIG_USB_EHCI_HCD_SSB + /* + * attach ehci function in this core + */ + if (dev->id.coreid == SSB_DEV_USB20_HOST) + err = ssb_ehci_attach(dev, &(ohcidev->ehci_hcd)); +#endif + return err; err_iounmap: --- a/drivers/usb/host/ehci-ssb.c +++ b/drivers/usb/host/ehci-ssb.c @@ -106,10 +106,18 @@ static void ssb_ehci_detach(struct ssb_d iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); +#ifndef CONFIG_USB_OHCI_HCD_SSB + ssb_device_disable(dev, 0); +#endif ssb_device_disable(dev, 0); } +EXPORT_SYMBOL_GPL(ssb_ehci_detach); +#ifndef CONFIG_USB_OHCI_HCD_SSB static int ssb_ehci_attach(struct ssb_device *dev) +#else +static int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **ehci_hcd) +#endif { struct ssb_ehci_device *ehcidev; struct usb_hcd *hcd; @@ -120,6 +128,7 @@ static int ssb_ehci_attach(struct ssb_de dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) return -EOPNOTSUPP; +#ifndef CONFIG_USB_OHCI_HCD_SSB /* * USB 2.0 special considerations: * @@ -155,6 +164,7 @@ static int ssb_ehci_attach(struct ssb_de tmp |= 0x1; ssb_write32(dev, 0x89c, tmp); } +#endif hcd = usb_create_hcd(&ssb_ehci_hc_driver, dev->dev, dev_name(dev->dev)); @@ -175,7 +185,11 @@ static int ssb_ehci_attach(struct ssb_de if (err) goto err_iounmap; +#ifndef CONFIG_USB_OHCI_HCD_SSB ssb_set_drvdata(dev, hcd); +#else + *ehci_hcd = hcd; +#endif return err; @@ -187,7 +201,9 @@ err_dev_disable: ssb_device_disable(dev, 0); return err; } +EXPORT_SYMBOL_GPL(ssb_ehci_attach); +#ifndef CONFIG_USB_OHCI_HCD_SSB static int ssb_ehci_probe(struct ssb_device *dev, const struct ssb_device_id *id) { @@ -238,6 +254,7 @@ static int ssb_ehci_resume(struct ssb_de #define ssb_ehci_suspend NULL #define ssb_ehci_resume NULL #endif /* CONFIG_PM */ +#endif /* !CONFIG_USB_OHCI_HCD_SSB */ static const struct ssb_device_id ssb_ehci_table[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), @@ -245,6 +262,8 @@ static const struct ssb_device_id ssb_eh }; MODULE_DEVICE_TABLE(ssb, ssb_ehci_table); + +#ifndef CONFIG_USB_OHCI_HCD_SSB static struct ssb_driver ssb_ehci_driver = { .name = KBUILD_MODNAME, .id_table = ssb_ehci_table, @@ -253,3 +272,4 @@ static struct ssb_driver ssb_ehci_driver .suspend = ssb_ehci_suspend, .resume = ssb_ehci_resume, }; +#endif --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1352,17 +1352,21 @@ static int __init ehci_hcd_init(void) goto clean4; #endif +#ifndef CONFIG_USB_OHCI_HCD_SSB #ifdef SSB_EHCI_DRIVER retval = ssb_driver_register(&SSB_EHCI_DRIVER); if (retval < 0) goto clean5; #endif +#endif /* !CONFIG_USB_OHCI_HCD_SSB */ return retval; +#ifndef CONFIG_USB_OHCI_HCD_SSB #ifdef SSB_EHCI_DRIVER /* ssb_driver_unregister(&SSB_EHCI_DRIVER); */ clean5: #endif +#endif /* !CONFIG_USB_OHCI_HCD_SSB */ #ifdef XILINX_OF_PLATFORM_DRIVER platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER); clean4: @@ -1395,9 +1399,11 @@ module_init(ehci_hcd_init); static void __exit ehci_hcd_cleanup(void) { +#ifndef CONFIG_USB_OHCI_HCD_SSB #ifdef SSB_EHCI_DRIVER ssb_driver_unregister(&SSB_EHCI_DRIVER); #endif +#endif /* !CONFIG_USB_OHCI_HCD_SSB */ #ifdef XILINX_OF_PLATFORM_DRIVER platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER); #endif