diff options
-rw-r--r-- | drivers/phy/phy-ti-pipe3.c | 58 |
1 files changed, 42 insertions, 16 deletions
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 8c854685a1a7..95c88f929f27 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c | |||
@@ -85,6 +85,8 @@ struct ti_pipe3 { | |||
85 | struct pipe3_dpll_map *dpll_map; | 85 | struct pipe3_dpll_map *dpll_map; |
86 | bool enabled; | 86 | bool enabled; |
87 | spinlock_t lock; /* serialize clock enable/disable */ | 87 | spinlock_t lock; /* serialize clock enable/disable */ |
88 | /* the below flag is needed specifically for SATA */ | ||
89 | bool refclk_enabled; | ||
88 | }; | 90 | }; |
89 | 91 | ||
90 | static struct pipe3_dpll_map dpll_map_usb[] = { | 92 | static struct pipe3_dpll_map dpll_map_usb[] = { |
@@ -337,21 +339,24 @@ static int ti_pipe3_probe(struct platform_device *pdev) | |||
337 | } | 339 | } |
338 | } | 340 | } |
339 | 341 | ||
342 | phy->refclk = devm_clk_get(phy->dev, "refclk"); | ||
343 | if (IS_ERR(phy->refclk)) { | ||
344 | dev_err(&pdev->dev, "unable to get refclk\n"); | ||
345 | /* older DTBs have missing refclk in SATA PHY | ||
346 | * so don't bail out in case of SATA PHY. | ||
347 | */ | ||
348 | if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) | ||
349 | return PTR_ERR(phy->refclk); | ||
350 | } | ||
351 | |||
340 | if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { | 352 | if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { |
341 | phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); | 353 | phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); |
342 | if (IS_ERR(phy->wkupclk)) { | 354 | if (IS_ERR(phy->wkupclk)) { |
343 | dev_err(&pdev->dev, "unable to get wkupclk\n"); | 355 | dev_err(&pdev->dev, "unable to get wkupclk\n"); |
344 | return PTR_ERR(phy->wkupclk); | 356 | return PTR_ERR(phy->wkupclk); |
345 | } | 357 | } |
346 | |||
347 | phy->refclk = devm_clk_get(phy->dev, "refclk"); | ||
348 | if (IS_ERR(phy->refclk)) { | ||
349 | dev_err(&pdev->dev, "unable to get refclk\n"); | ||
350 | return PTR_ERR(phy->refclk); | ||
351 | } | ||
352 | } else { | 358 | } else { |
353 | phy->wkupclk = ERR_PTR(-ENODEV); | 359 | phy->wkupclk = ERR_PTR(-ENODEV); |
354 | phy->refclk = ERR_PTR(-ENODEV); | ||
355 | } | 360 | } |
356 | 361 | ||
357 | if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { | 362 | if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { |
@@ -430,6 +435,29 @@ static int ti_pipe3_remove(struct platform_device *pdev) | |||
430 | } | 435 | } |
431 | 436 | ||
432 | #ifdef CONFIG_PM | 437 | #ifdef CONFIG_PM |
438 | static int ti_pipe3_enable_refclk(struct ti_pipe3 *phy) | ||
439 | { | ||
440 | if (!IS_ERR(phy->refclk) && !phy->refclk_enabled) { | ||
441 | int ret; | ||
442 | |||
443 | ret = clk_prepare_enable(phy->refclk); | ||
444 | if (ret) { | ||
445 | dev_err(phy->dev, "Failed to enable refclk %d\n", ret); | ||
446 | return ret; | ||
447 | } | ||
448 | phy->refclk_enabled = true; | ||
449 | } | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static void ti_pipe3_disable_refclk(struct ti_pipe3 *phy) | ||
455 | { | ||
456 | if (!IS_ERR(phy->refclk)) | ||
457 | clk_disable_unprepare(phy->refclk); | ||
458 | |||
459 | phy->refclk_enabled = false; | ||
460 | } | ||
433 | 461 | ||
434 | static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) | 462 | static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) |
435 | { | 463 | { |
@@ -440,13 +468,9 @@ static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) | |||
440 | if (phy->enabled) | 468 | if (phy->enabled) |
441 | goto err1; | 469 | goto err1; |
442 | 470 | ||
443 | if (!IS_ERR(phy->refclk)) { | 471 | ret = ti_pipe3_enable_refclk(phy); |
444 | ret = clk_prepare_enable(phy->refclk); | 472 | if (ret) |
445 | if (ret) { | 473 | goto err1; |
446 | dev_err(phy->dev, "Failed to enable refclk %d\n", ret); | ||
447 | goto err1; | ||
448 | } | ||
449 | } | ||
450 | 474 | ||
451 | if (!IS_ERR(phy->wkupclk)) { | 475 | if (!IS_ERR(phy->wkupclk)) { |
452 | ret = clk_prepare_enable(phy->wkupclk); | 476 | ret = clk_prepare_enable(phy->wkupclk); |
@@ -476,6 +500,7 @@ err2: | |||
476 | if (!IS_ERR(phy->refclk)) | 500 | if (!IS_ERR(phy->refclk)) |
477 | clk_disable_unprepare(phy->refclk); | 501 | clk_disable_unprepare(phy->refclk); |
478 | 502 | ||
503 | ti_pipe3_disable_refclk(phy); | ||
479 | err1: | 504 | err1: |
480 | spin_unlock_irqrestore(&phy->lock, flags); | 505 | spin_unlock_irqrestore(&phy->lock, flags); |
481 | return ret; | 506 | return ret; |
@@ -493,8 +518,9 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) | |||
493 | 518 | ||
494 | if (!IS_ERR(phy->wkupclk)) | 519 | if (!IS_ERR(phy->wkupclk)) |
495 | clk_disable_unprepare(phy->wkupclk); | 520 | clk_disable_unprepare(phy->wkupclk); |
496 | if (!IS_ERR(phy->refclk)) | 521 | /* Don't disable refclk for SATA PHY due to Errata i783 */ |
497 | clk_disable_unprepare(phy->refclk); | 522 | if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) |
523 | ti_pipe3_disable_refclk(phy); | ||
498 | if (!IS_ERR(phy->div_clk)) | 524 | if (!IS_ERR(phy->div_clk)) |
499 | clk_disable_unprepare(phy->div_clk); | 525 | clk_disable_unprepare(phy->div_clk); |
500 | phy->enabled = false; | 526 | phy->enabled = false; |