diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-10 18:23:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-10 18:23:45 -0400 |
commit | 548aa0e3c516d906dae5edb1fc9a1ad2e490120a (patch) | |
tree | 8ac109004d8e1a416b4ec62be795068ae02b8285 | |
parent | 322618684353315e14f586b33d8a016286ffa700 (diff) | |
parent | 6a71d8d77795e0f7d887baa95bfc0d1d2bc74899 (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.c | 4 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 2 | ||||
-rw-r--r-- | drivers/acpi/property.c | 117 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 10 | ||||
-rw-r--r-- | drivers/base/property.c | 348 | ||||
-rw-r--r-- | drivers/of/property.c | 148 | ||||
-rw-r--r-- | include/linux/acpi.h | 4 | ||||
-rw-r--r-- | include/linux/fwnode.h | 69 | ||||
-rw-r--r-- | include/linux/of.h | 2 | ||||
-rw-r--r-- | include/linux/property.h | 5 |
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); | |||
111 | void acpi_device_remove_files(struct acpi_device *dev); | 111 | void acpi_device_remove_files(struct acpi_device *dev); |
112 | void acpi_device_add_finalize(struct acpi_device *device); | 112 | void acpi_device_add_finalize(struct acpi_device *device); |
113 | void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); | 113 | void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); |
114 | bool acpi_device_is_present(struct acpi_device *adev); | 114 | bool acpi_device_is_present(const struct acpi_device *adev); |
115 | bool acpi_device_is_battery(struct acpi_device *adev); | 115 | bool acpi_device_is_battery(struct acpi_device *adev); |
116 | bool acpi_device_is_first_physical_node(struct acpi_device *adev, | 116 | bool 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 | |||
1124 | static 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 | |||
1132 | static 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 | |||
1138 | static 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 | |||
1165 | static 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 | |||
1173 | static struct fwnode_handle * | ||
1174 | acpi_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 | |||
1190 | static struct fwnode_handle * | ||
1191 | acpi_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 | |||
1203 | static struct fwnode_handle * | ||
1204 | acpi_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 | |||
1213 | static 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 | |||
1226 | const 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 | ||
1603 | bool acpi_device_is_present(struct acpi_device *adev) | 1604 | bool 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 | ||
1612 | static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, | 1609 | static 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 | } |
188 | EXPORT_SYMBOL_GPL(dev_fwnode); | 188 | EXPORT_SYMBOL_GPL(dev_fwnode); |
189 | 189 | ||
190 | static 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 | |||
196 | static 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 | |||
220 | static 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 | |||
228 | static 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 | } |
201 | EXPORT_SYMBOL_GPL(device_property_present); | 245 | EXPORT_SYMBOL_GPL(device_property_present); |
202 | 246 | ||
203 | static 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 | } |
230 | EXPORT_SYMBOL_GPL(fwnode_property_present); | 263 | EXPORT_SYMBOL_GPL(fwnode_property_present); |
@@ -398,42 +431,23 @@ int device_property_match_string(struct device *dev, const char *propname, | |||
398 | } | 431 | } |
399 | EXPORT_SYMBOL_GPL(device_property_match_string); | 432 | EXPORT_SYMBOL_GPL(device_property_match_string); |
400 | 433 | ||
401 | #define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ | 434 | static 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); | |||
456 | int fwnode_property_read_u8_array(struct fwnode_handle *fwnode, | 470 | int 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 | } |
462 | EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array); | 476 | EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array); |
463 | 477 | ||
@@ -482,8 +496,8 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array); | |||
482 | int fwnode_property_read_u16_array(struct fwnode_handle *fwnode, | 496 | int 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 | } |
488 | EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array); | 502 | EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array); |
489 | 503 | ||
@@ -508,8 +522,8 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array); | |||
508 | int fwnode_property_read_u32_array(struct fwnode_handle *fwnode, | 522 | int 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 | } |
514 | EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array); | 528 | EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array); |
515 | 529 | ||
@@ -534,29 +548,11 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array); | |||
534 | int fwnode_property_read_u64_array(struct fwnode_handle *fwnode, | 548 | int 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 | } |
540 | EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); | 554 | EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); |
541 | 555 | ||
542 | static 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 | } |
591 | EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); | 589 | EXPORT_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 | */ |
939 | struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode) | 938 | struct 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 | } |
955 | EXPORT_SYMBOL_GPL(fwnode_get_parent); | 942 | EXPORT_SYMBOL_GPL(fwnode_get_parent); |
956 | 943 | ||
@@ -962,18 +949,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_parent); | |||
962 | struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode, | 949 | struct 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 | } |
978 | EXPORT_SYMBOL_GPL(fwnode_get_next_child_node); | 954 | EXPORT_SYMBOL_GPL(fwnode_get_next_child_node); |
979 | 955 | ||
@@ -1005,23 +981,7 @@ EXPORT_SYMBOL_GPL(device_get_next_child_node); | |||
1005 | struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode, | 981 | struct 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 | } |
1026 | EXPORT_SYMBOL_GPL(fwnode_get_named_child_node); | 986 | EXPORT_SYMBOL_GPL(fwnode_get_named_child_node); |
1027 | 987 | ||
@@ -1043,8 +1003,7 @@ EXPORT_SYMBOL_GPL(device_get_named_child_node); | |||
1043 | */ | 1003 | */ |
1044 | void fwnode_handle_get(struct fwnode_handle *fwnode) | 1004 | void 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 | } |
1049 | EXPORT_SYMBOL_GPL(fwnode_handle_get); | 1008 | EXPORT_SYMBOL_GPL(fwnode_handle_get); |
1050 | 1009 | ||
@@ -1058,12 +1017,21 @@ EXPORT_SYMBOL_GPL(fwnode_handle_get); | |||
1058 | */ | 1017 | */ |
1059 | void fwnode_handle_put(struct fwnode_handle *fwnode) | 1018 | void 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 | } |
1064 | EXPORT_SYMBOL_GPL(fwnode_handle_put); | 1022 | EXPORT_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 | */ | ||
1028 | bool fwnode_device_is_available(struct fwnode_handle *fwnode) | ||
1029 | { | ||
1030 | return fwnode_call_int_op(fwnode, device_is_available); | ||
1031 | } | ||
1032 | EXPORT_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 * | |||
1198 | fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode, | 1166 | fwnode_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)) { | 1171 | EXPORT_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 | */ | ||
1179 | struct fwnode_handle * | ||
1180 | fwnode_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 | } |
1220 | EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint); | 1191 | EXPORT_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); | |||
1228 | struct fwnode_handle * | 1199 | struct fwnode_handle * |
1229 | fwnode_graph_get_remote_port_parent(struct fwnode_handle *fwnode) | 1200 | fwnode_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 | */ |
1258 | struct fwnode_handle *fwnode_graph_get_remote_port(struct fwnode_handle *fwnode) | 1219 | struct 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 | } |
1278 | EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port); | 1223 | EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port); |
1279 | 1224 | ||
@@ -1286,27 +1231,46 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port); | |||
1286 | struct fwnode_handle * | 1231 | struct fwnode_handle * |
1287 | fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode) | 1232 | fwnode_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 | } | ||
1236 | EXPORT_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 | */ | ||
1247 | struct 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 | } |
1309 | EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint); | 1273 | EXPORT_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); | |||
1320 | int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode, | 1284 | int 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 | } |
1341 | EXPORT_SYMBOL(fwnode_graph_parse_endpoint); | 1291 | EXPORT_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 | } |
806 | EXPORT_SYMBOL(of_graph_get_remote_node); | 806 | EXPORT_SYMBOL(of_graph_get_remote_node); |
807 | |||
808 | static void of_fwnode_get(struct fwnode_handle *fwnode) | ||
809 | { | ||
810 | of_node_get(to_of_node(fwnode)); | ||
811 | } | ||
812 | |||
813 | static void of_fwnode_put(struct fwnode_handle *fwnode) | ||
814 | { | ||
815 | of_node_put(to_of_node(fwnode)); | ||
816 | } | ||
817 | |||
818 | static bool of_fwnode_device_is_available(struct fwnode_handle *fwnode) | ||
819 | { | ||
820 | return of_device_is_available(to_of_node(fwnode)); | ||
821 | } | ||
822 | |||
823 | static 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 | |||
829 | static 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 | |||
854 | static 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 | |||
865 | static 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 | |||
870 | static struct fwnode_handle * | ||
871 | of_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 | |||
878 | static struct fwnode_handle * | ||
879 | of_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 | |||
892 | static struct fwnode_handle * | ||
893 | of_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 | |||
900 | static struct fwnode_handle * | ||
901 | of_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 | |||
907 | static struct fwnode_handle * | ||
908 | of_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 | |||
924 | static 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 | |||
940 | const 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 | |||
61 | extern const struct fwnode_operations acpi_fwnode_ops; | ||
62 | |||
60 | static inline struct fwnode_handle *acpi_alloc_fwnode_static(void) | 63 | static 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 | |||
15 | enum fwnode_type { | 17 | enum 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 | ||
27 | struct fwnode_operations; | ||
28 | |||
25 | struct fwnode_handle { | 29 | struct 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 | */ | ||
66 | struct 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 */ |
102 | extern struct kobj_type of_node_ktype; | 102 | extern struct kobj_type of_node_ktype; |
103 | extern const struct fwnode_operations of_fwnode_ops; | ||
103 | static inline void of_node_init(struct device_node *node) | 104 | static 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, | |||
51 | int device_property_match_string(struct device *dev, | 51 | int device_property_match_string(struct device *dev, |
52 | const char *propname, const char *string); | 52 | const char *propname, const char *string); |
53 | 53 | ||
54 | bool fwnode_device_is_available(struct fwnode_handle *fwnode); | ||
54 | bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname); | 55 | bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname); |
55 | int fwnode_property_read_u8_array(struct fwnode_handle *fwnode, | 56 | int 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 | ||
275 | struct fwnode_handle *fwnode_graph_get_next_endpoint( | 276 | struct 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); |
278 | struct fwnode_handle * | ||
279 | fwnode_graph_get_port_parent(struct fwnode_handle *fwnode); | ||
277 | struct fwnode_handle *fwnode_graph_get_remote_port_parent( | 280 | struct fwnode_handle *fwnode_graph_get_remote_port_parent( |
278 | struct fwnode_handle *fwnode); | 281 | struct fwnode_handle *fwnode); |
279 | struct fwnode_handle *fwnode_graph_get_remote_port( | 282 | struct fwnode_handle *fwnode_graph_get_remote_port( |
280 | struct fwnode_handle *fwnode); | 283 | struct fwnode_handle *fwnode); |
281 | struct fwnode_handle *fwnode_graph_get_remote_endpoint( | 284 | struct fwnode_handle *fwnode_graph_get_remote_endpoint( |
282 | struct fwnode_handle *fwnode); | 285 | struct fwnode_handle *fwnode); |
286 | struct fwnode_handle *fwnode_graph_get_remote_node(struct fwnode_handle *fwnode, | ||
287 | u32 port, u32 endpoint); | ||
283 | 288 | ||
284 | int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode, | 289 | int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode, |
285 | struct fwnode_endpoint *endpoint); | 290 | struct fwnode_endpoint *endpoint); |