diff options
Diffstat (limited to 'drivers/mfd/omap-usb-host.c')
-rw-r--r-- | drivers/mfd/omap-usb-host.c | 755 |
1 files changed, 304 insertions, 451 deletions
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 86e14583a082..3f565ef3e149 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c | |||
@@ -27,8 +27,9 @@ | |||
27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
28 | #include <linux/gpio.h> | 28 | #include <linux/gpio.h> |
29 | #include <plat/usb.h> | 29 | #include <plat/usb.h> |
30 | #include <linux/pm_runtime.h> | ||
30 | 31 | ||
31 | #define USBHS_DRIVER_NAME "usbhs-omap" | 32 | #define USBHS_DRIVER_NAME "usbhs_omap" |
32 | #define OMAP_EHCI_DEVICE "ehci-omap" | 33 | #define OMAP_EHCI_DEVICE "ehci-omap" |
33 | #define OMAP_OHCI_DEVICE "ohci-omap3" | 34 | #define OMAP_OHCI_DEVICE "ohci-omap3" |
34 | 35 | ||
@@ -147,9 +148,6 @@ | |||
147 | 148 | ||
148 | 149 | ||
149 | struct usbhs_hcd_omap { | 150 | struct usbhs_hcd_omap { |
150 | struct clk *usbhost_ick; | ||
151 | struct clk *usbhost_hs_fck; | ||
152 | struct clk *usbhost_fs_fck; | ||
153 | struct clk *xclk60mhsp1_ck; | 151 | struct clk *xclk60mhsp1_ck; |
154 | struct clk *xclk60mhsp2_ck; | 152 | struct clk *xclk60mhsp2_ck; |
155 | struct clk *utmi_p1_fck; | 153 | struct clk *utmi_p1_fck; |
@@ -159,8 +157,7 @@ struct usbhs_hcd_omap { | |||
159 | struct clk *usbhost_p2_fck; | 157 | struct clk *usbhost_p2_fck; |
160 | struct clk *usbtll_p2_fck; | 158 | struct clk *usbtll_p2_fck; |
161 | struct clk *init_60m_fclk; | 159 | struct clk *init_60m_fclk; |
162 | struct clk *usbtll_fck; | 160 | struct clk *ehci_logic_fck; |
163 | struct clk *usbtll_ick; | ||
164 | 161 | ||
165 | void __iomem *uhh_base; | 162 | void __iomem *uhh_base; |
166 | void __iomem *tll_base; | 163 | void __iomem *tll_base; |
@@ -169,7 +166,6 @@ struct usbhs_hcd_omap { | |||
169 | 166 | ||
170 | u32 usbhs_rev; | 167 | u32 usbhs_rev; |
171 | spinlock_t lock; | 168 | spinlock_t lock; |
172 | int count; | ||
173 | }; | 169 | }; |
174 | /*-------------------------------------------------------------------------*/ | 170 | /*-------------------------------------------------------------------------*/ |
175 | 171 | ||
@@ -319,269 +315,6 @@ err_end: | |||
319 | return ret; | 315 | return ret; |
320 | } | 316 | } |
321 | 317 | ||
322 | /** | ||
323 | * usbhs_omap_probe - initialize TI-based HCDs | ||
324 | * | ||
325 | * Allocates basic resources for this USB host controller. | ||
326 | */ | ||
327 | static int __devinit usbhs_omap_probe(struct platform_device *pdev) | ||
328 | { | ||
329 | struct device *dev = &pdev->dev; | ||
330 | struct usbhs_omap_platform_data *pdata = dev->platform_data; | ||
331 | struct usbhs_hcd_omap *omap; | ||
332 | struct resource *res; | ||
333 | int ret = 0; | ||
334 | int i; | ||
335 | |||
336 | if (!pdata) { | ||
337 | dev_err(dev, "Missing platform data\n"); | ||
338 | ret = -ENOMEM; | ||
339 | goto end_probe; | ||
340 | } | ||
341 | |||
342 | omap = kzalloc(sizeof(*omap), GFP_KERNEL); | ||
343 | if (!omap) { | ||
344 | dev_err(dev, "Memory allocation failed\n"); | ||
345 | ret = -ENOMEM; | ||
346 | goto end_probe; | ||
347 | } | ||
348 | |||
349 | spin_lock_init(&omap->lock); | ||
350 | |||
351 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) | ||
352 | omap->platdata.port_mode[i] = pdata->port_mode[i]; | ||
353 | |||
354 | omap->platdata.ehci_data = pdata->ehci_data; | ||
355 | omap->platdata.ohci_data = pdata->ohci_data; | ||
356 | |||
357 | omap->usbhost_ick = clk_get(dev, "usbhost_ick"); | ||
358 | if (IS_ERR(omap->usbhost_ick)) { | ||
359 | ret = PTR_ERR(omap->usbhost_ick); | ||
360 | dev_err(dev, "usbhost_ick failed error:%d\n", ret); | ||
361 | goto err_end; | ||
362 | } | ||
363 | |||
364 | omap->usbhost_hs_fck = clk_get(dev, "hs_fck"); | ||
365 | if (IS_ERR(omap->usbhost_hs_fck)) { | ||
366 | ret = PTR_ERR(omap->usbhost_hs_fck); | ||
367 | dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret); | ||
368 | goto err_usbhost_ick; | ||
369 | } | ||
370 | |||
371 | omap->usbhost_fs_fck = clk_get(dev, "fs_fck"); | ||
372 | if (IS_ERR(omap->usbhost_fs_fck)) { | ||
373 | ret = PTR_ERR(omap->usbhost_fs_fck); | ||
374 | dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret); | ||
375 | goto err_usbhost_hs_fck; | ||
376 | } | ||
377 | |||
378 | omap->usbtll_fck = clk_get(dev, "usbtll_fck"); | ||
379 | if (IS_ERR(omap->usbtll_fck)) { | ||
380 | ret = PTR_ERR(omap->usbtll_fck); | ||
381 | dev_err(dev, "usbtll_fck failed error:%d\n", ret); | ||
382 | goto err_usbhost_fs_fck; | ||
383 | } | ||
384 | |||
385 | omap->usbtll_ick = clk_get(dev, "usbtll_ick"); | ||
386 | if (IS_ERR(omap->usbtll_ick)) { | ||
387 | ret = PTR_ERR(omap->usbtll_ick); | ||
388 | dev_err(dev, "usbtll_ick failed error:%d\n", ret); | ||
389 | goto err_usbtll_fck; | ||
390 | } | ||
391 | |||
392 | omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); | ||
393 | if (IS_ERR(omap->utmi_p1_fck)) { | ||
394 | ret = PTR_ERR(omap->utmi_p1_fck); | ||
395 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); | ||
396 | goto err_usbtll_ick; | ||
397 | } | ||
398 | |||
399 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); | ||
400 | if (IS_ERR(omap->xclk60mhsp1_ck)) { | ||
401 | ret = PTR_ERR(omap->xclk60mhsp1_ck); | ||
402 | dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); | ||
403 | goto err_utmi_p1_fck; | ||
404 | } | ||
405 | |||
406 | omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk"); | ||
407 | if (IS_ERR(omap->utmi_p2_fck)) { | ||
408 | ret = PTR_ERR(omap->utmi_p2_fck); | ||
409 | dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); | ||
410 | goto err_xclk60mhsp1_ck; | ||
411 | } | ||
412 | |||
413 | omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); | ||
414 | if (IS_ERR(omap->xclk60mhsp2_ck)) { | ||
415 | ret = PTR_ERR(omap->xclk60mhsp2_ck); | ||
416 | dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); | ||
417 | goto err_utmi_p2_fck; | ||
418 | } | ||
419 | |||
420 | omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk"); | ||
421 | if (IS_ERR(omap->usbhost_p1_fck)) { | ||
422 | ret = PTR_ERR(omap->usbhost_p1_fck); | ||
423 | dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret); | ||
424 | goto err_xclk60mhsp2_ck; | ||
425 | } | ||
426 | |||
427 | omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); | ||
428 | if (IS_ERR(omap->usbtll_p1_fck)) { | ||
429 | ret = PTR_ERR(omap->usbtll_p1_fck); | ||
430 | dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); | ||
431 | goto err_usbhost_p1_fck; | ||
432 | } | ||
433 | |||
434 | omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); | ||
435 | if (IS_ERR(omap->usbhost_p2_fck)) { | ||
436 | ret = PTR_ERR(omap->usbhost_p2_fck); | ||
437 | dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); | ||
438 | goto err_usbtll_p1_fck; | ||
439 | } | ||
440 | |||
441 | omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); | ||
442 | if (IS_ERR(omap->usbtll_p2_fck)) { | ||
443 | ret = PTR_ERR(omap->usbtll_p2_fck); | ||
444 | dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); | ||
445 | goto err_usbhost_p2_fck; | ||
446 | } | ||
447 | |||
448 | omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); | ||
449 | if (IS_ERR(omap->init_60m_fclk)) { | ||
450 | ret = PTR_ERR(omap->init_60m_fclk); | ||
451 | dev_err(dev, "init_60m_fclk failed error:%d\n", ret); | ||
452 | goto err_usbtll_p2_fck; | ||
453 | } | ||
454 | |||
455 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); | ||
456 | if (!res) { | ||
457 | dev_err(dev, "UHH EHCI get resource failed\n"); | ||
458 | ret = -ENODEV; | ||
459 | goto err_init_60m_fclk; | ||
460 | } | ||
461 | |||
462 | omap->uhh_base = ioremap(res->start, resource_size(res)); | ||
463 | if (!omap->uhh_base) { | ||
464 | dev_err(dev, "UHH ioremap failed\n"); | ||
465 | ret = -ENOMEM; | ||
466 | goto err_init_60m_fclk; | ||
467 | } | ||
468 | |||
469 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll"); | ||
470 | if (!res) { | ||
471 | dev_err(dev, "UHH EHCI get resource failed\n"); | ||
472 | ret = -ENODEV; | ||
473 | goto err_tll; | ||
474 | } | ||
475 | |||
476 | omap->tll_base = ioremap(res->start, resource_size(res)); | ||
477 | if (!omap->tll_base) { | ||
478 | dev_err(dev, "TLL ioremap failed\n"); | ||
479 | ret = -ENOMEM; | ||
480 | goto err_tll; | ||
481 | } | ||
482 | |||
483 | platform_set_drvdata(pdev, omap); | ||
484 | |||
485 | ret = omap_usbhs_alloc_children(pdev); | ||
486 | if (ret) { | ||
487 | dev_err(dev, "omap_usbhs_alloc_children failed\n"); | ||
488 | goto err_alloc; | ||
489 | } | ||
490 | |||
491 | goto end_probe; | ||
492 | |||
493 | err_alloc: | ||
494 | iounmap(omap->tll_base); | ||
495 | |||
496 | err_tll: | ||
497 | iounmap(omap->uhh_base); | ||
498 | |||
499 | err_init_60m_fclk: | ||
500 | clk_put(omap->init_60m_fclk); | ||
501 | |||
502 | err_usbtll_p2_fck: | ||
503 | clk_put(omap->usbtll_p2_fck); | ||
504 | |||
505 | err_usbhost_p2_fck: | ||
506 | clk_put(omap->usbhost_p2_fck); | ||
507 | |||
508 | err_usbtll_p1_fck: | ||
509 | clk_put(omap->usbtll_p1_fck); | ||
510 | |||
511 | err_usbhost_p1_fck: | ||
512 | clk_put(omap->usbhost_p1_fck); | ||
513 | |||
514 | err_xclk60mhsp2_ck: | ||
515 | clk_put(omap->xclk60mhsp2_ck); | ||
516 | |||
517 | err_utmi_p2_fck: | ||
518 | clk_put(omap->utmi_p2_fck); | ||
519 | |||
520 | err_xclk60mhsp1_ck: | ||
521 | clk_put(omap->xclk60mhsp1_ck); | ||
522 | |||
523 | err_utmi_p1_fck: | ||
524 | clk_put(omap->utmi_p1_fck); | ||
525 | |||
526 | err_usbtll_ick: | ||
527 | clk_put(omap->usbtll_ick); | ||
528 | |||
529 | err_usbtll_fck: | ||
530 | clk_put(omap->usbtll_fck); | ||
531 | |||
532 | err_usbhost_fs_fck: | ||
533 | clk_put(omap->usbhost_fs_fck); | ||
534 | |||
535 | err_usbhost_hs_fck: | ||
536 | clk_put(omap->usbhost_hs_fck); | ||
537 | |||
538 | err_usbhost_ick: | ||
539 | clk_put(omap->usbhost_ick); | ||
540 | |||
541 | err_end: | ||
542 | kfree(omap); | ||
543 | |||
544 | end_probe: | ||
545 | return ret; | ||
546 | } | ||
547 | |||
548 | /** | ||
549 | * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs | ||
550 | * @pdev: USB Host Controller being removed | ||
551 | * | ||
552 | * Reverses the effect of usbhs_omap_probe(). | ||
553 | */ | ||
554 | static int __devexit usbhs_omap_remove(struct platform_device *pdev) | ||
555 | { | ||
556 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); | ||
557 | |||
558 | if (omap->count != 0) { | ||
559 | dev_err(&pdev->dev, | ||
560 | "Either EHCI or OHCI is still using usbhs core\n"); | ||
561 | return -EBUSY; | ||
562 | } | ||
563 | |||
564 | iounmap(omap->tll_base); | ||
565 | iounmap(omap->uhh_base); | ||
566 | clk_put(omap->init_60m_fclk); | ||
567 | clk_put(omap->usbtll_p2_fck); | ||
568 | clk_put(omap->usbhost_p2_fck); | ||
569 | clk_put(omap->usbtll_p1_fck); | ||
570 | clk_put(omap->usbhost_p1_fck); | ||
571 | clk_put(omap->xclk60mhsp2_ck); | ||
572 | clk_put(omap->utmi_p2_fck); | ||
573 | clk_put(omap->xclk60mhsp1_ck); | ||
574 | clk_put(omap->utmi_p1_fck); | ||
575 | clk_put(omap->usbtll_ick); | ||
576 | clk_put(omap->usbtll_fck); | ||
577 | clk_put(omap->usbhost_fs_fck); | ||
578 | clk_put(omap->usbhost_hs_fck); | ||
579 | clk_put(omap->usbhost_ick); | ||
580 | kfree(omap); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static bool is_ohci_port(enum usbhs_omap_port_mode pmode) | 318 | static bool is_ohci_port(enum usbhs_omap_port_mode pmode) |
586 | { | 319 | { |
587 | switch (pmode) { | 320 | switch (pmode) { |
@@ -689,30 +422,85 @@ static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count) | |||
689 | } | 422 | } |
690 | } | 423 | } |
691 | 424 | ||
692 | static int usbhs_enable(struct device *dev) | 425 | static int usbhs_runtime_resume(struct device *dev) |
693 | { | 426 | { |
694 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 427 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); |
695 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | 428 | struct usbhs_omap_platform_data *pdata = &omap->platdata; |
696 | unsigned long flags = 0; | 429 | unsigned long flags; |
697 | int ret = 0; | 430 | |
698 | unsigned long timeout; | 431 | dev_dbg(dev, "usbhs_runtime_resume\n"); |
699 | unsigned reg; | ||
700 | 432 | ||
701 | dev_dbg(dev, "starting TI HSUSB Controller\n"); | ||
702 | if (!pdata) { | 433 | if (!pdata) { |
703 | dev_dbg(dev, "missing platform_data\n"); | 434 | dev_dbg(dev, "missing platform_data\n"); |
704 | return -ENODEV; | 435 | return -ENODEV; |
705 | } | 436 | } |
706 | 437 | ||
707 | spin_lock_irqsave(&omap->lock, flags); | 438 | spin_lock_irqsave(&omap->lock, flags); |
708 | if (omap->count > 0) | ||
709 | goto end_count; | ||
710 | 439 | ||
711 | clk_enable(omap->usbhost_ick); | 440 | if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) |
712 | clk_enable(omap->usbhost_hs_fck); | 441 | clk_enable(omap->ehci_logic_fck); |
713 | clk_enable(omap->usbhost_fs_fck); | 442 | |
714 | clk_enable(omap->usbtll_fck); | 443 | if (is_ehci_tll_mode(pdata->port_mode[0])) { |
715 | clk_enable(omap->usbtll_ick); | 444 | clk_enable(omap->usbhost_p1_fck); |
445 | clk_enable(omap->usbtll_p1_fck); | ||
446 | } | ||
447 | if (is_ehci_tll_mode(pdata->port_mode[1])) { | ||
448 | clk_enable(omap->usbhost_p2_fck); | ||
449 | clk_enable(omap->usbtll_p2_fck); | ||
450 | } | ||
451 | clk_enable(omap->utmi_p1_fck); | ||
452 | clk_enable(omap->utmi_p2_fck); | ||
453 | |||
454 | spin_unlock_irqrestore(&omap->lock, flags); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static int usbhs_runtime_suspend(struct device *dev) | ||
460 | { | ||
461 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | ||
462 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | ||
463 | unsigned long flags; | ||
464 | |||
465 | dev_dbg(dev, "usbhs_runtime_suspend\n"); | ||
466 | |||
467 | if (!pdata) { | ||
468 | dev_dbg(dev, "missing platform_data\n"); | ||
469 | return -ENODEV; | ||
470 | } | ||
471 | |||
472 | spin_lock_irqsave(&omap->lock, flags); | ||
473 | |||
474 | if (is_ehci_tll_mode(pdata->port_mode[0])) { | ||
475 | clk_disable(omap->usbhost_p1_fck); | ||
476 | clk_disable(omap->usbtll_p1_fck); | ||
477 | } | ||
478 | if (is_ehci_tll_mode(pdata->port_mode[1])) { | ||
479 | clk_disable(omap->usbhost_p2_fck); | ||
480 | clk_disable(omap->usbtll_p2_fck); | ||
481 | } | ||
482 | clk_disable(omap->utmi_p2_fck); | ||
483 | clk_disable(omap->utmi_p1_fck); | ||
484 | |||
485 | if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) | ||
486 | clk_disable(omap->ehci_logic_fck); | ||
487 | |||
488 | spin_unlock_irqrestore(&omap->lock, flags); | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static void omap_usbhs_init(struct device *dev) | ||
494 | { | ||
495 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | ||
496 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | ||
497 | unsigned long flags; | ||
498 | unsigned reg; | ||
499 | |||
500 | dev_dbg(dev, "starting TI HSUSB Controller\n"); | ||
501 | |||
502 | pm_runtime_get_sync(dev); | ||
503 | spin_lock_irqsave(&omap->lock, flags); | ||
716 | 504 | ||
717 | if (pdata->ehci_data->phy_reset) { | 505 | if (pdata->ehci_data->phy_reset) { |
718 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { | 506 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { |
@@ -736,50 +524,6 @@ static int usbhs_enable(struct device *dev) | |||
736 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); | 524 | omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); |
737 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); | 525 | dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); |
738 | 526 | ||
739 | /* perform TLL soft reset, and wait until reset is complete */ | ||
740 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
741 | OMAP_USBTLL_SYSCONFIG_SOFTRESET); | ||
742 | |||
743 | /* Wait for TLL reset to complete */ | ||
744 | timeout = jiffies + msecs_to_jiffies(1000); | ||
745 | while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | ||
746 | & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { | ||
747 | cpu_relax(); | ||
748 | |||
749 | if (time_after(jiffies, timeout)) { | ||
750 | dev_dbg(dev, "operation timed out\n"); | ||
751 | ret = -EINVAL; | ||
752 | goto err_tll; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | dev_dbg(dev, "TLL RESET DONE\n"); | ||
757 | |||
758 | /* (1<<3) = no idle mode only for initial debugging */ | ||
759 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, | ||
760 | OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | | ||
761 | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | | ||
762 | OMAP_USBTLL_SYSCONFIG_AUTOIDLE); | ||
763 | |||
764 | /* Put UHH in NoIdle/NoStandby mode */ | ||
765 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG); | ||
766 | if (is_omap_usbhs_rev1(omap)) { | ||
767 | reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP | ||
768 | | OMAP_UHH_SYSCONFIG_SIDLEMODE | ||
769 | | OMAP_UHH_SYSCONFIG_CACTIVITY | ||
770 | | OMAP_UHH_SYSCONFIG_MIDLEMODE); | ||
771 | reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; | ||
772 | |||
773 | |||
774 | } else if (is_omap_usbhs_rev2(omap)) { | ||
775 | reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR; | ||
776 | reg |= OMAP4_UHH_SYSCONFIG_NOIDLE; | ||
777 | reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR; | ||
778 | reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY; | ||
779 | } | ||
780 | |||
781 | usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); | ||
782 | |||
783 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); | 527 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); |
784 | /* setup ULPI bypass and burst configurations */ | 528 | /* setup ULPI bypass and burst configurations */ |
785 | reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | 529 | reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN |
@@ -825,49 +569,6 @@ static int usbhs_enable(struct device *dev) | |||
825 | reg &= ~OMAP4_P1_MODE_CLEAR; | 569 | reg &= ~OMAP4_P1_MODE_CLEAR; |
826 | reg &= ~OMAP4_P2_MODE_CLEAR; | 570 | reg &= ~OMAP4_P2_MODE_CLEAR; |
827 | 571 | ||
828 | if (is_ehci_phy_mode(pdata->port_mode[0])) { | ||
829 | ret = clk_set_parent(omap->utmi_p1_fck, | ||
830 | omap->xclk60mhsp1_ck); | ||
831 | if (ret != 0) { | ||
832 | dev_err(dev, "xclk60mhsp1_ck set parent" | ||
833 | "failed error:%d\n", ret); | ||
834 | goto err_tll; | ||
835 | } | ||
836 | } else if (is_ehci_tll_mode(pdata->port_mode[0])) { | ||
837 | ret = clk_set_parent(omap->utmi_p1_fck, | ||
838 | omap->init_60m_fclk); | ||
839 | if (ret != 0) { | ||
840 | dev_err(dev, "init_60m_fclk set parent" | ||
841 | "failed error:%d\n", ret); | ||
842 | goto err_tll; | ||
843 | } | ||
844 | clk_enable(omap->usbhost_p1_fck); | ||
845 | clk_enable(omap->usbtll_p1_fck); | ||
846 | } | ||
847 | |||
848 | if (is_ehci_phy_mode(pdata->port_mode[1])) { | ||
849 | ret = clk_set_parent(omap->utmi_p2_fck, | ||
850 | omap->xclk60mhsp2_ck); | ||
851 | if (ret != 0) { | ||
852 | dev_err(dev, "xclk60mhsp1_ck set parent" | ||
853 | "failed error:%d\n", ret); | ||
854 | goto err_tll; | ||
855 | } | ||
856 | } else if (is_ehci_tll_mode(pdata->port_mode[1])) { | ||
857 | ret = clk_set_parent(omap->utmi_p2_fck, | ||
858 | omap->init_60m_fclk); | ||
859 | if (ret != 0) { | ||
860 | dev_err(dev, "init_60m_fclk set parent" | ||
861 | "failed error:%d\n", ret); | ||
862 | goto err_tll; | ||
863 | } | ||
864 | clk_enable(omap->usbhost_p2_fck); | ||
865 | clk_enable(omap->usbtll_p2_fck); | ||
866 | } | ||
867 | |||
868 | clk_enable(omap->utmi_p1_fck); | ||
869 | clk_enable(omap->utmi_p2_fck); | ||
870 | |||
871 | if (is_ehci_tll_mode(pdata->port_mode[0]) || | 572 | if (is_ehci_tll_mode(pdata->port_mode[0]) || |
872 | (is_ohci_port(pdata->port_mode[0]))) | 573 | (is_ohci_port(pdata->port_mode[0]))) |
873 | reg |= OMAP4_P1_MODE_TLL; | 574 | reg |= OMAP4_P1_MODE_TLL; |
@@ -913,12 +614,15 @@ static int usbhs_enable(struct device *dev) | |||
913 | (pdata->ehci_data->reset_gpio_port[1], 1); | 614 | (pdata->ehci_data->reset_gpio_port[1], 1); |
914 | } | 615 | } |
915 | 616 | ||
916 | end_count: | ||
917 | omap->count++; | ||
918 | spin_unlock_irqrestore(&omap->lock, flags); | 617 | spin_unlock_irqrestore(&omap->lock, flags); |
919 | return 0; | 618 | pm_runtime_put_sync(dev); |
619 | } | ||
620 | |||
621 | static void omap_usbhs_deinit(struct device *dev) | ||
622 | { | ||
623 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | ||
624 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | ||
920 | 625 | ||
921 | err_tll: | ||
922 | if (pdata->ehci_data->phy_reset) { | 626 | if (pdata->ehci_data->phy_reset) { |
923 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | 627 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) |
924 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); | 628 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); |
@@ -926,123 +630,272 @@ err_tll: | |||
926 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | 630 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) |
927 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); | 631 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); |
928 | } | 632 | } |
929 | |||
930 | clk_disable(omap->usbtll_ick); | ||
931 | clk_disable(omap->usbtll_fck); | ||
932 | clk_disable(omap->usbhost_fs_fck); | ||
933 | clk_disable(omap->usbhost_hs_fck); | ||
934 | clk_disable(omap->usbhost_ick); | ||
935 | spin_unlock_irqrestore(&omap->lock, flags); | ||
936 | return ret; | ||
937 | } | 633 | } |
938 | 634 | ||
939 | static void usbhs_disable(struct device *dev) | 635 | |
636 | /** | ||
637 | * usbhs_omap_probe - initialize TI-based HCDs | ||
638 | * | ||
639 | * Allocates basic resources for this USB host controller. | ||
640 | */ | ||
641 | static int __devinit usbhs_omap_probe(struct platform_device *pdev) | ||
940 | { | 642 | { |
941 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 643 | struct device *dev = &pdev->dev; |
942 | struct usbhs_omap_platform_data *pdata = &omap->platdata; | 644 | struct usbhs_omap_platform_data *pdata = dev->platform_data; |
943 | unsigned long flags = 0; | 645 | struct usbhs_hcd_omap *omap; |
944 | unsigned long timeout; | 646 | struct resource *res; |
647 | int ret = 0; | ||
648 | int i; | ||
945 | 649 | ||
946 | dev_dbg(dev, "stopping TI HSUSB Controller\n"); | 650 | if (!pdata) { |
651 | dev_err(dev, "Missing platform data\n"); | ||
652 | ret = -ENOMEM; | ||
653 | goto end_probe; | ||
654 | } | ||
947 | 655 | ||
948 | spin_lock_irqsave(&omap->lock, flags); | 656 | omap = kzalloc(sizeof(*omap), GFP_KERNEL); |
657 | if (!omap) { | ||
658 | dev_err(dev, "Memory allocation failed\n"); | ||
659 | ret = -ENOMEM; | ||
660 | goto end_probe; | ||
661 | } | ||
949 | 662 | ||
950 | if (omap->count == 0) | 663 | spin_lock_init(&omap->lock); |
951 | goto end_disble; | ||
952 | 664 | ||
953 | omap->count--; | 665 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) |
666 | omap->platdata.port_mode[i] = pdata->port_mode[i]; | ||
667 | |||
668 | omap->platdata.ehci_data = pdata->ehci_data; | ||
669 | omap->platdata.ohci_data = pdata->ohci_data; | ||
954 | 670 | ||
955 | if (omap->count != 0) | 671 | pm_runtime_enable(dev); |
956 | goto end_disble; | ||
957 | 672 | ||
958 | /* Reset OMAP modules for insmod/rmmod to work */ | ||
959 | usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, | ||
960 | is_omap_usbhs_rev2(omap) ? | ||
961 | OMAP4_UHH_SYSCONFIG_SOFTRESET : | ||
962 | OMAP_UHH_SYSCONFIG_SOFTRESET); | ||
963 | 673 | ||
964 | timeout = jiffies + msecs_to_jiffies(100); | 674 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) |
965 | while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) | 675 | if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) || |
966 | & (1 << 0))) { | 676 | is_ehci_hsic_mode(i)) { |
967 | cpu_relax(); | 677 | omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck"); |
678 | if (IS_ERR(omap->ehci_logic_fck)) { | ||
679 | ret = PTR_ERR(omap->ehci_logic_fck); | ||
680 | dev_warn(dev, "ehci_logic_fck failed:%d\n", | ||
681 | ret); | ||
682 | } | ||
683 | break; | ||
684 | } | ||
968 | 685 | ||
969 | if (time_after(jiffies, timeout)) | 686 | omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); |
970 | dev_dbg(dev, "operation timed out\n"); | 687 | if (IS_ERR(omap->utmi_p1_fck)) { |
688 | ret = PTR_ERR(omap->utmi_p1_fck); | ||
689 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); | ||
690 | goto err_end; | ||
971 | } | 691 | } |
972 | 692 | ||
973 | while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) | 693 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); |
974 | & (1 << 1))) { | 694 | if (IS_ERR(omap->xclk60mhsp1_ck)) { |
975 | cpu_relax(); | 695 | ret = PTR_ERR(omap->xclk60mhsp1_ck); |
696 | dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); | ||
697 | goto err_utmi_p1_fck; | ||
698 | } | ||
976 | 699 | ||
977 | if (time_after(jiffies, timeout)) | 700 | omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk"); |
978 | dev_dbg(dev, "operation timed out\n"); | 701 | if (IS_ERR(omap->utmi_p2_fck)) { |
702 | ret = PTR_ERR(omap->utmi_p2_fck); | ||
703 | dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); | ||
704 | goto err_xclk60mhsp1_ck; | ||
979 | } | 705 | } |
980 | 706 | ||
981 | while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) | 707 | omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); |
982 | & (1 << 2))) { | 708 | if (IS_ERR(omap->xclk60mhsp2_ck)) { |
983 | cpu_relax(); | 709 | ret = PTR_ERR(omap->xclk60mhsp2_ck); |
710 | dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); | ||
711 | goto err_utmi_p2_fck; | ||
712 | } | ||
984 | 713 | ||
985 | if (time_after(jiffies, timeout)) | 714 | omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk"); |
986 | dev_dbg(dev, "operation timed out\n"); | 715 | if (IS_ERR(omap->usbhost_p1_fck)) { |
716 | ret = PTR_ERR(omap->usbhost_p1_fck); | ||
717 | dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret); | ||
718 | goto err_xclk60mhsp2_ck; | ||
987 | } | 719 | } |
988 | 720 | ||
989 | usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1)); | 721 | omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); |
722 | if (IS_ERR(omap->usbtll_p1_fck)) { | ||
723 | ret = PTR_ERR(omap->usbtll_p1_fck); | ||
724 | dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); | ||
725 | goto err_usbhost_p1_fck; | ||
726 | } | ||
990 | 727 | ||
991 | while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) | 728 | omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); |
992 | & (1 << 0))) { | 729 | if (IS_ERR(omap->usbhost_p2_fck)) { |
993 | cpu_relax(); | 730 | ret = PTR_ERR(omap->usbhost_p2_fck); |
731 | dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); | ||
732 | goto err_usbtll_p1_fck; | ||
733 | } | ||
994 | 734 | ||
995 | if (time_after(jiffies, timeout)) | 735 | omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); |
996 | dev_dbg(dev, "operation timed out\n"); | 736 | if (IS_ERR(omap->usbtll_p2_fck)) { |
737 | ret = PTR_ERR(omap->usbtll_p2_fck); | ||
738 | dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); | ||
739 | goto err_usbhost_p2_fck; | ||
997 | } | 740 | } |
998 | 741 | ||
999 | if (is_omap_usbhs_rev2(omap)) { | 742 | omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); |
1000 | if (is_ehci_tll_mode(pdata->port_mode[0])) | 743 | if (IS_ERR(omap->init_60m_fclk)) { |
1001 | clk_disable(omap->usbtll_p1_fck); | 744 | ret = PTR_ERR(omap->init_60m_fclk); |
1002 | if (is_ehci_tll_mode(pdata->port_mode[1])) | 745 | dev_err(dev, "init_60m_fclk failed error:%d\n", ret); |
1003 | clk_disable(omap->usbtll_p2_fck); | 746 | goto err_usbtll_p2_fck; |
1004 | clk_disable(omap->utmi_p2_fck); | ||
1005 | clk_disable(omap->utmi_p1_fck); | ||
1006 | } | 747 | } |
1007 | 748 | ||
1008 | clk_disable(omap->usbtll_ick); | 749 | if (is_ehci_phy_mode(pdata->port_mode[0])) { |
1009 | clk_disable(omap->usbtll_fck); | 750 | /* for OMAP3 , the clk set paretn fails */ |
1010 | clk_disable(omap->usbhost_fs_fck); | 751 | ret = clk_set_parent(omap->utmi_p1_fck, |
1011 | clk_disable(omap->usbhost_hs_fck); | 752 | omap->xclk60mhsp1_ck); |
1012 | clk_disable(omap->usbhost_ick); | 753 | if (ret != 0) |
754 | dev_err(dev, "xclk60mhsp1_ck set parent" | ||
755 | "failed error:%d\n", ret); | ||
756 | } else if (is_ehci_tll_mode(pdata->port_mode[0])) { | ||
757 | ret = clk_set_parent(omap->utmi_p1_fck, | ||
758 | omap->init_60m_fclk); | ||
759 | if (ret != 0) | ||
760 | dev_err(dev, "init_60m_fclk set parent" | ||
761 | "failed error:%d\n", ret); | ||
762 | } | ||
1013 | 763 | ||
1014 | /* The gpio_free migh sleep; so unlock the spinlock */ | 764 | if (is_ehci_phy_mode(pdata->port_mode[1])) { |
1015 | spin_unlock_irqrestore(&omap->lock, flags); | 765 | ret = clk_set_parent(omap->utmi_p2_fck, |
766 | omap->xclk60mhsp2_ck); | ||
767 | if (ret != 0) | ||
768 | dev_err(dev, "xclk60mhsp2_ck set parent" | ||
769 | "failed error:%d\n", ret); | ||
770 | } else if (is_ehci_tll_mode(pdata->port_mode[1])) { | ||
771 | ret = clk_set_parent(omap->utmi_p2_fck, | ||
772 | omap->init_60m_fclk); | ||
773 | if (ret != 0) | ||
774 | dev_err(dev, "init_60m_fclk set parent" | ||
775 | "failed error:%d\n", ret); | ||
776 | } | ||
1016 | 777 | ||
1017 | if (pdata->ehci_data->phy_reset) { | 778 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); |
1018 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) | 779 | if (!res) { |
1019 | gpio_free(pdata->ehci_data->reset_gpio_port[0]); | 780 | dev_err(dev, "UHH EHCI get resource failed\n"); |
781 | ret = -ENODEV; | ||
782 | goto err_init_60m_fclk; | ||
783 | } | ||
1020 | 784 | ||
1021 | if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) | 785 | omap->uhh_base = ioremap(res->start, resource_size(res)); |
1022 | gpio_free(pdata->ehci_data->reset_gpio_port[1]); | 786 | if (!omap->uhh_base) { |
787 | dev_err(dev, "UHH ioremap failed\n"); | ||
788 | ret = -ENOMEM; | ||
789 | goto err_init_60m_fclk; | ||
1023 | } | 790 | } |
1024 | return; | ||
1025 | 791 | ||
1026 | end_disble: | 792 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll"); |
1027 | spin_unlock_irqrestore(&omap->lock, flags); | 793 | if (!res) { |
1028 | } | 794 | dev_err(dev, "UHH EHCI get resource failed\n"); |
795 | ret = -ENODEV; | ||
796 | goto err_tll; | ||
797 | } | ||
1029 | 798 | ||
1030 | int omap_usbhs_enable(struct device *dev) | 799 | omap->tll_base = ioremap(res->start, resource_size(res)); |
1031 | { | 800 | if (!omap->tll_base) { |
1032 | return usbhs_enable(dev->parent); | 801 | dev_err(dev, "TLL ioremap failed\n"); |
802 | ret = -ENOMEM; | ||
803 | goto err_tll; | ||
804 | } | ||
805 | |||
806 | platform_set_drvdata(pdev, omap); | ||
807 | |||
808 | ret = omap_usbhs_alloc_children(pdev); | ||
809 | if (ret) { | ||
810 | dev_err(dev, "omap_usbhs_alloc_children failed\n"); | ||
811 | goto err_alloc; | ||
812 | } | ||
813 | |||
814 | omap_usbhs_init(dev); | ||
815 | |||
816 | goto end_probe; | ||
817 | |||
818 | err_alloc: | ||
819 | iounmap(omap->tll_base); | ||
820 | |||
821 | err_tll: | ||
822 | iounmap(omap->uhh_base); | ||
823 | |||
824 | err_init_60m_fclk: | ||
825 | clk_put(omap->init_60m_fclk); | ||
826 | |||
827 | err_usbtll_p2_fck: | ||
828 | clk_put(omap->usbtll_p2_fck); | ||
829 | |||
830 | err_usbhost_p2_fck: | ||
831 | clk_put(omap->usbhost_p2_fck); | ||
832 | |||
833 | err_usbtll_p1_fck: | ||
834 | clk_put(omap->usbtll_p1_fck); | ||
835 | |||
836 | err_usbhost_p1_fck: | ||
837 | clk_put(omap->usbhost_p1_fck); | ||
838 | |||
839 | err_xclk60mhsp2_ck: | ||
840 | clk_put(omap->xclk60mhsp2_ck); | ||
841 | |||
842 | err_utmi_p2_fck: | ||
843 | clk_put(omap->utmi_p2_fck); | ||
844 | |||
845 | err_xclk60mhsp1_ck: | ||
846 | clk_put(omap->xclk60mhsp1_ck); | ||
847 | |||
848 | err_utmi_p1_fck: | ||
849 | clk_put(omap->utmi_p1_fck); | ||
850 | |||
851 | err_end: | ||
852 | clk_put(omap->ehci_logic_fck); | ||
853 | pm_runtime_disable(dev); | ||
854 | kfree(omap); | ||
855 | |||
856 | end_probe: | ||
857 | return ret; | ||
1033 | } | 858 | } |
1034 | EXPORT_SYMBOL_GPL(omap_usbhs_enable); | ||
1035 | 859 | ||
1036 | void omap_usbhs_disable(struct device *dev) | 860 | /** |
861 | * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs | ||
862 | * @pdev: USB Host Controller being removed | ||
863 | * | ||
864 | * Reverses the effect of usbhs_omap_probe(). | ||
865 | */ | ||
866 | static int __devexit usbhs_omap_remove(struct platform_device *pdev) | ||
1037 | { | 867 | { |
1038 | usbhs_disable(dev->parent); | 868 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); |
869 | |||
870 | omap_usbhs_deinit(&pdev->dev); | ||
871 | iounmap(omap->tll_base); | ||
872 | iounmap(omap->uhh_base); | ||
873 | clk_put(omap->init_60m_fclk); | ||
874 | clk_put(omap->usbtll_p2_fck); | ||
875 | clk_put(omap->usbhost_p2_fck); | ||
876 | clk_put(omap->usbtll_p1_fck); | ||
877 | clk_put(omap->usbhost_p1_fck); | ||
878 | clk_put(omap->xclk60mhsp2_ck); | ||
879 | clk_put(omap->utmi_p2_fck); | ||
880 | clk_put(omap->xclk60mhsp1_ck); | ||
881 | clk_put(omap->utmi_p1_fck); | ||
882 | clk_put(omap->ehci_logic_fck); | ||
883 | pm_runtime_disable(&pdev->dev); | ||
884 | kfree(omap); | ||
885 | |||
886 | return 0; | ||
1039 | } | 887 | } |
1040 | EXPORT_SYMBOL_GPL(omap_usbhs_disable); | 888 | |
889 | static const struct dev_pm_ops usbhsomap_dev_pm_ops = { | ||
890 | .runtime_suspend = usbhs_runtime_suspend, | ||
891 | .runtime_resume = usbhs_runtime_resume, | ||
892 | }; | ||
1041 | 893 | ||
1042 | static struct platform_driver usbhs_omap_driver = { | 894 | static struct platform_driver usbhs_omap_driver = { |
1043 | .driver = { | 895 | .driver = { |
1044 | .name = (char *)usbhs_driver_name, | 896 | .name = (char *)usbhs_driver_name, |
1045 | .owner = THIS_MODULE, | 897 | .owner = THIS_MODULE, |
898 | .pm = &usbhsomap_dev_pm_ops, | ||
1046 | }, | 899 | }, |
1047 | .remove = __exit_p(usbhs_omap_remove), | 900 | .remove = __exit_p(usbhs_omap_remove), |
1048 | }; | 901 | }; |