]> Pileus Git - ~andy/linux/blob - drivers/usb/host/ehci-ls1x.c
Merge tag 'bug-for-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/paulg/linux
[~andy/linux] / drivers / usb / host / ehci-ls1x.c
1 /*
2  *  Bus Glue for Loongson LS1X built-in EHCI controller.
3  *
4  *  Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com>
5  *
6  *  This program is free software; you can redistribute it and/or modify it
7  *  under the terms of the GNU General Public License version 2 as published
8  *  by the Free Software Foundation.
9  */
10
11
12 #include <linux/platform_device.h>
13
14 static int ehci_ls1x_reset(struct usb_hcd *hcd)
15 {
16         struct ehci_hcd *ehci = hcd_to_ehci(hcd);
17         int ret;
18
19         ehci->caps = hcd->regs;
20
21         ret = ehci_setup(hcd);
22         if (ret)
23                 return ret;
24
25         ehci_port_power(ehci, 0);
26
27         return 0;
28 }
29
30 static const struct hc_driver ehci_ls1x_hc_driver = {
31         .description            = hcd_name,
32         .product_desc           = "LOONGSON1 EHCI",
33         .hcd_priv_size          = sizeof(struct ehci_hcd),
34
35         /*
36          * generic hardware linkage
37          */
38         .irq                    = ehci_irq,
39         .flags                  = HCD_MEMORY | HCD_USB2,
40
41         /*
42          * basic lifecycle operations
43          */
44         .reset                  = ehci_ls1x_reset,
45         .start                  = ehci_run,
46         .stop                   = ehci_stop,
47         .shutdown               = ehci_shutdown,
48
49         /*
50          * managing i/o requests and associated device resources
51          */
52         .urb_enqueue            = ehci_urb_enqueue,
53         .urb_dequeue            = ehci_urb_dequeue,
54         .endpoint_disable       = ehci_endpoint_disable,
55         .endpoint_reset         = ehci_endpoint_reset,
56
57         /*
58          * scheduling support
59          */
60         .get_frame_number       = ehci_get_frame,
61
62         /*
63          * root hub support
64          */
65         .hub_status_data        = ehci_hub_status_data,
66         .hub_control            = ehci_hub_control,
67         .relinquish_port        = ehci_relinquish_port,
68         .port_handed_over       = ehci_port_handed_over,
69
70         .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
71 };
72
73 static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
74 {
75         struct usb_hcd *hcd;
76         struct resource *res;
77         int irq;
78         int ret;
79
80         pr_debug("initializing loongson1 ehci USB Controller\n");
81
82         if (usb_disabled())
83                 return -ENODEV;
84
85         res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
86         if (!res) {
87                 dev_err(&pdev->dev,
88                         "Found HC with no IRQ. Check %s setup!\n",
89                         dev_name(&pdev->dev));
90                 return -ENODEV;
91         }
92         irq = res->start;
93
94         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
95         if (!res) {
96                 dev_err(&pdev->dev,
97                         "Found HC with no register addr. Check %s setup!\n",
98                         dev_name(&pdev->dev));
99                 return -ENODEV;
100         }
101
102         hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev,
103                                 dev_name(&pdev->dev));
104         if (!hcd)
105                 return -ENOMEM;
106         hcd->rsrc_start = res->start;
107         hcd->rsrc_len   = resource_size(res);
108
109         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
110                 dev_dbg(&pdev->dev, "controller already in use\n");
111                 ret = -EBUSY;
112                 goto err_put_hcd;
113         }
114
115         hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
116         if (hcd->regs == NULL) {
117                 dev_dbg(&pdev->dev, "error mapping memory\n");
118                 ret = -EFAULT;
119                 goto err_release_region;
120         }
121
122         ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
123         if (ret)
124                 goto err_iounmap;
125
126         return ret;
127
128 err_iounmap:
129         iounmap(hcd->regs);
130 err_release_region:
131         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
132 err_put_hcd:
133         usb_put_hcd(hcd);
134         return ret;
135 }
136
137 static int ehci_hcd_ls1x_remove(struct platform_device *pdev)
138 {
139         struct usb_hcd *hcd = platform_get_drvdata(pdev);
140
141         usb_remove_hcd(hcd);
142         iounmap(hcd->regs);
143         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
144         usb_put_hcd(hcd);
145
146         return 0;
147 }
148
149 static struct platform_driver ehci_ls1x_driver = {
150         .probe = ehci_hcd_ls1x_probe,
151         .remove = ehci_hcd_ls1x_remove,
152         .shutdown = usb_hcd_platform_shutdown,
153         .driver = {
154                 .name = "ls1x-ehci",
155                 .owner  = THIS_MODULE,
156         },
157 };
158
159 MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci");