diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/mfd/omap-usb-host.c | 186 |
1 files changed, 106 insertions, 80 deletions
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 779588be8ab2..9fa0215e3df4 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c | |||
| @@ -92,13 +92,12 @@ | |||
| 92 | 92 | ||
| 93 | struct usbhs_hcd_omap { | 93 | struct usbhs_hcd_omap { |
| 94 | int nports; | 94 | int nports; |
| 95 | struct clk **utmi_clk; | ||
| 95 | 96 | ||
| 96 | struct clk *xclk60mhsp1_ck; | 97 | struct clk *xclk60mhsp1_ck; |
| 97 | struct clk *xclk60mhsp2_ck; | 98 | struct clk *xclk60mhsp2_ck; |
| 98 | struct clk *utmi_p1_fck; | 99 | struct clk *utmi_p1_gfclk; |
| 99 | struct clk *usbhost_p1_fck; | 100 | struct clk *utmi_p2_gfclk; |
| 100 | struct clk *utmi_p2_fck; | ||
| 101 | struct clk *usbhost_p2_fck; | ||
| 102 | struct clk *init_60m_fclk; | 101 | struct clk *init_60m_fclk; |
| 103 | struct clk *ehci_logic_fck; | 102 | struct clk *ehci_logic_fck; |
| 104 | 103 | ||
| @@ -276,22 +275,25 @@ static int usbhs_runtime_resume(struct device *dev) | |||
| 276 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 275 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); |
| 277 | struct usbhs_omap_platform_data *pdata = omap->pdata; | 276 | struct usbhs_omap_platform_data *pdata = omap->pdata; |
| 278 | unsigned long flags; | 277 | unsigned long flags; |
| 278 | int i, r; | ||
| 279 | 279 | ||
| 280 | dev_dbg(dev, "usbhs_runtime_resume\n"); | 280 | dev_dbg(dev, "usbhs_runtime_resume\n"); |
| 281 | 281 | ||
| 282 | omap_tll_enable(); | 282 | omap_tll_enable(); |
| 283 | spin_lock_irqsave(&omap->lock, flags); | 283 | spin_lock_irqsave(&omap->lock, flags); |
| 284 | 284 | ||
| 285 | if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) | 285 | if (!IS_ERR(omap->ehci_logic_fck)) |
| 286 | clk_enable(omap->ehci_logic_fck); | 286 | clk_enable(omap->ehci_logic_fck); |
| 287 | 287 | ||
| 288 | if (is_ehci_tll_mode(pdata->port_mode[0])) | 288 | for (i = 0; i < omap->nports; i++) { |
| 289 | clk_enable(omap->usbhost_p1_fck); | 289 | if (!is_ehci_tll_mode(pdata->port_mode[i]) || |
| 290 | if (is_ehci_tll_mode(pdata->port_mode[1])) | 290 | IS_ERR(omap->utmi_clk[i])) |
| 291 | clk_enable(omap->usbhost_p2_fck); | 291 | continue; |
| 292 | 292 | ||
| 293 | clk_enable(omap->utmi_p1_fck); | 293 | r = clk_enable(omap->utmi_clk[i]); |
| 294 | clk_enable(omap->utmi_p2_fck); | 294 | if (r) |
| 295 | dev_err(dev, "Can't enable port %d clk : %d\n", i, r); | ||
| 296 | } | ||
| 295 | 297 | ||
| 296 | spin_unlock_irqrestore(&omap->lock, flags); | 298 | spin_unlock_irqrestore(&omap->lock, flags); |
| 297 | 299 | ||
| @@ -303,20 +305,19 @@ static int usbhs_runtime_suspend(struct device *dev) | |||
| 303 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 305 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); |
| 304 | struct usbhs_omap_platform_data *pdata = omap->pdata; | 306 | struct usbhs_omap_platform_data *pdata = omap->pdata; |
| 305 | unsigned long flags; | 307 | unsigned long flags; |
| 308 | int i; | ||
| 306 | 309 | ||
| 307 | dev_dbg(dev, "usbhs_runtime_suspend\n"); | 310 | dev_dbg(dev, "usbhs_runtime_suspend\n"); |
| 308 | 311 | ||
| 309 | spin_lock_irqsave(&omap->lock, flags); | 312 | spin_lock_irqsave(&omap->lock, flags); |
| 310 | 313 | ||
| 311 | if (is_ehci_tll_mode(pdata->port_mode[0])) | 314 | for (i = 0; i < omap->nports; i++) { |
| 312 | clk_disable(omap->usbhost_p1_fck); | 315 | if (is_ehci_tll_mode(pdata->port_mode[i]) && |
| 313 | if (is_ehci_tll_mode(pdata->port_mode[1])) | 316 | !IS_ERR(omap->utmi_clk[i])) |
| 314 | clk_disable(omap->usbhost_p2_fck); | 317 | clk_disable(omap->utmi_clk[i]); |
| 315 | 318 | } | |
| 316 | clk_disable(omap->utmi_p2_fck); | ||
| 317 | clk_disable(omap->utmi_p1_fck); | ||
| 318 | 319 | ||
| 319 | if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) | 320 | if (!IS_ERR(omap->ehci_logic_fck)) |
| 320 | clk_disable(omap->ehci_logic_fck); | 321 | clk_disable(omap->ehci_logic_fck); |
| 321 | 322 | ||
| 322 | spin_unlock_irqrestore(&omap->lock, flags); | 323 | spin_unlock_irqrestore(&omap->lock, flags); |
| @@ -458,6 +459,7 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
| 458 | struct resource *res; | 459 | struct resource *res; |
| 459 | int ret = 0; | 460 | int ret = 0; |
| 460 | int i; | 461 | int i; |
| 462 | bool need_logic_fck; | ||
| 461 | 463 | ||
| 462 | if (!pdata) { | 464 | if (!pdata) { |
| 463 | dev_err(dev, "Missing platform data\n"); | 465 | dev_err(dev, "Missing platform data\n"); |
| @@ -516,76 +518,91 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
| 516 | } | 518 | } |
| 517 | } | 519 | } |
| 518 | 520 | ||
| 519 | for (i = 0; i < omap->nports; i++) | 521 | i = sizeof(struct clk *) * omap->nports; |
| 522 | omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL); | ||
| 523 | if (!omap->utmi_clk) { | ||
| 524 | dev_err(dev, "Memory allocation failed\n"); | ||
| 525 | ret = -ENOMEM; | ||
| 526 | goto err_mem; | ||
| 527 | } | ||
| 528 | |||
| 529 | need_logic_fck = false; | ||
| 530 | for (i = 0; i < omap->nports; i++) { | ||
| 520 | if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) || | 531 | if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) || |
| 521 | is_ehci_hsic_mode(i)) { | 532 | is_ehci_hsic_mode(i)) |
| 522 | omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck"); | 533 | need_logic_fck |= true; |
| 523 | if (IS_ERR(omap->ehci_logic_fck)) { | 534 | } |
| 524 | ret = PTR_ERR(omap->ehci_logic_fck); | 535 | |
| 525 | dev_warn(dev, "ehci_logic_fck failed:%d\n", | 536 | omap->ehci_logic_fck = ERR_PTR(-EINVAL); |
| 526 | ret); | 537 | if (need_logic_fck) { |
| 527 | } | 538 | omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck"); |
| 528 | break; | 539 | if (IS_ERR(omap->ehci_logic_fck)) { |
| 540 | ret = PTR_ERR(omap->ehci_logic_fck); | ||
| 541 | dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret); | ||
| 529 | } | 542 | } |
| 543 | } | ||
| 530 | 544 | ||
| 531 | omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); | 545 | omap->utmi_p1_gfclk = clk_get(dev, "utmi_p1_gfclk"); |
| 532 | if (IS_ERR(omap->utmi_p1_fck)) { | 546 | if (IS_ERR(omap->utmi_p1_gfclk)) { |
| 533 | ret = PTR_ERR(omap->utmi_p1_fck); | 547 | ret = PTR_ERR(omap->utmi_p1_gfclk); |
| 534 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); | 548 | dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); |
| 535 | goto err_end; | 549 | goto err_p1_gfclk; |
| 550 | } | ||
| 551 | |||
| 552 | omap->utmi_p2_gfclk = clk_get(dev, "utmi_p2_gfclk"); | ||
| 553 | if (IS_ERR(omap->utmi_p2_gfclk)) { | ||
| 554 | ret = PTR_ERR(omap->utmi_p2_gfclk); | ||
| 555 | dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); | ||
| 556 | goto err_p2_gfclk; | ||
| 536 | } | 557 | } |
| 537 | 558 | ||
| 538 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); | 559 | omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); |
| 539 | if (IS_ERR(omap->xclk60mhsp1_ck)) { | 560 | if (IS_ERR(omap->xclk60mhsp1_ck)) { |
| 540 | ret = PTR_ERR(omap->xclk60mhsp1_ck); | 561 | ret = PTR_ERR(omap->xclk60mhsp1_ck); |
| 541 | dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); | 562 | dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret); |
| 542 | goto err_utmi_p1_fck; | 563 | goto err_xclk60mhsp1; |
| 543 | } | ||
| 544 | |||
| 545 | omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk"); | ||
| 546 | if (IS_ERR(omap->utmi_p2_fck)) { | ||
| 547 | ret = PTR_ERR(omap->utmi_p2_fck); | ||
| 548 | dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); | ||
| 549 | goto err_xclk60mhsp1_ck; | ||
| 550 | } | 564 | } |
| 551 | 565 | ||
| 552 | omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); | 566 | omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck"); |
| 553 | if (IS_ERR(omap->xclk60mhsp2_ck)) { | 567 | if (IS_ERR(omap->xclk60mhsp2_ck)) { |
| 554 | ret = PTR_ERR(omap->xclk60mhsp2_ck); | 568 | ret = PTR_ERR(omap->xclk60mhsp2_ck); |
| 555 | dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); | 569 | dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret); |
| 556 | goto err_utmi_p2_fck; | 570 | goto err_xclk60mhsp2; |
| 557 | } | ||
| 558 | |||
| 559 | omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk"); | ||
| 560 | if (IS_ERR(omap->usbhost_p1_fck)) { | ||
| 561 | ret = PTR_ERR(omap->usbhost_p1_fck); | ||
| 562 | dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret); | ||
| 563 | goto err_xclk60mhsp2_ck; | ||
| 564 | } | ||
| 565 | |||
| 566 | omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); | ||
| 567 | if (IS_ERR(omap->usbhost_p2_fck)) { | ||
| 568 | ret = PTR_ERR(omap->usbhost_p2_fck); | ||
| 569 | dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); | ||
| 570 | goto err_usbhost_p1_fck; | ||
| 571 | } | 571 | } |
| 572 | 572 | ||
| 573 | omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); | 573 | omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); |
| 574 | if (IS_ERR(omap->init_60m_fclk)) { | 574 | if (IS_ERR(omap->init_60m_fclk)) { |
| 575 | ret = PTR_ERR(omap->init_60m_fclk); | 575 | ret = PTR_ERR(omap->init_60m_fclk); |
| 576 | dev_err(dev, "init_60m_fclk failed error:%d\n", ret); | 576 | dev_err(dev, "init_60m_fclk failed error:%d\n", ret); |
| 577 | goto err_usbhost_p2_fck; | 577 | goto err_init60m; |
| 578 | } | ||
| 579 | |||
| 580 | for (i = 0; i < omap->nports; i++) { | ||
| 581 | char clkname[] = "usb_host_hs_utmi_px_clk"; | ||
| 582 | |||
| 583 | /* clock names are indexed from 1*/ | ||
| 584 | snprintf(clkname, sizeof(clkname), | ||
| 585 | "usb_host_hs_utmi_p%d_clk", i + 1); | ||
| 586 | |||
| 587 | /* If a clock is not found we won't bail out as not all | ||
| 588 | * platforms have all clocks and we can function without | ||
| 589 | * them | ||
| 590 | */ | ||
| 591 | omap->utmi_clk[i] = clk_get(dev, clkname); | ||
| 592 | if (IS_ERR(omap->utmi_clk[i])) | ||
| 593 | dev_dbg(dev, "Failed to get clock : %s : %ld\n", | ||
| 594 | clkname, PTR_ERR(omap->utmi_clk[i])); | ||
| 578 | } | 595 | } |
| 579 | 596 | ||
| 580 | if (is_ehci_phy_mode(pdata->port_mode[0])) { | 597 | if (is_ehci_phy_mode(pdata->port_mode[0])) { |
| 581 | /* for OMAP3 , the clk set paretn fails */ | 598 | /* for OMAP3 , the clk set paretn fails */ |
| 582 | ret = clk_set_parent(omap->utmi_p1_fck, | 599 | ret = clk_set_parent(omap->utmi_p1_gfclk, |
| 583 | omap->xclk60mhsp1_ck); | 600 | omap->xclk60mhsp1_ck); |
| 584 | if (ret != 0) | 601 | if (ret != 0) |
| 585 | dev_err(dev, "xclk60mhsp1_ck set parent" | 602 | dev_err(dev, "xclk60mhsp1_ck set parent" |
| 586 | "failed error:%d\n", ret); | 603 | "failed error:%d\n", ret); |
| 587 | } else if (is_ehci_tll_mode(pdata->port_mode[0])) { | 604 | } else if (is_ehci_tll_mode(pdata->port_mode[0])) { |
| 588 | ret = clk_set_parent(omap->utmi_p1_fck, | 605 | ret = clk_set_parent(omap->utmi_p1_gfclk, |
| 589 | omap->init_60m_fclk); | 606 | omap->init_60m_fclk); |
| 590 | if (ret != 0) | 607 | if (ret != 0) |
| 591 | dev_err(dev, "init_60m_fclk set parent" | 608 | dev_err(dev, "init_60m_fclk set parent" |
| @@ -593,13 +610,13 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
| 593 | } | 610 | } |
| 594 | 611 | ||
| 595 | if (is_ehci_phy_mode(pdata->port_mode[1])) { | 612 | if (is_ehci_phy_mode(pdata->port_mode[1])) { |
| 596 | ret = clk_set_parent(omap->utmi_p2_fck, | 613 | ret = clk_set_parent(omap->utmi_p2_gfclk, |
| 597 | omap->xclk60mhsp2_ck); | 614 | omap->xclk60mhsp2_ck); |
| 598 | if (ret != 0) | 615 | if (ret != 0) |
| 599 | dev_err(dev, "xclk60mhsp2_ck set parent" | 616 | dev_err(dev, "xclk60mhsp2_ck set parent" |
| 600 | "failed error:%d\n", ret); | 617 | "failed error:%d\n", ret); |
| 601 | } else if (is_ehci_tll_mode(pdata->port_mode[1])) { | 618 | } else if (is_ehci_tll_mode(pdata->port_mode[1])) { |
| 602 | ret = clk_set_parent(omap->utmi_p2_fck, | 619 | ret = clk_set_parent(omap->utmi_p2_gfclk, |
| 603 | omap->init_60m_fclk); | 620 | omap->init_60m_fclk); |
| 604 | if (ret != 0) | 621 | if (ret != 0) |
| 605 | dev_err(dev, "init_60m_fclk set parent" | 622 | dev_err(dev, "init_60m_fclk set parent" |
| @@ -617,28 +634,30 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
| 617 | 634 | ||
| 618 | err_alloc: | 635 | err_alloc: |
| 619 | omap_usbhs_deinit(&pdev->dev); | 636 | omap_usbhs_deinit(&pdev->dev); |
| 620 | clk_put(omap->init_60m_fclk); | ||
| 621 | 637 | ||
| 622 | err_usbhost_p2_fck: | 638 | for (i = 0; i < omap->nports; i++) |
| 623 | clk_put(omap->usbhost_p2_fck); | 639 | if (!IS_ERR(omap->utmi_clk[i])) |
| 640 | clk_put(omap->utmi_clk[i]); | ||
| 624 | 641 | ||
| 625 | err_usbhost_p1_fck: | 642 | clk_put(omap->init_60m_fclk); |
| 626 | clk_put(omap->usbhost_p1_fck); | ||
| 627 | 643 | ||
| 628 | err_xclk60mhsp2_ck: | 644 | err_init60m: |
| 629 | clk_put(omap->xclk60mhsp2_ck); | 645 | clk_put(omap->xclk60mhsp2_ck); |
| 630 | 646 | ||
| 631 | err_utmi_p2_fck: | 647 | err_xclk60mhsp2: |
| 632 | clk_put(omap->utmi_p2_fck); | ||
| 633 | |||
| 634 | err_xclk60mhsp1_ck: | ||
| 635 | clk_put(omap->xclk60mhsp1_ck); | 648 | clk_put(omap->xclk60mhsp1_ck); |
| 636 | 649 | ||
| 637 | err_utmi_p1_fck: | 650 | err_xclk60mhsp1: |
| 638 | clk_put(omap->utmi_p1_fck); | 651 | clk_put(omap->utmi_p2_gfclk); |
| 639 | 652 | ||
| 640 | err_end: | 653 | err_p2_gfclk: |
| 641 | clk_put(omap->ehci_logic_fck); | 654 | clk_put(omap->utmi_p1_gfclk); |
| 655 | |||
| 656 | err_p1_gfclk: | ||
| 657 | if (!IS_ERR(omap->ehci_logic_fck)) | ||
| 658 | clk_put(omap->ehci_logic_fck); | ||
| 659 | |||
| 660 | err_mem: | ||
| 642 | pm_runtime_disable(dev); | 661 | pm_runtime_disable(dev); |
| 643 | 662 | ||
| 644 | return ret; | 663 | return ret; |
| @@ -653,16 +672,23 @@ err_end: | |||
| 653 | static int usbhs_omap_remove(struct platform_device *pdev) | 672 | static int usbhs_omap_remove(struct platform_device *pdev) |
| 654 | { | 673 | { |
| 655 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); | 674 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); |
| 675 | int i; | ||
| 656 | 676 | ||
| 657 | omap_usbhs_deinit(&pdev->dev); | 677 | omap_usbhs_deinit(&pdev->dev); |
| 678 | |||
| 679 | for (i = 0; i < omap->nports; i++) | ||
| 680 | if (!IS_ERR(omap->utmi_clk[i])) | ||
| 681 | clk_put(omap->utmi_clk[i]); | ||
| 682 | |||
| 658 | clk_put(omap->init_60m_fclk); | 683 | clk_put(omap->init_60m_fclk); |
| 659 | clk_put(omap->usbhost_p2_fck); | 684 | clk_put(omap->utmi_p1_gfclk); |
| 660 | clk_put(omap->usbhost_p1_fck); | 685 | clk_put(omap->utmi_p2_gfclk); |
| 661 | clk_put(omap->xclk60mhsp2_ck); | 686 | clk_put(omap->xclk60mhsp2_ck); |
| 662 | clk_put(omap->utmi_p2_fck); | ||
| 663 | clk_put(omap->xclk60mhsp1_ck); | 687 | clk_put(omap->xclk60mhsp1_ck); |
| 664 | clk_put(omap->utmi_p1_fck); | 688 | |
| 665 | clk_put(omap->ehci_logic_fck); | 689 | if (!IS_ERR(omap->ehci_logic_fck)) |
| 690 | clk_put(omap->ehci_logic_fck); | ||
| 691 | |||
| 666 | pm_runtime_disable(&pdev->dev); | 692 | pm_runtime_disable(&pdev->dev); |
| 667 | 693 | ||
| 668 | return 0; | 694 | return 0; |
