Commit | Line | Data |
---|---|---|
88ed0c97 AG |
1 | /* |
2 | * ohci-omap3.c - driver for OHCI on OMAP3 and later processors | |
3 | * | |
4 | * Bus Glue for OMAP3 USBHOST 3 port OHCI controller | |
5 | * This controller is also used in later OMAPs and AM35x chips | |
6 | * | |
7 | * Copyright (C) 2007-2010 Texas Instruments, Inc. | |
8 | * Author: Vikram Pandita <vikram.pandita@ti.com> | |
9 | * Author: Anand Gadiyar <gadiyar@ti.com> | |
19403165 | 10 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> |
88ed0c97 AG |
11 | * |
12 | * Based on ehci-omap.c and some other ohci glue layers | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU General Public License as published by | |
16 | * the Free Software Foundation; either version 2 of the License, or | |
17 | * (at your option) any later version. | |
18 | * | |
19 | * This program is distributed in the hope that it will be useful, | |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | * GNU General Public License for more details. | |
23 | * | |
24 | * You should have received a copy of the GNU General Public License | |
25 | * along with this program; if not, write to the Free Software | |
26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
27 | * | |
19403165 | 28 | * TODO (last updated Feb 27, 2011): |
88ed0c97 | 29 | * - add kernel-doc |
88ed0c97 AG |
30 | */ |
31 | ||
3a48fef1 MG |
32 | #include <linux/dma-mapping.h> |
33 | #include <linux/kernel.h> | |
34 | #include <linux/module.h> | |
35 | #include <linux/of.h> | |
36 | #include <linux/usb/otg.h> | |
88ed0c97 | 37 | #include <linux/platform_device.h> |
6c984b06 | 38 | #include <linux/pm_runtime.h> |
3a48fef1 MG |
39 | #include <linux/usb.h> |
40 | #include <linux/usb/hcd.h> | |
88ed0c97 | 41 | |
3a48fef1 | 42 | #include "ohci.h" |
88ed0c97 | 43 | |
3a48fef1 | 44 | #define DRIVER_DESC "OHCI OMAP3 driver" |
88ed0c97 | 45 | |
3a48fef1 MG |
46 | static const char hcd_name[] = "ohci-omap3"; |
47 | static struct hc_driver __read_mostly ohci_omap3_hc_driver; | |
88ed0c97 AG |
48 | |
49 | /* | |
50 | * configure so an HC device and id are always provided | |
51 | * always called with process context; sleeping is OK | |
52 | */ | |
53 | ||
54 | /** | |
55 | * ohci_hcd_omap3_probe - initialize OMAP-based HCDs | |
56 | * | |
57 | * Allocates basic resources for this USB host controller, and | |
58 | * then invokes the start() method for the HCD associated with it | |
59 | * through the hotplug entry's driver_data. | |
60 | */ | |
41ac7b3a | 61 | static int ohci_hcd_omap3_probe(struct platform_device *pdev) |
88ed0c97 | 62 | { |
19403165 | 63 | struct device *dev = &pdev->dev; |
3a48fef1 | 64 | struct ohci_hcd *ohci; |
19403165 KM |
65 | struct usb_hcd *hcd = NULL; |
66 | void __iomem *regs = NULL; | |
67 | struct resource *res; | |
22d9d8e8 | 68 | int ret; |
19403165 | 69 | int irq; |
88ed0c97 AG |
70 | |
71 | if (usb_disabled()) | |
6c984b06 | 72 | return -ENODEV; |
88ed0c97 | 73 | |
19403165 KM |
74 | if (!dev->parent) { |
75 | dev_err(dev, "Missing parent device\n"); | |
76 | return -ENODEV; | |
88ed0c97 AG |
77 | } |
78 | ||
8c3ec385 | 79 | irq = platform_get_irq(pdev, 0); |
19403165 KM |
80 | if (irq < 0) { |
81 | dev_err(dev, "OHCI irq failed\n"); | |
82 | return -ENODEV; | |
83 | } | |
88ed0c97 | 84 | |
8c3ec385 | 85 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
d80cba6c | 86 | if (!res) { |
19403165 KM |
87 | dev_err(dev, "UHH OHCI get resource failed\n"); |
88 | return -ENOMEM; | |
88ed0c97 AG |
89 | } |
90 | ||
19403165 KM |
91 | regs = ioremap(res->start, resource_size(res)); |
92 | if (!regs) { | |
93 | dev_err(dev, "UHH OHCI ioremap failed\n"); | |
94 | return -ENOMEM; | |
88ed0c97 AG |
95 | } |
96 | ||
5867320d RQ |
97 | /* |
98 | * Right now device-tree probed devices don't get dma_mask set. | |
99 | * Since shared usb code relies on it, set it here for now. | |
100 | * Once we have dma capability bindings this can go away. | |
101 | */ | |
e1fd7341 | 102 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); |
22d9d8e8 RK |
103 | if (ret) |
104 | goto err_io; | |
88ed0c97 | 105 | |
22d9d8e8 | 106 | ret = -ENODEV; |
19403165 KM |
107 | hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev, |
108 | dev_name(dev)); | |
109 | if (!hcd) { | |
110 | dev_err(dev, "usb_create_hcd failed\n"); | |
111 | goto err_io; | |
112 | } | |
88ed0c97 AG |
113 | |
114 | hcd->rsrc_start = res->start; | |
115 | hcd->rsrc_len = resource_size(res); | |
19403165 | 116 | hcd->regs = regs; |
88ed0c97 | 117 | |
6c984b06 KM |
118 | pm_runtime_enable(dev); |
119 | pm_runtime_get_sync(dev); | |
88ed0c97 | 120 | |
3a48fef1 MG |
121 | ohci = hcd_to_ohci(hcd); |
122 | /* | |
123 | * RemoteWakeupConnected has to be set explicitly before | |
124 | * calling ohci_run. The reset value of RWC is 0. | |
125 | */ | |
126 | ohci->hc_control = OHCI_CTRL_RWC; | |
88ed0c97 | 127 | |
b5dd18d8 | 128 | ret = usb_add_hcd(hcd, irq, 0); |
88ed0c97 | 129 | if (ret) { |
19403165 | 130 | dev_dbg(dev, "failed to add hcd with err %d\n", ret); |
88ed0c97 AG |
131 | goto err_add_hcd; |
132 | } | |
3c9740a1 | 133 | device_wakeup_enable(hcd->self.controller); |
88ed0c97 AG |
134 | |
135 | return 0; | |
136 | ||
137 | err_add_hcd: | |
6c984b06 | 138 | pm_runtime_put_sync(dev); |
88ed0c97 AG |
139 | usb_put_hcd(hcd); |
140 | ||
19403165 KM |
141 | err_io: |
142 | iounmap(regs); | |
143 | ||
88ed0c97 AG |
144 | return ret; |
145 | } | |
146 | ||
147 | /* | |
148 | * may be called without controller electrically present | |
149 | * may be called with controller, bus, and devices active | |
150 | */ | |
151 | ||
152 | /** | |
153 | * ohci_hcd_omap3_remove - shutdown processing for OHCI HCDs | |
154 | * @pdev: USB Host Controller being removed | |
155 | * | |
156 | * Reverses the effect of ohci_hcd_omap3_probe(), first invoking | |
157 | * the HCD's stop() method. It is always called from a thread | |
158 | * context, normally "rmmod", "apmd", or something similar. | |
159 | */ | |
fb4e98ab | 160 | static int ohci_hcd_omap3_remove(struct platform_device *pdev) |
88ed0c97 | 161 | { |
19403165 KM |
162 | struct device *dev = &pdev->dev; |
163 | struct usb_hcd *hcd = dev_get_drvdata(dev); | |
88ed0c97 | 164 | |
88ed0c97 | 165 | iounmap(hcd->regs); |
19403165 | 166 | usb_remove_hcd(hcd); |
6c984b06 KM |
167 | pm_runtime_put_sync(dev); |
168 | pm_runtime_disable(dev); | |
88ed0c97 | 169 | usb_put_hcd(hcd); |
88ed0c97 AG |
170 | return 0; |
171 | } | |
172 | ||
5867320d RQ |
173 | static const struct of_device_id omap_ohci_dt_ids[] = { |
174 | { .compatible = "ti,ohci-omap3" }, | |
175 | { } | |
176 | }; | |
177 | ||
178 | MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids); | |
179 | ||
88ed0c97 AG |
180 | static struct platform_driver ohci_hcd_omap3_driver = { |
181 | .probe = ohci_hcd_omap3_probe, | |
7690417d | 182 | .remove = ohci_hcd_omap3_remove, |
aaf6b52d | 183 | .shutdown = usb_hcd_platform_shutdown, |
88ed0c97 AG |
184 | .driver = { |
185 | .name = "ohci-omap3", | |
7a1cc240 | 186 | .of_match_table = omap_ohci_dt_ids, |
88ed0c97 AG |
187 | }, |
188 | }; | |
189 | ||
3a48fef1 MG |
190 | static int __init ohci_omap3_init(void) |
191 | { | |
192 | if (usb_disabled()) | |
193 | return -ENODEV; | |
194 | ||
195 | pr_info("%s: " DRIVER_DESC "\n", hcd_name); | |
196 | ||
197 | ohci_init_driver(&ohci_omap3_hc_driver, NULL); | |
198 | return platform_driver_register(&ohci_hcd_omap3_driver); | |
199 | } | |
200 | module_init(ohci_omap3_init); | |
201 | ||
202 | static void __exit ohci_omap3_cleanup(void) | |
203 | { | |
204 | platform_driver_unregister(&ohci_hcd_omap3_driver); | |
205 | } | |
206 | module_exit(ohci_omap3_cleanup); | |
207 | ||
208 | MODULE_DESCRIPTION(DRIVER_DESC); | |
88ed0c97 AG |
209 | MODULE_ALIAS("platform:ohci-omap3"); |
210 | MODULE_AUTHOR("Anand Gadiyar <gadiyar@ti.com>"); | |
3a48fef1 | 211 | MODULE_LICENSE("GPL"); |