aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy
diff options
context:
space:
mode:
authorRoger Quadros <rogerq@ti.com>2015-01-13 07:23:20 -0500
committerKishon Vijay Abraham I <kishon@ti.com>2015-01-21 04:53:06 -0500
commit7f33912d2978796662473f1f5e1fcfc387717e15 (patch)
tree391f756c4429e462aeb2f82704a3d2dedeae2df0 /drivers/phy
parent6e7384320ffa28a3732513f51fc56119003edbd3 (diff)
phy: ti-pipe3: Fix SATA across suspend/resume
Failed test case: Boot without SATA drive connected. Suspend/resume the board and then connect SATA drive. It fails to enumerate. Due to Errata i783 "SATA Lockup After SATA DPLL Unlock/Relock" we can't allow SATA DPLL to be in the unlocked state. The SATA refclk (sata_ref_clk) is the source of the SATA_DPLL. This clock is being controlled only by the AHCI SATA driver and is shut off during system suspend (if the SATA drive was not already attached) causing the SATA DPLL to be unlocked and so causing errata i783. To prevent sata_ref_clk from being disabled, we add the control of this clock to the SATA PHY driver and prevent it from being disabled. This also fixes the issue of SATA not working on OMAP5/DRA7 when AHCI platform driver is built as a module. NOTE: Device tree changes also required for OMAP5 & DRA7. Signed-off-by: Roger Quadros <rogerq@ti.com> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/phy-ti-pipe3.c58
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
90static struct pipe3_dpll_map dpll_map_usb[] = { 92static 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
438static 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
454static 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
434static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) 462static 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);
479err1: 504err1:
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;