OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * MCS814X EHCI Host Controller Driver |
||
3 | * |
||
4 | * Based on "ehci-fsl.c" by Randy Vinson <rvinson@mvista.com> |
||
5 | * |
||
6 | * 2007 (c) MontaVista Software, Inc. This file is licensed under |
||
7 | * the terms of the GNU General Public License version 2. This program |
||
8 | * is licensed "as is" without any warranty of any kind, whether express |
||
9 | * or implied. |
||
10 | */ |
||
11 | |||
12 | #include <linux/platform_device.h> |
||
13 | #include <linux/of.h> |
||
14 | |||
15 | #define MCS814X_EHCI_CAPS_OFFSET 0x68 |
||
16 | |||
17 | static int mcs814x_ehci_init(struct usb_hcd *hcd) |
||
18 | { |
||
19 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
||
20 | int retval = 0; |
||
21 | |||
22 | ehci->caps = hcd->regs + MCS814X_EHCI_CAPS_OFFSET; |
||
23 | ehci->regs = hcd->regs |
||
24 | + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); |
||
25 | ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); |
||
26 | ehci_reset(ehci); |
||
27 | |||
28 | retval = ehci_init(hcd); |
||
29 | if (retval) { |
||
30 | pr_err("ehci_init failed\n"); |
||
31 | return retval; |
||
32 | } |
||
33 | |||
34 | return retval; |
||
35 | } |
||
36 | |||
37 | static const struct hc_driver mcs814x_ehci_hc_driver = { |
||
38 | .description = hcd_name, |
||
39 | .product_desc = "MCS814X EHCI Host Controller", |
||
40 | .hcd_priv_size = sizeof(struct ehci_hcd), |
||
41 | .irq = ehci_irq, |
||
42 | .flags = HCD_MEMORY | HCD_USB2, |
||
43 | .reset = mcs814x_ehci_init, |
||
44 | .start = ehci_run, |
||
45 | .stop = ehci_stop, |
||
46 | .shutdown = ehci_shutdown, |
||
47 | .urb_enqueue = ehci_urb_enqueue, |
||
48 | .urb_dequeue = ehci_urb_dequeue, |
||
49 | .endpoint_disable = ehci_endpoint_disable, |
||
50 | .get_frame_number = ehci_get_frame, |
||
51 | .hub_status_data = ehci_hub_status_data, |
||
52 | .hub_control = ehci_hub_control, |
||
53 | #if defined(CONFIG_PM) |
||
54 | .bus_suspend = ehci_bus_suspend, |
||
55 | .bus_resume = ehci_bus_resume, |
||
56 | #endif |
||
57 | .relinquish_port = ehci_relinquish_port, |
||
58 | .port_handed_over = ehci_port_handed_over, |
||
59 | |||
60 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, |
||
61 | }; |
||
62 | |||
63 | static int mcs814x_ehci_probe(struct platform_device *pdev) |
||
64 | { |
||
65 | struct usb_hcd *hcd; |
||
66 | const struct hc_driver *driver = &mcs814x_ehci_hc_driver; |
||
67 | struct resource *res; |
||
68 | int irq; |
||
69 | int retval; |
||
70 | |||
71 | if (usb_disabled()) |
||
72 | return -ENODEV; |
||
73 | |||
74 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
||
75 | if (!res) { |
||
76 | dev_err(&pdev->dev, |
||
77 | "Found HC with no IRQ. Check %s setup!\n", |
||
78 | dev_name(&pdev->dev)); |
||
79 | return -ENODEV; |
||
80 | } |
||
81 | irq = res->start; |
||
82 | |||
83 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); |
||
84 | pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; |
||
85 | |||
86 | hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); |
||
87 | if (!hcd) { |
||
88 | retval = -ENOMEM; |
||
89 | goto fail_create_hcd; |
||
90 | } |
||
91 | |||
92 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
||
93 | if (!res) { |
||
94 | dev_err(&pdev->dev, |
||
95 | "Found HC with no register addr. Check %s setup!\n", |
||
96 | dev_name(&pdev->dev)); |
||
97 | retval = -ENODEV; |
||
98 | goto fail_request_resource; |
||
99 | } |
||
100 | hcd->rsrc_start = res->start; |
||
101 | hcd->rsrc_len = resource_size(res); |
||
102 | |||
103 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, |
||
104 | driver->description)) { |
||
105 | dev_dbg(&pdev->dev, "controller already in use\n"); |
||
106 | retval = -EBUSY; |
||
107 | goto fail_request_resource; |
||
108 | } |
||
109 | |||
110 | hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); |
||
111 | if (hcd->regs == NULL) { |
||
112 | dev_dbg(&pdev->dev, "error mapping memory\n"); |
||
113 | retval = -EFAULT; |
||
114 | goto fail_ioremap; |
||
115 | } |
||
116 | |||
117 | retval = usb_add_hcd(hcd, irq, IRQF_SHARED); |
||
118 | if (retval) |
||
119 | goto fail_add_hcd; |
||
120 | |||
121 | dev_info(&pdev->dev, "added MCS814X EHCI driver\n"); |
||
122 | |||
123 | return retval; |
||
124 | |||
125 | fail_add_hcd: |
||
126 | iounmap(hcd->regs); |
||
127 | fail_ioremap: |
||
128 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
||
129 | fail_request_resource: |
||
130 | usb_put_hcd(hcd); |
||
131 | fail_create_hcd: |
||
132 | dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); |
||
133 | return retval; |
||
134 | } |
||
135 | |||
136 | static int mcs814x_ehci_remove(struct platform_device *pdev) |
||
137 | { |
||
138 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
||
139 | |||
140 | usb_remove_hcd(hcd); |
||
141 | iounmap(hcd->regs); |
||
142 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
||
143 | usb_put_hcd(hcd); |
||
144 | |||
145 | return 0; |
||
146 | } |
||
147 | |||
148 | MODULE_ALIAS("platform:mcs814x-ehci"); |
||
149 | |||
150 | static const struct of_device_id mcs814x_ehci_id[] = { |
||
151 | { .compatible = "moschip,mcs814x-ehci" }, |
||
152 | { .compatible = "usb-ehci" }, |
||
153 | { /* sentinel */ }, |
||
154 | }; |
||
155 | |||
156 | static struct platform_driver mcs814x_ehci_driver = { |
||
157 | .probe = mcs814x_ehci_probe, |
||
158 | .remove = mcs814x_ehci_remove, |
||
159 | .driver = { |
||
160 | .name = "mcs814x-ehci", |
||
161 | .of_match_table = mcs814x_ehci_id, |
||
162 | }, |
||
163 | }; |