aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <lg@denx.de>2009-04-15 08:25:33 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-16 00:44:47 -0400
commit54e4026b64a970303349b952866641a7804ef594 (patch)
treea6410500a7218dfe8380e617dad58faf6572a221
parent568d422e9cf52b7b26d2e026ae1617971f62b560 (diff)
USB: gadget: Add i.MX3x support to the fsl_usb2_udc driver
This patch adds support for i.MX3x (only tested with i.MX31 so far) ARM SoCs to the fsl_usb2_udc driver. It also moves PHY configuration before controller reset, because otherwise an ULPI PHY doesn't get a reset and doesn't function after a reboot. The problem with longer control transfers is still not fixed. The patch renames the fsl_usb2_udc.c file to fsl_udc_core.c to preserve the same module name for user-space backwards compatibility. Signed-off-by: Guennadi Liakhovetski <lg@denx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/gadget/Makefile4
-rw-r--r--drivers/usb/gadget/fsl_mx3_udc.c95
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c (renamed from drivers/usb/gadget/fsl_usb2_udc.c)69
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h18
5 files changed, 164 insertions, 24 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 772dd3b9bab9..5de9b4f21713 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -156,7 +156,7 @@ config USB_ATMEL_USBA
156 156
157config USB_GADGET_FSL_USB2 157config USB_GADGET_FSL_USB2
158 boolean "Freescale Highspeed USB DR Peripheral Controller" 158 boolean "Freescale Highspeed USB DR Peripheral Controller"
159 depends on FSL_SOC 159 depends on FSL_SOC || ARCH_MXC
160 select USB_GADGET_DUALSPEED 160 select USB_GADGET_DUALSPEED
161 help 161 help
162 Some of Freescale PowerPC processors have a High Speed 162 Some of Freescale PowerPC processors have a High Speed
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 39a51d746cb7..c3fe06396b74 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -18,6 +18,10 @@ obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
18obj-$(CONFIG_USB_AT91) += at91_udc.o 18obj-$(CONFIG_USB_AT91) += at91_udc.o
19obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o 19obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
20obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o 20obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
21fsl_usb2_udc-objs := fsl_udc_core.o
22ifeq ($(CONFIG_ARCH_MXC),y)
23fsl_usb2_udc-objs += fsl_mx3_udc.o
24endif
21obj-$(CONFIG_USB_M66592) += m66592-udc.o 25obj-$(CONFIG_USB_M66592) += m66592-udc.o
22obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o 26obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
23obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o 27obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o
diff --git a/drivers/usb/gadget/fsl_mx3_udc.c b/drivers/usb/gadget/fsl_mx3_udc.c
new file mode 100644
index 000000000000..4bc2bf3d602e
--- /dev/null
+++ b/drivers/usb/gadget/fsl_mx3_udc.c
@@ -0,0 +1,95 @@
1/*
2 * Copyright (C) 2009
3 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
4 *
5 * Description:
6 * Helper routines for i.MX3x SoCs from Freescale, needed by the fsl_usb2_udc.c
7 * driver to function correctly on these systems.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */
14#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/err.h>
17#include <linux/fsl_devices.h>
18#include <linux/platform_device.h>
19
20static struct clk *mxc_ahb_clk;
21static struct clk *mxc_usb_clk;
22
23int fsl_udc_clk_init(struct platform_device *pdev)
24{
25 struct fsl_usb2_platform_data *pdata;
26 unsigned long freq;
27 int ret;
28
29 pdata = pdev->dev.platform_data;
30
31 mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
32 if (IS_ERR(mxc_ahb_clk))
33 return PTR_ERR(mxc_ahb_clk);
34
35 ret = clk_enable(mxc_ahb_clk);
36 if (ret < 0) {
37 dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n");
38 goto eenahb;
39 }
40
41 /* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
42 mxc_usb_clk = clk_get(&pdev->dev, "usb");
43 if (IS_ERR(mxc_usb_clk)) {
44 dev_err(&pdev->dev, "clk_get(\"usb\") failed\n");
45 ret = PTR_ERR(mxc_usb_clk);
46 goto egusb;
47 }
48
49 freq = clk_get_rate(mxc_usb_clk);
50 if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
51 (freq < 59999000 || freq > 60001000)) {
52 dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
53 goto eclkrate;
54 }
55
56 ret = clk_enable(mxc_usb_clk);
57 if (ret < 0) {
58 dev_err(&pdev->dev, "clk_enable(\"usb_clk\") failed\n");
59 goto eenusb;
60 }
61
62 return 0;
63
64eenusb:
65eclkrate:
66 clk_put(mxc_usb_clk);
67 mxc_usb_clk = NULL;
68egusb:
69 clk_disable(mxc_ahb_clk);
70eenahb:
71 clk_put(mxc_ahb_clk);
72 return ret;
73}
74
75void fsl_udc_clk_finalize(struct platform_device *pdev)
76{
77 struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
78
79 /* ULPI transceivers don't need usbpll */
80 if (pdata->phy_mode == FSL_USB2_PHY_ULPI) {
81 clk_disable(mxc_usb_clk);
82 clk_put(mxc_usb_clk);
83 mxc_usb_clk = NULL;
84 }
85}
86
87void fsl_udc_clk_release(void)
88{
89 if (mxc_usb_clk) {
90 clk_disable(mxc_usb_clk);
91 clk_put(mxc_usb_clk);
92 }
93 clk_disable(mxc_ahb_clk);
94 clk_put(mxc_ahb_clk);
95}
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_udc_core.c
index 9d7b95d4e3d2..42a74b8a0bb8 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -38,6 +38,7 @@
38#include <linux/platform_device.h> 38#include <linux/platform_device.h>
39#include <linux/fsl_devices.h> 39#include <linux/fsl_devices.h>
40#include <linux/dmapool.h> 40#include <linux/dmapool.h>
41#include <linux/delay.h>
41 42
42#include <asm/byteorder.h> 43#include <asm/byteorder.h>
43#include <asm/io.h> 44#include <asm/io.h>
@@ -57,7 +58,9 @@ static const char driver_name[] = "fsl-usb2-udc";
57static const char driver_desc[] = DRIVER_DESC; 58static const char driver_desc[] = DRIVER_DESC;
58 59
59static struct usb_dr_device *dr_regs; 60static struct usb_dr_device *dr_regs;
61#ifndef CONFIG_ARCH_MXC
60static struct usb_sys_interface *usb_sys_regs; 62static struct usb_sys_interface *usb_sys_regs;
63#endif
61 64
62/* it is initialized in probe() */ 65/* it is initialized in probe() */
63static struct fsl_udc *udc_controller = NULL; 66static struct fsl_udc *udc_controller = NULL;
@@ -174,10 +177,34 @@ static void nuke(struct fsl_ep *ep, int status)
174 177
175static int dr_controller_setup(struct fsl_udc *udc) 178static int dr_controller_setup(struct fsl_udc *udc)
176{ 179{
177 unsigned int tmp = 0, portctrl = 0, ctrl = 0; 180 unsigned int tmp, portctrl;
181#ifndef CONFIG_ARCH_MXC
182 unsigned int ctrl;
183#endif
178 unsigned long timeout; 184 unsigned long timeout;
179#define FSL_UDC_RESET_TIMEOUT 1000 185#define FSL_UDC_RESET_TIMEOUT 1000
180 186
187 /* Config PHY interface */
188 portctrl = fsl_readl(&dr_regs->portsc1);
189 portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
190 switch (udc->phy_mode) {
191 case FSL_USB2_PHY_ULPI:
192 portctrl |= PORTSCX_PTS_ULPI;
193 break;
194 case FSL_USB2_PHY_UTMI_WIDE:
195 portctrl |= PORTSCX_PTW_16BIT;
196 /* fall through */
197 case FSL_USB2_PHY_UTMI:
198 portctrl |= PORTSCX_PTS_UTMI;
199 break;
200 case FSL_USB2_PHY_SERIAL:
201 portctrl |= PORTSCX_PTS_FSLS;
202 break;
203 default:
204 return -EINVAL;
205 }
206 fsl_writel(portctrl, &dr_regs->portsc1);
207
181 /* Stop and reset the usb controller */ 208 /* Stop and reset the usb controller */
182 tmp = fsl_readl(&dr_regs->usbcmd); 209 tmp = fsl_readl(&dr_regs->usbcmd);
183 tmp &= ~USB_CMD_RUN_STOP; 210 tmp &= ~USB_CMD_RUN_STOP;
@@ -215,31 +242,12 @@ static int dr_controller_setup(struct fsl_udc *udc)
215 udc->ep_qh, (int)tmp, 242 udc->ep_qh, (int)tmp,
216 fsl_readl(&dr_regs->endpointlistaddr)); 243 fsl_readl(&dr_regs->endpointlistaddr));
217 244
218 /* Config PHY interface */
219 portctrl = fsl_readl(&dr_regs->portsc1);
220 portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
221 switch (udc->phy_mode) {
222 case FSL_USB2_PHY_ULPI:
223 portctrl |= PORTSCX_PTS_ULPI;
224 break;
225 case FSL_USB2_PHY_UTMI_WIDE:
226 portctrl |= PORTSCX_PTW_16BIT;
227 /* fall through */
228 case FSL_USB2_PHY_UTMI:
229 portctrl |= PORTSCX_PTS_UTMI;
230 break;
231 case FSL_USB2_PHY_SERIAL:
232 portctrl |= PORTSCX_PTS_FSLS;
233 break;
234 default:
235 return -EINVAL;
236 }
237 fsl_writel(portctrl, &dr_regs->portsc1);
238
239 /* Config control enable i/o output, cpu endian register */ 245 /* Config control enable i/o output, cpu endian register */
246#ifndef CONFIG_ARCH_MXC
240 ctrl = __raw_readl(&usb_sys_regs->control); 247 ctrl = __raw_readl(&usb_sys_regs->control);
241 ctrl |= USB_CTRL_IOENB; 248 ctrl |= USB_CTRL_IOENB;
242 __raw_writel(ctrl, &usb_sys_regs->control); 249 __raw_writel(ctrl, &usb_sys_regs->control);
250#endif
243 251
244#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) 252#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
245 /* Turn on cache snooping hardware, since some PowerPC platforms 253 /* Turn on cache snooping hardware, since some PowerPC platforms
@@ -2043,6 +2051,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
2043 size -= t; 2051 size -= t;
2044 next += t; 2052 next += t;
2045 2053
2054#ifndef CONFIG_ARCH_MXC
2046 tmp_reg = usb_sys_regs->snoop1; 2055 tmp_reg = usb_sys_regs->snoop1;
2047 t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg); 2056 t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
2048 size -= t; 2057 size -= t;
@@ -2053,6 +2062,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
2053 tmp_reg); 2062 tmp_reg);
2054 size -= t; 2063 size -= t;
2055 next += t; 2064 next += t;
2065#endif
2056 2066
2057 /* ------fsl_udc, fsl_ep, fsl_request structure information ----- */ 2067 /* ------fsl_udc, fsl_ep, fsl_request structure information ----- */
2058 ep = &udc->eps[0]; 2068 ep = &udc->eps[0];
@@ -2263,14 +2273,21 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
2263 goto err_kfree; 2273 goto err_kfree;
2264 } 2274 }
2265 2275
2266 dr_regs = ioremap(res->start, res->end - res->start + 1); 2276 dr_regs = ioremap(res->start, resource_size(res));
2267 if (!dr_regs) { 2277 if (!dr_regs) {
2268 ret = -ENOMEM; 2278 ret = -ENOMEM;
2269 goto err_release_mem_region; 2279 goto err_release_mem_region;
2270 } 2280 }
2271 2281
2282#ifndef CONFIG_ARCH_MXC
2272 usb_sys_regs = (struct usb_sys_interface *) 2283 usb_sys_regs = (struct usb_sys_interface *)
2273 ((u32)dr_regs + USB_DR_SYS_OFFSET); 2284 ((u32)dr_regs + USB_DR_SYS_OFFSET);
2285#endif
2286
2287 /* Initialize USB clocks */
2288 ret = fsl_udc_clk_init(pdev);
2289 if (ret < 0)
2290 goto err_iounmap_noclk;
2274 2291
2275 /* Read Device Controller Capability Parameters register */ 2292 /* Read Device Controller Capability Parameters register */
2276 dccparams = fsl_readl(&dr_regs->dccparams); 2293 dccparams = fsl_readl(&dr_regs->dccparams);
@@ -2308,6 +2325,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
2308 * leave usbintr reg untouched */ 2325 * leave usbintr reg untouched */
2309 dr_controller_setup(udc_controller); 2326 dr_controller_setup(udc_controller);
2310 2327
2328 fsl_udc_clk_finalize(pdev);
2329
2311 /* Setup gadget structure */ 2330 /* Setup gadget structure */
2312 udc_controller->gadget.ops = &fsl_gadget_ops; 2331 udc_controller->gadget.ops = &fsl_gadget_ops;
2313 udc_controller->gadget.is_dualspeed = 1; 2332 udc_controller->gadget.is_dualspeed = 1;
@@ -2362,6 +2381,8 @@ err_unregister:
2362err_free_irq: 2381err_free_irq:
2363 free_irq(udc_controller->irq, udc_controller); 2382 free_irq(udc_controller->irq, udc_controller);
2364err_iounmap: 2383err_iounmap:
2384 fsl_udc_clk_release();
2385err_iounmap_noclk:
2365 iounmap(dr_regs); 2386 iounmap(dr_regs);
2366err_release_mem_region: 2387err_release_mem_region:
2367 release_mem_region(res->start, res->end - res->start + 1); 2388 release_mem_region(res->start, res->end - res->start + 1);
@@ -2384,6 +2405,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
2384 return -ENODEV; 2405 return -ENODEV;
2385 udc_controller->done = &done; 2406 udc_controller->done = &done;
2386 2407
2408 fsl_udc_clk_release();
2409
2387 /* DR has been stopped in usb_gadget_unregister_driver() */ 2410 /* DR has been stopped in usb_gadget_unregister_driver() */
2388 remove_proc_file(); 2411 remove_proc_file();
2389 2412
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index e63ef12645f5..20aeceed48c7 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -563,4 +563,22 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
563 * 2 + ((windex & USB_DIR_IN) ? 1 : 0)) 563 * 2 + ((windex & USB_DIR_IN) ? 1 : 0))
564#define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP)) 564#define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP))
565 565
566struct platform_device;
567#ifdef CONFIG_ARCH_MXC
568int fsl_udc_clk_init(struct platform_device *pdev);
569void fsl_udc_clk_finalize(struct platform_device *pdev);
570void fsl_udc_clk_release(void);
571#else
572static inline int fsl_udc_clk_init(struct platform_device *pdev)
573{
574 return 0;
575}
576static inline void fsl_udc_clk_finalize(struct platform_device *pdev)
577{
578}
579static inline void fsl_udc_clk_release(void)
580{
581}
582#endif
583
566#endif 584#endif