diff options
Diffstat (limited to 'drivers/phy/phy-core.c')
| -rw-r--r-- | drivers/phy/phy-core.c | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 49c446530101..ff5eec5af817 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/phy/phy.h> | 21 | #include <linux/phy/phy.h> |
| 22 | #include <linux/idr.h> | 22 | #include <linux/idr.h> |
| 23 | #include <linux/pm_runtime.h> | 23 | #include <linux/pm_runtime.h> |
| 24 | #include <linux/regulator/consumer.h> | ||
| 24 | 25 | ||
| 25 | static struct class *phy_class; | 26 | static struct class *phy_class; |
| 26 | static DEFINE_MUTEX(phy_provider_mutex); | 27 | static DEFINE_MUTEX(phy_provider_mutex); |
| @@ -86,10 +87,15 @@ static struct phy *phy_lookup(struct device *device, const char *port) | |||
| 86 | static struct phy_provider *of_phy_provider_lookup(struct device_node *node) | 87 | static struct phy_provider *of_phy_provider_lookup(struct device_node *node) |
| 87 | { | 88 | { |
| 88 | struct phy_provider *phy_provider; | 89 | struct phy_provider *phy_provider; |
| 90 | struct device_node *child; | ||
| 89 | 91 | ||
| 90 | list_for_each_entry(phy_provider, &phy_provider_list, list) { | 92 | list_for_each_entry(phy_provider, &phy_provider_list, list) { |
| 91 | if (phy_provider->dev->of_node == node) | 93 | if (phy_provider->dev->of_node == node) |
| 92 | return phy_provider; | 94 | return phy_provider; |
| 95 | |||
| 96 | for_each_child_of_node(phy_provider->dev->of_node, child) | ||
| 97 | if (child == node) | ||
| 98 | return phy_provider; | ||
| 93 | } | 99 | } |
| 94 | 100 | ||
| 95 | return ERR_PTR(-EPROBE_DEFER); | 101 | return ERR_PTR(-EPROBE_DEFER); |
| @@ -226,6 +232,12 @@ int phy_power_on(struct phy *phy) | |||
| 226 | if (!phy) | 232 | if (!phy) |
| 227 | return 0; | 233 | return 0; |
| 228 | 234 | ||
| 235 | if (phy->pwr) { | ||
| 236 | ret = regulator_enable(phy->pwr); | ||
| 237 | if (ret) | ||
| 238 | return ret; | ||
| 239 | } | ||
| 240 | |||
| 229 | ret = phy_pm_runtime_get_sync(phy); | 241 | ret = phy_pm_runtime_get_sync(phy); |
| 230 | if (ret < 0 && ret != -ENOTSUPP) | 242 | if (ret < 0 && ret != -ENOTSUPP) |
| 231 | return ret; | 243 | return ret; |
| @@ -247,6 +259,8 @@ int phy_power_on(struct phy *phy) | |||
| 247 | out: | 259 | out: |
| 248 | mutex_unlock(&phy->mutex); | 260 | mutex_unlock(&phy->mutex); |
| 249 | phy_pm_runtime_put_sync(phy); | 261 | phy_pm_runtime_put_sync(phy); |
| 262 | if (phy->pwr) | ||
| 263 | regulator_disable(phy->pwr); | ||
| 250 | 264 | ||
| 251 | return ret; | 265 | return ret; |
| 252 | } | 266 | } |
| @@ -272,6 +286,9 @@ int phy_power_off(struct phy *phy) | |||
| 272 | mutex_unlock(&phy->mutex); | 286 | mutex_unlock(&phy->mutex); |
| 273 | phy_pm_runtime_put(phy); | 287 | phy_pm_runtime_put(phy); |
| 274 | 288 | ||
| 289 | if (phy->pwr) | ||
| 290 | regulator_disable(phy->pwr); | ||
| 291 | |||
| 275 | return 0; | 292 | return 0; |
| 276 | } | 293 | } |
| 277 | EXPORT_SYMBOL_GPL(phy_power_off); | 294 | EXPORT_SYMBOL_GPL(phy_power_off); |
| @@ -398,13 +415,20 @@ struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args | |||
| 398 | struct phy *phy; | 415 | struct phy *phy; |
| 399 | struct class_dev_iter iter; | 416 | struct class_dev_iter iter; |
| 400 | struct device_node *node = dev->of_node; | 417 | struct device_node *node = dev->of_node; |
| 418 | struct device_node *child; | ||
| 401 | 419 | ||
| 402 | class_dev_iter_init(&iter, phy_class, NULL, NULL); | 420 | class_dev_iter_init(&iter, phy_class, NULL, NULL); |
| 403 | while ((dev = class_dev_iter_next(&iter))) { | 421 | while ((dev = class_dev_iter_next(&iter))) { |
| 404 | phy = to_phy(dev); | 422 | phy = to_phy(dev); |
| 405 | if (node != phy->dev.of_node) | 423 | if (node != phy->dev.of_node) { |
| 424 | for_each_child_of_node(node, child) { | ||
| 425 | if (child == phy->dev.of_node) | ||
| 426 | goto phy_found; | ||
| 427 | } | ||
| 406 | continue; | 428 | continue; |
| 429 | } | ||
| 407 | 430 | ||
| 431 | phy_found: | ||
| 408 | class_dev_iter_exit(&iter); | 432 | class_dev_iter_exit(&iter); |
| 409 | return phy; | 433 | return phy; |
| 410 | } | 434 | } |
| @@ -562,13 +586,15 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get); | |||
| 562 | /** | 586 | /** |
| 563 | * phy_create() - create a new phy | 587 | * phy_create() - create a new phy |
| 564 | * @dev: device that is creating the new phy | 588 | * @dev: device that is creating the new phy |
| 589 | * @node: device node of the phy | ||
| 565 | * @ops: function pointers for performing phy operations | 590 | * @ops: function pointers for performing phy operations |
| 566 | * @init_data: contains the list of PHY consumers or NULL | 591 | * @init_data: contains the list of PHY consumers or NULL |
| 567 | * | 592 | * |
| 568 | * Called to create a phy using phy framework. | 593 | * Called to create a phy using phy framework. |
| 569 | */ | 594 | */ |
| 570 | struct phy *phy_create(struct device *dev, const struct phy_ops *ops, | 595 | struct phy *phy_create(struct device *dev, struct device_node *node, |
| 571 | struct phy_init_data *init_data) | 596 | const struct phy_ops *ops, |
| 597 | struct phy_init_data *init_data) | ||
| 572 | { | 598 | { |
| 573 | int ret; | 599 | int ret; |
| 574 | int id; | 600 | int id; |
| @@ -588,12 +614,22 @@ struct phy *phy_create(struct device *dev, const struct phy_ops *ops, | |||
| 588 | goto free_phy; | 614 | goto free_phy; |
| 589 | } | 615 | } |
| 590 | 616 | ||
| 617 | /* phy-supply */ | ||
| 618 | phy->pwr = regulator_get_optional(dev, "phy"); | ||
| 619 | if (IS_ERR(phy->pwr)) { | ||
| 620 | if (PTR_ERR(phy->pwr) == -EPROBE_DEFER) { | ||
| 621 | ret = -EPROBE_DEFER; | ||
| 622 | goto free_ida; | ||
| 623 | } | ||
| 624 | phy->pwr = NULL; | ||
| 625 | } | ||
| 626 | |||
| 591 | device_initialize(&phy->dev); | 627 | device_initialize(&phy->dev); |
| 592 | mutex_init(&phy->mutex); | 628 | mutex_init(&phy->mutex); |
| 593 | 629 | ||
| 594 | phy->dev.class = phy_class; | 630 | phy->dev.class = phy_class; |
| 595 | phy->dev.parent = dev; | 631 | phy->dev.parent = dev; |
| 596 | phy->dev.of_node = dev->of_node; | 632 | phy->dev.of_node = node ?: dev->of_node; |
| 597 | phy->id = id; | 633 | phy->id = id; |
| 598 | phy->ops = ops; | 634 | phy->ops = ops; |
| 599 | phy->init_data = init_data; | 635 | phy->init_data = init_data; |
| @@ -617,6 +653,9 @@ put_dev: | |||
| 617 | put_device(&phy->dev); /* calls phy_release() which frees resources */ | 653 | put_device(&phy->dev); /* calls phy_release() which frees resources */ |
| 618 | return ERR_PTR(ret); | 654 | return ERR_PTR(ret); |
| 619 | 655 | ||
| 656 | free_ida: | ||
| 657 | ida_simple_remove(&phy_ida, phy->id); | ||
| 658 | |||
| 620 | free_phy: | 659 | free_phy: |
| 621 | kfree(phy); | 660 | kfree(phy); |
| 622 | return ERR_PTR(ret); | 661 | return ERR_PTR(ret); |
| @@ -626,6 +665,7 @@ EXPORT_SYMBOL_GPL(phy_create); | |||
| 626 | /** | 665 | /** |
| 627 | * devm_phy_create() - create a new phy | 666 | * devm_phy_create() - create a new phy |
| 628 | * @dev: device that is creating the new phy | 667 | * @dev: device that is creating the new phy |
| 668 | * @node: device node of the phy | ||
| 629 | * @ops: function pointers for performing phy operations | 669 | * @ops: function pointers for performing phy operations |
| 630 | * @init_data: contains the list of PHY consumers or NULL | 670 | * @init_data: contains the list of PHY consumers or NULL |
| 631 | * | 671 | * |
| @@ -634,8 +674,9 @@ EXPORT_SYMBOL_GPL(phy_create); | |||
| 634 | * On driver detach, release function is invoked on the devres data, | 674 | * On driver detach, release function is invoked on the devres data, |
| 635 | * then, devres data is freed. | 675 | * then, devres data is freed. |
| 636 | */ | 676 | */ |
| 637 | struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops, | 677 | struct phy *devm_phy_create(struct device *dev, struct device_node *node, |
| 638 | struct phy_init_data *init_data) | 678 | const struct phy_ops *ops, |
| 679 | struct phy_init_data *init_data) | ||
| 639 | { | 680 | { |
| 640 | struct phy **ptr, *phy; | 681 | struct phy **ptr, *phy; |
| 641 | 682 | ||
| @@ -643,7 +684,7 @@ struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops, | |||
| 643 | if (!ptr) | 684 | if (!ptr) |
| 644 | return ERR_PTR(-ENOMEM); | 685 | return ERR_PTR(-ENOMEM); |
| 645 | 686 | ||
| 646 | phy = phy_create(dev, ops, init_data); | 687 | phy = phy_create(dev, node, ops, init_data); |
| 647 | if (!IS_ERR(phy)) { | 688 | if (!IS_ERR(phy)) { |
| 648 | *ptr = phy; | 689 | *ptr = phy; |
| 649 | devres_add(dev, ptr); | 690 | devres_add(dev, ptr); |
| @@ -800,6 +841,7 @@ static void phy_release(struct device *dev) | |||
| 800 | 841 | ||
| 801 | phy = to_phy(dev); | 842 | phy = to_phy(dev); |
| 802 | dev_vdbg(dev, "releasing '%s'\n", dev_name(dev)); | 843 | dev_vdbg(dev, "releasing '%s'\n", dev_name(dev)); |
| 844 | regulator_put(phy->pwr); | ||
| 803 | ida_simple_remove(&phy_ida, phy->id); | 845 | ida_simple_remove(&phy_ida, phy->id); |
| 804 | kfree(phy); | 846 | kfree(phy); |
| 805 | } | 847 | } |
