diff options
-rw-r--r-- | drivers/acpi/property.c | 10 | ||||
-rw-r--r-- | drivers/base/core.c | 5 | ||||
-rw-r--r-- | drivers/base/platform.c | 25 | ||||
-rw-r--r-- | drivers/base/property.c | 495 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-platdrv.c | 50 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss-acpi.c | 19 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss-pci.c | 44 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss.c | 16 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss.h | 2 | ||||
-rw-r--r-- | drivers/mfd/mfd-core.c | 7 | ||||
-rw-r--r-- | include/linux/mfd/core.h | 5 | ||||
-rw-r--r-- | include/linux/platform_device.h | 5 | ||||
-rw-r--r-- | include/linux/property.h | 107 |
13 files changed, 634 insertions, 156 deletions
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 88f4306744c0..2aee41655ce9 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c | |||
@@ -346,7 +346,7 @@ void acpi_free_properties(struct acpi_device *adev) | |||
346 | * | 346 | * |
347 | * Return: %0 if property with @name has been found (success), | 347 | * Return: %0 if property with @name has been found (success), |
348 | * %-EINVAL if the arguments are invalid, | 348 | * %-EINVAL if the arguments are invalid, |
349 | * %-ENODATA if the property doesn't exist, | 349 | * %-EINVAL if the property doesn't exist, |
350 | * %-EPROTO if the property value type doesn't match @type. | 350 | * %-EPROTO if the property value type doesn't match @type. |
351 | */ | 351 | */ |
352 | static int acpi_data_get_property(struct acpi_device_data *data, | 352 | static int acpi_data_get_property(struct acpi_device_data *data, |
@@ -360,7 +360,7 @@ static int acpi_data_get_property(struct acpi_device_data *data, | |||
360 | return -EINVAL; | 360 | return -EINVAL; |
361 | 361 | ||
362 | if (!data->pointer || !data->properties) | 362 | if (!data->pointer || !data->properties) |
363 | return -ENODATA; | 363 | return -EINVAL; |
364 | 364 | ||
365 | properties = data->properties; | 365 | properties = data->properties; |
366 | for (i = 0; i < properties->package.count; i++) { | 366 | for (i = 0; i < properties->package.count; i++) { |
@@ -375,13 +375,13 @@ static int acpi_data_get_property(struct acpi_device_data *data, | |||
375 | if (!strcmp(name, propname->string.pointer)) { | 375 | if (!strcmp(name, propname->string.pointer)) { |
376 | if (type != ACPI_TYPE_ANY && propvalue->type != type) | 376 | if (type != ACPI_TYPE_ANY && propvalue->type != type) |
377 | return -EPROTO; | 377 | return -EPROTO; |
378 | else if (obj) | 378 | if (obj) |
379 | *obj = propvalue; | 379 | *obj = propvalue; |
380 | 380 | ||
381 | return 0; | 381 | return 0; |
382 | } | 382 | } |
383 | } | 383 | } |
384 | return -ENODATA; | 384 | return -EINVAL; |
385 | } | 385 | } |
386 | 386 | ||
387 | /** | 387 | /** |
@@ -439,7 +439,7 @@ int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname, | |||
439 | * | 439 | * |
440 | * Return: %0 if array property (package) with @name has been found (success), | 440 | * Return: %0 if array property (package) with @name has been found (success), |
441 | * %-EINVAL if the arguments are invalid, | 441 | * %-EINVAL if the arguments are invalid, |
442 | * %-ENODATA if the property doesn't exist, | 442 | * %-EINVAL if the property doesn't exist, |
443 | * %-EPROTO if the property is not a package or the type of its elements | 443 | * %-EPROTO if the property is not a package or the type of its elements |
444 | * doesn't match @type. | 444 | * doesn't match @type. |
445 | */ | 445 | */ |
diff --git a/drivers/base/core.c b/drivers/base/core.c index b7d56c5ea3c6..0a8bdade53f2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -2261,7 +2261,10 @@ void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode) | |||
2261 | if (fwnode_is_primary(fn)) | 2261 | if (fwnode_is_primary(fn)) |
2262 | fn = fn->secondary; | 2262 | fn = fn->secondary; |
2263 | 2263 | ||
2264 | fwnode->secondary = fn; | 2264 | if (fn) { |
2265 | WARN_ON(fwnode->secondary); | ||
2266 | fwnode->secondary = fn; | ||
2267 | } | ||
2265 | dev->fwnode = fwnode; | 2268 | dev->fwnode = fwnode; |
2266 | } else { | 2269 | } else { |
2267 | dev->fwnode = fwnode_is_primary(dev->fwnode) ? | 2270 | dev->fwnode = fwnode_is_primary(dev->fwnode) ? |
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 1dd6d3bf1098..d77ed0c946dd 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/acpi.h> | 26 | #include <linux/acpi.h> |
27 | #include <linux/clk/clk-conf.h> | 27 | #include <linux/clk/clk-conf.h> |
28 | #include <linux/limits.h> | 28 | #include <linux/limits.h> |
29 | #include <linux/property.h> | ||
29 | 30 | ||
30 | #include "base.h" | 31 | #include "base.h" |
31 | #include "power/power.h" | 32 | #include "power/power.h" |
@@ -299,6 +300,22 @@ int platform_device_add_data(struct platform_device *pdev, const void *data, | |||
299 | EXPORT_SYMBOL_GPL(platform_device_add_data); | 300 | EXPORT_SYMBOL_GPL(platform_device_add_data); |
300 | 301 | ||
301 | /** | 302 | /** |
303 | * platform_device_add_properties - add built-in properties to a platform device | ||
304 | * @pdev: platform device to add properties to | ||
305 | * @pset: properties to add | ||
306 | * | ||
307 | * The function will take deep copy of the properties in @pset and attach | ||
308 | * the copy to the platform device. The memory associated with properties | ||
309 | * will be freed when the platform device is released. | ||
310 | */ | ||
311 | int platform_device_add_properties(struct platform_device *pdev, | ||
312 | const struct property_set *pset) | ||
313 | { | ||
314 | return device_add_property_set(&pdev->dev, pset); | ||
315 | } | ||
316 | EXPORT_SYMBOL_GPL(platform_device_add_properties); | ||
317 | |||
318 | /** | ||
302 | * platform_device_add - add a platform device to device hierarchy | 319 | * platform_device_add - add a platform device to device hierarchy |
303 | * @pdev: platform device we're adding | 320 | * @pdev: platform device we're adding |
304 | * | 321 | * |
@@ -409,6 +426,8 @@ void platform_device_del(struct platform_device *pdev) | |||
409 | if (r->parent) | 426 | if (r->parent) |
410 | release_resource(r); | 427 | release_resource(r); |
411 | } | 428 | } |
429 | |||
430 | device_remove_property_set(&pdev->dev); | ||
412 | } | 431 | } |
413 | } | 432 | } |
414 | EXPORT_SYMBOL_GPL(platform_device_del); | 433 | EXPORT_SYMBOL_GPL(platform_device_del); |
@@ -487,6 +506,12 @@ struct platform_device *platform_device_register_full( | |||
487 | if (ret) | 506 | if (ret) |
488 | goto err; | 507 | goto err; |
489 | 508 | ||
509 | if (pdevinfo->pset) { | ||
510 | ret = platform_device_add_properties(pdev, pdevinfo->pset); | ||
511 | if (ret) | ||
512 | goto err; | ||
513 | } | ||
514 | |||
490 | ret = platform_device_add(pdev); | 515 | ret = platform_device_add(pdev); |
491 | if (ret) { | 516 | if (ret) { |
492 | err: | 517 | err: |
diff --git a/drivers/base/property.c b/drivers/base/property.c index 1325ff225cc4..c359351d50f1 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c | |||
@@ -19,32 +19,14 @@ | |||
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/phy.h> | 20 | #include <linux/phy.h> |
21 | 21 | ||
22 | /** | 22 | static inline bool is_pset_node(struct fwnode_handle *fwnode) |
23 | * device_add_property_set - Add a collection of properties to a device object. | ||
24 | * @dev: Device to add properties to. | ||
25 | * @pset: Collection of properties to add. | ||
26 | * | ||
27 | * Associate a collection of device properties represented by @pset with @dev | ||
28 | * as its secondary firmware node. | ||
29 | */ | ||
30 | void device_add_property_set(struct device *dev, struct property_set *pset) | ||
31 | { | ||
32 | if (!pset) | ||
33 | return; | ||
34 | |||
35 | pset->fwnode.type = FWNODE_PDATA; | ||
36 | set_secondary_fwnode(dev, &pset->fwnode); | ||
37 | } | ||
38 | EXPORT_SYMBOL_GPL(device_add_property_set); | ||
39 | |||
40 | static inline bool is_pset(struct fwnode_handle *fwnode) | ||
41 | { | 23 | { |
42 | return fwnode && fwnode->type == FWNODE_PDATA; | 24 | return fwnode && fwnode->type == FWNODE_PDATA; |
43 | } | 25 | } |
44 | 26 | ||
45 | static inline struct property_set *to_pset(struct fwnode_handle *fwnode) | 27 | static inline struct property_set *to_pset_node(struct fwnode_handle *fwnode) |
46 | { | 28 | { |
47 | return is_pset(fwnode) ? | 29 | return is_pset_node(fwnode) ? |
48 | container_of(fwnode, struct property_set, fwnode) : NULL; | 30 | container_of(fwnode, struct property_set, fwnode) : NULL; |
49 | } | 31 | } |
50 | 32 | ||
@@ -63,45 +45,135 @@ static struct property_entry *pset_prop_get(struct property_set *pset, | |||
63 | return NULL; | 45 | return NULL; |
64 | } | 46 | } |
65 | 47 | ||
66 | static int pset_prop_read_array(struct property_set *pset, const char *name, | 48 | static void *pset_prop_find(struct property_set *pset, const char *propname, |
67 | enum dev_prop_type type, void *val, size_t nval) | 49 | size_t length) |
68 | { | 50 | { |
69 | struct property_entry *prop; | 51 | struct property_entry *prop; |
70 | unsigned int item_size; | 52 | void *pointer; |
71 | 53 | ||
72 | prop = pset_prop_get(pset, name); | 54 | prop = pset_prop_get(pset, propname); |
73 | if (!prop) | 55 | if (!prop) |
74 | return -ENODATA; | 56 | return ERR_PTR(-EINVAL); |
57 | if (prop->is_array) | ||
58 | pointer = prop->pointer.raw_data; | ||
59 | else | ||
60 | pointer = &prop->value.raw_data; | ||
61 | if (!pointer) | ||
62 | return ERR_PTR(-ENODATA); | ||
63 | if (length > prop->length) | ||
64 | return ERR_PTR(-EOVERFLOW); | ||
65 | return pointer; | ||
66 | } | ||
67 | |||
68 | static int pset_prop_read_u8_array(struct property_set *pset, | ||
69 | const char *propname, | ||
70 | u8 *values, size_t nval) | ||
71 | { | ||
72 | void *pointer; | ||
73 | size_t length = nval * sizeof(*values); | ||
74 | |||
75 | pointer = pset_prop_find(pset, propname, length); | ||
76 | if (IS_ERR(pointer)) | ||
77 | return PTR_ERR(pointer); | ||
78 | |||
79 | memcpy(values, pointer, length); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int pset_prop_read_u16_array(struct property_set *pset, | ||
84 | const char *propname, | ||
85 | u16 *values, size_t nval) | ||
86 | { | ||
87 | void *pointer; | ||
88 | size_t length = nval * sizeof(*values); | ||
89 | |||
90 | pointer = pset_prop_find(pset, propname, length); | ||
91 | if (IS_ERR(pointer)) | ||
92 | return PTR_ERR(pointer); | ||
93 | |||
94 | memcpy(values, pointer, length); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int pset_prop_read_u32_array(struct property_set *pset, | ||
99 | const char *propname, | ||
100 | u32 *values, size_t nval) | ||
101 | { | ||
102 | void *pointer; | ||
103 | size_t length = nval * sizeof(*values); | ||
104 | |||
105 | pointer = pset_prop_find(pset, propname, length); | ||
106 | if (IS_ERR(pointer)) | ||
107 | return PTR_ERR(pointer); | ||
108 | |||
109 | memcpy(values, pointer, length); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int pset_prop_read_u64_array(struct property_set *pset, | ||
114 | const char *propname, | ||
115 | u64 *values, size_t nval) | ||
116 | { | ||
117 | void *pointer; | ||
118 | size_t length = nval * sizeof(*values); | ||
119 | |||
120 | pointer = pset_prop_find(pset, propname, length); | ||
121 | if (IS_ERR(pointer)) | ||
122 | return PTR_ERR(pointer); | ||
123 | |||
124 | memcpy(values, pointer, length); | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int pset_prop_count_elems_of_size(struct property_set *pset, | ||
129 | const char *propname, size_t length) | ||
130 | { | ||
131 | struct property_entry *prop; | ||
132 | |||
133 | prop = pset_prop_get(pset, propname); | ||
134 | if (!prop) | ||
135 | return -EINVAL; | ||
136 | |||
137 | return prop->length / length; | ||
138 | } | ||
139 | |||
140 | static int pset_prop_read_string_array(struct property_set *pset, | ||
141 | const char *propname, | ||
142 | const char **strings, size_t nval) | ||
143 | { | ||
144 | void *pointer; | ||
145 | size_t length = nval * sizeof(*strings); | ||
146 | |||
147 | pointer = pset_prop_find(pset, propname, length); | ||
148 | if (IS_ERR(pointer)) | ||
149 | return PTR_ERR(pointer); | ||
150 | |||
151 | memcpy(strings, pointer, length); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static int pset_prop_read_string(struct property_set *pset, | ||
156 | const char *propname, const char **strings) | ||
157 | { | ||
158 | struct property_entry *prop; | ||
159 | const char **pointer; | ||
75 | 160 | ||
76 | if (prop->type != type) | 161 | prop = pset_prop_get(pset, propname); |
77 | return -EPROTO; | 162 | if (!prop) |
78 | |||
79 | if (!val) | ||
80 | return prop->nval; | ||
81 | |||
82 | if (prop->nval < nval) | ||
83 | return -EOVERFLOW; | ||
84 | |||
85 | switch (type) { | ||
86 | case DEV_PROP_U8: | ||
87 | item_size = sizeof(u8); | ||
88 | break; | ||
89 | case DEV_PROP_U16: | ||
90 | item_size = sizeof(u16); | ||
91 | break; | ||
92 | case DEV_PROP_U32: | ||
93 | item_size = sizeof(u32); | ||
94 | break; | ||
95 | case DEV_PROP_U64: | ||
96 | item_size = sizeof(u64); | ||
97 | break; | ||
98 | case DEV_PROP_STRING: | ||
99 | item_size = sizeof(const char *); | ||
100 | break; | ||
101 | default: | ||
102 | return -EINVAL; | 163 | return -EINVAL; |
164 | if (!prop->is_string) | ||
165 | return -EILSEQ; | ||
166 | if (prop->is_array) { | ||
167 | pointer = prop->pointer.str; | ||
168 | if (!pointer) | ||
169 | return -ENODATA; | ||
170 | } else { | ||
171 | pointer = &prop->value.str; | ||
172 | if (*pointer && strnlen(*pointer, prop->length) >= prop->length) | ||
173 | return -EILSEQ; | ||
103 | } | 174 | } |
104 | memcpy(val, prop->value.raw_data, nval * item_size); | 175 | |
176 | *strings = *pointer; | ||
105 | return 0; | 177 | return 0; |
106 | } | 178 | } |
107 | 179 | ||
@@ -124,6 +196,18 @@ bool device_property_present(struct device *dev, const char *propname) | |||
124 | } | 196 | } |
125 | EXPORT_SYMBOL_GPL(device_property_present); | 197 | EXPORT_SYMBOL_GPL(device_property_present); |
126 | 198 | ||
199 | static bool __fwnode_property_present(struct fwnode_handle *fwnode, | ||
200 | const char *propname) | ||
201 | { | ||
202 | if (is_of_node(fwnode)) | ||
203 | return of_property_read_bool(to_of_node(fwnode), propname); | ||
204 | else if (is_acpi_node(fwnode)) | ||
205 | return !acpi_node_prop_get(fwnode, propname, NULL); | ||
206 | else if (is_pset_node(fwnode)) | ||
207 | return !!pset_prop_get(to_pset_node(fwnode), propname); | ||
208 | return false; | ||
209 | } | ||
210 | |||
127 | /** | 211 | /** |
128 | * fwnode_property_present - check if a property of a firmware node is present | 212 | * fwnode_property_present - check if a property of a firmware node is present |
129 | * @fwnode: Firmware node whose property to check | 213 | * @fwnode: Firmware node whose property to check |
@@ -131,12 +215,12 @@ EXPORT_SYMBOL_GPL(device_property_present); | |||
131 | */ | 215 | */ |
132 | bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) | 216 | bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) |
133 | { | 217 | { |
134 | if (is_of_node(fwnode)) | 218 | bool ret; |
135 | return of_property_read_bool(to_of_node(fwnode), propname); | ||
136 | else if (is_acpi_node(fwnode)) | ||
137 | return !acpi_node_prop_get(fwnode, propname, NULL); | ||
138 | 219 | ||
139 | return !!pset_prop_get(to_pset(fwnode), propname); | 220 | ret = __fwnode_property_present(fwnode, propname); |
221 | if (ret == false && fwnode && fwnode->secondary) | ||
222 | ret = __fwnode_property_present(fwnode->secondary, propname); | ||
223 | return ret; | ||
140 | } | 224 | } |
141 | EXPORT_SYMBOL_GPL(fwnode_property_present); | 225 | EXPORT_SYMBOL_GPL(fwnode_property_present); |
142 | 226 | ||
@@ -309,25 +393,40 @@ int device_property_match_string(struct device *dev, const char *propname, | |||
309 | } | 393 | } |
310 | EXPORT_SYMBOL_GPL(device_property_match_string); | 394 | EXPORT_SYMBOL_GPL(device_property_match_string); |
311 | 395 | ||
312 | #define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ | 396 | #define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ |
313 | (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ | 397 | (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ |
314 | : of_property_count_elems_of_size((node), (propname), sizeof(type)) | 398 | : of_property_count_elems_of_size((node), (propname), sizeof(type)) |
315 | 399 | ||
316 | #define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ | 400 | #define PSET_PROP_READ_ARRAY(node, propname, type, val, nval) \ |
317 | ({ \ | 401 | (val) ? pset_prop_read_##type##_array((node), (propname), (val), (nval)) \ |
318 | int _ret_; \ | 402 | : pset_prop_count_elems_of_size((node), (propname), sizeof(type)) |
319 | if (is_of_node(_fwnode_)) \ | 403 | |
320 | _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \ | 404 | #define FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ |
321 | _type_, _val_, _nval_); \ | 405 | ({ \ |
322 | else if (is_acpi_node(_fwnode_)) \ | 406 | int _ret_; \ |
323 | _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \ | 407 | if (is_of_node(_fwnode_)) \ |
324 | _val_, _nval_); \ | 408 | _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \ |
325 | else if (is_pset(_fwnode_)) \ | 409 | _type_, _val_, _nval_); \ |
326 | _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \ | 410 | else if (is_acpi_node(_fwnode_)) \ |
327 | _proptype_, _val_, _nval_); \ | 411 | _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \ |
328 | else \ | 412 | _val_, _nval_); \ |
329 | _ret_ = -ENXIO; \ | 413 | else if (is_pset_node(_fwnode_)) \ |
330 | _ret_; \ | 414 | _ret_ = PSET_PROP_READ_ARRAY(to_pset_node(_fwnode_), _propname_, \ |
415 | _type_, _val_, _nval_); \ | ||
416 | else \ | ||
417 | _ret_ = -ENXIO; \ | ||
418 | _ret_; \ | ||
419 | }) | ||
420 | |||
421 | #define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ | ||
422 | ({ \ | ||
423 | int _ret_; \ | ||
424 | _ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, \ | ||
425 | _val_, _nval_); \ | ||
426 | if (_ret_ == -EINVAL && _fwnode_ && _fwnode_->secondary) \ | ||
427 | _ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_, \ | ||
428 | _proptype_, _val_, _nval_); \ | ||
429 | _ret_; \ | ||
331 | }) | 430 | }) |
332 | 431 | ||
333 | /** | 432 | /** |
@@ -434,6 +533,41 @@ int fwnode_property_read_u64_array(struct fwnode_handle *fwnode, | |||
434 | } | 533 | } |
435 | EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); | 534 | EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); |
436 | 535 | ||
536 | static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode, | ||
537 | const char *propname, | ||
538 | const char **val, size_t nval) | ||
539 | { | ||
540 | if (is_of_node(fwnode)) | ||
541 | return val ? | ||
542 | of_property_read_string_array(to_of_node(fwnode), | ||
543 | propname, val, nval) : | ||
544 | of_property_count_strings(to_of_node(fwnode), propname); | ||
545 | else if (is_acpi_node(fwnode)) | ||
546 | return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, | ||
547 | val, nval); | ||
548 | else if (is_pset_node(fwnode)) | ||
549 | return val ? | ||
550 | pset_prop_read_string_array(to_pset_node(fwnode), | ||
551 | propname, val, nval) : | ||
552 | pset_prop_count_elems_of_size(to_pset_node(fwnode), | ||
553 | propname, | ||
554 | sizeof(const char *)); | ||
555 | return -ENXIO; | ||
556 | } | ||
557 | |||
558 | static int __fwnode_property_read_string(struct fwnode_handle *fwnode, | ||
559 | const char *propname, const char **val) | ||
560 | { | ||
561 | if (is_of_node(fwnode)) | ||
562 | return of_property_read_string(to_of_node(fwnode), propname, val); | ||
563 | else if (is_acpi_node(fwnode)) | ||
564 | return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, | ||
565 | val, 1); | ||
566 | else if (is_pset_node(fwnode)) | ||
567 | return pset_prop_read_string(to_pset_node(fwnode), propname, val); | ||
568 | return -ENXIO; | ||
569 | } | ||
570 | |||
437 | /** | 571 | /** |
438 | * fwnode_property_read_string_array - return string array property of a node | 572 | * fwnode_property_read_string_array - return string array property of a node |
439 | * @fwnode: Firmware node to get the property of | 573 | * @fwnode: Firmware node to get the property of |
@@ -456,18 +590,13 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode, | |||
456 | const char *propname, const char **val, | 590 | const char *propname, const char **val, |
457 | size_t nval) | 591 | size_t nval) |
458 | { | 592 | { |
459 | if (is_of_node(fwnode)) | 593 | int ret; |
460 | return val ? | 594 | |
461 | of_property_read_string_array(to_of_node(fwnode), | 595 | ret = __fwnode_property_read_string_array(fwnode, propname, val, nval); |
462 | propname, val, nval) : | 596 | if (ret == -EINVAL && fwnode && fwnode->secondary) |
463 | of_property_count_strings(to_of_node(fwnode), propname); | 597 | ret = __fwnode_property_read_string_array(fwnode->secondary, |
464 | else if (is_acpi_node(fwnode)) | 598 | propname, val, nval); |
465 | return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, | 599 | return ret; |
466 | val, nval); | ||
467 | else if (is_pset(fwnode)) | ||
468 | return pset_prop_read_array(to_pset(fwnode), propname, | ||
469 | DEV_PROP_STRING, val, nval); | ||
470 | return -ENXIO; | ||
471 | } | 600 | } |
472 | EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); | 601 | EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); |
473 | 602 | ||
@@ -489,14 +618,13 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); | |||
489 | int fwnode_property_read_string(struct fwnode_handle *fwnode, | 618 | int fwnode_property_read_string(struct fwnode_handle *fwnode, |
490 | const char *propname, const char **val) | 619 | const char *propname, const char **val) |
491 | { | 620 | { |
492 | if (is_of_node(fwnode)) | 621 | int ret; |
493 | return of_property_read_string(to_of_node(fwnode), propname, val); | ||
494 | else if (is_acpi_node(fwnode)) | ||
495 | return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, | ||
496 | val, 1); | ||
497 | 622 | ||
498 | return pset_prop_read_array(to_pset(fwnode), propname, | 623 | ret = __fwnode_property_read_string(fwnode, propname, val); |
499 | DEV_PROP_STRING, val, 1); | 624 | if (ret == -EINVAL && fwnode && fwnode->secondary) |
625 | ret = __fwnode_property_read_string(fwnode->secondary, | ||
626 | propname, val); | ||
627 | return ret; | ||
500 | } | 628 | } |
501 | EXPORT_SYMBOL_GPL(fwnode_property_read_string); | 629 | EXPORT_SYMBOL_GPL(fwnode_property_read_string); |
502 | 630 | ||
@@ -525,6 +653,9 @@ int fwnode_property_match_string(struct fwnode_handle *fwnode, | |||
525 | if (nval < 0) | 653 | if (nval < 0) |
526 | return nval; | 654 | return nval; |
527 | 655 | ||
656 | if (nval == 0) | ||
657 | return -ENODATA; | ||
658 | |||
528 | values = kcalloc(nval, sizeof(*values), GFP_KERNEL); | 659 | values = kcalloc(nval, sizeof(*values), GFP_KERNEL); |
529 | if (!values) | 660 | if (!values) |
530 | return -ENOMEM; | 661 | return -ENOMEM; |
@@ -547,6 +678,182 @@ out: | |||
547 | EXPORT_SYMBOL_GPL(fwnode_property_match_string); | 678 | EXPORT_SYMBOL_GPL(fwnode_property_match_string); |
548 | 679 | ||
549 | /** | 680 | /** |
681 | * pset_free_set - releases memory allocated for copied property set | ||
682 | * @pset: Property set to release | ||
683 | * | ||
684 | * Function takes previously copied property set and releases all the | ||
685 | * memory allocated to it. | ||
686 | */ | ||
687 | static void pset_free_set(struct property_set *pset) | ||
688 | { | ||
689 | const struct property_entry *prop; | ||
690 | size_t i, nval; | ||
691 | |||
692 | if (!pset) | ||
693 | return; | ||
694 | |||
695 | for (prop = pset->properties; prop->name; prop++) { | ||
696 | if (prop->is_array) { | ||
697 | if (prop->is_string && prop->pointer.str) { | ||
698 | nval = prop->length / sizeof(const char *); | ||
699 | for (i = 0; i < nval; i++) | ||
700 | kfree(prop->pointer.str[i]); | ||
701 | } | ||
702 | kfree(prop->pointer.raw_data); | ||
703 | } else if (prop->is_string) { | ||
704 | kfree(prop->value.str); | ||
705 | } | ||
706 | kfree(prop->name); | ||
707 | } | ||
708 | |||
709 | kfree(pset->properties); | ||
710 | kfree(pset); | ||
711 | } | ||
712 | |||
713 | static int pset_copy_entry(struct property_entry *dst, | ||
714 | const struct property_entry *src) | ||
715 | { | ||
716 | const char **d, **s; | ||
717 | size_t i, nval; | ||
718 | |||
719 | dst->name = kstrdup(src->name, GFP_KERNEL); | ||
720 | if (!dst->name) | ||
721 | return -ENOMEM; | ||
722 | |||
723 | if (src->is_array) { | ||
724 | if (!src->length) | ||
725 | return -ENODATA; | ||
726 | |||
727 | if (src->is_string) { | ||
728 | nval = src->length / sizeof(const char *); | ||
729 | dst->pointer.str = kcalloc(nval, sizeof(const char *), | ||
730 | GFP_KERNEL); | ||
731 | if (!dst->pointer.str) | ||
732 | return -ENOMEM; | ||
733 | |||
734 | d = dst->pointer.str; | ||
735 | s = src->pointer.str; | ||
736 | for (i = 0; i < nval; i++) { | ||
737 | d[i] = kstrdup(s[i], GFP_KERNEL); | ||
738 | if (!d[i] && s[i]) | ||
739 | return -ENOMEM; | ||
740 | } | ||
741 | } else { | ||
742 | dst->pointer.raw_data = kmemdup(src->pointer.raw_data, | ||
743 | src->length, GFP_KERNEL); | ||
744 | if (!dst->pointer.raw_data) | ||
745 | return -ENOMEM; | ||
746 | } | ||
747 | } else if (src->is_string) { | ||
748 | dst->value.str = kstrdup(src->value.str, GFP_KERNEL); | ||
749 | if (!dst->value.str && src->value.str) | ||
750 | return -ENOMEM; | ||
751 | } else { | ||
752 | dst->value.raw_data = src->value.raw_data; | ||
753 | } | ||
754 | |||
755 | dst->length = src->length; | ||
756 | dst->is_array = src->is_array; | ||
757 | dst->is_string = src->is_string; | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | /** | ||
763 | * pset_copy_set - copies property set | ||
764 | * @pset: Property set to copy | ||
765 | * | ||
766 | * This function takes a deep copy of the given property set and returns | ||
767 | * pointer to the copy. Call device_free_property_set() to free resources | ||
768 | * allocated in this function. | ||
769 | * | ||
770 | * Return: Pointer to the new property set or error pointer. | ||
771 | */ | ||
772 | static struct property_set *pset_copy_set(const struct property_set *pset) | ||
773 | { | ||
774 | const struct property_entry *entry; | ||
775 | struct property_set *p; | ||
776 | size_t i, n = 0; | ||
777 | |||
778 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
779 | if (!p) | ||
780 | return ERR_PTR(-ENOMEM); | ||
781 | |||
782 | while (pset->properties[n].name) | ||
783 | n++; | ||
784 | |||
785 | p->properties = kcalloc(n + 1, sizeof(*entry), GFP_KERNEL); | ||
786 | if (!p->properties) { | ||
787 | kfree(p); | ||
788 | return ERR_PTR(-ENOMEM); | ||
789 | } | ||
790 | |||
791 | for (i = 0; i < n; i++) { | ||
792 | int ret = pset_copy_entry(&p->properties[i], | ||
793 | &pset->properties[i]); | ||
794 | if (ret) { | ||
795 | pset_free_set(p); | ||
796 | return ERR_PTR(ret); | ||
797 | } | ||
798 | } | ||
799 | |||
800 | return p; | ||
801 | } | ||
802 | |||
803 | /** | ||
804 | * device_remove_property_set - Remove properties from a device object. | ||
805 | * @dev: Device whose properties to remove. | ||
806 | * | ||
807 | * The function removes properties previously associated to the device | ||
808 | * secondary firmware node with device_add_property_set(). Memory allocated | ||
809 | * to the properties will also be released. | ||
810 | */ | ||
811 | void device_remove_property_set(struct device *dev) | ||
812 | { | ||
813 | struct fwnode_handle *fwnode; | ||
814 | |||
815 | fwnode = dev_fwnode(dev); | ||
816 | if (!fwnode) | ||
817 | return; | ||
818 | /* | ||
819 | * Pick either primary or secondary node depending which one holds | ||
820 | * the pset. If there is no real firmware node (ACPI/DT) primary | ||
821 | * will hold the pset. | ||
822 | */ | ||
823 | if (!is_pset_node(fwnode)) | ||
824 | fwnode = fwnode->secondary; | ||
825 | if (!IS_ERR(fwnode) && is_pset_node(fwnode)) | ||
826 | pset_free_set(to_pset_node(fwnode)); | ||
827 | set_secondary_fwnode(dev, NULL); | ||
828 | } | ||
829 | EXPORT_SYMBOL_GPL(device_remove_property_set); | ||
830 | |||
831 | /** | ||
832 | * device_add_property_set - Add a collection of properties to a device object. | ||
833 | * @dev: Device to add properties to. | ||
834 | * @pset: Collection of properties to add. | ||
835 | * | ||
836 | * Associate a collection of device properties represented by @pset with @dev | ||
837 | * as its secondary firmware node. The function takes a copy of @pset. | ||
838 | */ | ||
839 | int device_add_property_set(struct device *dev, const struct property_set *pset) | ||
840 | { | ||
841 | struct property_set *p; | ||
842 | |||
843 | if (!pset) | ||
844 | return -EINVAL; | ||
845 | |||
846 | p = pset_copy_set(pset); | ||
847 | if (IS_ERR(p)) | ||
848 | return PTR_ERR(p); | ||
849 | |||
850 | p->fwnode.type = FWNODE_PDATA; | ||
851 | set_secondary_fwnode(dev, &p->fwnode); | ||
852 | return 0; | ||
853 | } | ||
854 | EXPORT_SYMBOL_GPL(device_add_property_set); | ||
855 | |||
856 | /** | ||
550 | * device_get_next_child_node - Return the next child node handle for a device | 857 | * device_get_next_child_node - Return the next child node handle for a device |
551 | * @dev: Device to find the next child node for. | 858 | * @dev: Device to find the next child node for. |
552 | * @child: Handle to one of the device's child nodes or a null handle. | 859 | * @child: Handle to one of the device's child nodes or a null handle. |
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 6b00061c3746..cbd663deef38 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
37 | #include <linux/pm.h> | 37 | #include <linux/pm.h> |
38 | #include <linux/pm_runtime.h> | 38 | #include <linux/pm_runtime.h> |
39 | #include <linux/property.h> | ||
39 | #include <linux/io.h> | 40 | #include <linux/io.h> |
40 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
41 | #include <linux/acpi.h> | 42 | #include <linux/acpi.h> |
@@ -134,10 +135,10 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev) | |||
134 | 135 | ||
135 | static int dw_i2c_plat_probe(struct platform_device *pdev) | 136 | static int dw_i2c_plat_probe(struct platform_device *pdev) |
136 | { | 137 | { |
138 | struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); | ||
137 | struct dw_i2c_dev *dev; | 139 | struct dw_i2c_dev *dev; |
138 | struct i2c_adapter *adap; | 140 | struct i2c_adapter *adap; |
139 | struct resource *mem; | 141 | struct resource *mem; |
140 | struct dw_i2c_platform_data *pdata; | ||
141 | int irq, r; | 142 | int irq, r; |
142 | u32 clk_freq, ht = 0; | 143 | u32 clk_freq, ht = 0; |
143 | 144 | ||
@@ -161,33 +162,28 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) | |||
161 | /* fast mode by default because of legacy reasons */ | 162 | /* fast mode by default because of legacy reasons */ |
162 | clk_freq = 400000; | 163 | clk_freq = 400000; |
163 | 164 | ||
164 | if (has_acpi_companion(&pdev->dev)) { | 165 | if (pdata) { |
165 | dw_i2c_acpi_configure(pdev); | 166 | clk_freq = pdata->i2c_scl_freq; |
166 | } else if (pdev->dev.of_node) { | ||
167 | of_property_read_u32(pdev->dev.of_node, | ||
168 | "i2c-sda-hold-time-ns", &ht); | ||
169 | |||
170 | of_property_read_u32(pdev->dev.of_node, | ||
171 | "i2c-sda-falling-time-ns", | ||
172 | &dev->sda_falling_time); | ||
173 | of_property_read_u32(pdev->dev.of_node, | ||
174 | "i2c-scl-falling-time-ns", | ||
175 | &dev->scl_falling_time); | ||
176 | |||
177 | of_property_read_u32(pdev->dev.of_node, "clock-frequency", | ||
178 | &clk_freq); | ||
179 | |||
180 | /* Only standard mode at 100kHz and fast mode at 400kHz | ||
181 | * are supported. | ||
182 | */ | ||
183 | if (clk_freq != 100000 && clk_freq != 400000) { | ||
184 | dev_err(&pdev->dev, "Only 100kHz and 400kHz supported"); | ||
185 | return -EINVAL; | ||
186 | } | ||
187 | } else { | 167 | } else { |
188 | pdata = dev_get_platdata(&pdev->dev); | 168 | device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns", |
189 | if (pdata) | 169 | &ht); |
190 | clk_freq = pdata->i2c_scl_freq; | 170 | device_property_read_u32(&pdev->dev, "i2c-sda-falling-time-ns", |
171 | &dev->sda_falling_time); | ||
172 | device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns", | ||
173 | &dev->scl_falling_time); | ||
174 | device_property_read_u32(&pdev->dev, "clock-frequency", | ||
175 | &clk_freq); | ||
176 | } | ||
177 | |||
178 | if (has_acpi_companion(&pdev->dev)) | ||
179 | dw_i2c_acpi_configure(pdev); | ||
180 | |||
181 | /* | ||
182 | * Only standard mode at 100kHz and fast mode at 400kHz are supported. | ||
183 | */ | ||
184 | if (clk_freq != 100000 && clk_freq != 400000) { | ||
185 | dev_err(&pdev->dev, "Only 100kHz and 400kHz supported"); | ||
186 | return -EINVAL; | ||
191 | } | 187 | } |
192 | 188 | ||
193 | r = i2c_dw_eval_lock_support(dev); | 189 | r = i2c_dw_eval_lock_support(dev); |
diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index b6fd9041f82f..06f00d60be46 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
19 | #include <linux/pm_runtime.h> | 19 | #include <linux/pm_runtime.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/property.h> | ||
21 | 22 | ||
22 | #include "intel-lpss.h" | 23 | #include "intel-lpss.h" |
23 | 24 | ||
@@ -25,6 +26,20 @@ static const struct intel_lpss_platform_info spt_info = { | |||
25 | .clk_rate = 120000000, | 26 | .clk_rate = 120000000, |
26 | }; | 27 | }; |
27 | 28 | ||
29 | static struct property_entry spt_i2c_properties[] = { | ||
30 | PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230), | ||
31 | { }, | ||
32 | }; | ||
33 | |||
34 | static struct property_set spt_i2c_pset = { | ||
35 | .properties = spt_i2c_properties, | ||
36 | }; | ||
37 | |||
38 | static const struct intel_lpss_platform_info spt_i2c_info = { | ||
39 | .clk_rate = 120000000, | ||
40 | .pset = &spt_i2c_pset, | ||
41 | }; | ||
42 | |||
28 | static const struct intel_lpss_platform_info bxt_info = { | 43 | static const struct intel_lpss_platform_info bxt_info = { |
29 | .clk_rate = 100000000, | 44 | .clk_rate = 100000000, |
30 | }; | 45 | }; |
@@ -35,8 +50,8 @@ static const struct intel_lpss_platform_info bxt_i2c_info = { | |||
35 | 50 | ||
36 | static const struct acpi_device_id intel_lpss_acpi_ids[] = { | 51 | static const struct acpi_device_id intel_lpss_acpi_ids[] = { |
37 | /* SPT */ | 52 | /* SPT */ |
38 | { "INT3446", (kernel_ulong_t)&spt_info }, | 53 | { "INT3446", (kernel_ulong_t)&spt_i2c_info }, |
39 | { "INT3447", (kernel_ulong_t)&spt_info }, | 54 | { "INT3447", (kernel_ulong_t)&spt_i2c_info }, |
40 | /* BXT */ | 55 | /* BXT */ |
41 | { "80860AAC", (kernel_ulong_t)&bxt_i2c_info }, | 56 | { "80860AAC", (kernel_ulong_t)&bxt_i2c_info }, |
42 | { "80860ABC", (kernel_ulong_t)&bxt_info }, | 57 | { "80860ABC", (kernel_ulong_t)&bxt_info }, |
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 5bfdfccbb9a1..a7136c7ae9fb 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/pci.h> | 17 | #include <linux/pci.h> |
18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
19 | #include <linux/pm_runtime.h> | 19 | #include <linux/pm_runtime.h> |
20 | #include <linux/property.h> | ||
20 | 21 | ||
21 | #include "intel-lpss.h" | 22 | #include "intel-lpss.h" |
22 | 23 | ||
@@ -65,9 +66,35 @@ static const struct intel_lpss_platform_info spt_info = { | |||
65 | .clk_rate = 120000000, | 66 | .clk_rate = 120000000, |
66 | }; | 67 | }; |
67 | 68 | ||
69 | static struct property_entry spt_i2c_properties[] = { | ||
70 | PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230), | ||
71 | { }, | ||
72 | }; | ||
73 | |||
74 | static struct property_set spt_i2c_pset = { | ||
75 | .properties = spt_i2c_properties, | ||
76 | }; | ||
77 | |||
78 | static const struct intel_lpss_platform_info spt_i2c_info = { | ||
79 | .clk_rate = 120000000, | ||
80 | .pset = &spt_i2c_pset, | ||
81 | }; | ||
82 | |||
83 | static struct property_entry uart_properties[] = { | ||
84 | PROPERTY_ENTRY_U32("reg-io-width", 4), | ||
85 | PROPERTY_ENTRY_U32("reg-shift", 2), | ||
86 | PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"), | ||
87 | { }, | ||
88 | }; | ||
89 | |||
90 | static struct property_set uart_pset = { | ||
91 | .properties = uart_properties, | ||
92 | }; | ||
93 | |||
68 | static const struct intel_lpss_platform_info spt_uart_info = { | 94 | static const struct intel_lpss_platform_info spt_uart_info = { |
69 | .clk_rate = 120000000, | 95 | .clk_rate = 120000000, |
70 | .clk_con_id = "baudclk", | 96 | .clk_con_id = "baudclk", |
97 | .pset = &uart_pset, | ||
71 | }; | 98 | }; |
72 | 99 | ||
73 | static const struct intel_lpss_platform_info bxt_info = { | 100 | static const struct intel_lpss_platform_info bxt_info = { |
@@ -77,6 +104,7 @@ static const struct intel_lpss_platform_info bxt_info = { | |||
77 | static const struct intel_lpss_platform_info bxt_uart_info = { | 104 | static const struct intel_lpss_platform_info bxt_uart_info = { |
78 | .clk_rate = 100000000, | 105 | .clk_rate = 100000000, |
79 | .clk_con_id = "baudclk", | 106 | .clk_con_id = "baudclk", |
107 | .pset = &uart_pset, | ||
80 | }; | 108 | }; |
81 | 109 | ||
82 | static const struct intel_lpss_platform_info bxt_i2c_info = { | 110 | static const struct intel_lpss_platform_info bxt_i2c_info = { |
@@ -121,20 +149,20 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { | |||
121 | { PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info }, | 149 | { PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info }, |
122 | { PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_info }, | 150 | { PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_info }, |
123 | { PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_info }, | 151 | { PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_info }, |
124 | { PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_info }, | 152 | { PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_i2c_info }, |
125 | { PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_info }, | 153 | { PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_i2c_info }, |
126 | { PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_info }, | 154 | { PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_i2c_info }, |
127 | { PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_info }, | 155 | { PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_i2c_info }, |
128 | { PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_info }, | 156 | { PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_i2c_info }, |
129 | { PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_info }, | 157 | { PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_i2c_info }, |
130 | { PCI_VDEVICE(INTEL, 0x9d66), (kernel_ulong_t)&spt_uart_info }, | 158 | { PCI_VDEVICE(INTEL, 0x9d66), (kernel_ulong_t)&spt_uart_info }, |
131 | /* SPT-H */ | 159 | /* SPT-H */ |
132 | { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, | 160 | { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, |
133 | { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, | 161 | { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, |
134 | { PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_info }, | 162 | { PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_info }, |
135 | { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info }, | 163 | { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info }, |
136 | { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_info }, | 164 | { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info }, |
137 | { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_info }, | 165 | { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info }, |
138 | { PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info }, | 166 | { PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info }, |
139 | { } | 167 | { } |
140 | }; | 168 | }; |
diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 6255513f54c7..1743788f1595 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/mfd/core.h> | 24 | #include <linux/mfd/core.h> |
25 | #include <linux/pm_qos.h> | 25 | #include <linux/pm_qos.h> |
26 | #include <linux/pm_runtime.h> | 26 | #include <linux/pm_runtime.h> |
27 | #include <linux/property.h> | ||
27 | #include <linux/seq_file.h> | 28 | #include <linux/seq_file.h> |
28 | #include <linux/io-64-nonatomic-lo-hi.h> | 29 | #include <linux/io-64-nonatomic-lo-hi.h> |
29 | 30 | ||
@@ -72,7 +73,7 @@ struct intel_lpss { | |||
72 | enum intel_lpss_dev_type type; | 73 | enum intel_lpss_dev_type type; |
73 | struct clk *clk; | 74 | struct clk *clk; |
74 | struct clk_lookup *clock; | 75 | struct clk_lookup *clock; |
75 | const struct mfd_cell *cell; | 76 | struct mfd_cell *cell; |
76 | struct device *dev; | 77 | struct device *dev; |
77 | void __iomem *priv; | 78 | void __iomem *priv; |
78 | int devid; | 79 | int devid; |
@@ -217,6 +218,7 @@ static void intel_lpss_ltr_hide(struct intel_lpss *lpss) | |||
217 | 218 | ||
218 | static int intel_lpss_assign_devs(struct intel_lpss *lpss) | 219 | static int intel_lpss_assign_devs(struct intel_lpss *lpss) |
219 | { | 220 | { |
221 | const struct mfd_cell *cell; | ||
220 | unsigned int type; | 222 | unsigned int type; |
221 | 223 | ||
222 | type = lpss->caps & LPSS_PRIV_CAPS_TYPE_MASK; | 224 | type = lpss->caps & LPSS_PRIV_CAPS_TYPE_MASK; |
@@ -224,18 +226,22 @@ static int intel_lpss_assign_devs(struct intel_lpss *lpss) | |||
224 | 226 | ||
225 | switch (type) { | 227 | switch (type) { |
226 | case LPSS_DEV_I2C: | 228 | case LPSS_DEV_I2C: |
227 | lpss->cell = &intel_lpss_i2c_cell; | 229 | cell = &intel_lpss_i2c_cell; |
228 | break; | 230 | break; |
229 | case LPSS_DEV_UART: | 231 | case LPSS_DEV_UART: |
230 | lpss->cell = &intel_lpss_uart_cell; | 232 | cell = &intel_lpss_uart_cell; |
231 | break; | 233 | break; |
232 | case LPSS_DEV_SPI: | 234 | case LPSS_DEV_SPI: |
233 | lpss->cell = &intel_lpss_spi_cell; | 235 | cell = &intel_lpss_spi_cell; |
234 | break; | 236 | break; |
235 | default: | 237 | default: |
236 | return -ENODEV; | 238 | return -ENODEV; |
237 | } | 239 | } |
238 | 240 | ||
241 | lpss->cell = devm_kmemdup(lpss->dev, cell, sizeof(*cell), GFP_KERNEL); | ||
242 | if (!lpss->cell) | ||
243 | return -ENOMEM; | ||
244 | |||
239 | lpss->type = type; | 245 | lpss->type = type; |
240 | 246 | ||
241 | return 0; | 247 | return 0; |
@@ -401,6 +407,8 @@ int intel_lpss_probe(struct device *dev, | |||
401 | if (ret) | 407 | if (ret) |
402 | return ret; | 408 | return ret; |
403 | 409 | ||
410 | lpss->cell->pset = info->pset; | ||
411 | |||
404 | intel_lpss_init_dev(lpss); | 412 | intel_lpss_init_dev(lpss); |
405 | 413 | ||
406 | lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL); | 414 | lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL); |
diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h index 2c7f8d7c0595..0dcea9eb2d03 100644 --- a/drivers/mfd/intel-lpss.h +++ b/drivers/mfd/intel-lpss.h | |||
@@ -16,12 +16,14 @@ | |||
16 | 16 | ||
17 | struct device; | 17 | struct device; |
18 | struct resource; | 18 | struct resource; |
19 | struct property_set; | ||
19 | 20 | ||
20 | struct intel_lpss_platform_info { | 21 | struct intel_lpss_platform_info { |
21 | struct resource *mem; | 22 | struct resource *mem; |
22 | int irq; | 23 | int irq; |
23 | unsigned long clk_rate; | 24 | unsigned long clk_rate; |
24 | const char *clk_con_id; | 25 | const char *clk_con_id; |
26 | struct property_set *pset; | ||
25 | }; | 27 | }; |
26 | 28 | ||
27 | int intel_lpss_probe(struct device *dev, | 29 | int intel_lpss_probe(struct device *dev, |
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 60b60dc63ddd..88bd1b1e47be 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/acpi.h> | 16 | #include <linux/acpi.h> |
17 | #include <linux/property.h> | ||
17 | #include <linux/mfd/core.h> | 18 | #include <linux/mfd/core.h> |
18 | #include <linux/pm_runtime.h> | 19 | #include <linux/pm_runtime.h> |
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
@@ -192,6 +193,12 @@ static int mfd_add_device(struct device *parent, int id, | |||
192 | goto fail_alias; | 193 | goto fail_alias; |
193 | } | 194 | } |
194 | 195 | ||
196 | if (cell->pset) { | ||
197 | ret = platform_device_add_properties(pdev, cell->pset); | ||
198 | if (ret) | ||
199 | goto fail_alias; | ||
200 | } | ||
201 | |||
195 | ret = mfd_platform_add_cell(pdev, cell, usage_count); | 202 | ret = mfd_platform_add_cell(pdev, cell, usage_count); |
196 | if (ret) | 203 | if (ret) |
197 | goto fail_alias; | 204 | goto fail_alias; |
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index 27dac3ff18b9..bc6f7e00fb3d 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | 18 | ||
19 | struct irq_domain; | 19 | struct irq_domain; |
20 | struct property_set; | ||
20 | 21 | ||
21 | /* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */ | 22 | /* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */ |
22 | struct mfd_cell_acpi_match { | 23 | struct mfd_cell_acpi_match { |
@@ -44,6 +45,10 @@ struct mfd_cell { | |||
44 | /* platform data passed to the sub devices drivers */ | 45 | /* platform data passed to the sub devices drivers */ |
45 | void *platform_data; | 46 | void *platform_data; |
46 | size_t pdata_size; | 47 | size_t pdata_size; |
48 | |||
49 | /* device properties passed to the sub devices drivers */ | ||
50 | const struct property_set *pset; | ||
51 | |||
47 | /* | 52 | /* |
48 | * Device Tree compatible string | 53 | * Device Tree compatible string |
49 | * See: Documentation/devicetree/usage-model.txt Chapter 2.2 for details | 54 | * See: Documentation/devicetree/usage-model.txt Chapter 2.2 for details |
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index dc777be5f2e1..dba40b1c41dc 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #define PLATFORM_DEVID_AUTO (-2) | 18 | #define PLATFORM_DEVID_AUTO (-2) |
19 | 19 | ||
20 | struct mfd_cell; | 20 | struct mfd_cell; |
21 | struct property_set; | ||
21 | 22 | ||
22 | struct platform_device { | 23 | struct platform_device { |
23 | const char *name; | 24 | const char *name; |
@@ -70,6 +71,8 @@ struct platform_device_info { | |||
70 | const void *data; | 71 | const void *data; |
71 | size_t size_data; | 72 | size_t size_data; |
72 | u64 dma_mask; | 73 | u64 dma_mask; |
74 | |||
75 | const struct property_set *pset; | ||
73 | }; | 76 | }; |
74 | extern struct platform_device *platform_device_register_full( | 77 | extern struct platform_device *platform_device_register_full( |
75 | const struct platform_device_info *pdevinfo); | 78 | const struct platform_device_info *pdevinfo); |
@@ -167,6 +170,8 @@ extern int platform_device_add_resources(struct platform_device *pdev, | |||
167 | unsigned int num); | 170 | unsigned int num); |
168 | extern int platform_device_add_data(struct platform_device *pdev, | 171 | extern int platform_device_add_data(struct platform_device *pdev, |
169 | const void *data, size_t size); | 172 | const void *data, size_t size); |
173 | extern int platform_device_add_properties(struct platform_device *pdev, | ||
174 | const struct property_set *pset); | ||
170 | extern int platform_device_add(struct platform_device *pdev); | 175 | extern int platform_device_add(struct platform_device *pdev); |
171 | extern void platform_device_del(struct platform_device *pdev); | 176 | extern void platform_device_del(struct platform_device *pdev); |
172 | extern void platform_device_put(struct platform_device *pdev); | 177 | extern void platform_device_put(struct platform_device *pdev); |
diff --git a/include/linux/property.h b/include/linux/property.h index 0a3705a7c9f2..b51fcd36d892 100644 --- a/include/linux/property.h +++ b/include/linux/property.h | |||
@@ -73,8 +73,8 @@ int fwnode_property_match_string(struct fwnode_handle *fwnode, | |||
73 | struct fwnode_handle *device_get_next_child_node(struct device *dev, | 73 | struct fwnode_handle *device_get_next_child_node(struct device *dev, |
74 | struct fwnode_handle *child); | 74 | struct fwnode_handle *child); |
75 | 75 | ||
76 | #define device_for_each_child_node(dev, child) \ | 76 | #define device_for_each_child_node(dev, child) \ |
77 | for (child = device_get_next_child_node(dev, NULL); child; \ | 77 | for (child = device_get_next_child_node(dev, NULL); child; \ |
78 | child = device_get_next_child_node(dev, child)) | 78 | child = device_get_next_child_node(dev, child)) |
79 | 79 | ||
80 | void fwnode_handle_put(struct fwnode_handle *fwnode); | 80 | void fwnode_handle_put(struct fwnode_handle *fwnode); |
@@ -144,24 +144,100 @@ static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode, | |||
144 | /** | 144 | /** |
145 | * struct property_entry - "Built-in" device property representation. | 145 | * struct property_entry - "Built-in" device property representation. |
146 | * @name: Name of the property. | 146 | * @name: Name of the property. |
147 | * @type: Type of the property. | 147 | * @length: Length of data making up the value. |
148 | * @nval: Number of items of type @type making up the value. | 148 | * @is_array: True when the property is an array. |
149 | * @value: Value of the property (an array of @nval items of type @type). | 149 | * @is_string: True when property is a string. |
150 | * @pointer: Pointer to the property (an array of items of the given type). | ||
151 | * @value: Value of the property (when it is a single item of the given type). | ||
150 | */ | 152 | */ |
151 | struct property_entry { | 153 | struct property_entry { |
152 | const char *name; | 154 | const char *name; |
153 | enum dev_prop_type type; | 155 | size_t length; |
154 | size_t nval; | 156 | bool is_array; |
157 | bool is_string; | ||
155 | union { | 158 | union { |
156 | void *raw_data; | 159 | union { |
157 | u8 *u8_data; | 160 | void *raw_data; |
158 | u16 *u16_data; | 161 | u8 *u8_data; |
159 | u32 *u32_data; | 162 | u16 *u16_data; |
160 | u64 *u64_data; | 163 | u32 *u32_data; |
161 | const char **str; | 164 | u64 *u64_data; |
162 | } value; | 165 | const char **str; |
166 | } pointer; | ||
167 | union { | ||
168 | unsigned long long raw_data; | ||
169 | u8 u8_data; | ||
170 | u16 u16_data; | ||
171 | u32 u32_data; | ||
172 | u64 u64_data; | ||
173 | const char *str; | ||
174 | } value; | ||
175 | }; | ||
163 | }; | 176 | }; |
164 | 177 | ||
178 | /* | ||
179 | * Note: the below four initializers for the anonymous union are carefully | ||
180 | * crafted to avoid gcc-4.4.4's problems with initialization of anon unions | ||
181 | * and structs. | ||
182 | */ | ||
183 | |||
184 | #define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_) \ | ||
185 | { \ | ||
186 | .name = _name_, \ | ||
187 | .length = ARRAY_SIZE(_val_) * sizeof(_type_), \ | ||
188 | .is_array = true, \ | ||
189 | .is_string = false, \ | ||
190 | { .pointer = { _type_##_data = _val_ } }, \ | ||
191 | } | ||
192 | |||
193 | #define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \ | ||
194 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, _val_) | ||
195 | #define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \ | ||
196 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, _val_) | ||
197 | #define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \ | ||
198 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, _val_) | ||
199 | #define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \ | ||
200 | PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, _val_) | ||
201 | |||
202 | #define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \ | ||
203 | { \ | ||
204 | .name = _name_, \ | ||
205 | .length = ARRAY_SIZE(_val_) * sizeof(const char *), \ | ||
206 | .is_array = true, \ | ||
207 | .is_string = true, \ | ||
208 | { .pointer = { .str = _val_ } }, \ | ||
209 | } | ||
210 | |||
211 | #define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_) \ | ||
212 | { \ | ||
213 | .name = _name_, \ | ||
214 | .length = sizeof(_type_), \ | ||
215 | .is_string = false, \ | ||
216 | { .value = { ._type_##_data = _val_ } }, \ | ||
217 | } | ||
218 | |||
219 | #define PROPERTY_ENTRY_U8(_name_, _val_) \ | ||
220 | PROPERTY_ENTRY_INTEGER(_name_, u8, _val_) | ||
221 | #define PROPERTY_ENTRY_U16(_name_, _val_) \ | ||
222 | PROPERTY_ENTRY_INTEGER(_name_, u16, _val_) | ||
223 | #define PROPERTY_ENTRY_U32(_name_, _val_) \ | ||
224 | PROPERTY_ENTRY_INTEGER(_name_, u32, _val_) | ||
225 | #define PROPERTY_ENTRY_U64(_name_, _val_) \ | ||
226 | PROPERTY_ENTRY_INTEGER(_name_, u64, _val_) | ||
227 | |||
228 | #define PROPERTY_ENTRY_STRING(_name_, _val_) \ | ||
229 | { \ | ||
230 | .name = _name_, \ | ||
231 | .length = sizeof(_val_), \ | ||
232 | .is_string = true, \ | ||
233 | { .value = { .str = _val_ } }, \ | ||
234 | } | ||
235 | |||
236 | #define PROPERTY_ENTRY_BOOL(_name_) \ | ||
237 | { \ | ||
238 | .name = _name_, \ | ||
239 | } | ||
240 | |||
165 | /** | 241 | /** |
166 | * struct property_set - Collection of "built-in" device properties. | 242 | * struct property_set - Collection of "built-in" device properties. |
167 | * @fwnode: Handle to be pointed to by the fwnode field of struct device. | 243 | * @fwnode: Handle to be pointed to by the fwnode field of struct device. |
@@ -172,7 +248,8 @@ struct property_set { | |||
172 | struct property_entry *properties; | 248 | struct property_entry *properties; |
173 | }; | 249 | }; |
174 | 250 | ||
175 | void device_add_property_set(struct device *dev, struct property_set *pset); | 251 | int device_add_property_set(struct device *dev, const struct property_set *pset); |
252 | void device_remove_property_set(struct device *dev); | ||
176 | 253 | ||
177 | bool device_dma_supported(struct device *dev); | 254 | bool device_dma_supported(struct device *dev); |
178 | 255 | ||