diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-04-03 10:05:11 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-04-03 17:23:51 -0400 |
commit | 16ba08d5c9ec44f89ec03c67ecf7a9c5e2d204fd (patch) | |
tree | 7a269ca24db329c53ada5e30fabc872d68c67164 | |
parent | 97badf873ab60e841243b66133ff9eff2a46ef29 (diff) |
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 <rafael.j.wysocki@intel.com>
Tested-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/base/property.c | 98 | ||||
-rw-r--r-- | include/linux/fwnode.h | 1 | ||||
-rw-r--r-- | include/linux/property.h | 33 |
3 files changed, 127 insertions, 5 deletions
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 @@ | |||
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/property.h> | ||
14 | #include <linux/export.h> | ||
15 | #include <linux/acpi.h> | 13 | #include <linux/acpi.h> |
14 | #include <linux/export.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/of.h> | 16 | #include <linux/of.h> |
17 | #include <linux/property.h> | ||
18 | |||
19 | /** | ||
20 | * device_add_property_set - Add a collection of properties to a device object. | ||
21 | * @dev: Device to add properties to. | ||
22 | * @pset: Collection of properties to add. | ||
23 | * | ||
24 | * Associate a collection of device properties represented by @pset with @dev | ||
25 | * as its secondary firmware node. | ||
26 | */ | ||
27 | void device_add_property_set(struct device *dev, struct property_set *pset) | ||
28 | { | ||
29 | if (pset) | ||
30 | pset->fwnode.type = FWNODE_PDATA; | ||
31 | |||
32 | set_secondary_fwnode(dev, &pset->fwnode); | ||
33 | } | ||
34 | EXPORT_SYMBOL_GPL(device_add_property_set); | ||
35 | |||
36 | static inline bool is_pset(struct fwnode_handle *fwnode) | ||
37 | { | ||
38 | return fwnode && fwnode->type == FWNODE_PDATA; | ||
39 | } | ||
40 | |||
41 | static inline struct property_set *to_pset(struct fwnode_handle *fwnode) | ||
42 | { | ||
43 | return is_pset(fwnode) ? | ||
44 | container_of(fwnode, struct property_set, fwnode) : NULL; | ||
45 | } | ||
46 | |||
47 | static struct property_entry *pset_prop_get(struct property_set *pset, | ||
48 | const char *name) | ||
49 | { | ||
50 | struct property_entry *prop; | ||
51 | |||
52 | if (!pset || !pset->properties) | ||
53 | return NULL; | ||
54 | |||
55 | for (prop = pset->properties; prop->name; prop++) | ||
56 | if (!strcmp(name, prop->name)) | ||
57 | return prop; | ||
58 | |||
59 | return NULL; | ||
60 | } | ||
61 | |||
62 | static int pset_prop_read_array(struct property_set *pset, const char *name, | ||
63 | enum dev_prop_type type, void *val, size_t nval) | ||
64 | { | ||
65 | struct property_entry *prop; | ||
66 | unsigned int item_size; | ||
67 | |||
68 | prop = pset_prop_get(pset, name); | ||
69 | if (!prop) | ||
70 | return -ENODATA; | ||
71 | |||
72 | if (prop->type != type) | ||
73 | return -EPROTO; | ||
74 | |||
75 | if (!val) | ||
76 | return prop->nval; | ||
77 | |||
78 | if (prop->nval < nval) | ||
79 | return -EOVERFLOW; | ||
80 | |||
81 | switch (type) { | ||
82 | case DEV_PROP_U8: | ||
83 | item_size = sizeof(u8); | ||
84 | break; | ||
85 | case DEV_PROP_U16: | ||
86 | item_size = sizeof(u16); | ||
87 | break; | ||
88 | case DEV_PROP_U32: | ||
89 | item_size = sizeof(u32); | ||
90 | break; | ||
91 | case DEV_PROP_U64: | ||
92 | item_size = sizeof(u64); | ||
93 | break; | ||
94 | case DEV_PROP_STRING: | ||
95 | item_size = sizeof(const char *); | ||
96 | break; | ||
97 | default: | ||
98 | return -EINVAL; | ||
99 | } | ||
100 | memcpy(val, prop->value.raw_data, nval * item_size); | ||
101 | return 0; | ||
102 | } | ||
17 | 103 | ||
18 | static inline struct fwnode_handle *dev_fwnode(struct device *dev) | 104 | static inline struct fwnode_handle *dev_fwnode(struct device *dev) |
19 | { | 105 | { |
@@ -46,7 +132,7 @@ bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) | |||
46 | else if (is_acpi_node(fwnode)) | 132 | else if (is_acpi_node(fwnode)) |
47 | return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL); | 133 | return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL); |
48 | 134 | ||
49 | return false; | 135 | return !!pset_prop_get(to_pset(fwnode), propname); |
50 | } | 136 | } |
51 | EXPORT_SYMBOL_GPL(fwnode_property_present); | 137 | EXPORT_SYMBOL_GPL(fwnode_property_present); |
52 | 138 | ||
@@ -205,7 +291,8 @@ EXPORT_SYMBOL_GPL(device_property_read_string); | |||
205 | _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \ | 291 | _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \ |
206 | _proptype_, _val_, _nval_); \ | 292 | _proptype_, _val_, _nval_); \ |
207 | else \ | 293 | else \ |
208 | _ret_ = -ENXIO; \ | 294 | _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \ |
295 | _proptype_, _val_, _nval_); \ | ||
209 | _ret_; \ | 296 | _ret_; \ |
210 | }) | 297 | }) |
211 | 298 | ||
@@ -344,7 +431,8 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode, | |||
344 | return acpi_dev_prop_read(acpi_node(fwnode), propname, | 431 | return acpi_dev_prop_read(acpi_node(fwnode), propname, |
345 | DEV_PROP_STRING, val, nval); | 432 | DEV_PROP_STRING, val, nval); |
346 | 433 | ||
347 | return -ENXIO; | 434 | return pset_prop_read_array(to_pset(fwnode), propname, |
435 | DEV_PROP_STRING, val, nval); | ||
348 | } | 436 | } |
349 | EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); | 437 | EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); |
350 | 438 | ||
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 { | |||
16 | FWNODE_INVALID = 0, | 16 | FWNODE_INVALID = 0, |
17 | FWNODE_OF, | 17 | FWNODE_OF, |
18 | FWNODE_ACPI, | 18 | FWNODE_ACPI, |
19 | FWNODE_PDATA, | ||
19 | }; | 20 | }; |
20 | 21 | ||
21 | struct fwnode_handle { | 22 | 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, | |||
131 | return fwnode_property_read_u64_array(fwnode, propname, val, 1); | 131 | return fwnode_property_read_u64_array(fwnode, propname, val, 1); |
132 | } | 132 | } |
133 | 133 | ||
134 | /** | ||
135 | * struct property_entry - "Built-in" device property representation. | ||
136 | * @name: Name of the property. | ||
137 | * @type: Type of the property. | ||
138 | * @nval: Number of items of type @type making up the value. | ||
139 | * @value: Value of the property (an array of @nval items of type @type). | ||
140 | */ | ||
141 | struct property_entry { | ||
142 | const char *name; | ||
143 | enum dev_prop_type type; | ||
144 | size_t nval; | ||
145 | union { | ||
146 | void *raw_data; | ||
147 | u8 *u8_data; | ||
148 | u16 *u16_data; | ||
149 | u32 *u32_data; | ||
150 | u64 *u64_data; | ||
151 | const char **str; | ||
152 | } value; | ||
153 | }; | ||
154 | |||
155 | /** | ||
156 | * struct property_set - Collection of "built-in" device properties. | ||
157 | * @fwnode: Handle to be pointed to by the fwnode field of struct device. | ||
158 | * @properties: Array of properties terminated with a null entry. | ||
159 | */ | ||
160 | struct property_set { | ||
161 | struct fwnode_handle fwnode; | ||
162 | struct property_entry *properties; | ||
163 | }; | ||
164 | |||
165 | void device_add_property_set(struct device *dev, struct property_set *pset); | ||
166 | |||
134 | #endif /* _LINUX_PROPERTY_H_ */ | 167 | #endif /* _LINUX_PROPERTY_H_ */ |