From ce793486e23e0162a732c605189c8028e0910e86 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 16 Mar 2015 23:49:03 +0100 Subject: driver core / ACPI: Represent ACPI companions using fwnode_handle Now that we have struct fwnode_handle, we can use that to point to ACPI companions from struct device objects instead of pointing to struct acpi_device directly. There are two benefits from that. First, the somewhat ugly and hackish struct acpi_dev_node can be dropped and, second, the same struct fwnode_handle pointer can be used in the future to point to other (non-ACPI) firmware device node types. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Acked-by: Grant Likely --- drivers/base/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9421fed40905..17f0204fabef 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -454,7 +454,7 @@ struct platform_device *platform_device_register_full( goto err_alloc; pdev->dev.parent = pdevinfo->parent; - ACPI_COMPANION_SET(&pdev->dev, pdevinfo->acpi_node.companion); + pdev->dev.fwnode = pdevinfo->fwnode; if (pdevinfo->dma_mask) { /* -- cgit v1.2.3 From 5c0acf3b4f96abbd1fad40af7fdf0ed94cf523b7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 17 Mar 2015 09:58:58 +0200 Subject: driver core: Add comments about returning array counts The "read array" variants of the device property functions can be used to return the number of values in an array. Update the comments to reflect that. Signed-off-by: Adrian Hunter Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 53 +++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 21 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/property.c b/drivers/base/property.c index c45845874d4f..b524a4e42a83 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -62,13 +62,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_present); * device_property_read_u8_array - return a u8 array property of a device * @dev: Device to get the property of * @propname: Name of the property - * @val: The values are stored here + * @val: The values are stored here or %NULL to return the number of values * @nval: Size of the @val array * * Function reads an array of u8 properties with @propname from the device * firmware description and stores them to @val if found. * - * Return: %0 if the property was found (success), + * Return: number of values if @val was %NULL, + * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, @@ -85,13 +86,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array); * device_property_read_u16_array - return a u16 array property of a device * @dev: Device to get the property of * @propname: Name of the property - * @val: The values are stored here + * @val: The values are stored here or %NULL to return the number of values * @nval: Size of the @val array * * Function reads an array of u16 properties with @propname from the device * firmware description and stores them to @val if found. * - * Return: %0 if the property was found (success), + * Return: number of values if @val was %NULL, + * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, @@ -108,13 +110,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array); * device_property_read_u32_array - return a u32 array property of a device * @dev: Device to get the property of * @propname: Name of the property - * @val: The values are stored here + * @val: The values are stored here or %NULL to return the number of values * @nval: Size of the @val array * * Function reads an array of u32 properties with @propname from the device * firmware description and stores them to @val if found. * - * Return: %0 if the property was found (success), + * Return: number of values if @val was %NULL, + * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, @@ -131,13 +134,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array); * device_property_read_u64_array - return a u64 array property of a device * @dev: Device to get the property of * @propname: Name of the property - * @val: The values are stored here + * @val: The values are stored here or %NULL to return the number of values * @nval: Size of the @val array * * Function reads an array of u64 properties with @propname from the device * firmware description and stores them to @val if found. * - * Return: %0 if the property was found (success), + * Return: number of values if @val was %NULL, + * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, @@ -154,13 +158,14 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array); * device_property_read_string_array - return a string array property of device * @dev: Device to get the property of * @propname: Name of the property - * @val: The values are stored here + * @val: The values are stored here or %NULL to return the number of values * @nval: Size of the @val array * * Function reads an array of string properties with @propname from the device * firmware description and stores them to @val if found. * - * Return: %0 if the property was found (success), + * Return: number of values if @val was %NULL, + * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO or %-EILSEQ if the property is not an array of strings, @@ -170,7 +175,8 @@ int device_property_read_string_array(struct device *dev, const char *propname, const char **val, size_t nval) { return IS_ENABLED(CONFIG_OF) && dev->of_node ? - of_property_read_string_array(dev->of_node, propname, val, nval) : + (val ? of_property_read_string_array(dev->of_node, propname, val, nval) + : of_property_count_strings(dev->of_node, propname)) : acpi_dev_prop_read(ACPI_COMPANION(dev), propname, DEV_PROP_STRING, val, nval); } @@ -218,13 +224,14 @@ EXPORT_SYMBOL_GPL(device_property_read_string); * fwnode_property_read_u8_array - return a u8 array property of firmware node * @fwnode: Firmware node to get the property of * @propname: Name of the property - * @val: The values are stored here + * @val: The values are stored here or %NULL to return the number of values * @nval: Size of the @val array * * Read an array of u8 properties with @propname from @fwnode and stores them to * @val if found. * - * Return: %0 if the property was found (success), + * Return: number of values if @val was %NULL, + * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, @@ -243,13 +250,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array); * fwnode_property_read_u16_array - return a u16 array property of firmware node * @fwnode: Firmware node to get the property of * @propname: Name of the property - * @val: The values are stored here + * @val: The values are stored here or %NULL to return the number of values * @nval: Size of the @val array * * Read an array of u16 properties with @propname from @fwnode and store them to * @val if found. * - * Return: %0 if the property was found (success), + * Return: number of values if @val was %NULL, + * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, @@ -268,13 +276,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array); * fwnode_property_read_u32_array - return a u32 array property of firmware node * @fwnode: Firmware node to get the property of * @propname: Name of the property - * @val: The values are stored here + * @val: The values are stored here or %NULL to return the number of values * @nval: Size of the @val array * * Read an array of u32 properties with @propname from @fwnode store them to * @val if found. * - * Return: %0 if the property was found (success), + * Return: number of values if @val was %NULL, + * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, @@ -293,13 +302,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array); * fwnode_property_read_u64_array - return a u64 array property firmware node * @fwnode: Firmware node to get the property of * @propname: Name of the property - * @val: The values are stored here + * @val: The values are stored here or %NULL to return the number of values * @nval: Size of the @val array * * Read an array of u64 properties with @propname from @fwnode and store them to * @val if found. * - * Return: %0 if the property was found (success), + * Return: number of values if @val was %NULL, + * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, @@ -318,13 +328,14 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); * fwnode_property_read_string_array - return string array property of a node * @fwnode: Firmware node to get the property of * @propname: Name of the property - * @val: The values are stored here + * @val: The values are stored here or %NULL to return the number of values * @nval: Size of the @val array * * Read an string list property @propname from the given firmware node and store * them to @val if found. * - * Return: %0 if the property was found (success), + * Return: number of values if @val was %NULL, + * %0 if the property was found (success), * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of strings, -- cgit v1.2.3 From f42712a92e660fbee2193c5dde672470d099f63f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 24 Mar 2015 00:18:05 +0100 Subject: driver core: property: Update fwnode_property_read_string_array() Commit 5c0acf3b4f96 (driver core: Add comments about returning array counts) forgot to update fwnode_property_read_string_array() along the lines of device_property_read_string_array(), although it did change the kerneldoc comment of it. Fix that. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman --- drivers/base/property.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/property.c b/drivers/base/property.c index b524a4e42a83..cf3b2160e34e 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -347,8 +347,10 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode, size_t nval) { if (is_of_node(fwnode)) - return of_property_read_string_array(of_node(fwnode), propname, - val, nval); + return val ? + of_property_read_string_array(of_node(fwnode), propname, + val, nval) : + of_property_count_strings(of_node(fwnode), propname); else if (is_acpi_node(fwnode)) return acpi_dev_prop_read(acpi_node(fwnode), propname, DEV_PROP_STRING, val, nval); -- cgit v1.2.3 From 9017f25254e474f2cc05df489e4f83b972d3d6fd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 24 Mar 2015 00:24:16 +0100 Subject: driver core: Implement device property accessors through fwnode ones Now that the ACPI companions of devices are pointed to by the fwnode field in struct device, the device_property_*() accessor functions can be modified to use their fwnode_property_*() counterparts internally with minimum extra overhead in the IS_ENABLED(CONFIG_OF) case, so make those changes. This allows us to get rid of the rather ugly DEV_PROP_READ_ARRAY() macro among other things. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman --- drivers/base/property.c | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/property.c b/drivers/base/property.c index cf3b2160e34e..62787bc89a1d 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -15,6 +15,12 @@ #include #include +static inline struct fwnode_handle *dev_fwnode(struct device *dev) +{ + return IS_ENABLED(CONFIG_OF) && dev->of_node ? + &dev->of_node->fwnode : dev->fwnode; +} + /** * device_property_present - check if a property of a device is present * @dev: Device whose property is being checked @@ -24,10 +30,7 @@ */ bool device_property_present(struct device *dev, const char *propname) { - if (IS_ENABLED(CONFIG_OF) && dev->of_node) - return of_property_read_bool(dev->of_node, propname); - - return !acpi_dev_prop_get(ACPI_COMPANION(dev), propname, NULL); + return fwnode_property_present(dev_fwnode(dev), propname); } EXPORT_SYMBOL_GPL(device_property_present); @@ -47,17 +50,6 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) } EXPORT_SYMBOL_GPL(fwnode_property_present); -#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ - (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ - : of_property_count_elems_of_size((node), (propname), sizeof(type)) - -#define DEV_PROP_READ_ARRAY(_dev_, _propname_, _type_, _proptype_, _val_, _nval_) \ - IS_ENABLED(CONFIG_OF) && _dev_->of_node ? \ - (OF_DEV_PROP_READ_ARRAY(_dev_->of_node, _propname_, _type_, \ - _val_, _nval_)) : \ - acpi_dev_prop_read(ACPI_COMPANION(_dev_), _propname_, \ - _proptype_, _val_, _nval_) - /** * device_property_read_u8_array - return a u8 array property of a device * @dev: Device to get the property of @@ -78,7 +70,7 @@ EXPORT_SYMBOL_GPL(fwnode_property_present); int device_property_read_u8_array(struct device *dev, const char *propname, u8 *val, size_t nval) { - return DEV_PROP_READ_ARRAY(dev, propname, u8, DEV_PROP_U8, val, nval); + return fwnode_property_read_u8_array(dev_fwnode(dev), propname, val, nval); } EXPORT_SYMBOL_GPL(device_property_read_u8_array); @@ -102,7 +94,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array); int device_property_read_u16_array(struct device *dev, const char *propname, u16 *val, size_t nval) { - return DEV_PROP_READ_ARRAY(dev, propname, u16, DEV_PROP_U16, val, nval); + return fwnode_property_read_u16_array(dev_fwnode(dev), propname, val, nval); } EXPORT_SYMBOL_GPL(device_property_read_u16_array); @@ -126,7 +118,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array); int device_property_read_u32_array(struct device *dev, const char *propname, u32 *val, size_t nval) { - return DEV_PROP_READ_ARRAY(dev, propname, u32, DEV_PROP_U32, val, nval); + return fwnode_property_read_u32_array(dev_fwnode(dev), propname, val, nval); } EXPORT_SYMBOL_GPL(device_property_read_u32_array); @@ -150,7 +142,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array); int device_property_read_u64_array(struct device *dev, const char *propname, u64 *val, size_t nval) { - return DEV_PROP_READ_ARRAY(dev, propname, u64, DEV_PROP_U64, val, nval); + return fwnode_property_read_u64_array(dev_fwnode(dev), propname, val, nval); } EXPORT_SYMBOL_GPL(device_property_read_u64_array); @@ -174,11 +166,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array); int device_property_read_string_array(struct device *dev, const char *propname, const char **val, size_t nval) { - return IS_ENABLED(CONFIG_OF) && dev->of_node ? - (val ? of_property_read_string_array(dev->of_node, propname, val, nval) - : of_property_count_strings(dev->of_node, propname)) : - acpi_dev_prop_read(ACPI_COMPANION(dev), propname, - DEV_PROP_STRING, val, nval); + return fwnode_property_read_string_array(dev_fwnode(dev), propname, val, nval); } EXPORT_SYMBOL_GPL(device_property_read_string_array); @@ -199,13 +187,14 @@ EXPORT_SYMBOL_GPL(device_property_read_string_array); int device_property_read_string(struct device *dev, const char *propname, const char **val) { - return IS_ENABLED(CONFIG_OF) && dev->of_node ? - of_property_read_string(dev->of_node, propname, val) : - acpi_dev_prop_read(ACPI_COMPANION(dev), propname, - DEV_PROP_STRING, val, 1); + return fwnode_property_read_string(dev_fwnode(dev), propname, val); } EXPORT_SYMBOL_GPL(device_property_read_string); +#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ + (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ + : of_property_count_elems_of_size((node), (propname), sizeof(type)) + #define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ ({ \ int _ret_; \ -- cgit v1.2.3 From 97badf873ab60e841243b66133ff9eff2a46ef29 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 3 Apr 2015 23:23:37 +0200 Subject: device property: Make it possible to use secondary firmware nodes Add a secondary pointer to struct fwnode_handle so as to make it possible for a device to have two firmware nodes associated with it at the same time, for example, an ACPI node and a node with a set of properties provided by platform initialization code. In the future that will allow device property lookup to fall back from the primary firmware node to the secondary one if the given property is not present there to make it easier to provide defaults for device properties used by device drivers. Introduce two helper routines, set_primary_fwnode() and set_secondary_fwnode() allowing callers to add a primary/secondary firmware node to the given device in such a way that (1) If there's only one firmware node for that device, it will be pointed to by the device's firmware node pointer. (2) If both the primary and secondary firmware nodes are present, the primary one will be pointed to by the device's firmware node pointer, while the secondary one will be pointed to by the primary node's secondary pointer. (3) If one of these nodes is removed (by calling one of the new nelpers with NULL as the second argument), the other one will be preserved. Make ACPI use set_primary_fwnode() for attaching its firmware nodes to devices. Signed-off-by: Rafael J. Wysocki Tested-by: Heikki Krogerus Acked-by: Greg Kroah-Hartman --- drivers/base/core.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 4 ++-- include/linux/device.h | 3 +++ include/linux/fwnode.h | 1 + 4 files changed, 57 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/core.c b/drivers/base/core.c index 07304a3b9ee2..c7e2a9a70865 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -2133,3 +2134,53 @@ define_dev_printk_level(dev_notice, KERN_NOTICE); define_dev_printk_level(_dev_info, KERN_INFO); #endif + +static inline bool fwnode_is_primary(struct fwnode_handle *fwnode) +{ + return fwnode && !IS_ERR(fwnode->secondary); +} + +/** + * set_primary_fwnode - Change the primary firmware node of a given device. + * @dev: Device to handle. + * @fwnode: New primary firmware node of the device. + * + * Set the device's firmware node pointer to @fwnode, but if a secondary + * firmware node of the device is present, preserve it. + */ +void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode) +{ + if (fwnode) { + struct fwnode_handle *fn = dev->fwnode; + + if (fwnode_is_primary(fn)) + fn = fn->secondary; + + fwnode->secondary = fn; + dev->fwnode = fwnode; + } else { + dev->fwnode = fwnode_is_primary(dev->fwnode) ? + dev->fwnode->secondary : NULL; + } +} +EXPORT_SYMBOL_GPL(set_primary_fwnode); + +/** + * set_secondary_fwnode - Change the secondary firmware node of a given device. + * @dev: Device to handle. + * @fwnode: New secondary firmware node of the device. + * + * If a primary firmware node of the device is present, set its secondary + * pointer to @fwnode. Otherwise, set the device's firmware node pointer to + * @fwnode. + */ +void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode) +{ + if (fwnode) + fwnode->secondary = ERR_PTR(-ENODEV); + + if (fwnode_is_primary(dev->fwnode)) + dev->fwnode->secondary = fwnode; + else + dev->fwnode = fwnode; +} diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ec488d03b518..dd12127f171c 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -54,8 +54,8 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev) } #define ACPI_COMPANION(dev) acpi_node((dev)->fwnode) -#define ACPI_COMPANION_SET(dev, adev) (dev)->fwnode = (adev) ? \ - acpi_fwnode_handle(adev) : NULL +#define ACPI_COMPANION_SET(dev, adev) set_primary_fwnode(dev, (adev) ? \ + acpi_fwnode_handle(adev) : NULL) #define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev)) static inline bool has_acpi_companion(struct device *dev) diff --git a/include/linux/device.h b/include/linux/device.h index badef20b876a..324d02add7b4 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -940,6 +940,9 @@ extern void unlock_device_hotplug(void); extern int lock_device_hotplug_sysfs(void); extern int device_offline(struct device *dev); extern int device_online(struct device *dev); +extern void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode); +extern void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode); + /* * Root device objects for grouping under /sys/devices */ diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index 17bb5f039509..fc30b84b532a 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -20,6 +20,7 @@ enum fwnode_type { struct fwnode_handle { enum fwnode_type type; + struct fwnode_handle *secondary; }; #endif -- cgit v1.2.3 From 16ba08d5c9ec44f89ec03c67ecf7a9c5e2d204fd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 3 Apr 2015 16:05:11 +0200 Subject: device property: Introduce firmware node type for platform data Introduce data structures and code allowing "built-in" properties to be associated with devices in such a way that they will be used by the device_property_* API if no proper firmware node (neither DT nor ACPI) is present for the given device. Each property is to be represented by a property_entry structure. An array of property_entry structures (terminated with a null entry) can be pointed to by the properties field of struct property_set that can be added as a firmware node to a struct device using device_add_property_set(). That will cause the device_property_* API to use that property_set as the source of properties if the given device does not have a DT node or an ACPI companion device object associated with it. Signed-off-by: Rafael J. Wysocki Tested-by: Heikki Krogerus Acked-by: Greg Kroah-Hartman --- drivers/base/property.c | 98 +++++++++++++++++++++++++++++++++++++++++++++--- include/linux/fwnode.h | 1 + include/linux/property.h | 33 ++++++++++++++++ 3 files changed, 127 insertions(+), 5 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/property.c b/drivers/base/property.c index 62787bc89a1d..6a3f7d8af341 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -10,10 +10,96 @@ * published by the Free Software Foundation. */ -#include -#include #include +#include +#include #include +#include + +/** + * device_add_property_set - Add a collection of properties to a device object. + * @dev: Device to add properties to. + * @pset: Collection of properties to add. + * + * Associate a collection of device properties represented by @pset with @dev + * as its secondary firmware node. + */ +void device_add_property_set(struct device *dev, struct property_set *pset) +{ + if (pset) + pset->fwnode.type = FWNODE_PDATA; + + set_secondary_fwnode(dev, &pset->fwnode); +} +EXPORT_SYMBOL_GPL(device_add_property_set); + +static inline bool is_pset(struct fwnode_handle *fwnode) +{ + return fwnode && fwnode->type == FWNODE_PDATA; +} + +static inline struct property_set *to_pset(struct fwnode_handle *fwnode) +{ + return is_pset(fwnode) ? + container_of(fwnode, struct property_set, fwnode) : NULL; +} + +static struct property_entry *pset_prop_get(struct property_set *pset, + const char *name) +{ + struct property_entry *prop; + + if (!pset || !pset->properties) + return NULL; + + for (prop = pset->properties; prop->name; prop++) + if (!strcmp(name, prop->name)) + return prop; + + return NULL; +} + +static int pset_prop_read_array(struct property_set *pset, const char *name, + enum dev_prop_type type, void *val, size_t nval) +{ + struct property_entry *prop; + unsigned int item_size; + + prop = pset_prop_get(pset, name); + if (!prop) + return -ENODATA; + + if (prop->type != type) + return -EPROTO; + + if (!val) + return prop->nval; + + if (prop->nval < nval) + return -EOVERFLOW; + + switch (type) { + case DEV_PROP_U8: + item_size = sizeof(u8); + break; + case DEV_PROP_U16: + item_size = sizeof(u16); + break; + case DEV_PROP_U32: + item_size = sizeof(u32); + break; + case DEV_PROP_U64: + item_size = sizeof(u64); + break; + case DEV_PROP_STRING: + item_size = sizeof(const char *); + break; + default: + return -EINVAL; + } + memcpy(val, prop->value.raw_data, nval * item_size); + return 0; +} static inline struct fwnode_handle *dev_fwnode(struct device *dev) { @@ -46,7 +132,7 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) else if (is_acpi_node(fwnode)) return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL); - return false; + return !!pset_prop_get(to_pset(fwnode), propname); } EXPORT_SYMBOL_GPL(fwnode_property_present); @@ -205,7 +291,8 @@ EXPORT_SYMBOL_GPL(device_property_read_string); _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \ _proptype_, _val_, _nval_); \ else \ - _ret_ = -ENXIO; \ + _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \ + _proptype_, _val_, _nval_); \ _ret_; \ }) @@ -344,7 +431,8 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode, return acpi_dev_prop_read(acpi_node(fwnode), propname, DEV_PROP_STRING, val, nval); - return -ENXIO; + return pset_prop_read_array(to_pset(fwnode), propname, + DEV_PROP_STRING, val, nval); } EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index fc30b84b532a..0408545bce42 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -16,6 +16,7 @@ enum fwnode_type { FWNODE_INVALID = 0, FWNODE_OF, FWNODE_ACPI, + FWNODE_PDATA, }; struct fwnode_handle { diff --git a/include/linux/property.h b/include/linux/property.h index 31dfd3db35d6..de8bdf417a35 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -131,4 +131,37 @@ static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode, return fwnode_property_read_u64_array(fwnode, propname, val, 1); } +/** + * struct property_entry - "Built-in" device property representation. + * @name: Name of the property. + * @type: Type of the property. + * @nval: Number of items of type @type making up the value. + * @value: Value of the property (an array of @nval items of type @type). + */ +struct property_entry { + const char *name; + enum dev_prop_type type; + size_t nval; + union { + void *raw_data; + u8 *u8_data; + u16 *u16_data; + u32 *u32_data; + u64 *u64_data; + const char **str; + } value; +}; + +/** + * struct property_set - Collection of "built-in" device properties. + * @fwnode: Handle to be pointed to by the fwnode field of struct device. + * @properties: Array of properties terminated with a null entry. + */ +struct property_set { + struct fwnode_handle fwnode; + struct property_entry *properties; +}; + +void device_add_property_set(struct device *dev, struct property_set *pset); + #endif /* _LINUX_PROPERTY_H_ */ -- cgit v1.2.3