USB: Add nuvoton Ehci driver for w90p910 platform
authorWan ZongShun <mcuos.com@gmail.com>
Sat, 13 Jun 2009 01:14:28 +0000 (09:14 +0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 23 Sep 2009 13:46:20 +0000 (06:46 -0700)
Add ehci support for w90p910 platform.

Signed-off-by: Wan ZongShun <mcuos.com@gmail.com>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/Kconfig
drivers/usb/host/Kconfig
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-w90x900.c [new file with mode: 0644]

index dcd49f1e96d006d1abb04271687d90f0f52a9ef5..93cee3e5ca5852e9144e9316cedfc1fdaa4b804e 100644 (file)
@@ -39,6 +39,7 @@ config USB_ARCH_HAS_OHCI
        default y if ARCH_AT91
        default y if ARCH_PNX4008 && I2C
        default y if MFD_TC6393XB
+       default y if ARCH_W90X900
        # PPC:
        default y if STB03xxx
        default y if PPC_MPC52xx
@@ -58,6 +59,7 @@ config USB_ARCH_HAS_EHCI
        default y if PPC_83xx
        default y if SOC_AU1200
        default y if ARCH_IXP4XX
+       default y if ARCH_W90X900
        default PCI
 
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
index f21ca7d27a4305d7e27a093a7561cde91cfa9d3f..41b8d7de2e07032486f19f4bb4bce6229bd08c13 100644 (file)
@@ -113,6 +113,12 @@ config USB_EHCI_HCD_PPC_OF
          Enables support for the USB controller present on the PowerPC
          OpenFirmware platform bus.
 
+config USB_W90X900_EHCI
+       bool "W90X900(W90P910) EHCI support"
+       depends on USB_EHCI_HCD && ARCH_W90X900
+       ---help---
+               Enables support for the W90X900 USB controller
+
 config USB_OXU210HP_HCD
        tristate "OXU210HP HCD support"
        depends on USB
index 11c627ce60224754978bf495e40cd94496c3b7c7..54715b875759c0cc83fe5e4402bad822251a805c 100644 (file)
@@ -1117,6 +1117,11 @@ MODULE_LICENSE ("GPL");
 #define        PLATFORM_DRIVER         ixp4xx_ehci_driver
 #endif
 
+#ifdef CONFIG_USB_W90X900_EHCI
+#include "ehci-w90x900.c"
+#define        PLATFORM_DRIVER         ehci_hcd_w90x900_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
 #error "missing bus glue for ehci-hcd"
diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c
new file mode 100644 (file)
index 0000000..cfa21ea
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * linux/driver/usb/host/ehci-w90x900.c
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/platform_device.h>
+
+/*ebable phy0 and phy1 for w90p910*/
+#define        ENPHY           (0x01<<8)
+#define PHY0_CTR       (0xA4)
+#define PHY1_CTR       (0xA8)
+
+static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
+                     struct platform_device *pdev)
+{
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+       struct resource *res;
+       int retval = 0, irq;
+       unsigned long val;
+
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               retval = -ENXIO;
+               goto err1;
+       }
+
+       hcd = usb_create_hcd(driver, &pdev->dev, "w90x900 EHCI");
+       if (!hcd) {
+               retval = -ENOMEM;
+               goto err1;
+       }
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = res->end - res->start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+               retval = -EBUSY;
+               goto err2;
+       }
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (hcd->regs == NULL) {
+               retval = -EFAULT;
+               goto err3;
+       }
+
+       ehci = hcd_to_ehci(hcd);
+       ehci->caps = hcd->regs;
+       ehci->regs = hcd->regs +
+                HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+       /* enable PHY 0,1,the regs only apply to w90p910
+       *  0xA4,0xA8 were offsets of PHY0 and PHY1 controller of
+       *  w90p910 IC relative to ehci->regs.
+       */
+       val = __raw_readl(ehci->regs+PHY0_CTR);
+       val |= ENPHY;
+       __raw_writel(val, ehci->regs+PHY0_CTR);
+
+       val = __raw_readl(ehci->regs+PHY1_CTR);
+       val |= ENPHY;
+       __raw_writel(val, ehci->regs+PHY1_CTR);
+
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+       ehci->sbrn = 0x20;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               goto err4;
+
+       retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+       if (retval != 0)
+               goto err4;
+
+       ehci_writel(ehci, 1, &ehci->regs->configured_flag);
+
+       return retval;
+err4:
+       iounmap(hcd->regs);
+err3:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err2:
+       usb_put_hcd(hcd);
+err1:
+       return retval;
+}
+
+static
+void usb_w90x900_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+{
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+}
+
+static const struct hc_driver ehci_w90x900_hc_driver = {
+       .description = hcd_name,
+       .product_desc = "Nuvoton w90x900 EHCI Host Controller",
+       .hcd_priv_size = sizeof(struct ehci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq = ehci_irq,
+       .flags = HCD_USB2|HCD_MEMORY,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset = ehci_init,
+       .start = ehci_run,
+
+       .stop = ehci_stop,
+       .shutdown = ehci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue = ehci_urb_enqueue,
+       .urb_dequeue = ehci_urb_dequeue,
+       .endpoint_disable = ehci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data = ehci_hub_status_data,
+       .hub_control = ehci_hub_control,
+#ifdef CONFIG_PM
+       .bus_suspend = ehci_bus_suspend,
+       .bus_resume = ehci_bus_resume,
+#endif
+       .relinquish_port        = ehci_relinquish_port,
+       .port_handed_over       = ehci_port_handed_over,
+};
+
+static int __devinit ehci_w90x900_probe(struct platform_device *pdev)
+{
+       if (usb_disabled())
+               return -ENODEV;
+
+       return usb_w90x900_probe(&ehci_w90x900_hc_driver, pdev);
+}
+
+static int __devexit ehci_w90x900_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_w90x900_remove(hcd, pdev);
+
+       return 0;
+}
+
+static struct platform_driver ehci_hcd_w90x900_driver = {
+       .probe  = ehci_w90x900_probe,
+       .remove = __devexit_p(ehci_w90x900_remove),
+       .driver = {
+               .name = "w90x900-ehci",
+               .owner = THIS_MODULE,
+       },
+};
+
+MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("w90p910 usb ehci driver!");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:w90p910-ehci");