Skip to content

Commit f30cdbc

Browse files
kelvincheunggregkh
authored andcommitted
USB: Add EHCI bus glue for Loongson1x SoCs (UPDATED)
Use ehci_setup() in ehci_ls1x_reset(). The Loongson1x SoCs have a built-in EHCI controller. This patch adds the necessary glue code to make the generic EHCI driver usable for them. Signed-off-by: Kelvin Cheung <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 761bbcb commit f30cdbc

File tree

3 files changed

+165
-0
lines changed

3 files changed

+165
-0
lines changed

drivers/usb/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ config USB_ARCH_HAS_EHCI
7676
default y if MICROBLAZE
7777
default y if SPARC_LEON
7878
default y if ARCH_MMP
79+
default y if MACH_LOONGSON1
7980
default PCI
8081

8182
# some non-PCI HCDs implement xHCI

drivers/usb/host/ehci-hcd.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,11 @@ MODULE_LICENSE ("GPL");
13761376
#define PLATFORM_DRIVER ehci_mv_driver
13771377
#endif
13781378

1379+
#ifdef CONFIG_MACH_LOONGSON1
1380+
#include "ehci-ls1x.c"
1381+
#define PLATFORM_DRIVER ehci_ls1x_driver
1382+
#endif
1383+
13791384
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
13801385
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
13811386
!defined(XILINX_OF_PLATFORM_DRIVER)

drivers/usb/host/ehci-ls1x.c

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* Bus Glue for Loongson LS1X built-in EHCI controller.
3+
*
4+
* Copyright (c) 2012 Zhang, Keguang <[email protected]>
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");

0 commit comments

Comments
 (0)