aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/property.c10
-rw-r--r--drivers/base/core.c5
-rw-r--r--drivers/base/platform.c25
-rw-r--r--drivers/base/property.c495
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c50
-rw-r--r--drivers/mfd/intel-lpss-acpi.c19
-rw-r--r--drivers/mfd/intel-lpss-pci.c44
-rw-r--r--drivers/mfd/intel-lpss.c16
-rw-r--r--drivers/mfd/intel-lpss.h2
-rw-r--r--drivers/mfd/mfd-core.c7
-rw-r--r--include/linux/mfd/core.h5
-rw-r--r--include/linux/platform_device.h5
-rw-r--r--include/linux/property.h107
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 */
352static int acpi_data_get_property(struct acpi_device_data *data, 352static 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,
299EXPORT_SYMBOL_GPL(platform_device_add_data); 300EXPORT_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 */
311int 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}
316EXPORT_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}
414EXPORT_SYMBOL_GPL(platform_device_del); 433EXPORT_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) {
492err: 517err:
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/** 22static 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 */
30void 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}
38EXPORT_SYMBOL_GPL(device_add_property_set);
39
40static 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
45static inline struct property_set *to_pset(struct fwnode_handle *fwnode) 27static 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
66static int pset_prop_read_array(struct property_set *pset, const char *name, 48static 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
68static 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
83static 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
98static 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
113static 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
128static 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
140static 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
155static 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}
125EXPORT_SYMBOL_GPL(device_property_present); 197EXPORT_SYMBOL_GPL(device_property_present);
126 198
199static 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 */
132bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) 216bool 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}
141EXPORT_SYMBOL_GPL(fwnode_property_present); 225EXPORT_SYMBOL_GPL(fwnode_property_present);
142 226
@@ -309,25 +393,40 @@ int device_property_match_string(struct device *dev, const char *propname,
309} 393}
310EXPORT_SYMBOL_GPL(device_property_match_string); 394EXPORT_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}
435EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); 534EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
436 535
536static 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
558static 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}
472EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); 601EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
473 602
@@ -489,14 +618,13 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
489int fwnode_property_read_string(struct fwnode_handle *fwnode, 618int 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}
501EXPORT_SYMBOL_GPL(fwnode_property_read_string); 629EXPORT_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:
547EXPORT_SYMBOL_GPL(fwnode_property_match_string); 678EXPORT_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 */
687static 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
713static 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 */
772static 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 */
811void 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}
829EXPORT_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 */
839int 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}
854EXPORT_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
135static int dw_i2c_plat_probe(struct platform_device *pdev) 136static 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
29static struct property_entry spt_i2c_properties[] = {
30 PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
31 { },
32};
33
34static struct property_set spt_i2c_pset = {
35 .properties = spt_i2c_properties,
36};
37
38static const struct intel_lpss_platform_info spt_i2c_info = {
39 .clk_rate = 120000000,
40 .pset = &spt_i2c_pset,
41};
42
28static const struct intel_lpss_platform_info bxt_info = { 43static 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
36static const struct acpi_device_id intel_lpss_acpi_ids[] = { 51static 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
69static struct property_entry spt_i2c_properties[] = {
70 PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
71 { },
72};
73
74static struct property_set spt_i2c_pset = {
75 .properties = spt_i2c_properties,
76};
77
78static const struct intel_lpss_platform_info spt_i2c_info = {
79 .clk_rate = 120000000,
80 .pset = &spt_i2c_pset,
81};
82
83static 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
90static struct property_set uart_pset = {
91 .properties = uart_properties,
92};
93
68static const struct intel_lpss_platform_info spt_uart_info = { 94static 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
73static const struct intel_lpss_platform_info bxt_info = { 100static const struct intel_lpss_platform_info bxt_info = {
@@ -77,6 +104,7 @@ static const struct intel_lpss_platform_info bxt_info = {
77static const struct intel_lpss_platform_info bxt_uart_info = { 104static 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
82static const struct intel_lpss_platform_info bxt_i2c_info = { 110static 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
218static int intel_lpss_assign_devs(struct intel_lpss *lpss) 219static 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
17struct device; 17struct device;
18struct resource; 18struct resource;
19struct property_set;
19 20
20struct intel_lpss_platform_info { 21struct 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
27int intel_lpss_probe(struct device *dev, 29int 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
19struct irq_domain; 19struct irq_domain;
20struct 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 */
22struct mfd_cell_acpi_match { 23struct 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
20struct mfd_cell; 20struct mfd_cell;
21struct property_set;
21 22
22struct platform_device { 23struct 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};
74extern struct platform_device *platform_device_register_full( 77extern 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);
168extern int platform_device_add_data(struct platform_device *pdev, 171extern int platform_device_add_data(struct platform_device *pdev,
169 const void *data, size_t size); 172 const void *data, size_t size);
173extern int platform_device_add_properties(struct platform_device *pdev,
174 const struct property_set *pset);
170extern int platform_device_add(struct platform_device *pdev); 175extern int platform_device_add(struct platform_device *pdev);
171extern void platform_device_del(struct platform_device *pdev); 176extern void platform_device_del(struct platform_device *pdev);
172extern void platform_device_put(struct platform_device *pdev); 177extern 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,
73struct fwnode_handle *device_get_next_child_node(struct device *dev, 73struct 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
80void fwnode_handle_put(struct fwnode_handle *fwnode); 80void 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 */
151struct property_entry { 153struct 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
175void device_add_property_set(struct device *dev, struct property_set *pset); 251int device_add_property_set(struct device *dev, const struct property_set *pset);
252void device_remove_property_set(struct device *dev);
176 253
177bool device_dma_supported(struct device *dev); 254bool device_dma_supported(struct device *dev);
178 255