xref: /openbmc/linux/drivers/usb/host/ehci-mv.c (revision ded017ee)
1 /*
2  * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
3  * Author: Chao Xie <chao.xie@marvell.com>
4  *        Neil Zhang <zhangwm@marvell.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 as published by the
8  * Free Software Foundation;  either version 2 of the  License, or (at your
9  * option) any later version.
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/clk.h>
16 #include <linux/err.h>
17 #include <linux/usb/otg.h>
18 #include <linux/platform_data/mv_usb.h>
19 
20 #define CAPLENGTH_MASK         (0xff)
21 
22 struct ehci_hcd_mv {
23 	struct usb_hcd *hcd;
24 
25 	/* Which mode does this ehci running OTG/Host ? */
26 	int mode;
27 
28 	void __iomem *phy_regs;
29 	void __iomem *cap_regs;
30 	void __iomem *op_regs;
31 
32 	struct usb_phy *otg;
33 
34 	struct mv_usb_platform_data *pdata;
35 
36 	/* clock source and total clock number */
37 	unsigned int clknum;
38 	struct clk *clk[0];
39 };
40 
41 static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
42 {
43 	unsigned int i;
44 
45 	for (i = 0; i < ehci_mv->clknum; i++)
46 		clk_enable(ehci_mv->clk[i]);
47 }
48 
49 static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
50 {
51 	unsigned int i;
52 
53 	for (i = 0; i < ehci_mv->clknum; i++)
54 		clk_disable(ehci_mv->clk[i]);
55 }
56 
57 static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
58 {
59 	int retval;
60 
61 	ehci_clock_enable(ehci_mv);
62 	if (ehci_mv->pdata->phy_init) {
63 		retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs);
64 		if (retval)
65 			return retval;
66 	}
67 
68 	return 0;
69 }
70 
71 static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
72 {
73 	if (ehci_mv->pdata->phy_deinit)
74 		ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs);
75 	ehci_clock_disable(ehci_mv);
76 }
77 
78 static int mv_ehci_reset(struct usb_hcd *hcd)
79 {
80 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
81 	struct device *dev = hcd->self.controller;
82 	struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
83 	int retval;
84 
85 	if (ehci_mv == NULL) {
86 		dev_err(dev, "Can not find private ehci data\n");
87 		return -ENODEV;
88 	}
89 
90 	/*
91 	 * data structure init
92 	 */
93 	retval = ehci_init(hcd);
94 	if (retval) {
95 		dev_err(dev, "ehci_init failed %d\n", retval);
96 		return retval;
97 	}
98 
99 	hcd->has_tt = 1;
100 	ehci->sbrn = 0x20;
101 
102 	retval = ehci_reset(ehci);
103 	if (retval) {
104 		dev_err(dev, "ehci_reset failed %d\n", retval);
105 		return retval;
106 	}
107 
108 	return 0;
109 }
110 
111 static const struct hc_driver mv_ehci_hc_driver = {
112 	.description = hcd_name,
113 	.product_desc = "Marvell EHCI",
114 	.hcd_priv_size = sizeof(struct ehci_hcd),
115 
116 	/*
117 	 * generic hardware linkage
118 	 */
119 	.irq = ehci_irq,
120 	.flags = HCD_MEMORY | HCD_USB2,
121 
122 	/*
123 	 * basic lifecycle operations
124 	 */
125 	.reset = mv_ehci_reset,
126 	.start = ehci_run,
127 	.stop = ehci_stop,
128 	.shutdown = ehci_shutdown,
129 
130 	/*
131 	 * managing i/o requests and associated device resources
132 	 */
133 	.urb_enqueue = ehci_urb_enqueue,
134 	.urb_dequeue = ehci_urb_dequeue,
135 	.endpoint_disable = ehci_endpoint_disable,
136 	.endpoint_reset = ehci_endpoint_reset,
137 	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
138 
139 	/*
140 	 * scheduling support
141 	 */
142 	.get_frame_number = ehci_get_frame,
143 
144 	/*
145 	 * root hub support
146 	 */
147 	.hub_status_data = ehci_hub_status_data,
148 	.hub_control = ehci_hub_control,
149 	.bus_suspend = ehci_bus_suspend,
150 	.bus_resume = ehci_bus_resume,
151 };
152 
153 static int mv_ehci_probe(struct platform_device *pdev)
154 {
155 	struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
156 	struct usb_hcd *hcd;
157 	struct ehci_hcd *ehci;
158 	struct ehci_hcd_mv *ehci_mv;
159 	struct resource *r;
160 	int clk_i, retval = -ENODEV;
161 	u32 offset;
162 	size_t size;
163 
164 	if (!pdata) {
165 		dev_err(&pdev->dev, "missing platform_data\n");
166 		return -ENODEV;
167 	}
168 
169 	if (usb_disabled())
170 		return -ENODEV;
171 
172 	hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci");
173 	if (!hcd)
174 		return -ENOMEM;
175 
176 	size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
177 	ehci_mv = kzalloc(size, GFP_KERNEL);
178 	if (ehci_mv == NULL) {
179 		dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
180 		retval = -ENOMEM;
181 		goto err_put_hcd;
182 	}
183 
184 	platform_set_drvdata(pdev, ehci_mv);
185 	ehci_mv->pdata = pdata;
186 	ehci_mv->hcd = hcd;
187 
188 	ehci_mv->clknum = pdata->clknum;
189 	for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
190 		ehci_mv->clk[clk_i] =
191 		    clk_get(&pdev->dev, pdata->clkname[clk_i]);
192 		if (IS_ERR(ehci_mv->clk[clk_i])) {
193 			dev_err(&pdev->dev, "error get clck \"%s\"\n",
194 				pdata->clkname[clk_i]);
195 			retval = PTR_ERR(ehci_mv->clk[clk_i]);
196 			goto err_put_clk;
197 		}
198 	}
199 
200 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
201 	if (r == NULL) {
202 		dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
203 		retval = -ENODEV;
204 		goto err_put_clk;
205 	}
206 
207 	ehci_mv->phy_regs = ioremap(r->start, resource_size(r));
208 	if (ehci_mv->phy_regs == 0) {
209 		dev_err(&pdev->dev, "failed to map phy I/O memory\n");
210 		retval = -EFAULT;
211 		goto err_put_clk;
212 	}
213 
214 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
215 	if (!r) {
216 		dev_err(&pdev->dev, "no I/O memory resource defined\n");
217 		retval = -ENODEV;
218 		goto err_iounmap_phyreg;
219 	}
220 
221 	ehci_mv->cap_regs = ioremap(r->start, resource_size(r));
222 	if (ehci_mv->cap_regs == NULL) {
223 		dev_err(&pdev->dev, "failed to map I/O memory\n");
224 		retval = -EFAULT;
225 		goto err_iounmap_phyreg;
226 	}
227 
228 	retval = mv_ehci_enable(ehci_mv);
229 	if (retval) {
230 		dev_err(&pdev->dev, "init phy error %d\n", retval);
231 		goto err_iounmap_capreg;
232 	}
233 
234 	offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
235 	ehci_mv->op_regs =
236 		(void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
237 
238 	hcd->rsrc_start = r->start;
239 	hcd->rsrc_len = r->end - r->start + 1;
240 	hcd->regs = ehci_mv->op_regs;
241 
242 	hcd->irq = platform_get_irq(pdev, 0);
243 	if (!hcd->irq) {
244 		dev_err(&pdev->dev, "Cannot get irq.");
245 		retval = -ENODEV;
246 		goto err_disable_clk;
247 	}
248 
249 	ehci = hcd_to_ehci(hcd);
250 	ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
251 	ehci->regs = (struct ehci_regs *) ehci_mv->op_regs;
252 	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
253 
254 	ehci_mv->mode = pdata->mode;
255 	if (ehci_mv->mode == MV_USB_MODE_OTG) {
256 #ifdef CONFIG_USB_OTG_UTILS
257 		ehci_mv->otg = usb_get_phy(USB_PHY_TYPE_USB2);
258 		if (IS_ERR_OR_NULL(ehci_mv->otg)) {
259 			dev_err(&pdev->dev,
260 				"unable to find transceiver\n");
261 			retval = -ENODEV;
262 			goto err_disable_clk;
263 		}
264 
265 		retval = otg_set_host(ehci_mv->otg->otg, &hcd->self);
266 		if (retval < 0) {
267 			dev_err(&pdev->dev,
268 				"unable to register with transceiver\n");
269 			retval = -ENODEV;
270 			goto err_put_transceiver;
271 		}
272 		/* otg will enable clock before use as host */
273 		mv_ehci_disable(ehci_mv);
274 #else
275 		dev_info(&pdev->dev, "MV_USB_MODE_OTG "
276 			 "must have CONFIG_USB_OTG_UTILS enabled\n");
277 		goto err_disable_clk;
278 #endif
279 	} else {
280 		if (pdata->set_vbus)
281 			pdata->set_vbus(1);
282 
283 		retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
284 		if (retval) {
285 			dev_err(&pdev->dev,
286 				"failed to add hcd with err %d\n", retval);
287 			goto err_set_vbus;
288 		}
289 	}
290 
291 	if (pdata->private_init)
292 		pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs);
293 
294 	dev_info(&pdev->dev,
295 		 "successful find EHCI device with regs 0x%p irq %d"
296 		 " working in %s mode\n", hcd->regs, hcd->irq,
297 		 ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host");
298 
299 	return 0;
300 
301 err_set_vbus:
302 	if (pdata->set_vbus)
303 		pdata->set_vbus(0);
304 #ifdef CONFIG_USB_OTG_UTILS
305 err_put_transceiver:
306 	if (!IS_ERR_OR_NULL(ehci_mv->otg))
307 		usb_put_phy(ehci_mv->otg);
308 #endif
309 err_disable_clk:
310 	mv_ehci_disable(ehci_mv);
311 err_iounmap_capreg:
312 	iounmap(ehci_mv->cap_regs);
313 err_iounmap_phyreg:
314 	iounmap(ehci_mv->phy_regs);
315 err_put_clk:
316 	for (clk_i--; clk_i >= 0; clk_i--)
317 		clk_put(ehci_mv->clk[clk_i]);
318 	platform_set_drvdata(pdev, NULL);
319 	kfree(ehci_mv);
320 err_put_hcd:
321 	usb_put_hcd(hcd);
322 
323 	return retval;
324 }
325 
326 static int mv_ehci_remove(struct platform_device *pdev)
327 {
328 	struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
329 	struct usb_hcd *hcd = ehci_mv->hcd;
330 	int clk_i;
331 
332 	if (hcd->rh_registered)
333 		usb_remove_hcd(hcd);
334 
335 	if (!IS_ERR_OR_NULL(ehci_mv->otg)) {
336 		otg_set_host(ehci_mv->otg->otg, NULL);
337 		usb_put_phy(ehci_mv->otg);
338 	}
339 
340 	if (ehci_mv->mode == MV_USB_MODE_HOST) {
341 		if (ehci_mv->pdata->set_vbus)
342 			ehci_mv->pdata->set_vbus(0);
343 
344 		mv_ehci_disable(ehci_mv);
345 	}
346 
347 	iounmap(ehci_mv->cap_regs);
348 	iounmap(ehci_mv->phy_regs);
349 
350 	for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++)
351 		clk_put(ehci_mv->clk[clk_i]);
352 
353 	platform_set_drvdata(pdev, NULL);
354 
355 	kfree(ehci_mv);
356 	usb_put_hcd(hcd);
357 
358 	return 0;
359 }
360 
361 MODULE_ALIAS("mv-ehci");
362 
363 static const struct platform_device_id ehci_id_table[] = {
364 	{"pxa-u2oehci", PXA_U2OEHCI},
365 	{"pxa-sph", PXA_SPH},
366 	{"mmp3-hsic", MMP3_HSIC},
367 	{"mmp3-fsic", MMP3_FSIC},
368 	{},
369 };
370 
371 static void mv_ehci_shutdown(struct platform_device *pdev)
372 {
373 	struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
374 	struct usb_hcd *hcd = ehci_mv->hcd;
375 
376 	if (!hcd->rh_registered)
377 		return;
378 
379 	if (hcd->driver->shutdown)
380 		hcd->driver->shutdown(hcd);
381 }
382 
383 static struct platform_driver ehci_mv_driver = {
384 	.probe = mv_ehci_probe,
385 	.remove = mv_ehci_remove,
386 	.shutdown = mv_ehci_shutdown,
387 	.driver = {
388 		   .name = "mv-ehci",
389 		   .bus = &platform_bus_type,
390 		   },
391 	.id_table = ehci_id_table,
392 };
393