summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2017-03-28 10:52:21 +0300
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-03-29 00:00:28 +0200
commit07bb80d40b0e6a43aafb422296d33baed255569a (patch)
tree491e2ac61be49db67e9740ba893b024bf9cf8f38
parent79389a83bc3888a900191e3990cda5c76f2ca1ec (diff)
downloadlinux-07bb80d40b0e6a43aafb422296d33baed255569a.tar.bz2
device property: Add support for remote endpoints
This follows DT implementation of of_graph_* APIs but we call them fwnode_graph_* instead. For DT nodes the existing of_graph_* implementation will be used. For ACPI we use the new ACPI graph implementation instead. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/property.c123
-rw-r--r--include/linux/property.h9
2 files changed, 132 insertions, 0 deletions
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 538b248d5dcf..4e98a6fad33f 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_graph.h>
#include <linux/property.h>
#include <linux/etherdevice.h>
#include <linux/phy.h>
@@ -1176,3 +1177,125 @@ void *device_get_mac_address(struct device *dev, char *addr, int alen)
return device_get_mac_addr(dev, "address", addr, alen);
}
EXPORT_SYMBOL(device_get_mac_address);
+
+/**
+ * device_graph_get_next_endpoint - Get next endpoint firmware node
+ * @fwnode: Pointer to the parent firmware node
+ * @prev: Previous endpoint node or %NULL to get the first
+ *
+ * Returns an endpoint firmware node pointer or %NULL if no more endpoints
+ * are available.
+ */
+struct fwnode_handle *
+fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
+ struct fwnode_handle *prev)
+{
+ struct fwnode_handle *endpoint = NULL;
+
+ if (is_of_node(fwnode)) {
+ struct device_node *node;
+
+ node = of_graph_get_next_endpoint(to_of_node(fwnode),
+ to_of_node(prev));
+
+ if (node)
+ endpoint = &node->fwnode;
+ } else if (is_acpi_node(fwnode)) {
+ endpoint = acpi_graph_get_next_endpoint(fwnode, prev);
+ if (IS_ERR(endpoint))
+ endpoint = NULL;
+ }
+
+ return endpoint;
+
+}
+EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
+
+/**
+ * fwnode_graph_get_remote_port_parent - Return fwnode of a remote device
+ * @fwnode: Endpoint firmware node pointing to the remote endpoint
+ *
+ * Extracts firmware node of a remote device the @fwnode points to.
+ */
+struct fwnode_handle *
+fwnode_graph_get_remote_port_parent(struct fwnode_handle *fwnode)
+{
+ struct fwnode_handle *parent = NULL;
+
+ if (is_of_node(fwnode)) {
+ struct device_node *node;
+
+ node = of_graph_get_remote_port_parent(to_of_node(fwnode));
+ if (node)
+ parent = &node->fwnode;
+ } else if (is_acpi_node(fwnode)) {
+ int ret;
+
+ ret = acpi_graph_get_remote_endpoint(fwnode, &parent, NULL,
+ NULL);
+ if (ret)
+ return NULL;
+ }
+
+ return parent;
+}
+EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port_parent);
+
+/**
+ * fwnode_graph_get_remote_port - Return fwnode of a remote port
+ * @fwnode: Endpoint firmware node pointing to the remote endpoint
+ *
+ * Extracts firmware node of a remote port the @fwnode points to.
+ */
+struct fwnode_handle *fwnode_graph_get_remote_port(struct fwnode_handle *fwnode)
+{
+ struct fwnode_handle *port = NULL;
+
+ if (is_of_node(fwnode)) {
+ struct device_node *node;
+
+ node = of_graph_get_remote_port(to_of_node(fwnode));
+ if (node)
+ port = &node->fwnode;
+ } else if (is_acpi_node(fwnode)) {
+ int ret;
+
+ ret = acpi_graph_get_remote_endpoint(fwnode, NULL, &port, NULL);
+ if (ret)
+ return NULL;
+ }
+
+ return port;
+}
+EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port);
+
+/**
+ * fwnode_graph_get_remote_endpoint - Return fwnode of a remote endpoint
+ * @fwnode: Endpoint firmware node pointing to the remote endpoint
+ *
+ * Extracts firmware node of a remote endpoint the @fwnode points to.
+ */
+struct fwnode_handle *
+fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
+{
+ struct fwnode_handle *endpoint = NULL;
+
+ if (is_of_node(fwnode)) {
+ struct device_node *node;
+
+ node = of_parse_phandle(to_of_node(fwnode), "remote-endpoint",
+ 0);
+ if (node)
+ endpoint = &node->fwnode;
+ } else if (is_acpi_node(fwnode)) {
+ int ret;
+
+ ret = acpi_graph_get_remote_endpoint(fwnode, NULL, NULL,
+ &endpoint);
+ if (ret)
+ return NULL;
+ }
+
+ return endpoint;
+}
+EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
diff --git a/include/linux/property.h b/include/linux/property.h
index 514b19559fbe..8d7809c2c42d 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -268,4 +268,13 @@ int device_get_phy_mode(struct device *dev);
void *device_get_mac_address(struct device *dev, char *addr, int alen);
+struct fwnode_handle *fwnode_graph_get_next_endpoint(
+ struct fwnode_handle *fwnode, struct fwnode_handle *prev);
+struct fwnode_handle *fwnode_graph_get_remote_port_parent(
+ struct fwnode_handle *fwnode);
+struct fwnode_handle *fwnode_graph_get_remote_port(
+ struct fwnode_handle *fwnode);
+struct fwnode_handle *fwnode_graph_get_remote_endpoint(
+ struct fwnode_handle *fwnode);
+
#endif /* _LINUX_PROPERTY_H_ */