diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-07-22 17:22:24 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-07-22 17:22:24 -0400 |
| commit | 7021deae9735871c67ac0cc1c6ab0bdf634b665e (patch) | |
| tree | a17f76513121411d6c219907f79b0e307c6c6a8a | |
| parent | aca3a0489ac019b58cf32794d5362bb284cb9b94 (diff) | |
| parent | dcb54fcb3483862e993abdae99cec22fb3ae4099 (diff) | |
Merge tag 'phy-for-4.2-rc' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-linus
Kishon writes:
phy: for 4.2-rc
*) Fix PIPE3 PM so that all its users (PCIe, SATA, USB) can
idle and resume
*) Fix a compiler error in pxa
*) Fix pll divider values in berlin-usb phy driver
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
| -rw-r--r-- | drivers/phy/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/phy/phy-berlin-usb.c | 4 | ||||
| -rw-r--r-- | drivers/phy/phy-ti-pipe3.c | 172 |
3 files changed, 45 insertions, 133 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index c0e6ede3e27d..6b8dd162f644 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig | |||
| @@ -56,6 +56,7 @@ config PHY_EXYNOS_MIPI_VIDEO | |||
| 56 | 56 | ||
| 57 | config PHY_PXA_28NM_HSIC | 57 | config PHY_PXA_28NM_HSIC |
| 58 | tristate "Marvell USB HSIC 28nm PHY Driver" | 58 | tristate "Marvell USB HSIC 28nm PHY Driver" |
| 59 | depends on HAS_IOMEM | ||
| 59 | select GENERIC_PHY | 60 | select GENERIC_PHY |
| 60 | help | 61 | help |
| 61 | Enable this to support Marvell USB HSIC PHY driver for Marvell | 62 | Enable this to support Marvell USB HSIC PHY driver for Marvell |
| @@ -66,6 +67,7 @@ config PHY_PXA_28NM_HSIC | |||
| 66 | 67 | ||
| 67 | config PHY_PXA_28NM_USB2 | 68 | config PHY_PXA_28NM_USB2 |
| 68 | tristate "Marvell USB 2.0 28nm PHY Driver" | 69 | tristate "Marvell USB 2.0 28nm PHY Driver" |
| 70 | depends on HAS_IOMEM | ||
| 69 | select GENERIC_PHY | 71 | select GENERIC_PHY |
| 70 | help | 72 | help |
| 71 | Enable this to support Marvell USB 2.0 PHY driver for Marvell | 73 | Enable this to support Marvell USB 2.0 PHY driver for Marvell |
diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index c6fc95b53083..335e06d66ed9 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c | |||
| @@ -105,9 +105,9 @@ | |||
| 105 | 105 | ||
| 106 | static const u32 phy_berlin_pll_dividers[] = { | 106 | static const u32 phy_berlin_pll_dividers[] = { |
| 107 | /* Berlin 2 */ | 107 | /* Berlin 2 */ |
| 108 | CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54), | ||
| 109 | /* Berlin 2CD */ | ||
| 110 | CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55), | 108 | CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55), |
| 109 | /* Berlin 2CD/Q */ | ||
| 110 | CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54), | ||
| 111 | }; | 111 | }; |
| 112 | 112 | ||
| 113 | struct phy_berlin_usb_priv { | 113 | struct phy_berlin_usb_priv { |
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 53f295c1bab1..3510b81db3fa 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
| 29 | #include <linux/phy/omap_control_phy.h> | 29 | #include <linux/phy/omap_control_phy.h> |
| 30 | #include <linux/of_platform.h> | 30 | #include <linux/of_platform.h> |
| 31 | #include <linux/spinlock.h> | ||
| 32 | 31 | ||
| 33 | #define PLL_STATUS 0x00000004 | 32 | #define PLL_STATUS 0x00000004 |
| 34 | #define PLL_GO 0x00000008 | 33 | #define PLL_GO 0x00000008 |
| @@ -83,10 +82,6 @@ struct ti_pipe3 { | |||
| 83 | struct clk *refclk; | 82 | struct clk *refclk; |
| 84 | struct clk *div_clk; | 83 | struct clk *div_clk; |
| 85 | struct pipe3_dpll_map *dpll_map; | 84 | struct pipe3_dpll_map *dpll_map; |
| 86 | bool enabled; | ||
| 87 | spinlock_t lock; /* serialize clock enable/disable */ | ||
| 88 | /* the below flag is needed specifically for SATA */ | ||
| 89 | bool refclk_enabled; | ||
| 90 | }; | 85 | }; |
| 91 | 86 | ||
| 92 | static struct pipe3_dpll_map dpll_map_usb[] = { | 87 | static struct pipe3_dpll_map dpll_map_usb[] = { |
| @@ -137,6 +132,9 @@ static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(struct ti_pipe3 *phy) | |||
| 137 | return NULL; | 132 | return NULL; |
| 138 | } | 133 | } |
| 139 | 134 | ||
| 135 | static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy); | ||
| 136 | static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy); | ||
| 137 | |||
| 140 | static int ti_pipe3_power_off(struct phy *x) | 138 | static int ti_pipe3_power_off(struct phy *x) |
| 141 | { | 139 | { |
| 142 | struct ti_pipe3 *phy = phy_get_drvdata(x); | 140 | struct ti_pipe3 *phy = phy_get_drvdata(x); |
| @@ -217,6 +215,7 @@ static int ti_pipe3_init(struct phy *x) | |||
| 217 | u32 val; | 215 | u32 val; |
| 218 | int ret = 0; | 216 | int ret = 0; |
| 219 | 217 | ||
| 218 | ti_pipe3_enable_clocks(phy); | ||
| 220 | /* | 219 | /* |
| 221 | * Set pcie_pcs register to 0x96 for proper functioning of phy | 220 | * Set pcie_pcs register to 0x96 for proper functioning of phy |
| 222 | * as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table | 221 | * as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table |
| @@ -250,33 +249,35 @@ static int ti_pipe3_exit(struct phy *x) | |||
| 250 | u32 val; | 249 | u32 val; |
| 251 | unsigned long timeout; | 250 | unsigned long timeout; |
| 252 | 251 | ||
| 253 | /* SATA DPLL can't be powered down due to Errata i783 and PCIe | 252 | /* SATA DPLL can't be powered down due to Errata i783 */ |
| 254 | * does not have internal DPLL | 253 | if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) |
| 255 | */ | ||
| 256 | if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") || | ||
| 257 | of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) | ||
| 258 | return 0; | 254 | return 0; |
| 259 | 255 | ||
| 260 | /* Put DPLL in IDLE mode */ | 256 | /* PCIe doesn't have internal DPLL */ |
| 261 | val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); | 257 | if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) { |
| 262 | val |= PLL_IDLE; | 258 | /* Put DPLL in IDLE mode */ |
| 263 | ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); | 259 | val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); |
| 264 | 260 | val |= PLL_IDLE; | |
| 265 | /* wait for LDO and Oscillator to power down */ | 261 | ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); |
| 266 | timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME); | ||
| 267 | do { | ||
| 268 | cpu_relax(); | ||
| 269 | val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); | ||
| 270 | if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN)) | ||
| 271 | break; | ||
| 272 | } while (!time_after(jiffies, timeout)); | ||
| 273 | 262 | ||
| 274 | if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) { | 263 | /* wait for LDO and Oscillator to power down */ |
| 275 | dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n", | 264 | timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME); |
| 276 | val); | 265 | do { |
| 277 | return -EBUSY; | 266 | cpu_relax(); |
| 267 | val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); | ||
| 268 | if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN)) | ||
| 269 | break; | ||
| 270 | } while (!time_after(jiffies, timeout)); | ||
| 271 | |||
| 272 | if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) { | ||
| 273 | dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n", | ||
| 274 | val); | ||
| 275 | return -EBUSY; | ||
| 276 | } | ||
| 278 | } | 277 | } |
| 279 | 278 | ||
| 279 | ti_pipe3_disable_clocks(phy); | ||
| 280 | |||
| 280 | return 0; | 281 | return 0; |
| 281 | } | 282 | } |
| 282 | static struct phy_ops ops = { | 283 | static struct phy_ops ops = { |
| @@ -306,7 +307,6 @@ static int ti_pipe3_probe(struct platform_device *pdev) | |||
| 306 | return -ENOMEM; | 307 | return -ENOMEM; |
| 307 | 308 | ||
| 308 | phy->dev = &pdev->dev; | 309 | phy->dev = &pdev->dev; |
| 309 | spin_lock_init(&phy->lock); | ||
| 310 | 310 | ||
| 311 | if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { | 311 | if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { |
| 312 | match = of_match_device(ti_pipe3_id_table, &pdev->dev); | 312 | match = of_match_device(ti_pipe3_id_table, &pdev->dev); |
| @@ -402,6 +402,10 @@ static int ti_pipe3_probe(struct platform_device *pdev) | |||
| 402 | 402 | ||
| 403 | platform_set_drvdata(pdev, phy); | 403 | platform_set_drvdata(pdev, phy); |
| 404 | pm_runtime_enable(phy->dev); | 404 | pm_runtime_enable(phy->dev); |
| 405 | /* Prevent auto-disable of refclk for SATA PHY due to Errata i783 */ | ||
| 406 | if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) | ||
| 407 | if (!IS_ERR(phy->refclk)) | ||
| 408 | clk_prepare_enable(phy->refclk); | ||
| 405 | 409 | ||
| 406 | generic_phy = devm_phy_create(phy->dev, NULL, &ops); | 410 | generic_phy = devm_phy_create(phy->dev, NULL, &ops); |
| 407 | if (IS_ERR(generic_phy)) | 411 | if (IS_ERR(generic_phy)) |
| @@ -413,63 +417,33 @@ static int ti_pipe3_probe(struct platform_device *pdev) | |||
| 413 | if (IS_ERR(phy_provider)) | 417 | if (IS_ERR(phy_provider)) |
| 414 | return PTR_ERR(phy_provider); | 418 | return PTR_ERR(phy_provider); |
| 415 | 419 | ||
| 416 | pm_runtime_get(&pdev->dev); | ||
| 417 | |||
| 418 | return 0; | 420 | return 0; |
| 419 | } | 421 | } |
| 420 | 422 | ||
| 421 | static int ti_pipe3_remove(struct platform_device *pdev) | 423 | static int ti_pipe3_remove(struct platform_device *pdev) |
| 422 | { | 424 | { |
| 423 | if (!pm_runtime_suspended(&pdev->dev)) | ||
| 424 | pm_runtime_put(&pdev->dev); | ||
| 425 | pm_runtime_disable(&pdev->dev); | 425 | pm_runtime_disable(&pdev->dev); |
| 426 | 426 | ||
| 427 | return 0; | 427 | return 0; |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | #ifdef CONFIG_PM | 430 | static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) |
| 431 | static int ti_pipe3_enable_refclk(struct ti_pipe3 *phy) | ||
| 432 | { | 431 | { |
| 433 | if (!IS_ERR(phy->refclk) && !phy->refclk_enabled) { | 432 | int ret = 0; |
| 434 | int ret; | ||
| 435 | 433 | ||
| 434 | if (!IS_ERR(phy->refclk)) { | ||
| 436 | ret = clk_prepare_enable(phy->refclk); | 435 | ret = clk_prepare_enable(phy->refclk); |
| 437 | if (ret) { | 436 | if (ret) { |
| 438 | dev_err(phy->dev, "Failed to enable refclk %d\n", ret); | 437 | dev_err(phy->dev, "Failed to enable refclk %d\n", ret); |
| 439 | return ret; | 438 | return ret; |
| 440 | } | 439 | } |
| 441 | phy->refclk_enabled = true; | ||
| 442 | } | 440 | } |
| 443 | 441 | ||
| 444 | return 0; | ||
| 445 | } | ||
| 446 | |||
| 447 | static void ti_pipe3_disable_refclk(struct ti_pipe3 *phy) | ||
| 448 | { | ||
| 449 | if (!IS_ERR(phy->refclk)) | ||
| 450 | clk_disable_unprepare(phy->refclk); | ||
| 451 | |||
| 452 | phy->refclk_enabled = false; | ||
| 453 | } | ||
| 454 | |||
| 455 | static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) | ||
| 456 | { | ||
| 457 | int ret = 0; | ||
| 458 | unsigned long flags; | ||
| 459 | |||
| 460 | spin_lock_irqsave(&phy->lock, flags); | ||
| 461 | if (phy->enabled) | ||
| 462 | goto err1; | ||
| 463 | |||
| 464 | ret = ti_pipe3_enable_refclk(phy); | ||
| 465 | if (ret) | ||
| 466 | goto err1; | ||
| 467 | |||
| 468 | if (!IS_ERR(phy->wkupclk)) { | 442 | if (!IS_ERR(phy->wkupclk)) { |
| 469 | ret = clk_prepare_enable(phy->wkupclk); | 443 | ret = clk_prepare_enable(phy->wkupclk); |
| 470 | if (ret) { | 444 | if (ret) { |
| 471 | dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); | 445 | dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); |
| 472 | goto err2; | 446 | goto disable_refclk; |
| 473 | } | 447 | } |
| 474 | } | 448 | } |
| 475 | 449 | ||
| @@ -477,96 +451,33 @@ static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) | |||
| 477 | ret = clk_prepare_enable(phy->div_clk); | 451 | ret = clk_prepare_enable(phy->div_clk); |
| 478 | if (ret) { | 452 | if (ret) { |
| 479 | dev_err(phy->dev, "Failed to enable div_clk %d\n", ret); | 453 | dev_err(phy->dev, "Failed to enable div_clk %d\n", ret); |
| 480 | goto err3; | 454 | goto disable_wkupclk; |
| 481 | } | 455 | } |
| 482 | } | 456 | } |
| 483 | 457 | ||
| 484 | phy->enabled = true; | ||
| 485 | spin_unlock_irqrestore(&phy->lock, flags); | ||
| 486 | return 0; | 458 | return 0; |
| 487 | 459 | ||
| 488 | err3: | 460 | disable_wkupclk: |
| 489 | if (!IS_ERR(phy->wkupclk)) | 461 | if (!IS_ERR(phy->wkupclk)) |
| 490 | clk_disable_unprepare(phy->wkupclk); | 462 | clk_disable_unprepare(phy->wkupclk); |
| 491 | 463 | ||
| 492 | err2: | 464 | disable_refclk: |
| 493 | if (!IS_ERR(phy->refclk)) | 465 | if (!IS_ERR(phy->refclk)) |
| 494 | clk_disable_unprepare(phy->refclk); | 466 | clk_disable_unprepare(phy->refclk); |
| 495 | 467 | ||
| 496 | ti_pipe3_disable_refclk(phy); | ||
| 497 | err1: | ||
| 498 | spin_unlock_irqrestore(&phy->lock, flags); | ||
| 499 | return ret; | 468 | return ret; |
| 500 | } | 469 | } |
| 501 | 470 | ||
| 502 | static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) | 471 | static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) |
| 503 | { | 472 | { |
| 504 | unsigned long flags; | ||
| 505 | |||
| 506 | spin_lock_irqsave(&phy->lock, flags); | ||
| 507 | if (!phy->enabled) { | ||
| 508 | spin_unlock_irqrestore(&phy->lock, flags); | ||
| 509 | return; | ||
| 510 | } | ||
| 511 | |||
| 512 | if (!IS_ERR(phy->wkupclk)) | 473 | if (!IS_ERR(phy->wkupclk)) |
| 513 | clk_disable_unprepare(phy->wkupclk); | 474 | clk_disable_unprepare(phy->wkupclk); |
| 514 | /* Don't disable refclk for SATA PHY due to Errata i783 */ | 475 | if (!IS_ERR(phy->refclk)) |
| 515 | if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) | 476 | clk_disable_unprepare(phy->refclk); |
| 516 | ti_pipe3_disable_refclk(phy); | ||
| 517 | if (!IS_ERR(phy->div_clk)) | 477 | if (!IS_ERR(phy->div_clk)) |
| 518 | clk_disable_unprepare(phy->div_clk); | 478 | clk_disable_unprepare(phy->div_clk); |
| 519 | phy->enabled = false; | ||
| 520 | spin_unlock_irqrestore(&phy->lock, flags); | ||
| 521 | } | ||
| 522 | |||
| 523 | static int ti_pipe3_runtime_suspend(struct device *dev) | ||
| 524 | { | ||
| 525 | struct ti_pipe3 *phy = dev_get_drvdata(dev); | ||
| 526 | |||
| 527 | ti_pipe3_disable_clocks(phy); | ||
| 528 | return 0; | ||
| 529 | } | 479 | } |
| 530 | 480 | ||
| 531 | static int ti_pipe3_runtime_resume(struct device *dev) | ||
| 532 | { | ||
| 533 | struct ti_pipe3 *phy = dev_get_drvdata(dev); | ||
| 534 | int ret = 0; | ||
| 535 | |||
| 536 | ret = ti_pipe3_enable_clocks(phy); | ||
| 537 | return ret; | ||
| 538 | } | ||
| 539 | |||
| 540 | static int ti_pipe3_suspend(struct device *dev) | ||
| 541 | { | ||
| 542 | struct ti_pipe3 *phy = dev_get_drvdata(dev); | ||
| 543 | |||
| 544 | ti_pipe3_disable_clocks(phy); | ||
| 545 | return 0; | ||
| 546 | } | ||
| 547 | |||
| 548 | static int ti_pipe3_resume(struct device *dev) | ||
| 549 | { | ||
| 550 | struct ti_pipe3 *phy = dev_get_drvdata(dev); | ||
| 551 | int ret; | ||
| 552 | |||
| 553 | ret = ti_pipe3_enable_clocks(phy); | ||
| 554 | if (ret) | ||
| 555 | return ret; | ||
| 556 | |||
| 557 | pm_runtime_disable(dev); | ||
| 558 | pm_runtime_set_active(dev); | ||
| 559 | pm_runtime_enable(dev); | ||
| 560 | return 0; | ||
| 561 | } | ||
| 562 | #endif | ||
| 563 | |||
| 564 | static const struct dev_pm_ops ti_pipe3_pm_ops = { | ||
| 565 | SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend, | ||
| 566 | ti_pipe3_runtime_resume, NULL) | ||
| 567 | SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume) | ||
| 568 | }; | ||
| 569 | |||
| 570 | static const struct of_device_id ti_pipe3_id_table[] = { | 481 | static const struct of_device_id ti_pipe3_id_table[] = { |
| 571 | { | 482 | { |
| 572 | .compatible = "ti,phy-usb3", | 483 | .compatible = "ti,phy-usb3", |
| @@ -592,7 +503,6 @@ static struct platform_driver ti_pipe3_driver = { | |||
| 592 | .remove = ti_pipe3_remove, | 503 | .remove = ti_pipe3_remove, |
| 593 | .driver = { | 504 | .driver = { |
| 594 | .name = "ti-pipe3", | 505 | .name = "ti-pipe3", |
| 595 | .pm = &ti_pipe3_pm_ops, | ||
| 596 | .of_match_table = ti_pipe3_id_table, | 506 | .of_match_table = ti_pipe3_id_table, |
| 597 | }, | 507 | }, |
| 598 | }; | 508 | }; |
