aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-10 18:23:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-10 18:23:45 -0400
commit548aa0e3c516d906dae5edb1fc9a1ad2e490120a (patch)
tree8ac109004d8e1a416b4ec62be795068ae02b8285
parent322618684353315e14f586b33d8a016286ffa700 (diff)
parent6a71d8d77795e0f7d887baa95bfc0d1d2bc74899 (diff)
Merge tag 'devprop-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
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()
-rw-r--r--drivers/acpi/device_pm.c4
-rw-r--r--drivers/acpi/internal.h2
-rw-r--r--drivers/acpi/property.c117
-rw-r--r--drivers/acpi/scan.c10
-rw-r--r--drivers/base/property.c348
-rw-r--r--drivers/of/property.c148
-rw-r--r--include/linux/acpi.h4
-rw-r--r--include/linux/fwnode.h69
-rw-r--r--include/linux/of.h2
-rw-r--r--include/linux/property.h5
10 files changed, 502 insertions, 207 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 28938b5a334e..2ed6935d4483 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -262,8 +262,10 @@ int acpi_bus_init_power(struct acpi_device *device)
262 return -EINVAL; 262 return -EINVAL;
263 263
264 device->power.state = ACPI_STATE_UNKNOWN; 264 device->power.state = ACPI_STATE_UNKNOWN;
265 if (!acpi_device_is_present(device)) 265 if (!acpi_device_is_present(device)) {
266 device->flags.initialized = false;
266 return -ENXIO; 267 return -ENXIO;
268 }
267 269
268 result = acpi_device_get_power(device, &state); 270 result = acpi_device_get_power(device, &state);
269 if (result) 271 if (result)
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index be79f7db1850..9531d3276f65 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -111,7 +111,7 @@ int acpi_device_setup_files(struct acpi_device *dev);
111void acpi_device_remove_files(struct acpi_device *dev); 111void acpi_device_remove_files(struct acpi_device *dev);
112void acpi_device_add_finalize(struct acpi_device *device); 112void acpi_device_add_finalize(struct acpi_device *device);
113void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); 113void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
114bool acpi_device_is_present(struct acpi_device *adev); 114bool acpi_device_is_present(const struct acpi_device *adev);
115bool acpi_device_is_battery(struct acpi_device *adev); 115bool acpi_device_is_battery(struct acpi_device *adev);
116bool acpi_device_is_first_physical_node(struct acpi_device *adev, 116bool acpi_device_is_first_physical_node(struct acpi_device *adev,
117 const struct device *dev); 117 const struct device *dev);
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 9364398204e9..917c789f953d 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -57,6 +57,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
57 57
58 dn->name = link->package.elements[0].string.pointer; 58 dn->name = link->package.elements[0].string.pointer;
59 dn->fwnode.type = FWNODE_ACPI_DATA; 59 dn->fwnode.type = FWNODE_ACPI_DATA;
60 dn->fwnode.ops = &acpi_fwnode_ops;
60 dn->parent = parent; 61 dn->parent = parent;
61 INIT_LIST_HEAD(&dn->data.subnodes); 62 INIT_LIST_HEAD(&dn->data.subnodes);
62 63
@@ -1119,3 +1120,119 @@ int acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode,
1119 1120
1120 return 0; 1121 return 0;
1121} 1122}
1123
1124static bool acpi_fwnode_device_is_available(struct fwnode_handle *fwnode)
1125{
1126 if (!is_acpi_device_node(fwnode))
1127 return false;
1128
1129 return acpi_device_is_present(to_acpi_device_node(fwnode));
1130}
1131
1132static bool acpi_fwnode_property_present(struct fwnode_handle *fwnode,
1133 const char *propname)
1134{
1135 return !acpi_node_prop_get(fwnode, propname, NULL);
1136}
1137
1138static int acpi_fwnode_property_read_int_array(struct fwnode_handle *fwnode,
1139 const char *propname,
1140 unsigned int elem_size,
1141 void *val, size_t nval)
1142{
1143 enum dev_prop_type type;
1144
1145 switch (elem_size) {
1146 case sizeof(u8):
1147 type = DEV_PROP_U8;
1148 break;
1149 case sizeof(u16):
1150 type = DEV_PROP_U16;
1151 break;
1152 case sizeof(u32):
1153 type = DEV_PROP_U32;
1154 break;
1155 case sizeof(u64):
1156 type = DEV_PROP_U64;
1157 break;
1158 default:
1159 return -ENXIO;
1160 }
1161
1162 return acpi_node_prop_read(fwnode, propname, type, val, nval);
1163}
1164
1165static int acpi_fwnode_property_read_string_array(struct fwnode_handle *fwnode,
1166 const char *propname,
1167 const char **val, size_t nval)
1168{
1169 return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
1170 val, nval);
1171}
1172
1173static struct fwnode_handle *
1174acpi_fwnode_get_named_child_node(struct fwnode_handle *fwnode,
1175 const char *childname)
1176{
1177 struct fwnode_handle *child;
1178
1179 /*
1180 * Find first matching named child node of this fwnode.
1181 * For ACPI this will be a data only sub-node.
1182 */
1183 fwnode_for_each_child_node(fwnode, child)
1184 if (acpi_data_node_match(child, childname))
1185 return child;
1186
1187 return NULL;
1188}
1189
1190static struct fwnode_handle *
1191acpi_fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
1192 struct fwnode_handle *prev)
1193{
1194 struct fwnode_handle *endpoint;
1195
1196 endpoint = acpi_graph_get_next_endpoint(fwnode, prev);
1197 if (IS_ERR(endpoint))
1198 return NULL;
1199
1200 return endpoint;
1201}
1202
1203static struct fwnode_handle *
1204acpi_fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
1205{
1206 struct fwnode_handle *endpoint = NULL;
1207
1208 acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, &endpoint);
1209
1210 return endpoint;
1211}
1212
1213static int acpi_fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
1214 struct fwnode_endpoint *endpoint)
1215{
1216 struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
1217
1218 endpoint->local_fwnode = fwnode;
1219
1220 fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
1221 fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
1222
1223 return 0;
1224}
1225
1226const struct fwnode_operations acpi_fwnode_ops = {
1227 .device_is_available = acpi_fwnode_device_is_available,
1228 .property_present = acpi_fwnode_property_present,
1229 .property_read_int_array = acpi_fwnode_property_read_int_array,
1230 .property_read_string_array = acpi_fwnode_property_read_string_array,
1231 .get_parent = acpi_node_get_parent,
1232 .get_next_child_node = acpi_get_next_subnode,
1233 .get_named_child_node = acpi_fwnode_get_named_child_node,
1234 .graph_get_next_endpoint = acpi_fwnode_graph_get_next_endpoint,
1235 .graph_get_remote_endpoint = acpi_fwnode_graph_get_remote_endpoint,
1236 .graph_get_port_parent = acpi_node_get_parent,
1237 .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint,
1238};
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 59ebbd5f7b83..33897298f03e 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1468,6 +1468,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
1468 device->handle = handle; 1468 device->handle = handle;
1469 device->parent = acpi_bus_get_parent(handle); 1469 device->parent = acpi_bus_get_parent(handle);
1470 device->fwnode.type = FWNODE_ACPI; 1470 device->fwnode.type = FWNODE_ACPI;
1471 device->fwnode.ops = &acpi_fwnode_ops;
1471 acpi_set_device_status(device, sta); 1472 acpi_set_device_status(device, sta);
1472 acpi_device_get_busid(device); 1473 acpi_device_get_busid(device);
1473 acpi_set_pnp_ids(handle, &device->pnp, type); 1474 acpi_set_pnp_ids(handle, &device->pnp, type);
@@ -1600,13 +1601,9 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type,
1600 return 0; 1601 return 0;
1601} 1602}
1602 1603
1603bool acpi_device_is_present(struct acpi_device *adev) 1604bool acpi_device_is_present(const struct acpi_device *adev)
1604{ 1605{
1605 if (adev->status.present || adev->status.functional) 1606 return adev->status.present || adev->status.functional;
1606 return true;
1607
1608 adev->flags.initialized = false;
1609 return false;
1610} 1607}
1611 1608
1612static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, 1609static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
@@ -1839,6 +1836,7 @@ static void acpi_bus_attach(struct acpi_device *device)
1839 acpi_bus_get_status(device); 1836 acpi_bus_get_status(device);
1840 /* Skip devices that are not present. */ 1837 /* Skip devices that are not present. */
1841 if (!acpi_device_is_present(device)) { 1838 if (!acpi_device_is_present(device)) {
1839 device->flags.initialized = false;
1842 acpi_device_clear_enumerated(device); 1840 acpi_device_clear_enumerated(device);
1843 device->flags.power_manageable = 0; 1841 device->flags.power_manageable = 0;
1844 return; 1842 return;
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 149de311a10e..692007e5a94b 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -187,6 +187,50 @@ struct fwnode_handle *dev_fwnode(struct device *dev)
187} 187}
188EXPORT_SYMBOL_GPL(dev_fwnode); 188EXPORT_SYMBOL_GPL(dev_fwnode);
189 189
190static bool pset_fwnode_property_present(struct fwnode_handle *fwnode,
191 const char *propname)
192{
193 return !!pset_prop_get(to_pset_node(fwnode), propname);
194}
195
196static int pset_fwnode_read_int_array(struct fwnode_handle *fwnode,
197 const char *propname,
198 unsigned int elem_size, void *val,
199 size_t nval)
200{
201 struct property_set *node = to_pset_node(fwnode);
202
203 if (!val)
204 return pset_prop_count_elems_of_size(node, propname, elem_size);
205
206 switch (elem_size) {
207 case sizeof(u8):
208 return pset_prop_read_u8_array(node, propname, val, nval);
209 case sizeof(u16):
210 return pset_prop_read_u16_array(node, propname, val, nval);
211 case sizeof(u32):
212 return pset_prop_read_u32_array(node, propname, val, nval);
213 case sizeof(u64):
214 return pset_prop_read_u64_array(node, propname, val, nval);
215 }
216
217 return -ENXIO;
218}
219
220static int pset_fwnode_property_read_string_array(struct fwnode_handle *fwnode,
221 const char *propname,
222 const char **val, size_t nval)
223{
224 return pset_prop_read_string_array(to_pset_node(fwnode), propname,
225 val, nval);
226}
227
228static const struct fwnode_operations pset_fwnode_ops = {
229 .property_present = pset_fwnode_property_present,
230 .property_read_int_array = pset_fwnode_read_int_array,
231 .property_read_string_array = pset_fwnode_property_read_string_array,
232};
233
190/** 234/**
191 * device_property_present - check if a property of a device is present 235 * device_property_present - check if a property of a device is present
192 * @dev: Device whose property is being checked 236 * @dev: Device whose property is being checked
@@ -200,18 +244,6 @@ bool device_property_present(struct device *dev, const char *propname)
200} 244}
201EXPORT_SYMBOL_GPL(device_property_present); 245EXPORT_SYMBOL_GPL(device_property_present);
202 246
203static bool __fwnode_property_present(struct fwnode_handle *fwnode,
204 const char *propname)
205{
206 if (is_of_node(fwnode))
207 return of_property_read_bool(to_of_node(fwnode), propname);
208 else if (is_acpi_node(fwnode))
209 return !acpi_node_prop_get(fwnode, propname, NULL);
210 else if (is_pset_node(fwnode))
211 return !!pset_prop_get(to_pset_node(fwnode), propname);
212 return false;
213}
214
215/** 247/**
216 * fwnode_property_present - check if a property of a firmware node is present 248 * fwnode_property_present - check if a property of a firmware node is present
217 * @fwnode: Firmware node whose property to check 249 * @fwnode: Firmware node whose property to check
@@ -221,10 +253,11 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
221{ 253{
222 bool ret; 254 bool ret;
223 255
224 ret = __fwnode_property_present(fwnode, propname); 256 ret = fwnode_call_int_op(fwnode, property_present, propname);
225 if (ret == false && !IS_ERR_OR_NULL(fwnode) && 257 if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
226 !IS_ERR_OR_NULL(fwnode->secondary)) 258 !IS_ERR_OR_NULL(fwnode->secondary))
227 ret = __fwnode_property_present(fwnode->secondary, propname); 259 ret = fwnode_call_int_op(fwnode->secondary, property_present,
260 propname);
228 return ret; 261 return ret;
229} 262}
230EXPORT_SYMBOL_GPL(fwnode_property_present); 263EXPORT_SYMBOL_GPL(fwnode_property_present);
@@ -398,42 +431,23 @@ int device_property_match_string(struct device *dev, const char *propname,
398} 431}
399EXPORT_SYMBOL_GPL(device_property_match_string); 432EXPORT_SYMBOL_GPL(device_property_match_string);
400 433
401#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ 434static int fwnode_property_read_int_array(struct fwnode_handle *fwnode,
402 (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ 435 const char *propname,
403 : of_property_count_elems_of_size((node), (propname), sizeof(type)) 436 unsigned int elem_size, void *val,
404 437 size_t nval)
405#define PSET_PROP_READ_ARRAY(node, propname, type, val, nval) \ 438{
406 (val) ? pset_prop_read_##type##_array((node), (propname), (val), (nval)) \ 439 int ret;
407 : pset_prop_count_elems_of_size((node), (propname), sizeof(type)) 440
408 441 ret = fwnode_call_int_op(fwnode, property_read_int_array, propname,
409#define FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ 442 elem_size, val, nval);
410({ \ 443 if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
411 int _ret_; \ 444 !IS_ERR_OR_NULL(fwnode->secondary))
412 if (is_of_node(_fwnode_)) \ 445 ret = fwnode_call_int_op(
413 _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \ 446 fwnode->secondary, property_read_int_array, propname,
414 _type_, _val_, _nval_); \ 447 elem_size, val, nval);
415 else if (is_acpi_node(_fwnode_)) \ 448
416 _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \ 449 return ret;
417 _val_, _nval_); \ 450}
418 else if (is_pset_node(_fwnode_)) \
419 _ret_ = PSET_PROP_READ_ARRAY(to_pset_node(_fwnode_), _propname_, \
420 _type_, _val_, _nval_); \
421 else \
422 _ret_ = -ENXIO; \
423 _ret_; \
424})
425
426#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
427({ \
428 int _ret_; \
429 _ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, \
430 _val_, _nval_); \
431 if (_ret_ == -EINVAL && !IS_ERR_OR_NULL(_fwnode_) && \
432 !IS_ERR_OR_NULL(_fwnode_->secondary)) \
433 _ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_, \
434 _proptype_, _val_, _nval_); \
435 _ret_; \
436})
437 451
438/** 452/**
439 * fwnode_property_read_u8_array - return a u8 array property of firmware node 453 * fwnode_property_read_u8_array - return a u8 array property of firmware node
@@ -456,8 +470,8 @@ EXPORT_SYMBOL_GPL(device_property_match_string);
456int fwnode_property_read_u8_array(struct fwnode_handle *fwnode, 470int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
457 const char *propname, u8 *val, size_t nval) 471 const char *propname, u8 *val, size_t nval)
458{ 472{
459 return FWNODE_PROP_READ_ARRAY(fwnode, propname, u8, DEV_PROP_U8, 473 return fwnode_property_read_int_array(fwnode, propname, sizeof(u8),
460 val, nval); 474 val, nval);
461} 475}
462EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array); 476EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
463 477
@@ -482,8 +496,8 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
482int fwnode_property_read_u16_array(struct fwnode_handle *fwnode, 496int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
483 const char *propname, u16 *val, size_t nval) 497 const char *propname, u16 *val, size_t nval)
484{ 498{
485 return FWNODE_PROP_READ_ARRAY(fwnode, propname, u16, DEV_PROP_U16, 499 return fwnode_property_read_int_array(fwnode, propname, sizeof(u16),
486 val, nval); 500 val, nval);
487} 501}
488EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array); 502EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
489 503
@@ -508,8 +522,8 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
508int fwnode_property_read_u32_array(struct fwnode_handle *fwnode, 522int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
509 const char *propname, u32 *val, size_t nval) 523 const char *propname, u32 *val, size_t nval)
510{ 524{
511 return FWNODE_PROP_READ_ARRAY(fwnode, propname, u32, DEV_PROP_U32, 525 return fwnode_property_read_int_array(fwnode, propname, sizeof(u32),
512 val, nval); 526 val, nval);
513} 527}
514EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array); 528EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
515 529
@@ -534,29 +548,11 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
534int fwnode_property_read_u64_array(struct fwnode_handle *fwnode, 548int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
535 const char *propname, u64 *val, size_t nval) 549 const char *propname, u64 *val, size_t nval)
536{ 550{
537 return FWNODE_PROP_READ_ARRAY(fwnode, propname, u64, DEV_PROP_U64, 551 return fwnode_property_read_int_array(fwnode, propname, sizeof(u64),
538 val, nval); 552 val, nval);
539} 553}
540EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); 554EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
541 555
542static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode,
543 const char *propname,
544 const char **val, size_t nval)
545{
546 if (is_of_node(fwnode))
547 return val ?
548 of_property_read_string_array(to_of_node(fwnode),
549 propname, val, nval) :
550 of_property_count_strings(to_of_node(fwnode), propname);
551 else if (is_acpi_node(fwnode))
552 return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
553 val, nval);
554 else if (is_pset_node(fwnode))
555 return pset_prop_read_string_array(to_pset_node(fwnode),
556 propname, val, nval);
557 return -ENXIO;
558}
559
560/** 556/**
561 * fwnode_property_read_string_array - return string array property of a node 557 * fwnode_property_read_string_array - return string array property of a node
562 * @fwnode: Firmware node to get the property of 558 * @fwnode: Firmware node to get the property of
@@ -581,11 +577,13 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
581{ 577{
582 int ret; 578 int ret;
583 579
584 ret = __fwnode_property_read_string_array(fwnode, propname, val, nval); 580 ret = fwnode_call_int_op(fwnode, property_read_string_array, propname,
581 val, nval);
585 if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) && 582 if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
586 !IS_ERR_OR_NULL(fwnode->secondary)) 583 !IS_ERR_OR_NULL(fwnode->secondary))
587 ret = __fwnode_property_read_string_array(fwnode->secondary, 584 ret = fwnode_call_int_op(fwnode->secondary,
588 propname, val, nval); 585 property_read_string_array, propname,
586 val, nval);
589 return ret; 587 return ret;
590} 588}
591EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); 589EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
@@ -903,6 +901,7 @@ int device_add_properties(struct device *dev,
903 return PTR_ERR(p); 901 return PTR_ERR(p);
904 902
905 p->fwnode.type = FWNODE_PDATA; 903 p->fwnode.type = FWNODE_PDATA;
904 p->fwnode.ops = &pset_fwnode_ops;
906 set_secondary_fwnode(dev, &p->fwnode); 905 set_secondary_fwnode(dev, &p->fwnode);
907 return 0; 906 return 0;
908} 907}
@@ -938,19 +937,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
938 */ 937 */
939struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode) 938struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode)
940{ 939{
941 struct fwnode_handle *parent = NULL; 940 return fwnode_call_ptr_op(fwnode, get_parent);
942
943 if (is_of_node(fwnode)) {
944 struct device_node *node;
945
946 node = of_get_parent(to_of_node(fwnode));
947 if (node)
948 parent = &node->fwnode;
949 } else if (is_acpi_node(fwnode)) {
950 parent = acpi_node_get_parent(fwnode);
951 }
952
953 return parent;
954} 941}
955EXPORT_SYMBOL_GPL(fwnode_get_parent); 942EXPORT_SYMBOL_GPL(fwnode_get_parent);
956 943
@@ -962,18 +949,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_parent);
962struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode, 949struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode,
963 struct fwnode_handle *child) 950 struct fwnode_handle *child)
964{ 951{
965 if (is_of_node(fwnode)) { 952 return fwnode_call_ptr_op(fwnode, get_next_child_node, child);
966 struct device_node *node;
967
968 node = of_get_next_available_child(to_of_node(fwnode),
969 to_of_node(child));
970 if (node)
971 return &node->fwnode;
972 } else if (is_acpi_node(fwnode)) {
973 return acpi_get_next_subnode(fwnode, child);
974 }
975
976 return NULL;
977} 953}
978EXPORT_SYMBOL_GPL(fwnode_get_next_child_node); 954EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
979 955
@@ -1005,23 +981,7 @@ EXPORT_SYMBOL_GPL(device_get_next_child_node);
1005struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode, 981struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode,
1006 const char *childname) 982 const char *childname)
1007{ 983{
1008 struct fwnode_handle *child; 984 return fwnode_call_ptr_op(fwnode, get_named_child_node, childname);
1009
1010 /*
1011 * Find first matching named child node of this fwnode.
1012 * For ACPI this will be a data only sub-node.
1013 */
1014 fwnode_for_each_child_node(fwnode, child) {
1015 if (is_of_node(child)) {
1016 if (!of_node_cmp(to_of_node(child)->name, childname))
1017 return child;
1018 } else if (is_acpi_data_node(child)) {
1019 if (acpi_data_node_match(child, childname))
1020 return child;
1021 }
1022 }
1023
1024 return NULL;
1025} 985}
1026EXPORT_SYMBOL_GPL(fwnode_get_named_child_node); 986EXPORT_SYMBOL_GPL(fwnode_get_named_child_node);
1027 987
@@ -1043,8 +1003,7 @@ EXPORT_SYMBOL_GPL(device_get_named_child_node);
1043 */ 1003 */
1044void fwnode_handle_get(struct fwnode_handle *fwnode) 1004void fwnode_handle_get(struct fwnode_handle *fwnode)
1045{ 1005{
1046 if (is_of_node(fwnode)) 1006 fwnode_call_void_op(fwnode, get);
1047 of_node_get(to_of_node(fwnode));
1048} 1007}
1049EXPORT_SYMBOL_GPL(fwnode_handle_get); 1008EXPORT_SYMBOL_GPL(fwnode_handle_get);
1050 1009
@@ -1058,12 +1017,21 @@ EXPORT_SYMBOL_GPL(fwnode_handle_get);
1058 */ 1017 */
1059void fwnode_handle_put(struct fwnode_handle *fwnode) 1018void fwnode_handle_put(struct fwnode_handle *fwnode)
1060{ 1019{
1061 if (is_of_node(fwnode)) 1020 fwnode_call_void_op(fwnode, put);
1062 of_node_put(to_of_node(fwnode));
1063} 1021}
1064EXPORT_SYMBOL_GPL(fwnode_handle_put); 1022EXPORT_SYMBOL_GPL(fwnode_handle_put);
1065 1023
1066/** 1024/**
1025 * fwnode_device_is_available - check if a device is available for use
1026 * @fwnode: Pointer to the fwnode of the device.
1027 */
1028bool fwnode_device_is_available(struct fwnode_handle *fwnode)
1029{
1030 return fwnode_call_int_op(fwnode, device_is_available);
1031}
1032EXPORT_SYMBOL_GPL(fwnode_device_is_available);
1033
1034/**
1067 * device_get_child_node_count - return the number of child nodes for device 1035 * device_get_child_node_count - return the number of child nodes for device
1068 * @dev: Device to cound the child nodes for 1036 * @dev: Device to cound the child nodes for
1069 */ 1037 */
@@ -1198,26 +1166,29 @@ struct fwnode_handle *
1198fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode, 1166fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
1199 struct fwnode_handle *prev) 1167 struct fwnode_handle *prev)
1200{ 1168{
1201 struct fwnode_handle *endpoint = NULL; 1169 return fwnode_call_ptr_op(fwnode, graph_get_next_endpoint, prev);
1202 1170}
1203 if (is_of_node(fwnode)) { 1171EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
1204 struct device_node *node;
1205 1172
1206 node = of_graph_get_next_endpoint(to_of_node(fwnode), 1173/**
1207 to_of_node(prev)); 1174 * fwnode_graph_get_port_parent - Return the device fwnode of a port endpoint
1175 * @endpoint: Endpoint firmware node of the port
1176 *
1177 * Return: the firmware node of the device the @endpoint belongs to.
1178 */
1179struct fwnode_handle *
1180fwnode_graph_get_port_parent(struct fwnode_handle *endpoint)
1181{
1182 struct fwnode_handle *port, *parent;
1208 1183
1209 if (node) 1184 port = fwnode_get_parent(endpoint);
1210 endpoint = &node->fwnode; 1185 parent = fwnode_call_ptr_op(port, graph_get_port_parent);
1211 } else if (is_acpi_node(fwnode)) {
1212 endpoint = acpi_graph_get_next_endpoint(fwnode, prev);
1213 if (IS_ERR(endpoint))
1214 endpoint = NULL;
1215 }
1216 1186
1217 return endpoint; 1187 fwnode_handle_put(port);
1218 1188
1189 return parent;
1219} 1190}
1220EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint); 1191EXPORT_SYMBOL_GPL(fwnode_graph_get_port_parent);
1221 1192
1222/** 1193/**
1223 * fwnode_graph_get_remote_port_parent - Return fwnode of a remote device 1194 * fwnode_graph_get_remote_port_parent - Return fwnode of a remote device
@@ -1228,22 +1199,12 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
1228struct fwnode_handle * 1199struct fwnode_handle *
1229fwnode_graph_get_remote_port_parent(struct fwnode_handle *fwnode) 1200fwnode_graph_get_remote_port_parent(struct fwnode_handle *fwnode)
1230{ 1201{
1231 struct fwnode_handle *parent = NULL; 1202 struct fwnode_handle *endpoint, *parent;
1232
1233 if (is_of_node(fwnode)) {
1234 struct device_node *node;
1235 1203
1236 node = of_graph_get_remote_port_parent(to_of_node(fwnode)); 1204 endpoint = fwnode_graph_get_remote_endpoint(fwnode);
1237 if (node) 1205 parent = fwnode_graph_get_port_parent(endpoint);
1238 parent = &node->fwnode;
1239 } else if (is_acpi_node(fwnode)) {
1240 int ret;
1241 1206
1242 ret = acpi_graph_get_remote_endpoint(fwnode, &parent, NULL, 1207 fwnode_handle_put(endpoint);
1243 NULL);
1244 if (ret)
1245 return NULL;
1246 }
1247 1208
1248 return parent; 1209 return parent;
1249} 1210}
@@ -1257,23 +1218,7 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port_parent);
1257 */ 1218 */
1258struct fwnode_handle *fwnode_graph_get_remote_port(struct fwnode_handle *fwnode) 1219struct fwnode_handle *fwnode_graph_get_remote_port(struct fwnode_handle *fwnode)
1259{ 1220{
1260 struct fwnode_handle *port = NULL; 1221 return fwnode_get_next_parent(fwnode_graph_get_remote_endpoint(fwnode));
1261
1262 if (is_of_node(fwnode)) {
1263 struct device_node *node;
1264
1265 node = of_graph_get_remote_port(to_of_node(fwnode));
1266 if (node)
1267 port = &node->fwnode;
1268 } else if (is_acpi_node(fwnode)) {
1269 int ret;
1270
1271 ret = acpi_graph_get_remote_endpoint(fwnode, NULL, &port, NULL);
1272 if (ret)
1273 return NULL;
1274 }
1275
1276 return port;
1277} 1222}
1278EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port); 1223EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port);
1279 1224
@@ -1286,27 +1231,46 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port);
1286struct fwnode_handle * 1231struct fwnode_handle *
1287fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode) 1232fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
1288{ 1233{
1289 struct fwnode_handle *endpoint = NULL; 1234 return fwnode_call_ptr_op(fwnode, graph_get_remote_endpoint);
1235}
1236EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
1290 1237
1291 if (is_of_node(fwnode)) { 1238/**
1292 struct device_node *node; 1239 * fwnode_graph_get_remote_node - get remote parent node for given port/endpoint
1240 * @fwnode: pointer to parent fwnode_handle containing graph port/endpoint
1241 * @port_id: identifier of the parent port node
1242 * @endpoint_id: identifier of the endpoint node
1243 *
1244 * Return: Remote fwnode handle associated with remote endpoint node linked
1245 * to @node. Use fwnode_node_put() on it when done.
1246 */
1247struct fwnode_handle *fwnode_graph_get_remote_node(struct fwnode_handle *fwnode,
1248 u32 port_id, u32 endpoint_id)
1249{
1250 struct fwnode_handle *endpoint = NULL;
1293 1251
1294 node = of_parse_phandle(to_of_node(fwnode), "remote-endpoint", 1252 while ((endpoint = fwnode_graph_get_next_endpoint(fwnode, endpoint))) {
1295 0); 1253 struct fwnode_endpoint fwnode_ep;
1296 if (node) 1254 struct fwnode_handle *remote;
1297 endpoint = &node->fwnode;
1298 } else if (is_acpi_node(fwnode)) {
1299 int ret; 1255 int ret;
1300 1256
1301 ret = acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, 1257 ret = fwnode_graph_parse_endpoint(endpoint, &fwnode_ep);
1302 &endpoint); 1258 if (ret < 0)
1303 if (ret) 1259 continue;
1260
1261 if (fwnode_ep.port != port_id || fwnode_ep.id != endpoint_id)
1262 continue;
1263
1264 remote = fwnode_graph_get_remote_port_parent(endpoint);
1265 if (!remote)
1304 return NULL; 1266 return NULL;
1267
1268 return fwnode_device_is_available(remote) ? remote : NULL;
1305 } 1269 }
1306 1270
1307 return endpoint; 1271 return NULL;
1308} 1272}
1309EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint); 1273EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node);
1310 1274
1311/** 1275/**
1312 * fwnode_graph_parse_endpoint - parse common endpoint node properties 1276 * fwnode_graph_parse_endpoint - parse common endpoint node properties
@@ -1320,22 +1284,8 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
1320int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode, 1284int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
1321 struct fwnode_endpoint *endpoint) 1285 struct fwnode_endpoint *endpoint)
1322{ 1286{
1323 struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
1324
1325 memset(endpoint, 0, sizeof(*endpoint)); 1287 memset(endpoint, 0, sizeof(*endpoint));
1326 1288
1327 endpoint->local_fwnode = fwnode; 1289 return fwnode_call_int_op(fwnode, graph_parse_endpoint, endpoint);
1328
1329 if (is_acpi_node(port_fwnode)) {
1330 fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
1331 fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
1332 } else {
1333 fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port);
1334 fwnode_property_read_u32(fwnode, "reg", &endpoint->id);
1335 }
1336
1337 fwnode_handle_put(port_fwnode);
1338
1339 return 0;
1340} 1290}
1341EXPORT_SYMBOL(fwnode_graph_parse_endpoint); 1291EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
diff --git a/drivers/of/property.c b/drivers/of/property.c
index 07c7c36c5ca8..eda50b4be934 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -804,3 +804,151 @@ struct device_node *of_graph_get_remote_node(const struct device_node *node,
804 return remote; 804 return remote;
805} 805}
806EXPORT_SYMBOL(of_graph_get_remote_node); 806EXPORT_SYMBOL(of_graph_get_remote_node);
807
808static void of_fwnode_get(struct fwnode_handle *fwnode)
809{
810 of_node_get(to_of_node(fwnode));
811}
812
813static void of_fwnode_put(struct fwnode_handle *fwnode)
814{
815 of_node_put(to_of_node(fwnode));
816}
817
818static bool of_fwnode_device_is_available(struct fwnode_handle *fwnode)
819{
820 return of_device_is_available(to_of_node(fwnode));
821}
822
823static bool of_fwnode_property_present(struct fwnode_handle *fwnode,
824 const char *propname)
825{
826 return of_property_read_bool(to_of_node(fwnode), propname);
827}
828
829static int of_fwnode_property_read_int_array(struct fwnode_handle *fwnode,
830 const char *propname,
831 unsigned int elem_size, void *val,
832 size_t nval)
833{
834 struct device_node *node = to_of_node(fwnode);
835
836 if (!val)
837 return of_property_count_elems_of_size(node, propname,
838 elem_size);
839
840 switch (elem_size) {
841 case sizeof(u8):
842 return of_property_read_u8_array(node, propname, val, nval);
843 case sizeof(u16):
844 return of_property_read_u16_array(node, propname, val, nval);
845 case sizeof(u32):
846 return of_property_read_u32_array(node, propname, val, nval);
847 case sizeof(u64):
848 return of_property_read_u64_array(node, propname, val, nval);
849 }
850
851 return -ENXIO;
852}
853
854static int of_fwnode_property_read_string_array(struct fwnode_handle *fwnode,
855 const char *propname,
856 const char **val, size_t nval)
857{
858 struct device_node *node = to_of_node(fwnode);
859
860 return val ?
861 of_property_read_string_array(node, propname, val, nval) :
862 of_property_count_strings(node, propname);
863}
864
865static struct fwnode_handle *of_fwnode_get_parent(struct fwnode_handle *fwnode)
866{
867 return of_fwnode_handle(of_get_parent(to_of_node(fwnode)));
868}
869
870static struct fwnode_handle *
871of_fwnode_get_next_child_node(struct fwnode_handle *fwnode,
872 struct fwnode_handle *child)
873{
874 return of_fwnode_handle(of_get_next_available_child(to_of_node(fwnode),
875 to_of_node(child)));
876}
877
878static struct fwnode_handle *
879of_fwnode_get_named_child_node(struct fwnode_handle *fwnode,
880 const char *childname)
881{
882 struct device_node *node = to_of_node(fwnode);
883 struct device_node *child;
884
885 for_each_available_child_of_node(node, child)
886 if (!of_node_cmp(child->name, childname))
887 return of_fwnode_handle(child);
888
889 return NULL;
890}
891
892static struct fwnode_handle *
893of_fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
894 struct fwnode_handle *prev)
895{
896 return of_fwnode_handle(of_graph_get_next_endpoint(to_of_node(fwnode),
897 to_of_node(prev)));
898}
899
900static struct fwnode_handle *
901of_fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
902{
903 return of_fwnode_handle(of_parse_phandle(to_of_node(fwnode),
904 "remote-endpoint", 0));
905}
906
907static struct fwnode_handle *
908of_fwnode_graph_get_port_parent(struct fwnode_handle *fwnode)
909{
910 struct device_node *np;
911
912 /* Get the parent of the port */
913 np = of_get_next_parent(to_of_node(fwnode));
914 if (!np)
915 return NULL;
916
917 /* Is this the "ports" node? If not, it's the port parent. */
918 if (of_node_cmp(np->name, "ports"))
919 return of_fwnode_handle(np);
920
921 return of_fwnode_handle(of_get_next_parent(np));
922}
923
924static int of_fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
925 struct fwnode_endpoint *endpoint)
926{
927 struct device_node *node = to_of_node(fwnode);
928 struct device_node *port_node = of_get_parent(node);
929
930 endpoint->local_fwnode = fwnode;
931
932 of_property_read_u32(port_node, "reg", &endpoint->port);
933 of_property_read_u32(node, "reg", &endpoint->id);
934
935 of_node_put(port_node);
936
937 return 0;
938}
939
940const struct fwnode_operations of_fwnode_ops = {
941 .get = of_fwnode_get,
942 .put = of_fwnode_put,
943 .device_is_available = of_fwnode_device_is_available,
944 .property_present = of_fwnode_property_present,
945 .property_read_int_array = of_fwnode_property_read_int_array,
946 .property_read_string_array = of_fwnode_property_read_string_array,
947 .get_parent = of_fwnode_get_parent,
948 .get_next_child_node = of_fwnode_get_next_child_node,
949 .get_named_child_node = of_fwnode_get_named_child_node,
950 .graph_get_next_endpoint = of_fwnode_graph_get_next_endpoint,
951 .graph_get_remote_endpoint = of_fwnode_graph_get_remote_endpoint,
952 .graph_get_port_parent = of_fwnode_graph_get_port_parent,
953 .graph_parse_endpoint = of_fwnode_graph_parse_endpoint,
954};
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 99f96df83dd8..c749eef1daa1 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -57,6 +57,9 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev)
57 acpi_fwnode_handle(adev) : NULL) 57 acpi_fwnode_handle(adev) : NULL)
58#define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev)) 58#define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev))
59 59
60
61extern const struct fwnode_operations acpi_fwnode_ops;
62
60static inline struct fwnode_handle *acpi_alloc_fwnode_static(void) 63static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
61{ 64{
62 struct fwnode_handle *fwnode; 65 struct fwnode_handle *fwnode;
@@ -66,6 +69,7 @@ static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
66 return NULL; 69 return NULL;
67 70
68 fwnode->type = FWNODE_ACPI_STATIC; 71 fwnode->type = FWNODE_ACPI_STATIC;
72 fwnode->ops = &acpi_fwnode_ops;
69 73
70 return fwnode; 74 return fwnode;
71} 75}
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 3dff2398a5f0..9ab375419189 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -12,6 +12,8 @@
12#ifndef _LINUX_FWNODE_H_ 12#ifndef _LINUX_FWNODE_H_
13#define _LINUX_FWNODE_H_ 13#define _LINUX_FWNODE_H_
14 14
15#include <linux/types.h>
16
15enum fwnode_type { 17enum fwnode_type {
16 FWNODE_INVALID = 0, 18 FWNODE_INVALID = 0,
17 FWNODE_OF, 19 FWNODE_OF,
@@ -22,9 +24,12 @@ enum fwnode_type {
22 FWNODE_IRQCHIP 24 FWNODE_IRQCHIP
23}; 25};
24 26
27struct fwnode_operations;
28
25struct fwnode_handle { 29struct fwnode_handle {
26 enum fwnode_type type; 30 enum fwnode_type type;
27 struct fwnode_handle *secondary; 31 struct fwnode_handle *secondary;
32 const struct fwnode_operations *ops;
28}; 33};
29 34
30/** 35/**
@@ -39,4 +44,68 @@ struct fwnode_endpoint {
39 const struct fwnode_handle *local_fwnode; 44 const struct fwnode_handle *local_fwnode;
40}; 45};
41 46
47/**
48 * struct fwnode_operations - Operations for fwnode interface
49 * @get: Get a reference to an fwnode.
50 * @put: Put a reference to an fwnode.
51 * @property_present: Return true if a property is present.
52 * @property_read_integer_array: Read an array of integer properties. Return
53 * zero on success, a negative error code
54 * otherwise.
55 * @property_read_string_array: Read an array of string properties. Return zero
56 * on success, a negative error code otherwise.
57 * @get_parent: Return the parent of an fwnode.
58 * @get_next_child_node: Return the next child node in an iteration.
59 * @get_named_child_node: Return a child node with a given name.
60 * @graph_get_next_endpoint: Return an endpoint node in an iteration.
61 * @graph_get_remote_endpoint: Return the remote endpoint node of a local
62 * endpoint node.
63 * @graph_get_port_parent: Return the parent node of a port node.
64 * @graph_parse_endpoint: Parse endpoint for port and endpoint id.
65 */
66struct fwnode_operations {
67 void (*get)(struct fwnode_handle *fwnode);
68 void (*put)(struct fwnode_handle *fwnode);
69 bool (*device_is_available)(struct fwnode_handle *fwnode);
70 bool (*property_present)(struct fwnode_handle *fwnode,
71 const char *propname);
72 int (*property_read_int_array)(struct fwnode_handle *fwnode,
73 const char *propname,
74 unsigned int elem_size, void *val,
75 size_t nval);
76 int (*property_read_string_array)(struct fwnode_handle *fwnode_handle,
77 const char *propname,
78 const char **val, size_t nval);
79 struct fwnode_handle *(*get_parent)(struct fwnode_handle *fwnode);
80 struct fwnode_handle *
81 (*get_next_child_node)(struct fwnode_handle *fwnode,
82 struct fwnode_handle *child);
83 struct fwnode_handle *
84 (*get_named_child_node)(struct fwnode_handle *fwnode, const char *name);
85 struct fwnode_handle *
86 (*graph_get_next_endpoint)(struct fwnode_handle *fwnode,
87 struct fwnode_handle *prev);
88 struct fwnode_handle *
89 (*graph_get_remote_endpoint)(struct fwnode_handle *fwnode);
90 struct fwnode_handle *
91 (*graph_get_port_parent)(struct fwnode_handle *fwnode);
92 int (*graph_parse_endpoint)(struct fwnode_handle *fwnode,
93 struct fwnode_endpoint *endpoint);
94};
95
96#define fwnode_has_op(fwnode, op) \
97 ((fwnode) && (fwnode)->ops && (fwnode)->ops->op)
98#define fwnode_call_int_op(fwnode, op, ...) \
99 (fwnode ? (fwnode_has_op(fwnode, op) ? \
100 (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \
101 -EINVAL)
102#define fwnode_call_ptr_op(fwnode, op, ...) \
103 (fwnode_has_op(fwnode, op) ? \
104 (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : NULL)
105#define fwnode_call_void_op(fwnode, op, ...) \
106 do { \
107 if (fwnode_has_op(fwnode, op)) \
108 (fwnode)->ops->op(fwnode, ## __VA_ARGS__); \
109 } while (false)
110
42#endif 111#endif
diff --git a/include/linux/of.h b/include/linux/of.h
index fa089a2789a0..4a8a70916237 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -100,10 +100,12 @@ struct of_reconfig_data {
100 100
101/* initialize a node */ 101/* initialize a node */
102extern struct kobj_type of_node_ktype; 102extern struct kobj_type of_node_ktype;
103extern const struct fwnode_operations of_fwnode_ops;
103static inline void of_node_init(struct device_node *node) 104static inline void of_node_init(struct device_node *node)
104{ 105{
105 kobject_init(&node->kobj, &of_node_ktype); 106 kobject_init(&node->kobj, &of_node_ktype);
106 node->fwnode.type = FWNODE_OF; 107 node->fwnode.type = FWNODE_OF;
108 node->fwnode.ops = &of_fwnode_ops;
107} 109}
108 110
109/* true when node is initialized */ 111/* true when node is initialized */
diff --git a/include/linux/property.h b/include/linux/property.h
index 2f482616a2f2..7e77039e6b81 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -51,6 +51,7 @@ int device_property_read_string(struct device *dev, const char *propname,
51int device_property_match_string(struct device *dev, 51int device_property_match_string(struct device *dev,
52 const char *propname, const char *string); 52 const char *propname, const char *string);
53 53
54bool fwnode_device_is_available(struct fwnode_handle *fwnode);
54bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname); 55bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
55int fwnode_property_read_u8_array(struct fwnode_handle *fwnode, 56int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
56 const char *propname, u8 *val, 57 const char *propname, u8 *val,
@@ -274,12 +275,16 @@ void *device_get_mac_address(struct device *dev, char *addr, int alen);
274 275
275struct fwnode_handle *fwnode_graph_get_next_endpoint( 276struct fwnode_handle *fwnode_graph_get_next_endpoint(
276 struct fwnode_handle *fwnode, struct fwnode_handle *prev); 277 struct fwnode_handle *fwnode, struct fwnode_handle *prev);
278struct fwnode_handle *
279fwnode_graph_get_port_parent(struct fwnode_handle *fwnode);
277struct fwnode_handle *fwnode_graph_get_remote_port_parent( 280struct fwnode_handle *fwnode_graph_get_remote_port_parent(
278 struct fwnode_handle *fwnode); 281 struct fwnode_handle *fwnode);
279struct fwnode_handle *fwnode_graph_get_remote_port( 282struct fwnode_handle *fwnode_graph_get_remote_port(
280 struct fwnode_handle *fwnode); 283 struct fwnode_handle *fwnode);
281struct fwnode_handle *fwnode_graph_get_remote_endpoint( 284struct fwnode_handle *fwnode_graph_get_remote_endpoint(
282 struct fwnode_handle *fwnode); 285 struct fwnode_handle *fwnode);
286struct fwnode_handle *fwnode_graph_get_remote_node(struct fwnode_handle *fwnode,
287 u32 port, u32 endpoint);
283 288
284int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode, 289int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
285 struct fwnode_endpoint *endpoint); 290 struct fwnode_endpoint *endpoint);