diff options
| -rw-r--r-- | drivers/base/property.c | 75 | ||||
| -rw-r--r-- | include/linux/property.h | 18 |
2 files changed, 93 insertions, 0 deletions
diff --git a/drivers/base/property.c b/drivers/base/property.c index 8b91ab380d14..348b37e64944 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c | |||
| @@ -984,6 +984,81 @@ fwnode_graph_get_remote_node(const struct fwnode_handle *fwnode, u32 port_id, | |||
| 984 | EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node); | 984 | EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node); |
| 985 | 985 | ||
| 986 | /** | 986 | /** |
| 987 | * fwnode_graph_get_endpoint_by_id - get endpoint by port and endpoint numbers | ||
| 988 | * @fwnode: parent fwnode_handle containing the graph | ||
| 989 | * @port: identifier of the port node | ||
| 990 | * @endpoint: identifier of the endpoint node under the port node | ||
| 991 | * @flags: fwnode lookup flags | ||
| 992 | * | ||
| 993 | * Return the fwnode handle of the local endpoint corresponding the port and | ||
| 994 | * endpoint IDs or NULL if not found. | ||
| 995 | * | ||
| 996 | * If FWNODE_GRAPH_ENDPOINT_NEXT is passed in @flags and the specified endpoint | ||
| 997 | * has not been found, look for the closest endpoint ID greater than the | ||
| 998 | * specified one and return the endpoint that corresponds to it, if present. | ||
| 999 | * | ||
| 1000 | * Do not return endpoints that belong to disabled devices, unless | ||
| 1001 | * FWNODE_GRAPH_DEVICE_DISABLED is passed in @flags. | ||
| 1002 | * | ||
| 1003 | * The returned endpoint needs to be released by calling fwnode_handle_put() on | ||
| 1004 | * it when it is not needed any more. | ||
| 1005 | */ | ||
| 1006 | struct fwnode_handle * | ||
| 1007 | fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode, | ||
| 1008 | u32 port, u32 endpoint, unsigned long flags) | ||
| 1009 | { | ||
| 1010 | struct fwnode_handle *ep = NULL, *best_ep = NULL; | ||
| 1011 | unsigned int best_ep_id = 0; | ||
| 1012 | bool endpoint_next = flags & FWNODE_GRAPH_ENDPOINT_NEXT; | ||
| 1013 | bool enabled_only = !(flags & FWNODE_GRAPH_DEVICE_DISABLED); | ||
| 1014 | |||
| 1015 | while ((ep = fwnode_graph_get_next_endpoint(fwnode, ep))) { | ||
| 1016 | struct fwnode_endpoint fwnode_ep = { 0 }; | ||
| 1017 | int ret; | ||
| 1018 | |||
| 1019 | if (enabled_only) { | ||
| 1020 | struct fwnode_handle *dev_node; | ||
| 1021 | bool available; | ||
| 1022 | |||
| 1023 | dev_node = fwnode_graph_get_remote_port_parent(ep); | ||
| 1024 | available = fwnode_device_is_available(dev_node); | ||
| 1025 | fwnode_handle_put(dev_node); | ||
| 1026 | if (!available) | ||
| 1027 | continue; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | ret = fwnode_graph_parse_endpoint(ep, &fwnode_ep); | ||
| 1031 | if (ret < 0) | ||
| 1032 | continue; | ||
| 1033 | |||
| 1034 | if (fwnode_ep.port != port) | ||
| 1035 | continue; | ||
| 1036 | |||
| 1037 | if (fwnode_ep.id == endpoint) | ||
| 1038 | return ep; | ||
| 1039 | |||
| 1040 | if (!endpoint_next) | ||
| 1041 | continue; | ||
| 1042 | |||
| 1043 | /* | ||
| 1044 | * If the endpoint that has just been found is not the first | ||
| 1045 | * matching one and the ID of the one found previously is closer | ||
| 1046 | * to the requested endpoint ID, skip it. | ||
| 1047 | */ | ||
| 1048 | if (fwnode_ep.id < endpoint || | ||
| 1049 | (best_ep && best_ep_id < fwnode_ep.id)) | ||
| 1050 | continue; | ||
| 1051 | |||
| 1052 | fwnode_handle_put(best_ep); | ||
| 1053 | best_ep = fwnode_handle_get(ep); | ||
| 1054 | best_ep_id = fwnode_ep.id; | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | return best_ep; | ||
| 1058 | } | ||
| 1059 | EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_by_id); | ||
| 1060 | |||
| 1061 | /** | ||
| 987 | * fwnode_graph_parse_endpoint - parse common endpoint node properties | 1062 | * fwnode_graph_parse_endpoint - parse common endpoint node properties |
| 988 | * @fwnode: pointer to endpoint fwnode_handle | 1063 | * @fwnode: pointer to endpoint fwnode_handle |
| 989 | * @endpoint: pointer to the fwnode endpoint data structure | 1064 | * @endpoint: pointer to the fwnode endpoint data structure |
diff --git a/include/linux/property.h b/include/linux/property.h index 65d3420dd5d1..a29369c89e6e 100644 --- a/include/linux/property.h +++ b/include/linux/property.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #ifndef _LINUX_PROPERTY_H_ | 13 | #ifndef _LINUX_PROPERTY_H_ |
| 14 | #define _LINUX_PROPERTY_H_ | 14 | #define _LINUX_PROPERTY_H_ |
| 15 | 15 | ||
| 16 | #include <linux/bits.h> | ||
| 16 | #include <linux/fwnode.h> | 17 | #include <linux/fwnode.h> |
| 17 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 18 | 19 | ||
| @@ -304,6 +305,23 @@ struct fwnode_handle * | |||
| 304 | fwnode_graph_get_remote_node(const struct fwnode_handle *fwnode, u32 port, | 305 | fwnode_graph_get_remote_node(const struct fwnode_handle *fwnode, u32 port, |
| 305 | u32 endpoint); | 306 | u32 endpoint); |
| 306 | 307 | ||
| 308 | /* | ||
| 309 | * Fwnode lookup flags | ||
| 310 | * | ||
| 311 | * @FWNODE_GRAPH_ENDPOINT_NEXT: In the case of no exact match, look for the | ||
| 312 | * closest endpoint ID greater than the specified | ||
| 313 | * one. | ||
| 314 | * @FWNODE_GRAPH_DEVICE_DISABLED: That the device to which the remote | ||
| 315 | * endpoint of the given endpoint belongs to, | ||
| 316 | * may be disabled. | ||
| 317 | */ | ||
| 318 | #define FWNODE_GRAPH_ENDPOINT_NEXT BIT(0) | ||
| 319 | #define FWNODE_GRAPH_DEVICE_DISABLED BIT(1) | ||
| 320 | |||
| 321 | struct fwnode_handle * | ||
| 322 | fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode, | ||
| 323 | u32 port, u32 endpoint, unsigned long flags); | ||
| 324 | |||
| 307 | #define fwnode_graph_for_each_endpoint(fwnode, child) \ | 325 | #define fwnode_graph_for_each_endpoint(fwnode, child) \ |
| 308 | for (child = NULL; \ | 326 | for (child = NULL; \ |
| 309 | (child = fwnode_graph_get_next_endpoint(fwnode, child)); ) | 327 | (child = fwnode_graph_get_next_endpoint(fwnode, child)); ) |
