aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/property.c9
-rw-r--r--drivers/base/property.c75
-rw-r--r--include/linux/property.h18
3 files changed, 102 insertions, 0 deletions
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 77abe0ec4043..9d460a859be0 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -44,6 +44,7 @@ static const guid_t prp_guids[] = {
44 0xbf, 0xf0, 0x76, 0x14, 0x38, 0x07, 0xc3, 0x89), 44 0xbf, 0xf0, 0x76, 0x14, 0x38, 0x07, 0xc3, 0x89),
45}; 45};
46 46
47/* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
47static const guid_t ads_guid = 48static const guid_t ads_guid =
48 GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6, 49 GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6,
49 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b); 50 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b);
@@ -1031,6 +1032,14 @@ struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
1031 const struct acpi_data_node *data = to_acpi_data_node(fwnode); 1032 const struct acpi_data_node *data = to_acpi_data_node(fwnode);
1032 struct acpi_data_node *dn; 1033 struct acpi_data_node *dn;
1033 1034
1035 /*
1036 * We can have a combination of device and data nodes, e.g. with
1037 * hierarchical _DSD properties. Make sure the adev pointer is
1038 * restored before going through data nodes, otherwise we will
1039 * be looking for data_nodes below the last device found instead
1040 * of the common fwnode shared by device_nodes and data_nodes.
1041 */
1042 adev = to_acpi_device_node(fwnode);
1034 if (adev) 1043 if (adev)
1035 head = &adev->data.subnodes; 1044 head = &adev->data.subnodes;
1036 else if (data) 1045 else if (data)
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,
984EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node); 984EXPORT_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 */
1006struct fwnode_handle *
1007fwnode_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}
1059EXPORT_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 *
304fwnode_graph_get_remote_node(const struct fwnode_handle *fwnode, u32 port, 305fwnode_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
321struct fwnode_handle *
322fwnode_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)); )