| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * phy-core.c -- Generic Phy framework. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Author: Kishon Vijay Abraham I <kishon@ti.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 9 | | - * under the terms of the GNU General Public License as published by the |
|---|
| 10 | | - * Free Software Foundation; either version 2 of the License, or (at your |
|---|
| 11 | | - * option) any later version. |
|---|
| 12 | 8 | */ |
|---|
| 13 | 9 | |
|---|
| 14 | 10 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 33 | 29 | { |
|---|
| 34 | 30 | struct phy *phy = *(struct phy **)res; |
|---|
| 35 | 31 | |
|---|
| 36 | | - phy_put(phy); |
|---|
| 32 | + phy_put(dev, phy); |
|---|
| 37 | 33 | } |
|---|
| 38 | 34 | |
|---|
| 39 | 35 | static void devm_phy_provider_release(struct device *dev, void *res) |
|---|
| .. | .. |
|---|
| 360 | 356 | } |
|---|
| 361 | 357 | EXPORT_SYMBOL_GPL(phy_power_off); |
|---|
| 362 | 358 | |
|---|
| 363 | | -int phy_set_mode(struct phy *phy, enum phy_mode mode) |
|---|
| 359 | +int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode) |
|---|
| 364 | 360 | { |
|---|
| 365 | 361 | int ret; |
|---|
| 366 | 362 | |
|---|
| .. | .. |
|---|
| 368 | 364 | return 0; |
|---|
| 369 | 365 | |
|---|
| 370 | 366 | mutex_lock(&phy->mutex); |
|---|
| 371 | | - ret = phy->ops->set_mode(phy, mode); |
|---|
| 367 | + ret = phy->ops->set_mode(phy, mode, submode); |
|---|
| 372 | 368 | if (!ret) |
|---|
| 373 | 369 | phy->attrs.mode = mode; |
|---|
| 374 | 370 | mutex_unlock(&phy->mutex); |
|---|
| 375 | 371 | |
|---|
| 376 | 372 | return ret; |
|---|
| 377 | 373 | } |
|---|
| 378 | | -EXPORT_SYMBOL_GPL(phy_set_mode); |
|---|
| 374 | +EXPORT_SYMBOL_GPL(phy_set_mode_ext); |
|---|
| 379 | 375 | |
|---|
| 380 | 376 | int phy_reset(struct phy *phy) |
|---|
| 381 | 377 | { |
|---|
| .. | .. |
|---|
| 384 | 380 | if (!phy || !phy->ops->reset) |
|---|
| 385 | 381 | return 0; |
|---|
| 386 | 382 | |
|---|
| 383 | + ret = phy_pm_runtime_get_sync(phy); |
|---|
| 384 | + if (ret < 0 && ret != -ENOTSUPP) |
|---|
| 385 | + return ret; |
|---|
| 386 | + |
|---|
| 387 | 387 | mutex_lock(&phy->mutex); |
|---|
| 388 | 388 | ret = phy->ops->reset(phy); |
|---|
| 389 | 389 | mutex_unlock(&phy->mutex); |
|---|
| 390 | + |
|---|
| 391 | + phy_pm_runtime_put(phy); |
|---|
| 390 | 392 | |
|---|
| 391 | 393 | return ret; |
|---|
| 392 | 394 | } |
|---|
| 393 | 395 | EXPORT_SYMBOL_GPL(phy_reset); |
|---|
| 394 | 396 | |
|---|
| 397 | +/** |
|---|
| 398 | + * phy_calibrate() - Tunes the phy hw parameters for current configuration |
|---|
| 399 | + * @phy: the phy returned by phy_get() |
|---|
| 400 | + * |
|---|
| 401 | + * Used to calibrate phy hardware, typically by adjusting some parameters in |
|---|
| 402 | + * runtime, which are otherwise lost after host controller reset and cannot |
|---|
| 403 | + * be applied in phy_init() or phy_power_on(). |
|---|
| 404 | + * |
|---|
| 405 | + * Returns: 0 if successful, an negative error code otherwise |
|---|
| 406 | + */ |
|---|
| 395 | 407 | int phy_calibrate(struct phy *phy) |
|---|
| 396 | 408 | { |
|---|
| 397 | 409 | int ret; |
|---|
| 398 | 410 | |
|---|
| 399 | 411 | if (!phy || !phy->ops->calibrate) |
|---|
| 400 | 412 | return 0; |
|---|
| 401 | | - |
|---|
| 402 | | - if (phy->dev.parent && |
|---|
| 403 | | - of_device_is_compatible(phy->dev.parent->of_node, |
|---|
| 404 | | - "rockchip,rv1126-usb2phy")) { |
|---|
| 405 | | - ret = phy->ops->calibrate(phy); |
|---|
| 406 | | - return ret; |
|---|
| 407 | | - } |
|---|
| 408 | 413 | |
|---|
| 409 | 414 | mutex_lock(&phy->mutex); |
|---|
| 410 | 415 | ret = phy->ops->calibrate(phy); |
|---|
| .. | .. |
|---|
| 561 | 566 | EXPORT_SYMBOL_GPL(of_phy_get); |
|---|
| 562 | 567 | |
|---|
| 563 | 568 | /** |
|---|
| 564 | | - * phy_put() - release the PHY |
|---|
| 565 | | - * @phy: the phy returned by phy_get() |
|---|
| 569 | + * of_phy_put() - release the PHY |
|---|
| 570 | + * @phy: the phy returned by of_phy_get() |
|---|
| 566 | 571 | * |
|---|
| 567 | | - * Releases a refcount the caller received from phy_get(). |
|---|
| 572 | + * Releases a refcount the caller received from of_phy_get(). |
|---|
| 568 | 573 | */ |
|---|
| 569 | | -void phy_put(struct phy *phy) |
|---|
| 574 | +void of_phy_put(struct phy *phy) |
|---|
| 570 | 575 | { |
|---|
| 571 | 576 | if (!phy || IS_ERR(phy)) |
|---|
| 572 | 577 | return; |
|---|
| 573 | 578 | |
|---|
| 579 | + mutex_lock(&phy->mutex); |
|---|
| 580 | + if (phy->ops->release) |
|---|
| 581 | + phy->ops->release(phy); |
|---|
| 582 | + mutex_unlock(&phy->mutex); |
|---|
| 583 | + |
|---|
| 574 | 584 | module_put(phy->ops->owner); |
|---|
| 575 | 585 | put_device(&phy->dev); |
|---|
| 586 | +} |
|---|
| 587 | +EXPORT_SYMBOL_GPL(of_phy_put); |
|---|
| 588 | + |
|---|
| 589 | +/** |
|---|
| 590 | + * phy_put() - release the PHY |
|---|
| 591 | + * @dev: device that wants to release this phy |
|---|
| 592 | + * @phy: the phy returned by phy_get() |
|---|
| 593 | + * |
|---|
| 594 | + * Releases a refcount the caller received from phy_get(). |
|---|
| 595 | + */ |
|---|
| 596 | +void phy_put(struct device *dev, struct phy *phy) |
|---|
| 597 | +{ |
|---|
| 598 | + device_link_remove(dev, &phy->dev); |
|---|
| 599 | + of_phy_put(phy); |
|---|
| 576 | 600 | } |
|---|
| 577 | 601 | EXPORT_SYMBOL_GPL(phy_put); |
|---|
| 578 | 602 | |
|---|
| .. | .. |
|---|
| 641 | 665 | { |
|---|
| 642 | 666 | int index = 0; |
|---|
| 643 | 667 | struct phy *phy; |
|---|
| 668 | + struct device_link *link; |
|---|
| 644 | 669 | |
|---|
| 645 | 670 | if (string == NULL) { |
|---|
| 646 | 671 | dev_WARN(dev, "missing string\n"); |
|---|
| .. | .. |
|---|
| 662 | 687 | |
|---|
| 663 | 688 | get_device(&phy->dev); |
|---|
| 664 | 689 | |
|---|
| 690 | + link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS); |
|---|
| 691 | + if (!link) |
|---|
| 692 | + dev_dbg(dev, "failed to create device link to %s\n", |
|---|
| 693 | + dev_name(phy->dev.parent)); |
|---|
| 694 | + |
|---|
| 665 | 695 | return phy; |
|---|
| 666 | 696 | } |
|---|
| 667 | 697 | EXPORT_SYMBOL_GPL(phy_get); |
|---|
| .. | .. |
|---|
| 680 | 710 | { |
|---|
| 681 | 711 | struct phy *phy = phy_get(dev, string); |
|---|
| 682 | 712 | |
|---|
| 683 | | - if (IS_ERR(phy) && (PTR_ERR(phy) == -ENODEV)) |
|---|
| 713 | + if (PTR_ERR(phy) == -ENODEV) |
|---|
| 684 | 714 | phy = NULL; |
|---|
| 685 | 715 | |
|---|
| 686 | 716 | return phy; |
|---|
| .. | .. |
|---|
| 734 | 764 | { |
|---|
| 735 | 765 | struct phy *phy = devm_phy_get(dev, string); |
|---|
| 736 | 766 | |
|---|
| 737 | | - if (IS_ERR(phy) && (PTR_ERR(phy) == -ENODEV)) |
|---|
| 767 | + if (PTR_ERR(phy) == -ENODEV) |
|---|
| 738 | 768 | phy = NULL; |
|---|
| 739 | 769 | |
|---|
| 740 | 770 | return phy; |
|---|
| .. | .. |
|---|
| 755 | 785 | const char *con_id) |
|---|
| 756 | 786 | { |
|---|
| 757 | 787 | struct phy **ptr, *phy; |
|---|
| 788 | + struct device_link *link; |
|---|
| 758 | 789 | |
|---|
| 759 | 790 | ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL); |
|---|
| 760 | 791 | if (!ptr) |
|---|
| .. | .. |
|---|
| 766 | 797 | devres_add(dev, ptr); |
|---|
| 767 | 798 | } else { |
|---|
| 768 | 799 | devres_free(ptr); |
|---|
| 800 | + return phy; |
|---|
| 769 | 801 | } |
|---|
| 802 | + |
|---|
| 803 | + link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS); |
|---|
| 804 | + if (!link) |
|---|
| 805 | + dev_dbg(dev, "failed to create device link to %s\n", |
|---|
| 806 | + dev_name(phy->dev.parent)); |
|---|
| 770 | 807 | |
|---|
| 771 | 808 | return phy; |
|---|
| 772 | 809 | } |
|---|
| .. | .. |
|---|
| 788 | 825 | int index) |
|---|
| 789 | 826 | { |
|---|
| 790 | 827 | struct phy **ptr, *phy; |
|---|
| 828 | + struct device_link *link; |
|---|
| 791 | 829 | |
|---|
| 792 | 830 | ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL); |
|---|
| 793 | 831 | if (!ptr) |
|---|
| .. | .. |
|---|
| 808 | 846 | |
|---|
| 809 | 847 | *ptr = phy; |
|---|
| 810 | 848 | devres_add(dev, ptr); |
|---|
| 849 | + |
|---|
| 850 | + link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS); |
|---|
| 851 | + if (!link) |
|---|
| 852 | + dev_dbg(dev, "failed to create device link to %s\n", |
|---|
| 853 | + dev_name(phy->dev.parent)); |
|---|
| 811 | 854 | |
|---|
| 812 | 855 | return phy; |
|---|
| 813 | 856 | } |
|---|
| .. | .. |
|---|
| 1019 | 1062 | * __devm_of_phy_provider_register() - create/register phy provider with the |
|---|
| 1020 | 1063 | * framework |
|---|
| 1021 | 1064 | * @dev: struct device of the phy provider |
|---|
| 1065 | + * @children: device node containing children (if different from dev->of_node) |
|---|
| 1022 | 1066 | * @owner: the module owner containing of_xlate |
|---|
| 1023 | 1067 | * @of_xlate: function pointer to obtain phy instance from phy provider |
|---|
| 1024 | 1068 | * |
|---|
| .. | .. |
|---|
| 1074 | 1118 | /** |
|---|
| 1075 | 1119 | * devm_of_phy_provider_unregister() - remove phy provider from the framework |
|---|
| 1076 | 1120 | * @dev: struct device of the phy provider |
|---|
| 1121 | + * @phy_provider: phy provider returned by of_phy_provider_register() |
|---|
| 1077 | 1122 | * |
|---|
| 1078 | 1123 | * destroys the devres associated with this phy provider and invokes |
|---|
| 1079 | 1124 | * of_phy_provider_unregister to unregister the phy provider. |
|---|
| 1080 | 1125 | */ |
|---|
| 1081 | 1126 | void devm_of_phy_provider_unregister(struct device *dev, |
|---|
| 1082 | | - struct phy_provider *phy_provider) { |
|---|
| 1127 | + struct phy_provider *phy_provider) |
|---|
| 1128 | +{ |
|---|
| 1083 | 1129 | int r; |
|---|
| 1084 | 1130 | |
|---|
| 1085 | 1131 | r = devres_destroy(dev, devm_phy_provider_release, devm_phy_match, |
|---|
| .. | .. |
|---|
| 1119 | 1165 | |
|---|
| 1120 | 1166 | return 0; |
|---|
| 1121 | 1167 | } |
|---|
| 1122 | | -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT |
|---|
| 1123 | | -subsys_initcall(phy_core_init); |
|---|
| 1124 | | -#else |
|---|
| 1125 | | -module_init(phy_core_init); |
|---|
| 1126 | | -#endif |
|---|
| 1127 | | - |
|---|
| 1128 | | -static void __exit phy_core_exit(void) |
|---|
| 1129 | | -{ |
|---|
| 1130 | | - class_destroy(phy_class); |
|---|
| 1131 | | -} |
|---|
| 1132 | | -module_exit(phy_core_exit); |
|---|
| 1133 | | - |
|---|
| 1134 | | -MODULE_DESCRIPTION("Generic PHY Framework"); |
|---|
| 1135 | | -MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); |
|---|
| 1136 | | -MODULE_LICENSE("GPL v2"); |
|---|
| 1168 | +device_initcall(phy_core_init); |
|---|