diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/property.c | 75 |
1 files changed, 75 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, EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node); /** + * fwnode_graph_get_endpoint_by_id - get endpoint by port and endpoint numbers + * @fwnode: parent fwnode_handle containing the graph + * @port: identifier of the port node + * @endpoint: identifier of the endpoint node under the port node + * @flags: fwnode lookup flags + * + * Return the fwnode handle of the local endpoint corresponding the port and + * endpoint IDs or NULL if not found. + * + * If FWNODE_GRAPH_ENDPOINT_NEXT is passed in @flags and the specified endpoint + * has not been found, look for the closest endpoint ID greater than the + * specified one and return the endpoint that corresponds to it, if present. + * + * Do not return endpoints that belong to disabled devices, unless + * FWNODE_GRAPH_DEVICE_DISABLED is passed in @flags. + * + * The returned endpoint needs to be released by calling fwnode_handle_put() on + * it when it is not needed any more. + */ +struct fwnode_handle * +fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode, + u32 port, u32 endpoint, unsigned long flags) +{ + struct fwnode_handle *ep = NULL, *best_ep = NULL; + unsigned int best_ep_id = 0; + bool endpoint_next = flags & FWNODE_GRAPH_ENDPOINT_NEXT; + bool enabled_only = !(flags & FWNODE_GRAPH_DEVICE_DISABLED); + + while ((ep = fwnode_graph_get_next_endpoint(fwnode, ep))) { + struct fwnode_endpoint fwnode_ep = { 0 }; + int ret; + + if (enabled_only) { + struct fwnode_handle *dev_node; + bool available; + + dev_node = fwnode_graph_get_remote_port_parent(ep); + available = fwnode_device_is_available(dev_node); + fwnode_handle_put(dev_node); + if (!available) + continue; + } + + ret = fwnode_graph_parse_endpoint(ep, &fwnode_ep); + if (ret < 0) + continue; + + if (fwnode_ep.port != port) + continue; + + if (fwnode_ep.id == endpoint) + return ep; + + if (!endpoint_next) + continue; + + /* + * If the endpoint that has just been found is not the first + * matching one and the ID of the one found previously is closer + * to the requested endpoint ID, skip it. + */ + if (fwnode_ep.id < endpoint || + (best_ep && best_ep_id < fwnode_ep.id)) + continue; + + fwnode_handle_put(best_ep); + best_ep = fwnode_handle_get(ep); + best_ep_id = fwnode_ep.id; + } + + return best_ep; +} +EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_by_id); + +/** * fwnode_graph_parse_endpoint - parse common endpoint node properties * @fwnode: pointer to endpoint fwnode_handle * @endpoint: pointer to the fwnode endpoint data structure |