Merge tag 'devprop-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Jul 2017 22:23:45 +0000 (15:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Jul 2017 22:23:45 +0000 (15:23 -0700)
Pull device properties framework updates from Rafael Wysocki:
 "These mostly rearrange the device properties core code and add a few
  helper functions to it as a foundation for future work.

  Specifics:

   - Rearrange the core device properties code by moving the code
     specific to each supported platform configuration framework (ACPI,
     DT and build-in) into a separate file (Sakari Ailus).

   - Add helper functions for accessing device properties in a
     firmware-agnostic way (Sakari Ailus, Kieran Bingham)"

* tag 'devprop-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  device property: Add fwnode_graph_get_port_parent
  device property: Add FW type agnostic fwnode_graph_get_remote_node
  device property: Introduce fwnode_device_is_available()
  device property: Move fwnode graph ops to firmware specific locations
  device property: Move FW type specific functionality to FW specific files
  ACPI: Constify argument to acpi_device_is_present()

drivers/acpi/device_pm.c
drivers/acpi/internal.h
drivers/acpi/property.c
drivers/acpi/scan.c
drivers/base/property.c
drivers/of/property.c
include/linux/acpi.h
include/linux/fwnode.h
include/linux/of.h
include/linux/property.h

index 28938b5a334e1297cfe230a8290b5cfb38a7f9e9..2ed6935d4483bb0139e1ed9cc4cf27854c328c0d 100644 (file)
@@ -262,8 +262,10 @@ int acpi_bus_init_power(struct acpi_device *device)
                return -EINVAL;
 
        device->power.state = ACPI_STATE_UNKNOWN;
-       if (!acpi_device_is_present(device))
+       if (!acpi_device_is_present(device)) {
+               device->flags.initialized = false;
                return -ENXIO;
+       }
 
        result = acpi_device_get_power(device, &state);
        if (result)
index be79f7db1850c10168dff094bb2e1030808bd257..9531d3276f652a14e5eb39d9e0cb8a0325353f72 100644 (file)
@@ -111,7 +111,7 @@ int acpi_device_setup_files(struct acpi_device *dev);
 void acpi_device_remove_files(struct acpi_device *dev);
 void acpi_device_add_finalize(struct acpi_device *device);
 void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
-bool acpi_device_is_present(struct acpi_device *adev);
+bool acpi_device_is_present(const struct acpi_device *adev);
 bool acpi_device_is_battery(struct acpi_device *adev);
 bool acpi_device_is_first_physical_node(struct acpi_device *adev,
                                        const struct device *dev);
index 9364398204e91b23958eef08d306771f7d4cbd92..917c789f953dfb280f6f00895ce1fcf7ae2484ec 100644 (file)
@@ -57,6 +57,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
 
        dn->name = link->package.elements[0].string.pointer;
        dn->fwnode.type = FWNODE_ACPI_DATA;
+       dn->fwnode.ops = &acpi_fwnode_ops;
        dn->parent = parent;
        INIT_LIST_HEAD(&dn->data.subnodes);
 
@@ -1119,3 +1120,119 @@ int acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode,
 
        return 0;
 }
+
+static bool acpi_fwnode_device_is_available(struct fwnode_handle *fwnode)
+{
+       if (!is_acpi_device_node(fwnode))
+               return false;
+
+       return acpi_device_is_present(to_acpi_device_node(fwnode));
+}
+
+static bool acpi_fwnode_property_present(struct fwnode_handle *fwnode,
+                                        const char *propname)
+{
+       return !acpi_node_prop_get(fwnode, propname, NULL);
+}
+
+static int acpi_fwnode_property_read_int_array(struct fwnode_handle *fwnode,
+                                              const char *propname,
+                                              unsigned int elem_size,
+                                              void *val, size_t nval)
+{
+       enum dev_prop_type type;
+
+       switch (elem_size) {
+       case sizeof(u8):
+               type = DEV_PROP_U8;
+               break;
+       case sizeof(u16):
+               type = DEV_PROP_U16;
+               break;
+       case sizeof(u32):
+               type = DEV_PROP_U32;
+               break;
+       case sizeof(u64):
+               type = DEV_PROP_U64;
+               break;
+       default:
+               return -ENXIO;
+       }
+
+       return acpi_node_prop_read(fwnode, propname, type, val, nval);
+}
+
+static int acpi_fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+                                                 const char *propname,
+                                                 const char **val, size_t nval)
+{
+       return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
+                                  val, nval);
+}
+
+static struct fwnode_handle *
+acpi_fwnode_get_named_child_node(struct fwnode_handle *fwnode,
+                                const char *childname)
+{
+       struct fwnode_handle *child;
+
+       /*
+        * Find first matching named child node of this fwnode.
+        * For ACPI this will be a data only sub-node.
+        */
+       fwnode_for_each_child_node(fwnode, child)
+               if (acpi_data_node_match(child, childname))
+                       return child;
+
+       return NULL;
+}
+
+static struct fwnode_handle *
+acpi_fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
+                                   struct fwnode_handle *prev)
+{
+       struct fwnode_handle *endpoint;
+
+       endpoint = acpi_graph_get_next_endpoint(fwnode, prev);
+       if (IS_ERR(endpoint))
+               return NULL;
+
+       return endpoint;
+}
+
+static struct fwnode_handle *
+acpi_fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
+{
+       struct fwnode_handle *endpoint = NULL;
+
+       acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, &endpoint);
+
+       return endpoint;
+}
+
+static int acpi_fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
+                                           struct fwnode_endpoint *endpoint)
+{
+       struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
+
+       endpoint->local_fwnode = fwnode;
+
+       fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
+       fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
+
+       return 0;
+}
+
+const struct fwnode_operations acpi_fwnode_ops = {
+       .device_is_available = acpi_fwnode_device_is_available,
+       .property_present = acpi_fwnode_property_present,
+       .property_read_int_array = acpi_fwnode_property_read_int_array,
+       .property_read_string_array = acpi_fwnode_property_read_string_array,
+       .get_parent = acpi_node_get_parent,
+       .get_next_child_node = acpi_get_next_subnode,
+       .get_named_child_node = acpi_fwnode_get_named_child_node,
+       .graph_get_next_endpoint = acpi_fwnode_graph_get_next_endpoint,
+       .graph_get_remote_endpoint = acpi_fwnode_graph_get_remote_endpoint,
+       .graph_get_port_parent = acpi_node_get_parent,
+       .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint,
+};
index 59ebbd5f7b835b1aa5d119930c65f34b57a0dedc..33897298f03e3ed680272ba6f4109077d434a0d8 100644 (file)
@@ -1468,6 +1468,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
        device->handle = handle;
        device->parent = acpi_bus_get_parent(handle);
        device->fwnode.type = FWNODE_ACPI;
+       device->fwnode.ops = &acpi_fwnode_ops;
        acpi_set_device_status(device, sta);
        acpi_device_get_busid(device);
        acpi_set_pnp_ids(handle, &device->pnp, type);
@@ -1600,13 +1601,9 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type,
        return 0;
 }
 
-bool acpi_device_is_present(struct acpi_device *adev)
+bool acpi_device_is_present(const struct acpi_device *adev)
 {
-       if (adev->status.present || adev->status.functional)
-               return true;
-
-       adev->flags.initialized = false;
-       return false;
+       return adev->status.present || adev->status.functional;
 }
 
 static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
@@ -1839,6 +1836,7 @@ static void acpi_bus_attach(struct acpi_device *device)
        acpi_bus_get_status(device);
        /* Skip devices that are not present. */
        if (!acpi_device_is_present(device)) {
+               device->flags.initialized = false;
                acpi_device_clear_enumerated(device);
                device->flags.power_manageable = 0;
                return;
index 149de311a10e63fc9636401771365684985f18a3..692007e5a94b10437a537440cc0b5a4f236772fd 100644 (file)
@@ -187,6 +187,50 @@ struct fwnode_handle *dev_fwnode(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(dev_fwnode);
 
+static bool pset_fwnode_property_present(struct fwnode_handle *fwnode,
+                                        const char *propname)
+{
+       return !!pset_prop_get(to_pset_node(fwnode), propname);
+}
+
+static int pset_fwnode_read_int_array(struct fwnode_handle *fwnode,
+                                     const char *propname,
+                                     unsigned int elem_size, void *val,
+                                     size_t nval)
+{
+       struct property_set *node = to_pset_node(fwnode);
+
+       if (!val)
+               return pset_prop_count_elems_of_size(node, propname, elem_size);
+
+       switch (elem_size) {
+       case sizeof(u8):
+               return pset_prop_read_u8_array(node, propname, val, nval);
+       case sizeof(u16):
+               return pset_prop_read_u16_array(node, propname, val, nval);
+       case sizeof(u32):
+               return pset_prop_read_u32_array(node, propname, val, nval);
+       case sizeof(u64):
+               return pset_prop_read_u64_array(node, propname, val, nval);
+       }
+
+       return -ENXIO;
+}
+
+static int pset_fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+                                                 const char *propname,
+                                                 const char **val, size_t nval)
+{
+       return pset_prop_read_string_array(to_pset_node(fwnode), propname,
+                                          val, nval);
+}
+
+static const struct fwnode_operations pset_fwnode_ops = {
+       .property_present = pset_fwnode_property_present,
+       .property_read_int_array = pset_fwnode_read_int_array,
+       .property_read_string_array = pset_fwnode_property_read_string_array,
+};
+
 /**
  * device_property_present - check if a property of a device is present
  * @dev: Device whose property is being checked
@@ -200,18 +244,6 @@ bool device_property_present(struct device *dev, const char *propname)
 }
 EXPORT_SYMBOL_GPL(device_property_present);
 
-static bool __fwnode_property_present(struct fwnode_handle *fwnode,
-                                     const char *propname)
-{
-       if (is_of_node(fwnode))
-               return of_property_read_bool(to_of_node(fwnode), propname);
-       else if (is_acpi_node(fwnode))
-               return !acpi_node_prop_get(fwnode, propname, NULL);
-       else if (is_pset_node(fwnode))
-               return !!pset_prop_get(to_pset_node(fwnode), propname);
-       return false;
-}
-
 /**
  * fwnode_property_present - check if a property of a firmware node is present
  * @fwnode: Firmware node whose property to check
@@ -221,10 +253,11 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
 {
        bool ret;
 
-       ret = __fwnode_property_present(fwnode, propname);
+       ret = fwnode_call_int_op(fwnode, property_present, propname);
        if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
            !IS_ERR_OR_NULL(fwnode->secondary))
-               ret = __fwnode_property_present(fwnode->secondary, propname);
+               ret = fwnode_call_int_op(fwnode->secondary, property_present,
+                                        propname);
        return ret;
 }
 EXPORT_SYMBOL_GPL(fwnode_property_present);
@@ -398,42 +431,23 @@ int device_property_match_string(struct device *dev, const char *propname,
 }
 EXPORT_SYMBOL_GPL(device_property_match_string);
 
-#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval)                                \
-       (val) ? of_property_read_##type##_array((node), (propname), (val), (nval))      \
-             : of_property_count_elems_of_size((node), (propname), sizeof(type))
-
-#define PSET_PROP_READ_ARRAY(node, propname, type, val, nval)                          \
-       (val) ? pset_prop_read_##type##_array((node), (propname), (val), (nval))        \
-             : pset_prop_count_elems_of_size((node), (propname), sizeof(type))
-
-#define FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_)      \
-({                                                                                     \
-       int _ret_;                                                                      \
-       if (is_of_node(_fwnode_))                                                       \
-               _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_,        \
-                                              _type_, _val_, _nval_);                  \
-       else if (is_acpi_node(_fwnode_))                                                \
-               _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_,           \
-                                           _val_, _nval_);                             \
-       else if (is_pset_node(_fwnode_))                                                \
-               _ret_ = PSET_PROP_READ_ARRAY(to_pset_node(_fwnode_), _propname_,        \
-                                            _type_, _val_, _nval_);                    \
-       else                                                                            \
-               _ret_ = -ENXIO;                                                         \
-       _ret_;                                                                          \
-})
-
-#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_)        \
-({                                                                                     \
-       int _ret_;                                                                      \
-       _ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_,              \
-                                _val_, _nval_);                                        \
-       if (_ret_ == -EINVAL && !IS_ERR_OR_NULL(_fwnode_) &&                            \
-           !IS_ERR_OR_NULL(_fwnode_->secondary))                                       \
-               _ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_,       \
-                               _proptype_, _val_, _nval_);                             \
-       _ret_;                                                                          \
-})
+static int fwnode_property_read_int_array(struct fwnode_handle *fwnode,
+                                         const char *propname,
+                                         unsigned int elem_size, void *val,
+                                         size_t nval)
+{
+       int ret;
+
+       ret = fwnode_call_int_op(fwnode, property_read_int_array, propname,
+                                elem_size, val, nval);
+       if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
+           !IS_ERR_OR_NULL(fwnode->secondary))
+               ret = fwnode_call_int_op(
+                       fwnode->secondary, property_read_int_array, propname,
+                       elem_size, val, nval);
+
+       return ret;
+}
 
 /**
  * fwnode_property_read_u8_array - return a u8 array property of firmware node
@@ -456,8 +470,8 @@ EXPORT_SYMBOL_GPL(device_property_match_string);
 int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
                                  const char *propname, u8 *val, size_t nval)
 {
-       return FWNODE_PROP_READ_ARRAY(fwnode, propname, u8, DEV_PROP_U8,
-                                     val, nval);
+       return fwnode_property_read_int_array(fwnode, propname, sizeof(u8),
+                                             val, nval);
 }
 EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
 
@@ -482,8 +496,8 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
 int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
                                   const char *propname, u16 *val, size_t nval)
 {
-       return FWNODE_PROP_READ_ARRAY(fwnode, propname, u16, DEV_PROP_U16,
-                                     val, nval);
+       return fwnode_property_read_int_array(fwnode, propname, sizeof(u16),
+                                             val, nval);
 }
 EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
 
@@ -508,8 +522,8 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
 int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
                                   const char *propname, u32 *val, size_t nval)
 {
-       return FWNODE_PROP_READ_ARRAY(fwnode, propname, u32, DEV_PROP_U32,
-                                     val, nval);
+       return fwnode_property_read_int_array(fwnode, propname, sizeof(u32),
+                                             val, nval);
 }
 EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
 
@@ -534,29 +548,11 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
 int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
                                   const char *propname, u64 *val, size_t nval)
 {
-       return FWNODE_PROP_READ_ARRAY(fwnode, propname, u64, DEV_PROP_U64,
-                                     val, nval);
+       return fwnode_property_read_int_array(fwnode, propname, sizeof(u64),
+                                             val, nval);
 }
 EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
 
-static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode,
-                                              const char *propname,
-                                              const char **val, size_t nval)
-{
-       if (is_of_node(fwnode))
-               return val ?
-                       of_property_read_string_array(to_of_node(fwnode),
-                                                     propname, val, nval) :
-                       of_property_count_strings(to_of_node(fwnode), propname);
-       else if (is_acpi_node(fwnode))
-               return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
-                                          val, nval);
-       else if (is_pset_node(fwnode))
-               return pset_prop_read_string_array(to_pset_node(fwnode),
-                                                  propname, val, nval);
-       return -ENXIO;
-}
-
 /**
  * fwnode_property_read_string_array - return string array property of a node
  * @fwnode: Firmware node to get the property of
@@ -581,11 +577,13 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
 {
        int ret;
 
-       ret = __fwnode_property_read_string_array(fwnode, propname, val, nval);
+       ret = fwnode_call_int_op(fwnode, property_read_string_array, propname,
+                                val, nval);
        if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
            !IS_ERR_OR_NULL(fwnode->secondary))
-               ret = __fwnode_property_read_string_array(fwnode->secondary,
-                                                         propname, val, nval);
+               ret = fwnode_call_int_op(fwnode->secondary,
+                                        property_read_string_array, propname,
+                                        val, nval);
        return ret;
 }
 EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
@@ -903,6 +901,7 @@ int device_add_properties(struct device *dev,
                return PTR_ERR(p);
 
        p->fwnode.type = FWNODE_PDATA;
+       p->fwnode.ops = &pset_fwnode_ops;
        set_secondary_fwnode(dev, &p->fwnode);
        return 0;
 }
@@ -938,19 +937,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
  */
 struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode)
 {
-       struct fwnode_handle *parent = NULL;
-
-       if (is_of_node(fwnode)) {
-               struct device_node *node;
-
-               node = of_get_parent(to_of_node(fwnode));
-               if (node)
-                       parent = &node->fwnode;
-       } else if (is_acpi_node(fwnode)) {
-               parent = acpi_node_get_parent(fwnode);
-       }
-
-       return parent;
+       return fwnode_call_ptr_op(fwnode, get_parent);
 }
 EXPORT_SYMBOL_GPL(fwnode_get_parent);
 
@@ -962,18 +949,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_parent);
 struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode,
                                                 struct fwnode_handle *child)
 {
-       if (is_of_node(fwnode)) {
-               struct device_node *node;
-
-               node = of_get_next_available_child(to_of_node(fwnode),
-                                                  to_of_node(child));
-               if (node)
-                       return &node->fwnode;
-       } else if (is_acpi_node(fwnode)) {
-               return acpi_get_next_subnode(fwnode, child);
-       }
-
-       return NULL;
+       return fwnode_call_ptr_op(fwnode, get_next_child_node, child);
 }
 EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
 
@@ -1005,23 +981,7 @@ EXPORT_SYMBOL_GPL(device_get_next_child_node);
 struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode,
                                                  const char *childname)
 {
-       struct fwnode_handle *child;
-
-       /*
-        * Find first matching named child node of this fwnode.
-        * For ACPI this will be a data only sub-node.
-        */
-       fwnode_for_each_child_node(fwnode, child) {
-               if (is_of_node(child)) {
-                       if (!of_node_cmp(to_of_node(child)->name, childname))
-                               return child;
-               } else if (is_acpi_data_node(child)) {
-                       if (acpi_data_node_match(child, childname))
-                               return child;
-               }
-       }
-
-       return NULL;
+       return fwnode_call_ptr_op(fwnode, get_named_child_node, childname);
 }
 EXPORT_SYMBOL_GPL(fwnode_get_named_child_node);
 
@@ -1043,8 +1003,7 @@ EXPORT_SYMBOL_GPL(device_get_named_child_node);
  */
 void fwnode_handle_get(struct fwnode_handle *fwnode)
 {
-       if (is_of_node(fwnode))
-               of_node_get(to_of_node(fwnode));
+       fwnode_call_void_op(fwnode, get);
 }
 EXPORT_SYMBOL_GPL(fwnode_handle_get);
 
@@ -1058,11 +1017,20 @@ EXPORT_SYMBOL_GPL(fwnode_handle_get);
  */
 void fwnode_handle_put(struct fwnode_handle *fwnode)
 {
-       if (is_of_node(fwnode))
-               of_node_put(to_of_node(fwnode));
+       fwnode_call_void_op(fwnode, put);
 }
 EXPORT_SYMBOL_GPL(fwnode_handle_put);
 
+/**
+ * fwnode_device_is_available - check if a device is available for use
+ * @fwnode: Pointer to the fwnode of the device.
+ */
+bool fwnode_device_is_available(struct fwnode_handle *fwnode)
+{
+       return fwnode_call_int_op(fwnode, device_is_available);
+}
+EXPORT_SYMBOL_GPL(fwnode_device_is_available);
+
 /**
  * device_get_child_node_count - return the number of child nodes for device
  * @dev: Device to cound the child nodes for
@@ -1198,26 +1166,29 @@ 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;
+       return fwnode_call_ptr_op(fwnode, graph_get_next_endpoint, prev);
+}
+EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
 
-               node = of_graph_get_next_endpoint(to_of_node(fwnode),
-                                                 to_of_node(prev));
+/**
+ * fwnode_graph_get_port_parent - Return the device fwnode of a port endpoint
+ * @endpoint: Endpoint firmware node of the port
+ *
+ * Return: the firmware node of the device the @endpoint belongs to.
+ */
+struct fwnode_handle *
+fwnode_graph_get_port_parent(struct fwnode_handle *endpoint)
+{
+       struct fwnode_handle *port, *parent;
 
-               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;
-       }
+       port = fwnode_get_parent(endpoint);
+       parent = fwnode_call_ptr_op(port, graph_get_port_parent);
 
-       return endpoint;
+       fwnode_handle_put(port);
 
+       return parent;
 }
-EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
+EXPORT_SYMBOL_GPL(fwnode_graph_get_port_parent);
 
 /**
  * fwnode_graph_get_remote_port_parent - Return fwnode of a remote device
@@ -1228,22 +1199,12 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
 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;
+       struct fwnode_handle *endpoint, *parent;
 
-               node = of_graph_get_remote_port_parent(to_of_node(fwnode));
-               if (node)
-                       parent = &node->fwnode;
-       } else if (is_acpi_node(fwnode)) {
-               int ret;
+       endpoint = fwnode_graph_get_remote_endpoint(fwnode);
+       parent = fwnode_graph_get_port_parent(endpoint);
 
-               ret = acpi_graph_get_remote_endpoint(fwnode, &parent, NULL,
-                                                    NULL);
-               if (ret)
-                       return NULL;
-       }
+       fwnode_handle_put(endpoint);
 
        return parent;
 }
@@ -1257,23 +1218,7 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port_parent);
  */
 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;
+       return fwnode_get_next_parent(fwnode_graph_get_remote_endpoint(fwnode));
 }
 EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port);
 
@@ -1286,27 +1231,46 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port);
 struct fwnode_handle *
 fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
 {
-       struct fwnode_handle *endpoint = NULL;
+       return fwnode_call_ptr_op(fwnode, graph_get_remote_endpoint);
+}
+EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
 
-       if (is_of_node(fwnode)) {
-               struct device_node *node;
+/**
+ * fwnode_graph_get_remote_node - get remote parent node for given port/endpoint
+ * @fwnode: pointer to parent fwnode_handle containing graph port/endpoint
+ * @port_id: identifier of the parent port node
+ * @endpoint_id: identifier of the endpoint node
+ *
+ * Return: Remote fwnode handle associated with remote endpoint node linked
+ *        to @node. Use fwnode_node_put() on it when done.
+ */
+struct fwnode_handle *fwnode_graph_get_remote_node(struct fwnode_handle *fwnode,
+                                                  u32 port_id, u32 endpoint_id)
+{
+       struct fwnode_handle *endpoint = NULL;
 
-               node = of_parse_phandle(to_of_node(fwnode), "remote-endpoint",
-                                       0);
-               if (node)
-                       endpoint = &node->fwnode;
-       } else if (is_acpi_node(fwnode)) {
+       while ((endpoint = fwnode_graph_get_next_endpoint(fwnode, endpoint))) {
+               struct fwnode_endpoint fwnode_ep;
+               struct fwnode_handle *remote;
                int ret;
 
-               ret = acpi_graph_get_remote_endpoint(fwnode, NULL, NULL,
-                                                    &endpoint);
-               if (ret)
+               ret = fwnode_graph_parse_endpoint(endpoint, &fwnode_ep);
+               if (ret < 0)
+                       continue;
+
+               if (fwnode_ep.port != port_id || fwnode_ep.id != endpoint_id)
+                       continue;
+
+               remote = fwnode_graph_get_remote_port_parent(endpoint);
+               if (!remote)
                        return NULL;
+
+               return fwnode_device_is_available(remote) ? remote : NULL;
        }
 
-       return endpoint;
+       return NULL;
 }
-EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
+EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node);
 
 /**
  * fwnode_graph_parse_endpoint - parse common endpoint node properties
@@ -1320,22 +1284,8 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
 int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
                                struct fwnode_endpoint *endpoint)
 {
-       struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
-
        memset(endpoint, 0, sizeof(*endpoint));
 
-       endpoint->local_fwnode = fwnode;
-
-       if (is_acpi_node(port_fwnode)) {
-               fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
-               fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
-       } else {
-               fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port);
-               fwnode_property_read_u32(fwnode, "reg", &endpoint->id);
-       }
-
-       fwnode_handle_put(port_fwnode);
-
-       return 0;
+       return fwnode_call_int_op(fwnode, graph_parse_endpoint, endpoint);
 }
 EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
index 07c7c36c5ca8a0d23eafbbc65909242b52585fe8..eda50b4be9349d26c5600a19426cdc1d7f7fe92b 100644 (file)
@@ -804,3 +804,151 @@ struct device_node *of_graph_get_remote_node(const struct device_node *node,
        return remote;
 }
 EXPORT_SYMBOL(of_graph_get_remote_node);
+
+static void of_fwnode_get(struct fwnode_handle *fwnode)
+{
+       of_node_get(to_of_node(fwnode));
+}
+
+static void of_fwnode_put(struct fwnode_handle *fwnode)
+{
+       of_node_put(to_of_node(fwnode));
+}
+
+static bool of_fwnode_device_is_available(struct fwnode_handle *fwnode)
+{
+       return of_device_is_available(to_of_node(fwnode));
+}
+
+static bool of_fwnode_property_present(struct fwnode_handle *fwnode,
+                                      const char *propname)
+{
+       return of_property_read_bool(to_of_node(fwnode), propname);
+}
+
+static int of_fwnode_property_read_int_array(struct fwnode_handle *fwnode,
+                                            const char *propname,
+                                            unsigned int elem_size, void *val,
+                                            size_t nval)
+{
+       struct device_node *node = to_of_node(fwnode);
+
+       if (!val)
+               return of_property_count_elems_of_size(node, propname,
+                                                      elem_size);
+
+       switch (elem_size) {
+       case sizeof(u8):
+               return of_property_read_u8_array(node, propname, val, nval);
+       case sizeof(u16):
+               return of_property_read_u16_array(node, propname, val, nval);
+       case sizeof(u32):
+               return of_property_read_u32_array(node, propname, val, nval);
+       case sizeof(u64):
+               return of_property_read_u64_array(node, propname, val, nval);
+       }
+
+       return -ENXIO;
+}
+
+static int of_fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+                                               const char *propname,
+                                               const char **val, size_t nval)
+{
+       struct device_node *node = to_of_node(fwnode);
+
+       return val ?
+               of_property_read_string_array(node, propname, val, nval) :
+               of_property_count_strings(node, propname);
+}
+
+static struct fwnode_handle *of_fwnode_get_parent(struct fwnode_handle *fwnode)
+{
+       return of_fwnode_handle(of_get_parent(to_of_node(fwnode)));
+}
+
+static struct fwnode_handle *
+of_fwnode_get_next_child_node(struct fwnode_handle *fwnode,
+                             struct fwnode_handle *child)
+{
+       return of_fwnode_handle(of_get_next_available_child(to_of_node(fwnode),
+                                                           to_of_node(child)));
+}
+
+static struct fwnode_handle *
+of_fwnode_get_named_child_node(struct fwnode_handle *fwnode,
+                              const char *childname)
+{
+       struct device_node *node = to_of_node(fwnode);
+       struct device_node *child;
+
+       for_each_available_child_of_node(node, child)
+               if (!of_node_cmp(child->name, childname))
+                       return of_fwnode_handle(child);
+
+       return NULL;
+}
+
+static struct fwnode_handle *
+of_fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
+                                 struct fwnode_handle *prev)
+{
+       return of_fwnode_handle(of_graph_get_next_endpoint(to_of_node(fwnode),
+                                                          to_of_node(prev)));
+}
+
+static struct fwnode_handle *
+of_fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
+{
+       return of_fwnode_handle(of_parse_phandle(to_of_node(fwnode),
+                                                "remote-endpoint", 0));
+}
+
+static struct fwnode_handle *
+of_fwnode_graph_get_port_parent(struct fwnode_handle *fwnode)
+{
+       struct device_node *np;
+
+       /* Get the parent of the port */
+       np = of_get_next_parent(to_of_node(fwnode));
+       if (!np)
+               return NULL;
+
+       /* Is this the "ports" node? If not, it's the port parent. */
+       if (of_node_cmp(np->name, "ports"))
+               return of_fwnode_handle(np);
+
+       return of_fwnode_handle(of_get_next_parent(np));
+}
+
+static int of_fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
+                                         struct fwnode_endpoint *endpoint)
+{
+       struct device_node *node = to_of_node(fwnode);
+       struct device_node *port_node = of_get_parent(node);
+
+       endpoint->local_fwnode = fwnode;
+
+       of_property_read_u32(port_node, "reg", &endpoint->port);
+       of_property_read_u32(node, "reg", &endpoint->id);
+
+       of_node_put(port_node);
+
+       return 0;
+}
+
+const struct fwnode_operations of_fwnode_ops = {
+       .get = of_fwnode_get,
+       .put = of_fwnode_put,
+       .device_is_available = of_fwnode_device_is_available,
+       .property_present = of_fwnode_property_present,
+       .property_read_int_array = of_fwnode_property_read_int_array,
+       .property_read_string_array = of_fwnode_property_read_string_array,
+       .get_parent = of_fwnode_get_parent,
+       .get_next_child_node = of_fwnode_get_next_child_node,
+       .get_named_child_node = of_fwnode_get_named_child_node,
+       .graph_get_next_endpoint = of_fwnode_graph_get_next_endpoint,
+       .graph_get_remote_endpoint = of_fwnode_graph_get_remote_endpoint,
+       .graph_get_port_parent = of_fwnode_graph_get_port_parent,
+       .graph_parse_endpoint = of_fwnode_graph_parse_endpoint,
+};
index 99f96df83dd8db2b09bad8735b29d2900f824e44..c749eef1daa1557910ec81c5f296dc907f5ccab2 100644 (file)
@@ -57,6 +57,9 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev)
        acpi_fwnode_handle(adev) : NULL)
 #define ACPI_HANDLE(dev)               acpi_device_handle(ACPI_COMPANION(dev))
 
+
+extern const struct fwnode_operations acpi_fwnode_ops;
+
 static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
 {
        struct fwnode_handle *fwnode;
@@ -66,6 +69,7 @@ static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
                return NULL;
 
        fwnode->type = FWNODE_ACPI_STATIC;
+       fwnode->ops = &acpi_fwnode_ops;
 
        return fwnode;
 }
index 3dff2398a5f0beb8cf0e5f4dd1d139bb727bf480..9ab37541918929d5d1db6b409615df305f07c727 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef _LINUX_FWNODE_H_
 #define _LINUX_FWNODE_H_
 
+#include <linux/types.h>
+
 enum fwnode_type {
        FWNODE_INVALID = 0,
        FWNODE_OF,
@@ -22,9 +24,12 @@ enum fwnode_type {
        FWNODE_IRQCHIP
 };
 
+struct fwnode_operations;
+
 struct fwnode_handle {
        enum fwnode_type type;
        struct fwnode_handle *secondary;
+       const struct fwnode_operations *ops;
 };
 
 /**
@@ -39,4 +44,68 @@ struct fwnode_endpoint {
        const struct fwnode_handle *local_fwnode;
 };
 
+/**
+ * struct fwnode_operations - Operations for fwnode interface
+ * @get: Get a reference to an fwnode.
+ * @put: Put a reference to an fwnode.
+ * @property_present: Return true if a property is present.
+ * @property_read_integer_array: Read an array of integer properties. Return
+ *                              zero on success, a negative error code
+ *                              otherwise.
+ * @property_read_string_array: Read an array of string properties. Return zero
+ *                             on success, a negative error code otherwise.
+ * @get_parent: Return the parent of an fwnode.
+ * @get_next_child_node: Return the next child node in an iteration.
+ * @get_named_child_node: Return a child node with a given name.
+ * @graph_get_next_endpoint: Return an endpoint node in an iteration.
+ * @graph_get_remote_endpoint: Return the remote endpoint node of a local
+ *                            endpoint node.
+ * @graph_get_port_parent: Return the parent node of a port node.
+ * @graph_parse_endpoint: Parse endpoint for port and endpoint id.
+ */
+struct fwnode_operations {
+       void (*get)(struct fwnode_handle *fwnode);
+       void (*put)(struct fwnode_handle *fwnode);
+       bool (*device_is_available)(struct fwnode_handle *fwnode);
+       bool (*property_present)(struct fwnode_handle *fwnode,
+                                const char *propname);
+       int (*property_read_int_array)(struct fwnode_handle *fwnode,
+                                      const char *propname,
+                                      unsigned int elem_size, void *val,
+                                      size_t nval);
+       int (*property_read_string_array)(struct fwnode_handle *fwnode_handle,
+                                         const char *propname,
+                                         const char **val, size_t nval);
+       struct fwnode_handle *(*get_parent)(struct fwnode_handle *fwnode);
+       struct fwnode_handle *
+       (*get_next_child_node)(struct fwnode_handle *fwnode,
+                              struct fwnode_handle *child);
+       struct fwnode_handle *
+       (*get_named_child_node)(struct fwnode_handle *fwnode, const char *name);
+       struct fwnode_handle *
+       (*graph_get_next_endpoint)(struct fwnode_handle *fwnode,
+                                  struct fwnode_handle *prev);
+       struct fwnode_handle *
+       (*graph_get_remote_endpoint)(struct fwnode_handle *fwnode);
+       struct fwnode_handle *
+       (*graph_get_port_parent)(struct fwnode_handle *fwnode);
+       int (*graph_parse_endpoint)(struct fwnode_handle *fwnode,
+                                   struct fwnode_endpoint *endpoint);
+};
+
+#define fwnode_has_op(fwnode, op)                              \
+       ((fwnode) && (fwnode)->ops && (fwnode)->ops->op)
+#define fwnode_call_int_op(fwnode, op, ...)                            \
+       (fwnode ? (fwnode_has_op(fwnode, op) ?                          \
+                  (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \
+        -EINVAL)
+#define fwnode_call_ptr_op(fwnode, op, ...)            \
+       (fwnode_has_op(fwnode, op) ?                    \
+        (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : NULL)
+#define fwnode_call_void_op(fwnode, op, ...)                           \
+       do {                                                            \
+               if (fwnode_has_op(fwnode, op))                          \
+                       (fwnode)->ops->op(fwnode, ## __VA_ARGS__);      \
+       } while (false)
+
 #endif
index fa089a2789a017f88adc95a49cafa18d161d2bc2..4a8a70916237ec1f9d1583d6cd69bf86f48102cc 100644 (file)
@@ -100,10 +100,12 @@ struct of_reconfig_data {
 
 /* initialize a node */
 extern struct kobj_type of_node_ktype;
+extern const struct fwnode_operations of_fwnode_ops;
 static inline void of_node_init(struct device_node *node)
 {
        kobject_init(&node->kobj, &of_node_ktype);
        node->fwnode.type = FWNODE_OF;
+       node->fwnode.ops = &of_fwnode_ops;
 }
 
 /* true when node is initialized */
index 2f482616a2f22e2e26192a0a47a1c1b22d2bf015..7e77039e6b81814357493bf02f5a47b47a6f7e8e 100644 (file)
@@ -51,6 +51,7 @@ int device_property_read_string(struct device *dev, const char *propname,
 int device_property_match_string(struct device *dev,
                                 const char *propname, const char *string);
 
+bool fwnode_device_is_available(struct fwnode_handle *fwnode);
 bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
 int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
                                  const char *propname, u8 *val,
@@ -274,12 +275,16 @@ 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_port_parent(struct fwnode_handle *fwnode);
 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);
+struct fwnode_handle *fwnode_graph_get_remote_node(struct fwnode_handle *fwnode,
+                                                  u32 port, u32 endpoint);
 
 int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
                                struct fwnode_endpoint *endpoint);