linux/drivers/usb/host/ehci-w90x900.c
<<
>>
Prefs
   1/*
   2 * linux/driver/usb/host/ehci-w90x900.c
   3 *
   4 * Copyright (c) 2008 Nuvoton technology corporation.
   5 *
   6 * Wan ZongShun <mcuos.com@gmail.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation;version 2 of the License.
  11 *
  12 */
  13
  14#include <linux/platform_device.h>
  15
  16/*ebable phy0 and phy1 for w90p910*/
  17#define ENPHY           (0x01<<8)
  18#define PHY0_CTR        (0xA4)
  19#define PHY1_CTR        (0xA8)
  20
  21static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
  22                      struct platform_device *pdev)
  23{
  24        struct usb_hcd *hcd;
  25        struct ehci_hcd *ehci;
  26        struct resource *res;
  27        int retval = 0, irq;
  28        unsigned long val;
  29
  30
  31        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  32        if (!res) {
  33                retval = -ENXIO;
  34                goto err1;
  35        }
  36
  37        hcd = usb_create_hcd(driver, &pdev->dev, "w90x900 EHCI");
  38        if (!hcd) {
  39                retval = -ENOMEM;
  40                goto err1;
  41        }
  42
  43        hcd->rsrc_start = res->start;
  44        hcd->rsrc_len = res->end - res->start + 1;
  45
  46        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
  47                retval = -EBUSY;
  48                goto err2;
  49        }
  50
  51        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
  52        if (hcd->regs == NULL) {
  53                retval = -EFAULT;
  54                goto err3;
  55        }
  56
  57        ehci = hcd_to_ehci(hcd);
  58        ehci->caps = hcd->regs;
  59        ehci->regs = hcd->regs +
  60                 HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
  61
  62        /* enable PHY 0,1,the regs only apply to w90p910
  63        *  0xA4,0xA8 were offsets of PHY0 and PHY1 controller of
  64        *  w90p910 IC relative to ehci->regs.
  65        */
  66        val = __raw_readl(ehci->regs+PHY0_CTR);
  67        val |= ENPHY;
  68        __raw_writel(val, ehci->regs+PHY0_CTR);
  69
  70        val = __raw_readl(ehci->regs+PHY1_CTR);
  71        val |= ENPHY;
  72        __raw_writel(val, ehci->regs+PHY1_CTR);
  73
  74        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
  75        ehci->sbrn = 0x20;
  76
  77        irq = platform_get_irq(pdev, 0);
  78        if (irq < 0)
  79                goto err4;
  80
  81        retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
  82        if (retval != 0)
  83                goto err4;
  84
  85        ehci_writel(ehci, 1, &ehci->regs->configured_flag);
  86
  87        return retval;
  88err4:
  89        iounmap(hcd->regs);
  90err3:
  91        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  92err2:
  93        usb_put_hcd(hcd);
  94err1:
  95        return retval;
  96}
  97
  98static
  99void usb_w90x900_remove(struct usb_hcd *hcd, struct platform_device *pdev)
 100{
 101        usb_remove_hcd(hcd);
 102        iounmap(hcd->regs);
 103        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 104        usb_put_hcd(hcd);
 105}
 106
 107static const struct hc_driver ehci_w90x900_hc_driver = {
 108        .description = hcd_name,
 109        .product_desc = "Nuvoton w90x900 EHCI Host Controller",
 110        .hcd_priv_size = sizeof(struct ehci_hcd),
 111
 112        /*
 113         * generic hardware linkage
 114         */
 115        .irq = ehci_irq,
 116        .flags = HCD_USB2|HCD_MEMORY,
 117
 118        /*
 119         * basic lifecycle operations
 120         */
 121        .reset = ehci_init,
 122        .start = ehci_run,
 123
 124        .stop = ehci_stop,
 125        .shutdown = ehci_shutdown,
 126
 127        /*
 128         * managing i/o requests and associated device resources
 129         */
 130        .urb_enqueue = ehci_urb_enqueue,
 131        .urb_dequeue = ehci_urb_dequeue,
 132        .endpoint_disable = ehci_endpoint_disable,
 133
 134        /*
 135         * scheduling support
 136         */
 137        .get_frame_number = ehci_get_frame,
 138
 139        /*
 140         * root hub support
 141         */
 142        .hub_status_data = ehci_hub_status_data,
 143        .hub_control = ehci_hub_control,
 144#ifdef  CONFIG_PM
 145        .bus_suspend = ehci_bus_suspend,
 146        .bus_resume = ehci_bus_resume,
 147#endif
 148        .relinquish_port        = ehci_relinquish_port,
 149        .port_handed_over       = ehci_port_handed_over,
 150};
 151
 152static int __devinit ehci_w90x900_probe(struct platform_device *pdev)
 153{
 154        if (usb_disabled())
 155                return -ENODEV;
 156
 157        return usb_w90x900_probe(&ehci_w90x900_hc_driver, pdev);
 158}
 159
 160static int __devexit ehci_w90x900_remove(struct platform_device *pdev)
 161{
 162        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 163
 164        usb_w90x900_remove(hcd, pdev);
 165
 166        return 0;
 167}
 168
 169static struct platform_driver ehci_hcd_w90x900_driver = {
 170        .probe  = ehci_w90x900_probe,
 171        .remove = __devexit_p(ehci_w90x900_remove),
 172        .driver = {
 173                .name = "w90x900-ehci",
 174                .owner = THIS_MODULE,
 175        },
 176};
 177
 178MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
 179MODULE_DESCRIPTION("w90p910 usb ehci driver!");
 180MODULE_LICENSE("GPL");
 181MODULE_ALIAS("platform:w90p910-ehci");
 182