1 /*
2  *  Bus Glue for Atheros AR7XXX/AR9XXX built-in EHCI controller.
3  *
4  *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
5  *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
6  *
7  *  Parts of this file are based on Atheros' 2.6.15 BSP
8  *	Copyright (C) 2007 Atheros Communications, Inc.
9  *
10  *  This program is free software; you can redistribute it and/or modify it
11  *  under the terms of the GNU General Public License version 2 as published
12  *  by the Free Software Foundation.
13  */
14 
15 #include <linux/platform_device.h>
16 
17 enum {
18 	EHCI_ATH79_IP_V1 = 0,
19 	EHCI_ATH79_IP_V2,
20 };
21 
22 static const struct platform_device_id ehci_ath79_id_table[] = {
23 	{
24 		.name		= "ar71xx-ehci",
25 		.driver_data	= EHCI_ATH79_IP_V1,
26 	},
27 	{
28 		.name		= "ar724x-ehci",
29 		.driver_data	= EHCI_ATH79_IP_V2,
30 	},
31 	{
32 		.name		= "ar913x-ehci",
33 		.driver_data	= EHCI_ATH79_IP_V2,
34 	},
35 	{
36 		.name		= "ar933x-ehci",
37 		.driver_data	= EHCI_ATH79_IP_V2,
38 	},
39 	{
40 		/* terminating entry */
41 	},
42 };
43 
44 MODULE_DEVICE_TABLE(platform, ehci_ath79_id_table);
45 
ehci_ath79_init(struct usb_hcd * hcd)46 static int ehci_ath79_init(struct usb_hcd *hcd)
47 {
48 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
49 	struct platform_device *pdev = to_platform_device(hcd->self.controller);
50 	const struct platform_device_id *id;
51 	int ret;
52 
53 	id = platform_get_device_id(pdev);
54 	if (!id) {
55 		dev_err(hcd->self.controller, "missing device id\n");
56 		return -EINVAL;
57 	}
58 
59 	switch (id->driver_data) {
60 	case EHCI_ATH79_IP_V1:
61 		ehci->has_synopsys_hc_bug = 1;
62 
63 		ehci->caps = hcd->regs;
64 		ehci->regs = hcd->regs +
65 			HC_LENGTH(ehci,
66 				  ehci_readl(ehci, &ehci->caps->hc_capbase));
67 		break;
68 
69 	case EHCI_ATH79_IP_V2:
70 		hcd->has_tt = 1;
71 
72 		ehci->caps = hcd->regs + 0x100;
73 		ehci->regs = hcd->regs + 0x100 +
74 			HC_LENGTH(ehci,
75 				  ehci_readl(ehci, &ehci->caps->hc_capbase));
76 		break;
77 
78 	default:
79 		BUG();
80 	}
81 
82 	dbg_hcs_params(ehci, "reset");
83 	dbg_hcc_params(ehci, "reset");
84 	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
85 	ehci->sbrn = 0x20;
86 
87 	ehci_reset(ehci);
88 
89 	ret = ehci_init(hcd);
90 	if (ret)
91 		return ret;
92 
93 	ehci_port_power(ehci, 0);
94 
95 	return 0;
96 }
97 
98 static const struct hc_driver ehci_ath79_hc_driver = {
99 	.description		= hcd_name,
100 	.product_desc		= "Atheros built-in EHCI controller",
101 	.hcd_priv_size		= sizeof(struct ehci_hcd),
102 	.irq			= ehci_irq,
103 	.flags			= HCD_MEMORY | HCD_USB2,
104 
105 	.reset			= ehci_ath79_init,
106 	.start			= ehci_run,
107 	.stop			= ehci_stop,
108 	.shutdown		= ehci_shutdown,
109 
110 	.urb_enqueue		= ehci_urb_enqueue,
111 	.urb_dequeue		= ehci_urb_dequeue,
112 	.endpoint_disable	= ehci_endpoint_disable,
113 	.endpoint_reset		= ehci_endpoint_reset,
114 
115 	.get_frame_number	= ehci_get_frame,
116 
117 	.hub_status_data	= ehci_hub_status_data,
118 	.hub_control		= ehci_hub_control,
119 
120 	.relinquish_port	= ehci_relinquish_port,
121 	.port_handed_over	= ehci_port_handed_over,
122 
123 	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
124 };
125 
ehci_ath79_probe(struct platform_device * pdev)126 static int ehci_ath79_probe(struct platform_device *pdev)
127 {
128 	struct usb_hcd *hcd;
129 	struct resource *res;
130 	int irq;
131 	int ret;
132 
133 	if (usb_disabled())
134 		return -ENODEV;
135 
136 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
137 	if (!res) {
138 		dev_dbg(&pdev->dev, "no IRQ specified\n");
139 		return -ENODEV;
140 	}
141 	irq = res->start;
142 
143 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
144 	if (!res) {
145 		dev_dbg(&pdev->dev, "no base address specified\n");
146 		return -ENODEV;
147 	}
148 
149 	hcd = usb_create_hcd(&ehci_ath79_hc_driver, &pdev->dev,
150 			     dev_name(&pdev->dev));
151 	if (!hcd)
152 		return -ENOMEM;
153 
154 	hcd->rsrc_start	= res->start;
155 	hcd->rsrc_len	= resource_size(res);
156 
157 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
158 		dev_dbg(&pdev->dev, "controller already in use\n");
159 		ret = -EBUSY;
160 		goto err_put_hcd;
161 	}
162 
163 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
164 	if (!hcd->regs) {
165 		dev_dbg(&pdev->dev, "error mapping memory\n");
166 		ret = -EFAULT;
167 		goto err_release_region;
168 	}
169 
170 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
171 	if (ret)
172 		goto err_iounmap;
173 
174 	return 0;
175 
176 err_iounmap:
177 	iounmap(hcd->regs);
178 
179 err_release_region:
180 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
181 err_put_hcd:
182 	usb_put_hcd(hcd);
183 	return ret;
184 }
185 
ehci_ath79_remove(struct platform_device * pdev)186 static int ehci_ath79_remove(struct platform_device *pdev)
187 {
188 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
189 
190 	usb_remove_hcd(hcd);
191 	iounmap(hcd->regs);
192 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
193 	usb_put_hcd(hcd);
194 
195 	return 0;
196 }
197 
198 static struct platform_driver ehci_ath79_driver = {
199 	.probe		= ehci_ath79_probe,
200 	.remove		= ehci_ath79_remove,
201 	.id_table	= ehci_ath79_id_table,
202 	.driver = {
203 		.owner	= THIS_MODULE,
204 		.name	= "ath79-ehci",
205 	}
206 };
207 
208 MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ehci");
209