diff options
Diffstat (limited to 'drivers/mfd/omap-usb-tll.c')
-rw-r--r-- | drivers/mfd/omap-usb-tll.c | 219 |
1 files changed, 110 insertions, 109 deletions
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 0aef1a768880..e59ac4cbac96 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c | |||
@@ -1,8 +1,9 @@ | |||
1 | /** | 1 | /** |
2 | * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI | 2 | * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI |
3 | * | 3 | * |
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com | 4 | * Copyright (C) 2012-2013 Texas Instruments Incorporated - http://www.ti.com |
5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> | 5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> |
6 | * Author: Roger Quadros <rogerq@ti.com> | ||
6 | * | 7 | * |
7 | * This program is free software: you can redistribute it and/or modify | 8 | * This program is free software: you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 of | 9 | * it under the terms of the GNU General Public License version 2 of |
@@ -27,6 +28,7 @@ | |||
27 | #include <linux/err.h> | 28 | #include <linux/err.h> |
28 | #include <linux/pm_runtime.h> | 29 | #include <linux/pm_runtime.h> |
29 | #include <linux/platform_data/usb-omap.h> | 30 | #include <linux/platform_data/usb-omap.h> |
31 | #include <linux/of.h> | ||
30 | 32 | ||
31 | #define USBTLL_DRIVER_NAME "usbhs_tll" | 33 | #define USBTLL_DRIVER_NAME "usbhs_tll" |
32 | 34 | ||
@@ -105,8 +107,8 @@ | |||
105 | 107 | ||
106 | struct usbtll_omap { | 108 | struct usbtll_omap { |
107 | int nch; /* num. of channels */ | 109 | int nch; /* num. of channels */ |
108 | struct usbhs_omap_platform_data *pdata; | ||
109 | struct clk **ch_clk; | 110 | struct clk **ch_clk; |
111 | void __iomem *base; | ||
110 | }; | 112 | }; |
111 | 113 | ||
112 | /*-------------------------------------------------------------------------*/ | 114 | /*-------------------------------------------------------------------------*/ |
@@ -210,14 +212,10 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) | |||
210 | static int usbtll_omap_probe(struct platform_device *pdev) | 212 | static int usbtll_omap_probe(struct platform_device *pdev) |
211 | { | 213 | { |
212 | struct device *dev = &pdev->dev; | 214 | struct device *dev = &pdev->dev; |
213 | struct usbhs_omap_platform_data *pdata = dev->platform_data; | ||
214 | void __iomem *base; | ||
215 | struct resource *res; | 215 | struct resource *res; |
216 | struct usbtll_omap *tll; | 216 | struct usbtll_omap *tll; |
217 | unsigned reg; | ||
218 | int ret = 0; | 217 | int ret = 0; |
219 | int i, ver; | 218 | int i, ver; |
220 | bool needs_tll; | ||
221 | 219 | ||
222 | dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); | 220 | dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); |
223 | 221 | ||
@@ -227,26 +225,16 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
227 | return -ENOMEM; | 225 | return -ENOMEM; |
228 | } | 226 | } |
229 | 227 | ||
230 | if (!pdata) { | ||
231 | dev_err(dev, "Platform data missing\n"); | ||
232 | return -ENODEV; | ||
233 | } | ||
234 | |||
235 | tll->pdata = pdata; | ||
236 | |||
237 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 228 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
238 | base = devm_request_and_ioremap(dev, res); | 229 | tll->base = devm_ioremap_resource(dev, res); |
239 | if (!base) { | 230 | if (IS_ERR(tll->base)) |
240 | ret = -EADDRNOTAVAIL; | 231 | return PTR_ERR(tll->base); |
241 | dev_err(dev, "Resource request/ioremap failed:%d\n", ret); | ||
242 | return ret; | ||
243 | } | ||
244 | 232 | ||
245 | platform_set_drvdata(pdev, tll); | 233 | platform_set_drvdata(pdev, tll); |
246 | pm_runtime_enable(dev); | 234 | pm_runtime_enable(dev); |
247 | pm_runtime_get_sync(dev); | 235 | pm_runtime_get_sync(dev); |
248 | 236 | ||
249 | ver = usbtll_read(base, OMAP_USBTLL_REVISION); | 237 | ver = usbtll_read(tll->base, OMAP_USBTLL_REVISION); |
250 | switch (ver) { | 238 | switch (ver) { |
251 | case OMAP_USBTLL_REV1: | 239 | case OMAP_USBTLL_REV1: |
252 | case OMAP_USBTLL_REV4: | 240 | case OMAP_USBTLL_REV4: |
@@ -283,11 +271,85 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
283 | dev_dbg(dev, "can't get clock : %s\n", clkname); | 271 | dev_dbg(dev, "can't get clock : %s\n", clkname); |
284 | } | 272 | } |
285 | 273 | ||
274 | pm_runtime_put_sync(dev); | ||
275 | /* only after this can omap_tll_enable/disable work */ | ||
276 | spin_lock(&tll_lock); | ||
277 | tll_dev = dev; | ||
278 | spin_unlock(&tll_lock); | ||
279 | |||
280 | return 0; | ||
281 | |||
282 | err_clk_alloc: | ||
283 | pm_runtime_put_sync(dev); | ||
284 | pm_runtime_disable(dev); | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs | ||
291 | * @pdev: USB Host Controller being removed | ||
292 | * | ||
293 | * Reverses the effect of usbtll_omap_probe(). | ||
294 | */ | ||
295 | static int usbtll_omap_remove(struct platform_device *pdev) | ||
296 | { | ||
297 | struct usbtll_omap *tll = platform_get_drvdata(pdev); | ||
298 | int i; | ||
299 | |||
300 | spin_lock(&tll_lock); | ||
301 | tll_dev = NULL; | ||
302 | spin_unlock(&tll_lock); | ||
303 | |||
304 | for (i = 0; i < tll->nch; i++) | ||
305 | if (!IS_ERR(tll->ch_clk[i])) | ||
306 | clk_put(tll->ch_clk[i]); | ||
307 | |||
308 | pm_runtime_disable(&pdev->dev); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static const struct of_device_id usbtll_omap_dt_ids[] = { | ||
313 | { .compatible = "ti,usbhs-tll" }, | ||
314 | { } | ||
315 | }; | ||
316 | |||
317 | MODULE_DEVICE_TABLE(of, usbtll_omap_dt_ids); | ||
318 | |||
319 | static struct platform_driver usbtll_omap_driver = { | ||
320 | .driver = { | ||
321 | .name = (char *)usbtll_driver_name, | ||
322 | .owner = THIS_MODULE, | ||
323 | .of_match_table = of_match_ptr(usbtll_omap_dt_ids), | ||
324 | }, | ||
325 | .probe = usbtll_omap_probe, | ||
326 | .remove = usbtll_omap_remove, | ||
327 | }; | ||
328 | |||
329 | int omap_tll_init(struct usbhs_omap_platform_data *pdata) | ||
330 | { | ||
331 | int i; | ||
332 | bool needs_tll; | ||
333 | unsigned reg; | ||
334 | struct usbtll_omap *tll; | ||
335 | |||
336 | spin_lock(&tll_lock); | ||
337 | |||
338 | if (!tll_dev) { | ||
339 | spin_unlock(&tll_lock); | ||
340 | return -ENODEV; | ||
341 | } | ||
342 | |||
343 | tll = dev_get_drvdata(tll_dev); | ||
344 | |||
286 | needs_tll = false; | 345 | needs_tll = false; |
287 | for (i = 0; i < tll->nch; i++) | 346 | for (i = 0; i < tll->nch; i++) |
288 | needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); | 347 | needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); |
289 | 348 | ||
349 | pm_runtime_get_sync(tll_dev); | ||
350 | |||
290 | if (needs_tll) { | 351 | if (needs_tll) { |
352 | void __iomem *base = tll->base; | ||
291 | 353 | ||
292 | /* Program Common TLL register */ | 354 | /* Program Common TLL register */ |
293 | reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); | 355 | reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); |
@@ -336,51 +398,29 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
336 | } | 398 | } |
337 | } | 399 | } |
338 | 400 | ||
339 | pm_runtime_put_sync(dev); | 401 | pm_runtime_put_sync(tll_dev); |
340 | /* only after this can omap_tll_enable/disable work */ | 402 | |
341 | spin_lock(&tll_lock); | ||
342 | tll_dev = dev; | ||
343 | spin_unlock(&tll_lock); | 403 | spin_unlock(&tll_lock); |
344 | 404 | ||
345 | return 0; | 405 | return 0; |
346 | |||
347 | err_clk_alloc: | ||
348 | pm_runtime_put_sync(dev); | ||
349 | pm_runtime_disable(dev); | ||
350 | |||
351 | return ret; | ||
352 | } | 406 | } |
407 | EXPORT_SYMBOL_GPL(omap_tll_init); | ||
353 | 408 | ||
354 | /** | 409 | int omap_tll_enable(struct usbhs_omap_platform_data *pdata) |
355 | * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs | ||
356 | * @pdev: USB Host Controller being removed | ||
357 | * | ||
358 | * Reverses the effect of usbtll_omap_probe(). | ||
359 | */ | ||
360 | static int usbtll_omap_remove(struct platform_device *pdev) | ||
361 | { | 410 | { |
362 | struct usbtll_omap *tll = platform_get_drvdata(pdev); | ||
363 | int i; | 411 | int i; |
412 | struct usbtll_omap *tll; | ||
364 | 413 | ||
365 | spin_lock(&tll_lock); | 414 | spin_lock(&tll_lock); |
366 | tll_dev = NULL; | ||
367 | spin_unlock(&tll_lock); | ||
368 | 415 | ||
369 | for (i = 0; i < tll->nch; i++) | 416 | if (!tll_dev) { |
370 | if (!IS_ERR(tll->ch_clk[i])) | 417 | spin_unlock(&tll_lock); |
371 | clk_put(tll->ch_clk[i]); | 418 | return -ENODEV; |
372 | 419 | } | |
373 | pm_runtime_disable(&pdev->dev); | ||
374 | return 0; | ||
375 | } | ||
376 | 420 | ||
377 | static int usbtll_runtime_resume(struct device *dev) | 421 | tll = dev_get_drvdata(tll_dev); |
378 | { | ||
379 | struct usbtll_omap *tll = dev_get_drvdata(dev); | ||
380 | struct usbhs_omap_platform_data *pdata = tll->pdata; | ||
381 | int i; | ||
382 | 422 | ||
383 | dev_dbg(dev, "usbtll_runtime_resume\n"); | 423 | pm_runtime_get_sync(tll_dev); |
384 | 424 | ||
385 | for (i = 0; i < tll->nch; i++) { | 425 | for (i = 0; i < tll->nch; i++) { |
386 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { | 426 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { |
@@ -391,22 +431,31 @@ static int usbtll_runtime_resume(struct device *dev) | |||
391 | 431 | ||
392 | r = clk_enable(tll->ch_clk[i]); | 432 | r = clk_enable(tll->ch_clk[i]); |
393 | if (r) { | 433 | if (r) { |
394 | dev_err(dev, | 434 | dev_err(tll_dev, |
395 | "Error enabling ch %d clock: %d\n", i, r); | 435 | "Error enabling ch %d clock: %d\n", i, r); |
396 | } | 436 | } |
397 | } | 437 | } |
398 | } | 438 | } |
399 | 439 | ||
440 | spin_unlock(&tll_lock); | ||
441 | |||
400 | return 0; | 442 | return 0; |
401 | } | 443 | } |
444 | EXPORT_SYMBOL_GPL(omap_tll_enable); | ||
402 | 445 | ||
403 | static int usbtll_runtime_suspend(struct device *dev) | 446 | int omap_tll_disable(struct usbhs_omap_platform_data *pdata) |
404 | { | 447 | { |
405 | struct usbtll_omap *tll = dev_get_drvdata(dev); | ||
406 | struct usbhs_omap_platform_data *pdata = tll->pdata; | ||
407 | int i; | 448 | int i; |
449 | struct usbtll_omap *tll; | ||
408 | 450 | ||
409 | dev_dbg(dev, "usbtll_runtime_suspend\n"); | 451 | spin_lock(&tll_lock); |
452 | |||
453 | if (!tll_dev) { | ||
454 | spin_unlock(&tll_lock); | ||
455 | return -ENODEV; | ||
456 | } | ||
457 | |||
458 | tll = dev_get_drvdata(tll_dev); | ||
410 | 459 | ||
411 | for (i = 0; i < tll->nch; i++) { | 460 | for (i = 0; i < tll->nch; i++) { |
412 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { | 461 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { |
@@ -415,64 +464,16 @@ static int usbtll_runtime_suspend(struct device *dev) | |||
415 | } | 464 | } |
416 | } | 465 | } |
417 | 466 | ||
418 | return 0; | 467 | pm_runtime_put_sync(tll_dev); |
419 | } | ||
420 | |||
421 | static const struct dev_pm_ops usbtllomap_dev_pm_ops = { | ||
422 | SET_RUNTIME_PM_OPS(usbtll_runtime_suspend, | ||
423 | usbtll_runtime_resume, | ||
424 | NULL) | ||
425 | }; | ||
426 | |||
427 | static struct platform_driver usbtll_omap_driver = { | ||
428 | .driver = { | ||
429 | .name = (char *)usbtll_driver_name, | ||
430 | .owner = THIS_MODULE, | ||
431 | .pm = &usbtllomap_dev_pm_ops, | ||
432 | }, | ||
433 | .probe = usbtll_omap_probe, | ||
434 | .remove = usbtll_omap_remove, | ||
435 | }; | ||
436 | |||
437 | int omap_tll_enable(void) | ||
438 | { | ||
439 | int ret; | ||
440 | |||
441 | spin_lock(&tll_lock); | ||
442 | |||
443 | if (!tll_dev) { | ||
444 | pr_err("%s: OMAP USB TLL not initialized\n", __func__); | ||
445 | ret = -ENODEV; | ||
446 | } else { | ||
447 | ret = pm_runtime_get_sync(tll_dev); | ||
448 | } | ||
449 | |||
450 | spin_unlock(&tll_lock); | ||
451 | |||
452 | return ret; | ||
453 | } | ||
454 | EXPORT_SYMBOL_GPL(omap_tll_enable); | ||
455 | |||
456 | int omap_tll_disable(void) | ||
457 | { | ||
458 | int ret; | ||
459 | |||
460 | spin_lock(&tll_lock); | ||
461 | |||
462 | if (!tll_dev) { | ||
463 | pr_err("%s: OMAP USB TLL not initialized\n", __func__); | ||
464 | ret = -ENODEV; | ||
465 | } else { | ||
466 | ret = pm_runtime_put_sync(tll_dev); | ||
467 | } | ||
468 | 468 | ||
469 | spin_unlock(&tll_lock); | 469 | spin_unlock(&tll_lock); |
470 | 470 | ||
471 | return ret; | 471 | return 0; |
472 | } | 472 | } |
473 | EXPORT_SYMBOL_GPL(omap_tll_disable); | 473 | EXPORT_SYMBOL_GPL(omap_tll_disable); |
474 | 474 | ||
475 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); | 475 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); |
476 | MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); | ||
476 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); | 477 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); |
477 | MODULE_LICENSE("GPL v2"); | 478 | MODULE_LICENSE("GPL v2"); |
478 | MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); | 479 | MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); |