diff options
Diffstat (limited to 'drivers/phy/phy-core.c')
-rw-r--r-- | drivers/phy/phy-core.c | 115 |
1 files changed, 74 insertions, 41 deletions
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index ff5eec5af817..a12d35338313 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c | |||
@@ -26,6 +26,7 @@ | |||
26 | static struct class *phy_class; | 26 | static struct class *phy_class; |
27 | static DEFINE_MUTEX(phy_provider_mutex); | 27 | static DEFINE_MUTEX(phy_provider_mutex); |
28 | static LIST_HEAD(phy_provider_list); | 28 | static LIST_HEAD(phy_provider_list); |
29 | static LIST_HEAD(phys); | ||
29 | static DEFINE_IDA(phy_ida); | 30 | static DEFINE_IDA(phy_ida); |
30 | 31 | ||
31 | static void devm_phy_release(struct device *dev, void *res) | 32 | static void devm_phy_release(struct device *dev, void *res) |
@@ -54,34 +55,79 @@ static int devm_phy_match(struct device *dev, void *res, void *match_data) | |||
54 | return res == match_data; | 55 | return res == match_data; |
55 | } | 56 | } |
56 | 57 | ||
57 | static struct phy *phy_lookup(struct device *device, const char *port) | 58 | /** |
59 | * phy_create_lookup() - allocate and register PHY/device association | ||
60 | * @phy: the phy of the association | ||
61 | * @con_id: connection ID string on device | ||
62 | * @dev_id: the device of the association | ||
63 | * | ||
64 | * Creates and registers phy_lookup entry. | ||
65 | */ | ||
66 | int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id) | ||
58 | { | 67 | { |
59 | unsigned int count; | 68 | struct phy_lookup *pl; |
60 | struct phy *phy; | ||
61 | struct device *dev; | ||
62 | struct phy_consumer *consumers; | ||
63 | struct class_dev_iter iter; | ||
64 | 69 | ||
65 | class_dev_iter_init(&iter, phy_class, NULL, NULL); | 70 | if (!phy || !dev_id || !con_id) |
66 | while ((dev = class_dev_iter_next(&iter))) { | 71 | return -EINVAL; |
67 | phy = to_phy(dev); | ||
68 | 72 | ||
69 | if (!phy->init_data) | 73 | pl = kzalloc(sizeof(*pl), GFP_KERNEL); |
70 | continue; | 74 | if (!pl) |
71 | count = phy->init_data->num_consumers; | 75 | return -ENOMEM; |
72 | consumers = phy->init_data->consumers; | 76 | |
73 | while (count--) { | 77 | pl->dev_id = dev_id; |
74 | if (!strcmp(consumers->dev_name, dev_name(device)) && | 78 | pl->con_id = con_id; |
75 | !strcmp(consumers->port, port)) { | 79 | pl->phy = phy; |
76 | class_dev_iter_exit(&iter); | 80 | |
77 | return phy; | 81 | mutex_lock(&phy_provider_mutex); |
78 | } | 82 | list_add_tail(&pl->node, &phys); |
79 | consumers++; | 83 | mutex_unlock(&phy_provider_mutex); |
84 | |||
85 | return 0; | ||
86 | } | ||
87 | EXPORT_SYMBOL_GPL(phy_create_lookup); | ||
88 | |||
89 | /** | ||
90 | * phy_remove_lookup() - find and remove PHY/device association | ||
91 | * @phy: the phy of the association | ||
92 | * @con_id: connection ID string on device | ||
93 | * @dev_id: the device of the association | ||
94 | * | ||
95 | * Finds and unregisters phy_lookup entry that was created with | ||
96 | * phy_create_lookup(). | ||
97 | */ | ||
98 | void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id) | ||
99 | { | ||
100 | struct phy_lookup *pl; | ||
101 | |||
102 | if (!phy || !dev_id || !con_id) | ||
103 | return; | ||
104 | |||
105 | mutex_lock(&phy_provider_mutex); | ||
106 | list_for_each_entry(pl, &phys, node) | ||
107 | if (pl->phy == phy && !strcmp(pl->dev_id, dev_id) && | ||
108 | !strcmp(pl->con_id, con_id)) { | ||
109 | list_del(&pl->node); | ||
110 | kfree(pl); | ||
111 | break; | ||
80 | } | 112 | } |
81 | } | 113 | mutex_unlock(&phy_provider_mutex); |
114 | } | ||
115 | EXPORT_SYMBOL_GPL(phy_remove_lookup); | ||
82 | 116 | ||
83 | class_dev_iter_exit(&iter); | 117 | static struct phy *phy_find(struct device *dev, const char *con_id) |
84 | return ERR_PTR(-ENODEV); | 118 | { |
119 | const char *dev_id = dev_name(dev); | ||
120 | struct phy_lookup *p, *pl = NULL; | ||
121 | |||
122 | mutex_lock(&phy_provider_mutex); | ||
123 | list_for_each_entry(p, &phys, node) | ||
124 | if (!strcmp(p->dev_id, dev_id) && !strcmp(p->con_id, con_id)) { | ||
125 | pl = p; | ||
126 | break; | ||
127 | } | ||
128 | mutex_unlock(&phy_provider_mutex); | ||
129 | |||
130 | return pl ? pl->phy : ERR_PTR(-ENODEV); | ||
85 | } | 131 | } |
86 | 132 | ||
87 | static struct phy_provider *of_phy_provider_lookup(struct device_node *node) | 133 | static struct phy_provider *of_phy_provider_lookup(struct device_node *node) |
@@ -414,21 +460,13 @@ struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args | |||
414 | { | 460 | { |
415 | struct phy *phy; | 461 | struct phy *phy; |
416 | struct class_dev_iter iter; | 462 | struct class_dev_iter iter; |
417 | struct device_node *node = dev->of_node; | ||
418 | struct device_node *child; | ||
419 | 463 | ||
420 | class_dev_iter_init(&iter, phy_class, NULL, NULL); | 464 | class_dev_iter_init(&iter, phy_class, NULL, NULL); |
421 | while ((dev = class_dev_iter_next(&iter))) { | 465 | while ((dev = class_dev_iter_next(&iter))) { |
422 | phy = to_phy(dev); | 466 | phy = to_phy(dev); |
423 | if (node != phy->dev.of_node) { | 467 | if (args->np != phy->dev.of_node) |
424 | for_each_child_of_node(node, child) { | ||
425 | if (child == phy->dev.of_node) | ||
426 | goto phy_found; | ||
427 | } | ||
428 | continue; | 468 | continue; |
429 | } | ||
430 | 469 | ||
431 | phy_found: | ||
432 | class_dev_iter_exit(&iter); | 470 | class_dev_iter_exit(&iter); |
433 | return phy; | 471 | return phy; |
434 | } | 472 | } |
@@ -463,7 +501,7 @@ struct phy *phy_get(struct device *dev, const char *string) | |||
463 | string); | 501 | string); |
464 | phy = _of_phy_get(dev->of_node, index); | 502 | phy = _of_phy_get(dev->of_node, index); |
465 | } else { | 503 | } else { |
466 | phy = phy_lookup(dev, string); | 504 | phy = phy_find(dev, string); |
467 | } | 505 | } |
468 | if (IS_ERR(phy)) | 506 | if (IS_ERR(phy)) |
469 | return phy; | 507 | return phy; |
@@ -588,13 +626,11 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get); | |||
588 | * @dev: device that is creating the new phy | 626 | * @dev: device that is creating the new phy |
589 | * @node: device node of the phy | 627 | * @node: device node of the phy |
590 | * @ops: function pointers for performing phy operations | 628 | * @ops: function pointers for performing phy operations |
591 | * @init_data: contains the list of PHY consumers or NULL | ||
592 | * | 629 | * |
593 | * Called to create a phy using phy framework. | 630 | * Called to create a phy using phy framework. |
594 | */ | 631 | */ |
595 | struct phy *phy_create(struct device *dev, struct device_node *node, | 632 | struct phy *phy_create(struct device *dev, struct device_node *node, |
596 | const struct phy_ops *ops, | 633 | const struct phy_ops *ops) |
597 | struct phy_init_data *init_data) | ||
598 | { | 634 | { |
599 | int ret; | 635 | int ret; |
600 | int id; | 636 | int id; |
@@ -632,7 +668,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node, | |||
632 | phy->dev.of_node = node ?: dev->of_node; | 668 | phy->dev.of_node = node ?: dev->of_node; |
633 | phy->id = id; | 669 | phy->id = id; |
634 | phy->ops = ops; | 670 | phy->ops = ops; |
635 | phy->init_data = init_data; | ||
636 | 671 | ||
637 | ret = dev_set_name(&phy->dev, "phy-%s.%d", dev_name(dev), id); | 672 | ret = dev_set_name(&phy->dev, "phy-%s.%d", dev_name(dev), id); |
638 | if (ret) | 673 | if (ret) |
@@ -667,7 +702,6 @@ EXPORT_SYMBOL_GPL(phy_create); | |||
667 | * @dev: device that is creating the new phy | 702 | * @dev: device that is creating the new phy |
668 | * @node: device node of the phy | 703 | * @node: device node of the phy |
669 | * @ops: function pointers for performing phy operations | 704 | * @ops: function pointers for performing phy operations |
670 | * @init_data: contains the list of PHY consumers or NULL | ||
671 | * | 705 | * |
672 | * Creates a new PHY device adding it to the PHY class. | 706 | * Creates a new PHY device adding it to the PHY class. |
673 | * While at that, it also associates the device with the phy using devres. | 707 | * While at that, it also associates the device with the phy using devres. |
@@ -675,8 +709,7 @@ EXPORT_SYMBOL_GPL(phy_create); | |||
675 | * then, devres data is freed. | 709 | * then, devres data is freed. |
676 | */ | 710 | */ |
677 | struct phy *devm_phy_create(struct device *dev, struct device_node *node, | 711 | struct phy *devm_phy_create(struct device *dev, struct device_node *node, |
678 | const struct phy_ops *ops, | 712 | const struct phy_ops *ops) |
679 | struct phy_init_data *init_data) | ||
680 | { | 713 | { |
681 | struct phy **ptr, *phy; | 714 | struct phy **ptr, *phy; |
682 | 715 | ||
@@ -684,7 +717,7 @@ struct phy *devm_phy_create(struct device *dev, struct device_node *node, | |||
684 | if (!ptr) | 717 | if (!ptr) |
685 | return ERR_PTR(-ENOMEM); | 718 | return ERR_PTR(-ENOMEM); |
686 | 719 | ||
687 | phy = phy_create(dev, node, ops, init_data); | 720 | phy = phy_create(dev, node, ops); |
688 | if (!IS_ERR(phy)) { | 721 | if (!IS_ERR(phy)) { |
689 | *ptr = phy; | 722 | *ptr = phy; |
690 | devres_add(dev, ptr); | 723 | devres_add(dev, ptr); |