diff options
-rw-r--r-- | drivers/usb/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ehci-ls1x.c | 159 |
3 files changed, 165 insertions, 0 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 75823a1abeb6..0b0afc81a542 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig | |||
@@ -76,6 +76,7 @@ config USB_ARCH_HAS_EHCI | |||
76 | default y if MICROBLAZE | 76 | default y if MICROBLAZE |
77 | default y if SPARC_LEON | 77 | default y if SPARC_LEON |
78 | default y if ARCH_MMP | 78 | default y if ARCH_MMP |
79 | default y if MACH_LOONGSON1 | ||
79 | default PCI | 80 | default PCI |
80 | 81 | ||
81 | # some non-PCI HCDs implement xHCI | 82 | # some non-PCI HCDs implement xHCI |
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index a007a9fe0f87..4918b0c59af9 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -1376,6 +1376,11 @@ MODULE_LICENSE ("GPL"); | |||
1376 | #define PLATFORM_DRIVER ehci_mv_driver | 1376 | #define PLATFORM_DRIVER ehci_mv_driver |
1377 | #endif | 1377 | #endif |
1378 | 1378 | ||
1379 | #ifdef CONFIG_MACH_LOONGSON1 | ||
1380 | #include "ehci-ls1x.c" | ||
1381 | #define PLATFORM_DRIVER ehci_ls1x_driver | ||
1382 | #endif | ||
1383 | |||
1379 | #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ | 1384 | #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ |
1380 | !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ | 1385 | !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ |
1381 | !defined(XILINX_OF_PLATFORM_DRIVER) | 1386 | !defined(XILINX_OF_PLATFORM_DRIVER) |
diff --git a/drivers/usb/host/ehci-ls1x.c b/drivers/usb/host/ehci-ls1x.c new file mode 100644 index 000000000000..a283e59709d6 --- /dev/null +++ b/drivers/usb/host/ehci-ls1x.c | |||
@@ -0,0 +1,159 @@ | |||
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"); | ||