From: Alek Du <alek.du@xxxxxxxxx> The Intel Moorestown platform has EHCI MPH and EHCI OTG host. This patch adds PCI probe part for them. The HNP part and SRAM part will be added later. Signed-off-by: Jacob Pan <jacob.jun.pan@xxxxxxxxx> Signed-off-by: Alek Du <alek.du@xxxxxxxxx> Signed-off-by: Alan Cox <alan@xxxxxxxxxxxxxxx> Signed-off-by: Hao Wu <hao.wu@xxxxxxxxx> Signed-off-by: Dirk Brandewie <dirk.brandewie@xxxxxxxxx> --- drivers/usb/core/hub.c | 10 ++++++++++ drivers/usb/core/usb.h | 1 - drivers/usb/host/ehci-hcd.c | 19 +++++++++++++++++++ drivers/usb/host/ehci-hub.c | 13 +++++++++++-- drivers/usb/host/ehci-pci.c | 15 +++++++++++++++ drivers/usb/host/ehci.h | 6 ++++++ include/linux/usb/hcd.h | 6 ++++++ 7 files changed, 67 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5ca3714..df2215f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1614,6 +1614,14 @@ static void hub_free_dev(struct usb_device *udev) hcd->driver->free_dev(hcd, udev); } +static void otg_notify(struct usb_device *udev, unsigned action) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (hcd->otg_notify) + hcd->otg_notify(udev, action); +} + /** * usb_disconnect - disconnect a device (usbcore-internal) * @pdev: pointer to device being disconnected @@ -1670,6 +1678,7 @@ void usb_disconnect(struct usb_device **pdev) * notifier chain (used by usbfs and possibly others). */ device_del(&udev->dev); + otg_notify(udev, USB_DEVICE_REMOVE); /* Free the device number and delete the parent's children[] * (or root_hub) pointer. @@ -1900,6 +1909,7 @@ int usb_new_device(struct usb_device *udev) dev_err(&udev->dev, "can't device_add, error %d\n", err); goto fail; } + otg_notify(udev, USB_DEVICE_ADD); (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); usb_mark_last_busy(udev); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index d44d4b7..e369957 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -161,4 +161,3 @@ extern void usb_notify_add_device(struct usb_device *udev); extern void usb_notify_remove_device(struct usb_device *udev); extern void usb_notify_add_bus(struct usb_bus *ubus); extern void usb_notify_remove_bus(struct usb_bus *ubus); - diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 8696489..ee2a382 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -47,6 +47,8 @@ #include <asm/irq.h> #include <asm/system.h> #include <asm/unaligned.h> +#include <linux/usb/otg.h> +#include <linux/usb/langwell_otg.h> /*-------------------------------------------------------------------------*/ @@ -1179,6 +1181,10 @@ MODULE_LICENSE ("GPL"); #ifdef CONFIG_PCI #include "ehci-pci.c" #define PCI_DRIVER ehci_pci_driver +#ifdef CONFIG_USB_LANGWELL_OTG +#include "ehci-langwell-pci.c" +#define LNW_OTG_HOST_DRIVER ehci_otg_driver +#endif #endif #ifdef CONFIG_USB_EHCI_FSL @@ -1363,8 +1369,18 @@ static int __init ehci_hcd_init(void) if (retval < 0) goto clean4; #endif + +#ifdef LNW_OTG_HOST_DRIVER + retval = langwell_register_host(&LNW_OTG_HOST_DRIVER); + if (retval < 0) + goto clean5; +#endif return retval; +#ifdef LNW_OTG_HOST_DRIVER +clean5: + langwell_unregister_host(&LNW_OTG_HOST_DRIVER); +#endif #ifdef XILINX_OF_PLATFORM_DRIVER /* platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER); */ clean4: @@ -1397,6 +1413,9 @@ module_init(ehci_hcd_init); static void __exit ehci_hcd_cleanup(void) { +#ifdef LNW_OTG_HOST_DRIVER + langwell_unregister_host(&LNW_OTG_HOST_DRIVER); +#endif #ifdef XILINX_OF_PLATFORM_DRIVER platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER); #endif diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 77bbb23..c052d1c 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -207,6 +207,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) int port; int mask; int changed; + int rc = 0; ehci_dbg(ehci, "suspend root hub\n"); @@ -324,13 +325,17 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) ehci_readl(ehci, &ehci->regs->intr_enable); ehci->next_statechange = jiffies + msecs_to_jiffies(10); + + if (ehci->has_otg && ehci->otg_suspend) + rc = ehci->otg_suspend(hcd); + spin_unlock_irq (&ehci->lock); /* ehci_work() may have re-enabled the watchdog timer, which we do not * want, and so we must delete any pending watchdog timer events. */ del_timer_sync(&ehci->watchdog); - return 0; + return rc; } @@ -342,6 +347,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) u32 power_okay; int i; unsigned long resume_needed = 0; + int rc = 0; if (time_before (jiffies, ehci->next_statechange)) msleep(5); @@ -454,9 +460,12 @@ static int ehci_bus_resume (struct usb_hcd *hcd) /* Now we can safely re-enable irqs */ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); + if (ehci->has_otg && ehci->otg_resume) + rc = ehci->otg_resume(hcd); + spin_unlock_irq (&ehci->lock); ehci_handover_companion_ports(ehci); - return 0; + return rc; } #else diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 8311de7..f4e718c 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -53,6 +53,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) u8 rev; u32 temp; int retval; + int force_otg_hc_mode = 0; switch (pdev->vendor) { case PCI_VENDOR_ID_TOSHIBA_2: @@ -66,6 +67,18 @@ static int ehci_pci_setup(struct usb_hcd *hcd) #endif } break; + case PCI_VENDOR_ID_INTEL: + if (pdev->device == 0x0811) { + ehci_info(ehci, "Detected Langwell OTG HC\n"); + hcd->has_tt = 1; + ehci->has_hostpc = 1; + ehci->has_otg = 1; + force_otg_hc_mode = 1; + } else if (pdev->device == 0x0806) { + ehci_info(ehci, "Detected Langwell MPH\n"); + hcd->has_tt = 1; + ehci->has_hostpc = 1; + } } ehci->caps = hcd->regs; @@ -101,6 +114,8 @@ static int ehci_pci_setup(struct usb_hcd *hcd) /* cache this readonly data; minimize chip reads */ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + if (force_otg_hc_mode) + ehci_reset(ehci); retval = ehci_halt(ehci); if (retval) diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index c161d97..264051a 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -158,6 +158,8 @@ struct ehci_hcd { /* one per controller */ unsigned has_hostpc:1; unsigned has_lpm:1; /* support link power management */ unsigned has_ppcd:1; /* support per-port change bits */ + + unsigned has_otg:1; /* if it is otg host*/ u8 sbrn; /* packed release number */ /* irq statistics */ @@ -168,6 +170,10 @@ struct ehci_hcd { /* one per controller */ # define COUNT(x) do {} while (0) #endif + /* otg host has additional bus_suspend and bus_resume */ + int (*otg_suspend)(struct usb_hcd *hcd); + int (*otg_resume)(struct usb_hcd *hcd); + /* debug files */ #ifdef DEBUG struct dentry *debug_dir; diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 0097136..a91e7e5 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -174,6 +174,12 @@ struct usb_hcd { * (ohci 32, uhci 1024, ehci 256/512/1024). */ + /* some otg HCDs need this to get USB_DEVICE_ADD and USB_DEVICE_REMOVE + * from root hub, we do not want to use USB notification chain, since + * it would be a over kill to use high level notification. + */ + void (*otg_notify) (struct usb_device *udev, unsigned action); + /* The HC driver's private data is stored at the end of * this structure. */ -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html