device property: Add support for remote endpoints
authorMika Westerberg <mika.westerberg@linux.intel.com>
Tue, 28 Mar 2017 07:52:21 +0000 (10:52 +0300)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 28 Mar 2017 22:00:28 +0000 (00:00 +0200)
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>
drivers/base/property.c
include/linux/property.h

index 538b248d5dcf5d4e351d0b82894539101f061293..4e98a6fad33fc812a9db005cce90d62e64a61fe8 100644 (file)
@@ -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);
index 514b19559fbe18354511725f73b50fdb0574870f..8d7809c2c42df7c62f994d5b5ef537f9c594027f 100644 (file)
@@ -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_ */