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 | }; |