From 0780aa22781b0bc98428dbfaa312a0249475b632 Mon Sep 17 00:00:00 2001
From: "Alexandros C. Couloumbis" <alex@ozo.com>
Date: Sun, 15 Aug 2010 16:30:00 +0000
Subject: [PATCH] brcm47xx/patches-2.6.35: Allow SSB EHCI/OHCI drivers to
 co-exist (thank you Steve Brown)

SVN-Revision: 22661
---
 .../patches-2.6.35/023-usb_ehci_ohci.patch    | 188 ++++++++++++++++++
 1 file changed, 188 insertions(+)
 create mode 100644 target/linux/brcm47xx/patches-2.6.35/023-usb_ehci_ohci.patch

diff --git a/target/linux/brcm47xx/patches-2.6.35/023-usb_ehci_ohci.patch b/target/linux/brcm47xx/patches-2.6.35/023-usb_ehci_ohci.patch
new file mode 100644
index 0000000000..15d43ccc36
--- /dev/null
+++ b/target/linux/brcm47xx/patches-2.6.35/023-usb_ehci_ohci.patch
@@ -0,0 +1,188 @@
+--- 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
+@@ -1226,17 +1226,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
+ 	of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER);
+ clean4:
+@@ -1269,9 +1273,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
+ 	of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER);
+ #endif
-- 
GitLab