.. | .. |
---|
| 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); |
---|