xref: /openbmc/linux/drivers/usb/host/ehci-spear.c (revision b9ccfda2)
1 /*
2 * Driver for EHCI HCD on SPEAR SOC
3 *
4 * Copyright (C) 2010 ST Micro Electronics,
5 * Deepak Sikri <deepak.sikri@st.com>
6 *
7 * Based on various ehci-*.c drivers
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive for
11 * more details.
12 */
13 
14 #include <linux/clk.h>
15 #include <linux/jiffies.h>
16 #include <linux/of.h>
17 #include <linux/platform_device.h>
18 #include <linux/pm.h>
19 
20 struct spear_ehci {
21 	struct ehci_hcd ehci;
22 	struct clk *clk;
23 };
24 
25 #define to_spear_ehci(hcd)	(struct spear_ehci *)hcd_to_ehci(hcd)
26 
27 static void spear_start_ehci(struct spear_ehci *ehci)
28 {
29 	clk_prepare_enable(ehci->clk);
30 }
31 
32 static void spear_stop_ehci(struct spear_ehci *ehci)
33 {
34 	clk_disable_unprepare(ehci->clk);
35 }
36 
37 static int ehci_spear_setup(struct usb_hcd *hcd)
38 {
39 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
40 	int retval = 0;
41 
42 	/* registers start at offset 0x0 */
43 	ehci->caps = hcd->regs;
44 	ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
45 				&ehci->caps->hc_capbase));
46 	/* cache this readonly data; minimize chip reads */
47 	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
48 	retval = ehci_halt(ehci);
49 	if (retval)
50 		return retval;
51 
52 	retval = ehci_init(hcd);
53 	if (retval)
54 		return retval;
55 
56 	ehci_reset(ehci);
57 	ehci_port_power(ehci, 0);
58 
59 	return retval;
60 }
61 
62 static const struct hc_driver ehci_spear_hc_driver = {
63 	.description			= hcd_name,
64 	.product_desc			= "SPEAr EHCI",
65 	.hcd_priv_size			= sizeof(struct spear_ehci),
66 
67 	/* generic hardware linkage */
68 	.irq				= ehci_irq,
69 	.flags				= HCD_MEMORY | HCD_USB2,
70 
71 	/* basic lifecycle operations */
72 	.reset				= ehci_spear_setup,
73 	.start				= ehci_run,
74 	.stop				= ehci_stop,
75 	.shutdown			= ehci_shutdown,
76 
77 	/* managing i/o requests and associated device resources */
78 	.urb_enqueue			= ehci_urb_enqueue,
79 	.urb_dequeue			= ehci_urb_dequeue,
80 	.endpoint_disable		= ehci_endpoint_disable,
81 	.endpoint_reset			= ehci_endpoint_reset,
82 
83 	/* scheduling support */
84 	.get_frame_number		= ehci_get_frame,
85 
86 	/* root hub support */
87 	.hub_status_data		= ehci_hub_status_data,
88 	.hub_control			= ehci_hub_control,
89 	.bus_suspend			= ehci_bus_suspend,
90 	.bus_resume			= ehci_bus_resume,
91 	.relinquish_port		= ehci_relinquish_port,
92 	.port_handed_over		= ehci_port_handed_over,
93 	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
94 };
95 
96 #ifdef CONFIG_PM
97 static int ehci_spear_drv_suspend(struct device *dev)
98 {
99 	struct usb_hcd *hcd = dev_get_drvdata(dev);
100 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
101 	unsigned long flags;
102 	int rc = 0;
103 
104 	if (time_before(jiffies, ehci->next_statechange))
105 		msleep(10);
106 
107 	/*
108 	 * Root hub was already suspended. Disable irq emission and mark HW
109 	 * unaccessible. The PM and USB cores make sure that the root hub is
110 	 * either suspended or stopped.
111 	 */
112 	spin_lock_irqsave(&ehci->lock, flags);
113 	ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
114 	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
115 	ehci_readl(ehci, &ehci->regs->intr_enable);
116 	spin_unlock_irqrestore(&ehci->lock, flags);
117 
118 	return rc;
119 }
120 
121 static int ehci_spear_drv_resume(struct device *dev)
122 {
123 	struct usb_hcd *hcd = dev_get_drvdata(dev);
124 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
125 
126 	if (time_before(jiffies, ehci->next_statechange))
127 		msleep(100);
128 
129 	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
130 		int mask = INTR_MASK;
131 
132 		ehci_prepare_ports_for_controller_resume(ehci);
133 
134 		if (!hcd->self.root_hub->do_remote_wakeup)
135 			mask &= ~STS_PCD;
136 
137 		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
138 		ehci_readl(ehci, &ehci->regs->intr_enable);
139 		return 0;
140 	}
141 
142 	usb_root_hub_lost_power(hcd->self.root_hub);
143 
144 	/*
145 	 * Else reset, to cope with power loss or flush-to-storage style
146 	 * "resume" having let BIOS kick in during reboot.
147 	 */
148 	ehci_halt(ehci);
149 	ehci_reset(ehci);
150 
151 	/* emptying the schedule aborts any urbs */
152 	spin_lock_irq(&ehci->lock);
153 	if (ehci->reclaim)
154 		end_unlink_async(ehci);
155 
156 	ehci_work(ehci);
157 	spin_unlock_irq(&ehci->lock);
158 
159 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
160 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
161 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
162 
163 	/* here we "know" root ports should always stay powered */
164 	ehci_port_power(ehci, 1);
165 	return 0;
166 }
167 #endif /* CONFIG_PM */
168 
169 static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
170 		ehci_spear_drv_resume);
171 
172 static u64 spear_ehci_dma_mask = DMA_BIT_MASK(32);
173 
174 static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
175 {
176 	struct usb_hcd *hcd ;
177 	struct spear_ehci *ehci;
178 	struct resource *res;
179 	struct clk *usbh_clk;
180 	const struct hc_driver *driver = &ehci_spear_hc_driver;
181 	int irq, retval;
182 	char clk_name[20] = "usbh_clk";
183 	static int instance = -1;
184 
185 	if (usb_disabled())
186 		return -ENODEV;
187 
188 	irq = platform_get_irq(pdev, 0);
189 	if (irq < 0) {
190 		retval = irq;
191 		goto fail_irq_get;
192 	}
193 
194 	/*
195 	 * Right now device-tree probed devices don't get dma_mask set.
196 	 * Since shared usb code relies on it, set it here for now.
197 	 * Once we have dma capability bindings this can go away.
198 	 */
199 	if (!pdev->dev.dma_mask)
200 		pdev->dev.dma_mask = &spear_ehci_dma_mask;
201 
202 	/*
203 	 * Increment the device instance, when probing via device-tree
204 	 */
205 	if (pdev->id < 0)
206 		instance++;
207 	else
208 		instance = pdev->id;
209 	sprintf(clk_name, "usbh.%01d_clk", instance);
210 
211 	usbh_clk = clk_get(NULL, clk_name);
212 	if (IS_ERR(usbh_clk)) {
213 		dev_err(&pdev->dev, "Error getting interface clock\n");
214 		retval = PTR_ERR(usbh_clk);
215 		goto fail_get_usbh_clk;
216 	}
217 
218 	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
219 	if (!hcd) {
220 		retval = -ENOMEM;
221 		goto fail_create_hcd;
222 	}
223 
224 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
225 	if (!res) {
226 		retval = -ENODEV;
227 		goto fail_request_resource;
228 	}
229 
230 	hcd->rsrc_start = res->start;
231 	hcd->rsrc_len = resource_size(res);
232 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
233 				driver->description)) {
234 		retval = -EBUSY;
235 		goto fail_request_resource;
236 	}
237 
238 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
239 	if (hcd->regs == NULL) {
240 		dev_dbg(&pdev->dev, "error mapping memory\n");
241 		retval = -ENOMEM;
242 		goto fail_ioremap;
243 	}
244 
245 	ehci = (struct spear_ehci *)hcd_to_ehci(hcd);
246 	ehci->clk = usbh_clk;
247 
248 	spear_start_ehci(ehci);
249 	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
250 	if (retval)
251 		goto fail_add_hcd;
252 
253 	return retval;
254 
255 fail_add_hcd:
256 	spear_stop_ehci(ehci);
257 	iounmap(hcd->regs);
258 fail_ioremap:
259 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
260 fail_request_resource:
261 	usb_put_hcd(hcd);
262 fail_create_hcd:
263 	clk_put(usbh_clk);
264 fail_get_usbh_clk:
265 fail_irq_get:
266 	dev_err(&pdev->dev, "init fail, %d\n", retval);
267 
268 	return retval ;
269 }
270 
271 static int spear_ehci_hcd_drv_remove(struct platform_device *pdev)
272 {
273 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
274 	struct spear_ehci *ehci_p = to_spear_ehci(hcd);
275 
276 	if (!hcd)
277 		return 0;
278 	if (in_interrupt())
279 		BUG();
280 	usb_remove_hcd(hcd);
281 
282 	if (ehci_p->clk)
283 		spear_stop_ehci(ehci_p);
284 	iounmap(hcd->regs);
285 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
286 	usb_put_hcd(hcd);
287 
288 	if (ehci_p->clk)
289 		clk_put(ehci_p->clk);
290 
291 	return 0;
292 }
293 
294 static struct of_device_id spear_ehci_id_table[] __devinitdata = {
295 	{ .compatible = "st,spear600-ehci", },
296 	{ },
297 };
298 
299 static struct platform_driver spear_ehci_hcd_driver = {
300 	.probe		= spear_ehci_hcd_drv_probe,
301 	.remove		= spear_ehci_hcd_drv_remove,
302 	.shutdown	= usb_hcd_platform_shutdown,
303 	.driver		= {
304 		.name = "spear-ehci",
305 		.bus = &platform_bus_type,
306 		.pm = &ehci_spear_pm_ops,
307 		.of_match_table = of_match_ptr(spear_ehci_id_table),
308 	}
309 };
310 
311 MODULE_ALIAS("platform:spear-ehci");
312