aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/omap-usb-tll.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/omap-usb-tll.c')
-rw-r--r--drivers/mfd/omap-usb-tll.c219
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
106struct usbtll_omap { 108struct 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)
210static int usbtll_omap_probe(struct platform_device *pdev) 212static 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
282err_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 */
295static 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
312static const struct of_device_id usbtll_omap_dt_ids[] = {
313 { .compatible = "ti,usbhs-tll" },
314 { }
315};
316
317MODULE_DEVICE_TABLE(of, usbtll_omap_dt_ids);
318
319static 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
329int 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
347err_clk_alloc:
348 pm_runtime_put_sync(dev);
349 pm_runtime_disable(dev);
350
351 return ret;
352} 406}
407EXPORT_SYMBOL_GPL(omap_tll_init);
353 408
354/** 409int 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 */
360static 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
377static 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}
444EXPORT_SYMBOL_GPL(omap_tll_enable);
402 445
403static int usbtll_runtime_suspend(struct device *dev) 446int 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
421static 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
427static 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
437int 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}
454EXPORT_SYMBOL_GPL(omap_tll_enable);
455
456int 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}
473EXPORT_SYMBOL_GPL(omap_tll_disable); 473EXPORT_SYMBOL_GPL(omap_tll_disable);
474 474
475MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); 475MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
476MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
476MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); 477MODULE_ALIAS("platform:" USBHS_DRIVER_NAME);
477MODULE_LICENSE("GPL v2"); 478MODULE_LICENSE("GPL v2");
478MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); 479MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers");