diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mfd/Kconfig | 9 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/omap-usb-host.c | 1061 |
3 files changed, 1071 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fd018366d670..a6dfa37a674d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -624,6 +624,15 @@ config MFD_WL1273_CORE | |||
624 | driver connects the radio-wl1273 V4L2 module and the wl1273 | 624 | driver connects the radio-wl1273 V4L2 module and the wl1273 |
625 | audio codec. | 625 | audio codec. |
626 | 626 | ||
627 | config MFD_OMAP_USB_HOST | ||
628 | bool "Support OMAP USBHS core driver" | ||
629 | depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 | ||
630 | default y | ||
631 | help | ||
632 | This is the core driver for the OAMP EHCI and OHCI drivers. | ||
633 | This MFD driver does the required setup functionalities for | ||
634 | OMAP USB Host drivers. | ||
635 | |||
627 | endif # MFD_SUPPORT | 636 | endif # MFD_SUPPORT |
628 | 637 | ||
629 | menu "Multimedia Capabilities Port drivers" | 638 | menu "Multimedia Capabilities Port drivers" |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index a54e2c7c6a1c..91fe384459ab 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -83,3 +83,4 @@ obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o | |||
83 | obj-$(CONFIG_MFD_VX855) += vx855.o | 83 | obj-$(CONFIG_MFD_VX855) += vx855.o |
84 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o | 84 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o |
85 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o | 85 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o |
86 | obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o | ||
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c new file mode 100644 index 000000000000..cb01209754e0 --- /dev/null +++ b/drivers/mfd/omap-usb-host.c | |||
@@ -0,0 +1,1061 @@ | |||
1 | /** | ||
2 | * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 of | ||
9 | * the License as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/gpio.h> | ||
28 | #include <linux/regulator/consumer.h> | ||
29 | #include <plat/usb.h> | ||
30 | |||
31 | #define USBHS_DRIVER_NAME "usbhs-omap" | ||
32 | #define OMAP_EHCI_DEVICE "ehci-omap" | ||
33 | #define OMAP_OHCI_DEVICE "ohci-omap3" | ||
34 | |||
35 | /* OMAP USBHOST Register addresses */ | ||
36 | |||
37 | /* TLL Register Set */ | ||
38 | #define OMAP_USBTLL_REVISION (0x00) | ||
39 | #define OMAP_USBTLL_SYSCONFIG (0x10) | ||
40 | #define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) | ||
41 | #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) | ||
42 | #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) | ||
43 | #define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) | ||
44 | #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) | ||
45 | |||
46 | #define OMAP_USBTLL_SYSSTATUS (0x14) | ||
47 | #define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) | ||
48 | |||
49 | #define OMAP_USBTLL_IRQSTATUS (0x18) | ||
50 | #define OMAP_USBTLL_IRQENABLE (0x1C) | ||
51 | |||
52 | #define OMAP_TLL_SHARED_CONF (0x30) | ||
53 | #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) | ||
54 | #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) | ||
55 | #define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) | ||
56 | #define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) | ||
57 | #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) | ||
58 | |||
59 | #define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) | ||
60 | #define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 | ||
61 | #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) | ||
62 | #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) | ||
63 | #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) | ||
64 | #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) | ||
65 | #define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) | ||
66 | #define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) | ||
67 | |||
68 | #define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 | ||
69 | #define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 | ||
70 | #define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 | ||
71 | #define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 | ||
72 | #define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 | ||
73 | #define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 | ||
74 | #define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 | ||
75 | #define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 | ||
76 | #define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA | ||
77 | #define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB | ||
78 | |||
79 | #define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) | ||
80 | #define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) | ||
81 | #define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) | ||
82 | #define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) | ||
83 | #define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) | ||
84 | #define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) | ||
85 | #define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) | ||
86 | #define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) | ||
87 | #define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) | ||
88 | |||
89 | #define OMAP_TLL_CHANNEL_COUNT 3 | ||
90 | #define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) | ||
91 | #define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) | ||
92 | #define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) | ||
93 | |||
94 | /* UHH Register Set */ | ||
95 | #define OMAP_UHH_REVISION (0x00) | ||
96 | #define OMAP_UHH_SYSCONFIG (0x10) | ||
97 | #define OMAP_UHH_SYSCONFIG_MIDLEMODE (1 << 12) | ||
98 | #define OMAP_UHH_SYSCONFIG_CACTIVITY (1 << 8) | ||
99 | #define OMAP_UHH_SYSCONFIG_SIDLEMODE (1 << 3) | ||
100 | #define OMAP_UHH_SYSCONFIG_ENAWAKEUP (1 << 2) | ||
101 | #define OMAP_UHH_SYSCONFIG_SOFTRESET (1 << 1) | ||
102 | #define OMAP_UHH_SYSCONFIG_AUTOIDLE (1 << 0) | ||
103 | |||
104 | #define OMAP_UHH_SYSSTATUS (0x14) | ||
105 | #define OMAP_UHH_HOSTCONFIG (0x40) | ||
106 | #define OMAP_UHH_HOSTCONFIG_ULPI_BYPASS (1 << 0) | ||
107 | #define OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS (1 << 0) | ||
108 | #define OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS (1 << 11) | ||
109 | #define OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS (1 << 12) | ||
110 | #define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN (1 << 2) | ||
111 | #define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN (1 << 3) | ||
112 | #define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN (1 << 4) | ||
113 | #define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN (1 << 5) | ||
114 | #define OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS (1 << 8) | ||
115 | #define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS (1 << 9) | ||
116 | #define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS (1 << 10) | ||
117 | #define OMAP4_UHH_HOSTCONFIG_APP_START_CLK (1 << 31) | ||
118 | |||
119 | /* OMAP4-specific defines */ | ||
120 | #define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR (3 << 2) | ||
121 | #define OMAP4_UHH_SYSCONFIG_NOIDLE (1 << 2) | ||
122 | #define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR (3 << 4) | ||
123 | #define OMAP4_UHH_SYSCONFIG_NOSTDBY (1 << 4) | ||
124 | #define OMAP4_UHH_SYSCONFIG_SOFTRESET (1 << 0) | ||
125 | |||
126 | #define OMAP4_P1_MODE_CLEAR (3 << 16) | ||
127 | #define OMAP4_P1_MODE_TLL (1 << 16) | ||
128 | #define OMAP4_P1_MODE_HSIC (3 << 16) | ||
129 | #define OMAP4_P2_MODE_CLEAR (3 << 18) | ||
130 | #define OMAP4_P2_MODE_TLL (1 << 18) | ||
131 | #define OMAP4_P2_MODE_HSIC (3 << 18) | ||
132 | |||
133 | #define OMAP_REV2_TLL_CHANNEL_COUNT 2 | ||
134 | |||
135 | #define OMAP_UHH_DEBUG_CSR (0x44) | ||
136 | |||
137 | /* Values of UHH_REVISION - Note: these are not given in the TRM */ | ||
138 | #define OMAP_USBHS_REV1 0x00000010 /* OMAP3 */ | ||
139 | #define OMAP_USBHS_REV2 0x50700100 /* OMAP4 */ | ||
140 | |||
141 | #define is_omap_usbhs_rev1(x) (x->usbhs_rev == OMAP_USBHS_REV1) | ||
142 | #define is_omap_usbhs_rev2(x) (x->usbhs_rev == OMAP_USBHS_REV2) | ||
143 | |||
144 | #define is_ehci_phy_mode(x) (x == OMAP_EHCI_PORT_MODE_PHY) | ||
145 | #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) | ||
146 | #define is_ehci_hsic_mode(x) (x == OMAP_EHCI_PORT_MODE_HSIC) | ||
147 | |||
148 | |||
149 | struct usbhs_hcd_omap { | ||
150 | struct clk *usbhost_ick; | ||
151 | struct clk *usbhost_hs_fck; | ||
152 | struct clk *usbhost_fs_fck; | ||
153 | struct clk *xclk60mhsp1_ck; | ||
154 | struct clk *xclk60mhsp2_ck; | ||
155 | struct clk *utmi_p1_fck; | ||
156 | struct clk *usbhost_p1_fck; | ||
157 | struct clk *usbtll_p1_fck; | ||
158 | struct clk *utmi_p2_fck; | ||
159 | struct clk *usbhost_p2_fck; | ||
160 | struct clk *usbtll_p2_fck; | ||
161 | struct clk *init_60m_fclk; | ||
162 | struct clk *usbtll_fck; | ||
163 | struct clk *usbtll_ick; | ||
164 | |||
165 | void __iomem *uhh_base; | ||
166 | void __iomem *tll_base; | ||
167 | |||
168 | struct usbhs_omap_platform_data platdata; | ||
169 | |||
170 | u32 usbhs_rev; | ||
171 | spinlock_t lock; | ||
172 | int count; | ||
173 | }; | ||
174 | /*-------------------------------------------------------------------------*/ | ||
175 | |||
176 | const char usbhs_driver_name[] = USBHS_DRIVER_NAME; | ||
177 | static u64 usbhs_dmamask = ~(u32)0; | ||
178 | |||
179 | /*-------------------------------------------------------------------------*/ | ||
180 | |||
181 | static inline void usbhs_write(void __iomem *base, u32 reg, u32 val) | ||
182 | { | ||
183 | __raw_writel(val, base + reg); | ||
184 | } | ||
185 | |||
186 | static inline u32 usbhs_read(void __iomem *base, u32 reg) | ||
187 | { | ||
188 | return __raw_readl(base + reg); | ||
189 | } | ||
190 | |||
191 | static inline void usbhs_writeb(void __iomem *base, u8 reg, u8 val) | ||
192 | { | ||
193 | __raw_writeb(val, base + reg); | ||
194 | } | ||
195 | |||
196 | static inline u8 usbhs_readb(void __iomem *base, u8 reg) | ||
197 | { | ||
198 | return __raw_readb(base + reg); | ||
199 | } | ||
200 | |||
201 | /*-------------------------------------------------------------------------*/ | ||
202 | |||
203 | static struct platform_device *omap_usbhs_alloc_child(const char *name, | ||
204 | struct resource *res, int num_resources, void *pdata, | ||
205 | size_t pdata_size, struct device *dev) | ||
206 | { | ||
207 | struct platform_device *child; | ||
208 | int ret; | ||
209 | |||
210 | child = platform_device_alloc(name, 0); | ||
211 | |||
212 | if (!child) { | ||
213 | dev_err(dev, "platform_device_alloc %s failed\n", name); | ||
214 | goto err_end; | ||
215 | } | ||
216 | |||
217 | ret = platform_device_add_resources(child, res, num_resources); | ||
218 | if (ret) { | ||
219 | dev_err(dev, "platform_device_add_resources failed\n"); | ||
220 | goto err_alloc; | ||
221 | } | ||
222 | |||
223 | ret = platform_device_add_data(child, pdata, pdata_size); | ||
224 | if (ret) { | ||
225 | dev_err(dev, "platform_device_add_data failed\n"); | ||
226 | goto err_alloc; | ||
227 | } | ||
228 | |||
229 | child->dev.dma_mask = &usbhs_dmamask; | ||
230 | child->dev.coherent_dma_mask = 0xffffffff; | ||
231 | child->dev.parent = dev; | ||
232 | |||
233 | ret = platform_device_add(child); | ||
234 | if (ret) { | ||
235 | dev_err(dev, "platform_device_add failed\n"); | ||
236 | goto err_alloc; | ||
237 | } | ||
238 | |||
239 | return child; | ||
240 | |||
241 | err_alloc: | ||
242 | platform_device_put(child); | ||
243 | |||
244 | err_end: | ||
245 | return NULL; | ||
246 | } | ||
247 | |||
248 | static int omap_usbhs_alloc_children(struct platform_device *pdev) | ||
249 | { | ||
250 | struct device *dev = &pdev->dev; | ||
251 | struct usbhs_hcd_omap *omap; | ||
252 | struct ehci_hcd_omap_platform_data *ehci_data; | ||
253 | struct ohci_hcd_omap_platform_data *ohci_data; | ||
254 | struct platform_device *ehci; | ||
255 | struct platform_device *ohci; | ||
256 | struct resource *res; | ||
257 | struct resource resources[2]; | ||
258 | int ret; | ||
259 | |||
260 | omap = platform_get_drvdata(pdev); | ||
261 | ehci_data = omap->platdata.ehci_data; | ||
262 | ohci_data = omap->platdata.ohci_data; | ||
263 | |||
264 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci"); | ||
265 | if (!res) { | ||
266 | dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n"); | ||
267 | ret = -ENODEV; | ||
268 | goto err_end; | ||
269 | } | ||
270 | resources[0] = *res; | ||
271 | |||
272 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ehci-irq"); | ||
273 | if (!res) { | ||
274 | dev_err(dev, " EHCI get resource IORESOURCE_IRQ failed\n"); | ||
275 | ret = -ENODEV; | ||
276 | goto err_end; | ||
277 | } | ||
278 | resources[1] = *res; | ||
279 | |||
280 | ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, ehci_data, | ||
281 | sizeof(*ehci_data), dev); | ||
282 | |||
283 | if (!ehci) { | ||
284 | dev_err(dev, "omap_usbhs_alloc_child failed\n"); | ||
285 | goto err_end; | ||
286 | } | ||
287 | |||
288 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ohci"); | ||
289 | if (!res) { | ||
290 | dev_err(dev, "OHCI get resource IORESOURCE_MEM failed\n"); | ||
291 | ret = -ENODEV; | ||
292 | goto err_ehci; | ||
293 | } | ||
294 | resources[0] = *res; | ||
295 | |||
296 | res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ohci-irq"); | ||
297 | if (!res) { | ||
298 | dev_err(dev, "OHCI get resource IORESOURCE_IRQ failed\n"); | ||
299 | ret = -ENODEV; | ||
300 | goto err_ehci; | ||
301 | } | ||
302 | resources[1] = *res; | ||
303 | |||
304 | ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, ohci_data, | ||
305 | sizeof(*ohci_data), dev); | ||
306 | if (!ohci) { | ||
307 | dev_err(dev, "omap_usbhs_alloc_child failed\n"); | ||
308 | goto err_ehci; | ||
309 | } | ||
310 | |||
311 | return 0; | ||
312 | |||
313 | err_ehci: | ||
314 | platform_device_put(ehci); | ||
315 | |||
316 | err_end: | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * usbhs_omap_probe - initialize TI-based HCDs | ||
322 | * | ||
323 | * Allocates basic resources for this USB host controller. | ||
324 | */ | ||
325 | static int __devinit usbhs_omap_probe(struct platform_device *pdev) | ||
326 | { | ||
327 | struct device *dev = &pdev->dev; | ||
328 | struct usbhs_omap_platform_data *pdata = dev->platform_data; | ||
329 | struct usbhs_hcd_omap *omap; | ||
330 | struct resource *res; | ||
331 | int ret = 0; | ||
332 | int i; | ||
333 | |||
334 | if (!pdata) { | ||
335 | dev_err(dev, "Missing platfrom data\n"); | ||
336 | ret = -ENOMEM; | ||
337 | goto end_probe; | ||
338 | } | ||
339 | |||
340 | omap = kzalloc(sizeof(*omap), GFP_KERNEL); | ||
341 | if (!omap) { | ||
342 | dev_err(dev, "Memory allocation failed\n"); | ||
343 | ret = -ENOMEM; | ||
344 | goto end_probe; | ||
345 | } | ||
346 | |||
347 | spin_lock_init(&omap->lock); | ||
348 | |||
349 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) | ||
350 | omap->platdata.port_mode[i] = pdata->port_mode[i]; | ||
351 | |||
352 | omap->platdata.ehci_data = pdata->ehci_data; | ||
353 | omap->platdata.ohci_data = pdata->ohci_data; | ||
354 | |||
355 | omap->usbhost_ick = clk_get(dev, "usbhost_ick"); | ||
356 | if (IS_ERR(omap->usbhost_ick)) { | ||
357 | ret = PTR_ERR(omap->usbhost_ick); | ||
358 | dev_err(dev, "usbhost_ick failed error:%d\n", ret); | ||
359 | goto err_end; | ||
360 | } | ||
361 | |||
362 | omap->usbhost_hs_fck = clk_get(dev, "hs_fck"); | ||
363 | if (IS_ERR(omap->usbhost_hs_fck)) { | ||
364 | ret = PTR_ERR(omap->usbhost_hs_fck); | ||
365 | dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret); | ||
366 | goto err_usbhost_ick; | ||
367 | } | ||
368 | |||
369 | omap->usbhost_fs_fck = clk_get(dev, "fs_fck"); | ||
370 | if (IS_ERR(omap->usbhost_fs_fck)) { | ||
371 | ret = PTR_ERR(omap->usbhost_fs_fck); | ||
372 | dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret); | ||
373 | goto err_usbhost_hs_fck; | ||
374 | } | ||
375 | |||
376 | omap->usbtll_fck = clk_get(dev, "usbtll_fck"); | ||
377 | if (IS_ERR(omap->usbtll_fck)) { | ||
378 | ret = PTR_ERR(omap->usbtll_fck); | ||
379 | dev_err(dev, "usbtll_fck failed error:%d\n", ret); | ||
380 | goto err_usbhost_fs_fck; | ||
381 | } | ||
382 | |||
383 | omap->usbtll_ick = clk_get(dev, "usbtll_ick"); | ||
384 | if (IS_ERR(omap->usbtll_ick)) { | ||
385 | ret = PTR_ERR(omap->usbtll_ick); | ||
386 | dev_err(dev, "usbtll_ick failed error:%d\n", ret); | ||
387 | goto err_usbtll_fck; | ||
388 | } | ||
389 | |||
390 | omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); | ||
391 | if (IS_ERR(omap->utmi_p1_fck)) { | ||
392 | ret = PTR_ERR(omap->utmi_p1_fck); | ||
393 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); | ||
394 | goto err_usbtll_ick; | ||
395 | } | ||
396 | |||
397 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); | ||
398 | if (IS_ERR(omap->xclk60mhsp1_ck)) { | ||
399 | ret = PTR_ERR(omap->xclk60mhsp1_ck); | ||
400 | dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); | ||
401 | goto err_utmi_p1_fck; | ||
402 | } | ||
403 | |||
404 | omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk"); | ||
405 | if (IS_ERR(omap->utmi_p2_fck)) { | ||
406 | ret = PTR_ERR(omap->utmi_p2_fck); | ||
407 | dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); | ||
408 | goto err_xclk60mhsp1_ck; | ||
409 | } | ||
410 | |||
411 | omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); | ||
412 | if (IS_ERR(omap->xclk60mhsp2_ck)) { | ||
413 | ret = PTR_ERR(omap->xclk60mhsp2_ck); | ||
414 | dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); | ||
415 | goto err_utmi_p2_fck; | ||
416 | } | ||
417 | |||
418 | omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk"); | ||
419 | if (IS_ERR(omap->usbhost_p1_fck)) { | ||
420 | ret = PTR_ERR(omap->usbhost_p1_fck); | ||
421 | dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret); | ||
422 | goto err_xclk60mhsp2_ck; | ||
423 | } | ||
424 | |||
425 | omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); | ||
426 | if (IS_ERR(omap->usbtll_p1_fck)) { | ||
427 | ret = PTR_ERR(omap->usbtll_p1_fck); | ||
428 | dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); | ||
429 | goto err_usbhost_p1_fck; | ||
430 | } | ||
431 | |||
432 | omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); | ||
433 | if (IS_ERR(omap->usbhost_p2_fck)) { | ||
434 | ret = PTR_ERR(omap->usbhost_p2_fck); | ||
435 | dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); | ||
436 | goto err_usbtll_p1_fck; | ||
437 | } | ||
438 | |||
439 | omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); | ||
440 | if (IS_ERR(omap->usbtll_p2_fck)) { | ||
441 | ret = PTR_ERR(omap->usbtll_p2_fck); | ||
442 | dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); | ||
443 | goto err_usbhost_p2_fck; | ||
444 | } | ||
445 | |||
446 | omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); | ||
447 | if (IS_ERR(omap->init_60m_fclk)) { | ||
448 | ret = PTR_ERR(omap->init_60m_fclk); | ||
449 | dev_err(dev, "init_60m_fclk failed error:%d\n", ret); | ||
450 | goto err_usbtll_p2_fck; | ||
451 | } | ||
452 | |||
453 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); | ||
454 | if (!res) { | ||
455 | dev_err(dev, "UHH EHCI get resource failed\n"); | ||
456 | ret = -ENODEV; | ||
457 | goto err_init_60m_fclk; | ||
458 | } | ||
459 | |||
460 | omap->uhh_base = ioremap(res->start, resource_size(res)); | ||
461 | if (!omap->uhh_base) { | ||
462 | dev_err(dev, "UHH ioremap failed\n"); | ||
463 | ret = -ENOMEM; | ||
464 | goto err_init_60m_fclk; | ||
465 | } | ||
466 | |||
467 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll"); | ||
468 | if (!res) { | ||
469 | dev_err(dev, "UHH EHCI get resource failed\n"); | ||
470 | ret = -ENODEV; | ||
471 | goto err_tll; | ||
472 | } | ||
473 | |||
474 | omap->tll_base = ioremap(res->start, resource_size(res)); | ||
475 | if (!omap->tll_base) { | ||
476 | dev_err(dev, "TLL ioremap failed\n"); | ||
477 | ret = -ENOMEM; | ||
478 | goto err_tll; | ||
479 | } | ||
480 | |||
481 | platform_set_drvdata(pdev, omap); | ||
482 | |||
483 | ret = omap_usbhs_alloc_children(pdev); | ||
484 | if (ret) { | ||
485 | dev_err(dev, "omap_usbhs_alloc_children failed\n"); | ||
486 | goto err_alloc; | ||
487 | } | ||
488 | |||
489 | goto end_probe; | ||
490 | |||
491 | err_alloc: | ||
492 | iounmap(omap->tll_base); | ||
493 | |||
494 | err_tll: | ||
495 | iounmap(omap->uhh_base); | ||
496 | |||
497 | err_init_60m_fclk: | ||
498 | clk_put(omap->init_60m_fclk); | ||
499 | |||
500 | err_usbtll_p2_fck: | ||
501 | clk_put(omap->usbtll_p2_fck); | ||
502 | |||
503 | err_usbhost_p2_fck: | ||
504 | clk_put(omap->usbhost_p2_fck); | ||
505 | |||
506 | err_usbtll_p1_fck: | ||
507 | clk_put(omap->usbtll_p1_fck); | ||
508 | |||
509 | err_usbhost_p1_fck: | ||
510 | clk_put(omap->usbhost_p1_fck); | ||
511 | |||
512 | err_xclk60mhsp2_ck: | ||
513 | clk_put(omap->xclk60mhsp2_ck); | ||
514 | |||
515 | err_utmi_p2_fck: | ||
516 | clk_put(omap->utmi_p2_fck); | ||
517 | |||
518 | err_xclk60mhsp1_ck: | ||
519 | clk_put(omap->xclk60mhsp1_ck); | ||
520 | |||
521 | err_utmi_p1_fck: | ||
522 | clk_put(omap->utmi_p1_fck); | ||
523 | |||
524 | err_usbtll_ick: | ||
525 | clk_put(omap->usbtll_ick); | ||
526 | |||
527 | err_usbtll_fck: | ||
528 | clk_put(omap->usbtll_fck); | ||
529 | |||
530 | err_usbhost_fs_fck: | ||
531 | clk_put(omap->usbhost_fs_fck); | ||
532 | |||
533 | err_usbhost_hs_fck: | ||
534 | clk_put(omap->usbhost_hs_fck); | ||
535 | |||
536 | err_usbhost_ick: | ||
537 | clk_put(omap->usbhost_ick); | ||
538 | |||
539 | err_end: | ||
540 | kfree(omap); | ||
541 | |||
542 | end_probe: | ||
543 | return ret; | ||
544 | } | ||
545 | |||
546 | /** | ||
547 | * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs | ||
548 | * @pdev: USB Host Controller being removed | ||
549 | * | ||
550 | * Reverses the effect of usbhs_omap_probe(). | ||
551 | */ | ||
552 | static int __devexit usbhs_omap_remove(struct platform_device *pdev) | ||
553 | { | ||
554 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); | ||
555 | |||
556 | if (omap->count != 0) { | ||
557 | dev_err(&pdev->dev, | ||
558 | "Either EHCI or OHCI is still using usbhs core\n"); | ||
559 | return -EBUSY; | ||
560 | } | ||
561 | |||
562 | iounmap(omap->tll_base); | ||
563 | iounmap(omap->uhh_base); | ||
564 | clk_put(omap->init_60m_fclk); | ||
565 | clk_put(omap->usbtll_p2_fck); | ||
566 | clk_put(omap->usbhost_p2_fck); | ||
567 | clk_put(omap->usbtll_p1_fck); | ||
568 | clk_put(omap->usbhost_p1_fck); | ||
569 | clk_put(omap->xclk60mhsp2_ck); | ||
570 | clk_put(omap->utmi_p2_fck); | ||
571 | clk_put(omap->xclk60mhsp1_ck); | ||
572 | clk_put(omap->utmi_p1_fck); | ||
573 | clk_put(omap->usbtll_ick); | ||
574 | clk_put(omap->usbtll_fck); | ||
575 | clk_put(omap->usbhost_fs_fck); | ||
576 | clk_put(omap->usbhost_hs_fck); | ||
577 | clk_put(omap->usbhost_ick); | ||
578 | kfree(omap); | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static bool is_ohci_port(enum usbhs_omap_port_mode pmode) | ||
584 | { | ||
585 | switch (pmode) { | ||
586 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: | ||
587 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: | ||
588 | case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: | ||
589 | case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: | ||
590 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: | ||
591 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: | ||
592 | case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: | ||
593 | case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: | ||
594 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: | ||
595 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: | ||
596 | return true; | ||
597 | |||
598 | default: | ||
599 | return false; | ||
600 | } | ||
601 | } | ||
602 | |||
603 | /* | ||
604 | * convert the port-mode enum to a value we can use in the FSLSMODE | ||
605 | * field of USBTLL_CHANNEL_CONF | ||
606 | */ | ||
607 | static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) | ||
608 | { | ||
609 | switch (mode) { | ||
610 | case OMAP_USBHS_PORT_MODE_UNUSED: | ||
611 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: | ||
612 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; | ||
613 | |||
614 | case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: | ||
615 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; | ||
616 | |||
617 | case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: | ||
618 | return OMAP_TLL_FSLSMODE_3PIN_PHY; | ||
619 | |||
620 | case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: | ||
621 | return OMAP_TLL_FSLSMODE_4PIN_PHY; | ||
622 | |||
623 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: | ||
624 | return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; | ||
625 | |||
626 | case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: | ||
627 | return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; | ||
628 | |||
629 | case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: | ||
630 | return OMAP_TLL_FSLSMODE_3PIN_TLL; | ||
631 | |||
632 | case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: | ||
633 | return OMAP_TLL_FSLSMODE_4PIN_TLL; | ||
634 | |||
635 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: | ||
636 | return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; | ||
637 | |||
638 | case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: | ||
639 | return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; | ||
640 | default: | ||
641 | pr_warning("Invalid port mode, using default\n"); | ||
642 | return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; | ||
643 | } | ||
644 | } | ||
645 | |||
646 | static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count) | ||
647 | { | ||
648 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | ||
649 | struct usbhs_omap_platform_data *pdata = dev->platform_data; | ||
650 | unsigned reg; | ||
651 | int i; | ||
652 | |||
653 | /* Program Common TLL register */ | ||
654 | reg = usbhs_read(omap->tll_base, OMAP_TLL_SHARED_CONF); | ||
655 | reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON | ||
656 | | OMAP_TLL_SHARED_CONF_USB_DIVRATION); | ||
657 | reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; | ||
658 | reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; | ||
659 | |||
660 | usbhs_write(omap->tll_base, OMAP_TLL_SHARED_CONF, reg); | ||
661 | |||
662 | /* Enable channels now */ | ||
663 | for (i = 0; i < tll_channel_count; i++) { | ||
664 | reg = usbhs_read(omap->tll_base, | ||
665 | OMAP_TLL_CHANNEL_CONF(i)); | ||
666 | |||
667 | if (is_ohci_port(pdata->port_mode[i])) { | ||
668 | reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) | ||
669 | << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; | ||
670 | reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; | ||
671 | } else if (pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_TLL) { | ||
672 | |||
673 | /* Disable AutoIdle, BitStuffing and use SDR Mode */ | ||
674 | reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE | ||
675 | | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF | ||
676 | | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); | ||
677 | |||
678 | reg |= (1 << (i + 1)); | ||
679 | } else | ||
680 | continue; | ||
681 | |||
682 | reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; | ||
683 | usbhs_write(omap->tll_base, | ||
684 | OMAP_TLL_CHANNEL_CONF(i), reg); | ||
685 | |||
686 | usbhs_writeb(omap->tll_base, | ||
687 | OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe); | ||
688 | } | ||
689 | } | ||
690 | |||
691 | static int usbhs_enable(struct device *dev) | ||
692 | { | ||
693 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | ||
694 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | ||
695 | unsigned long flags = 0; | ||
696 | int ret = 0; | ||
697 | unsigned long timeout; | ||
698 | unsigned reg; | ||
699 | |||
700 | dev_dbg(dev, "starting TI HSUSB Controller\n"); | ||
701 | if (!pdata) { | ||
702 | dev_dbg(dev, "missing platform_data\n"); | ||
703 | ret = -ENODEV; | ||
704 | goto end_enable; | ||
705 | } | ||
706 | |||
707 | spin_lock_irqsave(&omap->lock, flags); | ||
708 | if (omap->count > 0) | ||
709 | goto end_count; | ||
710 | |||
711 | clk_enable(omap->usbhost_ick); | ||
712 | clk_enable(omap->usbhost_hs_fck); | ||
713 | clk_enable(omap->usbhost_fs_fck); | ||
714 | clk_enable(omap->usbtll_fck); | ||
715 | clk_enable(omap->usbtll_ick); | ||
716 | |||
717 | if (pdata->ehci_data->phy_reset) { | ||
718 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { | ||
719 | gpio_request(pdata->ehci_data->reset_gpio_port[0], | ||
720 | "USB1 PHY reset"); | ||
721 | gpio_direction_output | ||
722 | (pdata->ehci_data->reset_gpio_port[0], 1); | ||
723 | } | ||
724 | |||
725 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) { | ||
726 | gpio_request(pdata->ehci_data->reset_gpio_port[1], | ||
727 | "USB2 PHY reset"); | ||
728 | gpio_direction_output | ||
729 | (pdata->ehci_data->reset_gpio_port[1], 1); | ||
730 | } | ||
731 | |||
732 | /* Hold the PHY in RESET for enough time till DIR is high */ | ||
733 | udelay(10); | ||
734 | } | ||
735 | |||
736 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); | ||
737 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); | ||
738 | |||
739 | /* perform TLL soft reset, and wait until reset is complete */ | ||
740 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
741 | OMAP_USBTLL_SYSCONFIG_SOFTRESET); | ||
742 | |||
743 | /* Wait for TLL reset to complete */ | ||
744 | timeout = jiffies + msecs_to_jiffies(1000); | ||
745 | while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | ||
746 | & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { | ||
747 | cpu_relax(); | ||
748 | |||
749 | if (time_after(jiffies, timeout)) { | ||
750 | dev_dbg(dev, "operation timed out\n"); | ||
751 | ret = -EINVAL; | ||
752 | goto err_tll; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | dev_dbg(dev, "TLL RESET DONE\n"); | ||
757 | |||
758 | /* (1<<3) = no idle mode only for initial debugging */ | ||
759 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
760 | OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | | ||
761 | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | | ||
762 | OMAP_USBTLL_SYSCONFIG_AUTOIDLE); | ||
763 | |||
764 | /* Put UHH in NoIdle/NoStandby mode */ | ||
765 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG); | ||
766 | if (is_omap_usbhs_rev1(omap)) { | ||
767 | reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP | ||
768 | | OMAP_UHH_SYSCONFIG_SIDLEMODE | ||
769 | | OMAP_UHH_SYSCONFIG_CACTIVITY | ||
770 | | OMAP_UHH_SYSCONFIG_MIDLEMODE); | ||
771 | reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; | ||
772 | |||
773 | |||
774 | } else if (is_omap_usbhs_rev2(omap)) { | ||
775 | reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR; | ||
776 | reg |= OMAP4_UHH_SYSCONFIG_NOIDLE; | ||
777 | reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR; | ||
778 | reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY; | ||
779 | } | ||
780 | |||
781 | usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); | ||
782 | |||
783 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); | ||
784 | /* setup ULPI bypass and burst configurations */ | ||
785 | reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | ||
786 | | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | ||
787 | | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); | ||
788 | reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK; | ||
789 | reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; | ||
790 | |||
791 | if (is_omap_usbhs_rev1(omap)) { | ||
792 | if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED) | ||
793 | reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; | ||
794 | if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED) | ||
795 | reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; | ||
796 | if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED) | ||
797 | reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; | ||
798 | |||
799 | /* Bypass the TLL module for PHY mode operation */ | ||
800 | if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) { | ||
801 | dev_dbg(dev, "OMAP3 ES version <= ES2.1\n"); | ||
802 | if (is_ehci_phy_mode(pdata->port_mode[0]) || | ||
803 | is_ehci_phy_mode(pdata->port_mode[1]) || | ||
804 | is_ehci_phy_mode(pdata->port_mode[2])) | ||
805 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
806 | else | ||
807 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; | ||
808 | } else { | ||
809 | dev_dbg(dev, "OMAP3 ES version > ES2.1\n"); | ||
810 | if (is_ehci_phy_mode(pdata->port_mode[0])) | ||
811 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
812 | else | ||
813 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; | ||
814 | if (is_ehci_phy_mode(pdata->port_mode[1])) | ||
815 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; | ||
816 | else | ||
817 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; | ||
818 | if (is_ehci_phy_mode(pdata->port_mode[2])) | ||
819 | reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; | ||
820 | else | ||
821 | reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; | ||
822 | } | ||
823 | } else if (is_omap_usbhs_rev2(omap)) { | ||
824 | /* Clear port mode fields for PHY mode*/ | ||
825 | reg &= ~OMAP4_P1_MODE_CLEAR; | ||
826 | reg &= ~OMAP4_P2_MODE_CLEAR; | ||
827 | |||
828 | if (is_ehci_phy_mode(pdata->port_mode[0])) { | ||
829 | ret = clk_set_parent(omap->utmi_p1_fck, | ||
830 | omap->xclk60mhsp1_ck); | ||
831 | if (ret != 0) { | ||
832 | dev_err(dev, "xclk60mhsp1_ck set parent" | ||
833 | "failed error:%d\n", ret); | ||
834 | goto err_tll; | ||
835 | } | ||
836 | } else if (is_ehci_tll_mode(pdata->port_mode[0])) { | ||
837 | ret = clk_set_parent(omap->utmi_p1_fck, | ||
838 | omap->init_60m_fclk); | ||
839 | if (ret != 0) { | ||
840 | dev_err(dev, "init_60m_fclk set parent" | ||
841 | "failed error:%d\n", ret); | ||
842 | goto err_tll; | ||
843 | } | ||
844 | clk_enable(omap->usbhost_p1_fck); | ||
845 | clk_enable(omap->usbtll_p1_fck); | ||
846 | } | ||
847 | |||
848 | if (is_ehci_phy_mode(pdata->port_mode[1])) { | ||
849 | ret = clk_set_parent(omap->utmi_p2_fck, | ||
850 | omap->xclk60mhsp2_ck); | ||
851 | if (ret != 0) { | ||
852 | dev_err(dev, "xclk60mhsp1_ck set parent" | ||
853 | "failed error:%d\n", ret); | ||
854 | goto err_tll; | ||
855 | } | ||
856 | } else if (is_ehci_tll_mode(pdata->port_mode[1])) { | ||
857 | ret = clk_set_parent(omap->utmi_p2_fck, | ||
858 | omap->init_60m_fclk); | ||
859 | if (ret != 0) { | ||
860 | dev_err(dev, "init_60m_fclk set parent" | ||
861 | "failed error:%d\n", ret); | ||
862 | goto err_tll; | ||
863 | } | ||
864 | clk_enable(omap->usbhost_p2_fck); | ||
865 | clk_enable(omap->usbtll_p2_fck); | ||
866 | } | ||
867 | |||
868 | clk_enable(omap->utmi_p1_fck); | ||
869 | clk_enable(omap->utmi_p2_fck); | ||
870 | |||
871 | if (is_ehci_tll_mode(pdata->port_mode[0]) || | ||
872 | (is_ohci_port(pdata->port_mode[0]))) | ||
873 | reg |= OMAP4_P1_MODE_TLL; | ||
874 | else if (is_ehci_hsic_mode(pdata->port_mode[0])) | ||
875 | reg |= OMAP4_P1_MODE_HSIC; | ||
876 | |||
877 | if (is_ehci_tll_mode(pdata->port_mode[1]) || | ||
878 | (is_ohci_port(pdata->port_mode[1]))) | ||
879 | reg |= OMAP4_P2_MODE_TLL; | ||
880 | else if (is_ehci_hsic_mode(pdata->port_mode[1])) | ||
881 | reg |= OMAP4_P2_MODE_HSIC; | ||
882 | } | ||
883 | |||
884 | usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); | ||
885 | dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); | ||
886 | |||
887 | if (is_ehci_tll_mode(pdata->port_mode[0]) || | ||
888 | is_ehci_tll_mode(pdata->port_mode[1]) || | ||
889 | is_ehci_tll_mode(pdata->port_mode[2]) || | ||
890 | (is_ohci_port(pdata->port_mode[0])) || | ||
891 | (is_ohci_port(pdata->port_mode[1])) || | ||
892 | (is_ohci_port(pdata->port_mode[2]))) { | ||
893 | |||
894 | /* Enable UTMI mode for required TLL channels */ | ||
895 | if (is_omap_usbhs_rev2(omap)) | ||
896 | usbhs_omap_tll_init(dev, OMAP_REV2_TLL_CHANNEL_COUNT); | ||
897 | else | ||
898 | usbhs_omap_tll_init(dev, OMAP_TLL_CHANNEL_COUNT); | ||
899 | } | ||
900 | |||
901 | if (pdata->ehci_data->phy_reset) { | ||
902 | /* Hold the PHY in RESET for enough time till | ||
903 | * PHY is settled and ready | ||
904 | */ | ||
905 | udelay(10); | ||
906 | |||
907 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | ||
908 | gpio_set_value | ||
909 | (pdata->ehci_data->reset_gpio_port[0], 0); | ||
910 | |||
911 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | ||
912 | gpio_set_value | ||
913 | (pdata->ehci_data->reset_gpio_port[1], 0); | ||
914 | } | ||
915 | |||
916 | end_count: | ||
917 | omap->count++; | ||
918 | goto end_enable; | ||
919 | |||
920 | err_tll: | ||
921 | if (pdata->ehci_data->phy_reset) { | ||
922 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | ||
923 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); | ||
924 | |||
925 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | ||
926 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); | ||
927 | } | ||
928 | |||
929 | clk_disable(omap->usbtll_ick); | ||
930 | clk_disable(omap->usbtll_fck); | ||
931 | clk_disable(omap->usbhost_fs_fck); | ||
932 | clk_disable(omap->usbhost_hs_fck); | ||
933 | clk_disable(omap->usbhost_ick); | ||
934 | |||
935 | end_enable: | ||
936 | spin_unlock_irqrestore(&omap->lock, flags); | ||
937 | return ret; | ||
938 | } | ||
939 | |||
940 | static void usbhs_disable(struct device *dev) | ||
941 | { | ||
942 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | ||
943 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | ||
944 | unsigned long flags = 0; | ||
945 | unsigned long timeout; | ||
946 | |||
947 | dev_dbg(dev, "stopping TI HSUSB Controller\n"); | ||
948 | |||
949 | spin_lock_irqsave(&omap->lock, flags); | ||
950 | |||
951 | if (omap->count == 0) | ||
952 | goto end_disble; | ||
953 | |||
954 | omap->count--; | ||
955 | |||
956 | if (omap->count != 0) | ||
957 | goto end_disble; | ||
958 | |||
959 | /* Reset OMAP modules for insmod/rmmod to work */ | ||
960 | usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, | ||
961 | is_omap_usbhs_rev2(omap) ? | ||
962 | OMAP4_UHH_SYSCONFIG_SOFTRESET : | ||
963 | OMAP_UHH_SYSCONFIG_SOFTRESET); | ||
964 | |||
965 | timeout = jiffies + msecs_to_jiffies(100); | ||
966 | while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
967 | & (1 << 0))) { | ||
968 | cpu_relax(); | ||
969 | |||
970 | if (time_after(jiffies, timeout)) | ||
971 | dev_dbg(dev, "operation timed out\n"); | ||
972 | } | ||
973 | |||
974 | while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
975 | & (1 << 1))) { | ||
976 | cpu_relax(); | ||
977 | |||
978 | if (time_after(jiffies, timeout)) | ||
979 | dev_dbg(dev, "operation timed out\n"); | ||
980 | } | ||
981 | |||
982 | while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) | ||
983 | & (1 << 2))) { | ||
984 | cpu_relax(); | ||
985 | |||
986 | if (time_after(jiffies, timeout)) | ||
987 | dev_dbg(dev, "operation timed out\n"); | ||
988 | } | ||
989 | |||
990 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1)); | ||
991 | |||
992 | while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | ||
993 | & (1 << 0))) { | ||
994 | cpu_relax(); | ||
995 | |||
996 | if (time_after(jiffies, timeout)) | ||
997 | dev_dbg(dev, "operation timed out\n"); | ||
998 | } | ||
999 | |||
1000 | if (pdata->ehci_data->phy_reset) { | ||
1001 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | ||
1002 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); | ||
1003 | |||
1004 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | ||
1005 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); | ||
1006 | } | ||
1007 | |||
1008 | clk_disable(omap->utmi_p2_fck); | ||
1009 | clk_disable(omap->utmi_p1_fck); | ||
1010 | clk_disable(omap->usbtll_ick); | ||
1011 | clk_disable(omap->usbtll_fck); | ||
1012 | clk_disable(omap->usbhost_fs_fck); | ||
1013 | clk_disable(omap->usbhost_hs_fck); | ||
1014 | clk_disable(omap->usbhost_ick); | ||
1015 | |||
1016 | end_disble: | ||
1017 | spin_unlock_irqrestore(&omap->lock, flags); | ||
1018 | } | ||
1019 | |||
1020 | int omap_usbhs_enable(struct device *dev) | ||
1021 | { | ||
1022 | return usbhs_enable(dev->parent); | ||
1023 | } | ||
1024 | EXPORT_SYMBOL_GPL(omap_usbhs_enable); | ||
1025 | |||
1026 | void omap_usbhs_disable(struct device *dev) | ||
1027 | { | ||
1028 | usbhs_disable(dev->parent); | ||
1029 | } | ||
1030 | EXPORT_SYMBOL_GPL(omap_usbhs_disable); | ||
1031 | |||
1032 | static struct platform_driver usbhs_omap_driver = { | ||
1033 | .driver = { | ||
1034 | .name = (char *)usbhs_driver_name, | ||
1035 | .owner = THIS_MODULE, | ||
1036 | }, | ||
1037 | .remove = __exit_p(usbhs_omap_remove), | ||
1038 | }; | ||
1039 | |||
1040 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); | ||
1041 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); | ||
1042 | MODULE_LICENSE("GPL v2"); | ||
1043 | MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI"); | ||
1044 | |||
1045 | static int __init omap_usbhs_drvinit(void) | ||
1046 | { | ||
1047 | return platform_driver_probe(&usbhs_omap_driver, usbhs_omap_probe); | ||
1048 | } | ||
1049 | |||
1050 | /* | ||
1051 | * init before ehci and ohci drivers; | ||
1052 | * The usbhs core driver should be initialized much before | ||
1053 | * the omap ehci and ohci probe functions are called. | ||
1054 | */ | ||
1055 | fs_initcall(omap_usbhs_drvinit); | ||
1056 | |||
1057 | static void __exit omap_usbhs_drvexit(void) | ||
1058 | { | ||
1059 | platform_driver_unregister(&usbhs_omap_driver); | ||
1060 | } | ||
1061 | module_exit(omap_usbhs_drvexit); | ||