.. | .. |
---|
18 | 18 | #include <linux/etherdevice.h> |
---|
19 | 19 | #include <linux/phy.h> |
---|
20 | 20 | |
---|
21 | | -struct property_set { |
---|
22 | | - struct device *dev; |
---|
23 | | - struct fwnode_handle fwnode; |
---|
24 | | - const struct property_entry *properties; |
---|
25 | | -}; |
---|
26 | | - |
---|
27 | | -static const struct fwnode_operations pset_fwnode_ops; |
---|
28 | | - |
---|
29 | | -static inline bool is_pset_node(const struct fwnode_handle *fwnode) |
---|
30 | | -{ |
---|
31 | | - return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &pset_fwnode_ops; |
---|
32 | | -} |
---|
33 | | - |
---|
34 | | -#define to_pset_node(__fwnode) \ |
---|
35 | | - ({ \ |
---|
36 | | - typeof(__fwnode) __to_pset_node_fwnode = __fwnode; \ |
---|
37 | | - \ |
---|
38 | | - is_pset_node(__to_pset_node_fwnode) ? \ |
---|
39 | | - container_of(__to_pset_node_fwnode, \ |
---|
40 | | - struct property_set, fwnode) : \ |
---|
41 | | - NULL; \ |
---|
42 | | - }) |
---|
43 | | - |
---|
44 | | -static const struct property_entry * |
---|
45 | | -pset_prop_get(const struct property_set *pset, const char *name) |
---|
46 | | -{ |
---|
47 | | - const struct property_entry *prop; |
---|
48 | | - |
---|
49 | | - if (!pset || !pset->properties) |
---|
50 | | - return NULL; |
---|
51 | | - |
---|
52 | | - for (prop = pset->properties; prop->name; prop++) |
---|
53 | | - if (!strcmp(name, prop->name)) |
---|
54 | | - return prop; |
---|
55 | | - |
---|
56 | | - return NULL; |
---|
57 | | -} |
---|
58 | | - |
---|
59 | | -static const void *property_get_pointer(const struct property_entry *prop) |
---|
60 | | -{ |
---|
61 | | - switch (prop->type) { |
---|
62 | | - case DEV_PROP_U8: |
---|
63 | | - if (prop->is_array) |
---|
64 | | - return prop->pointer.u8_data; |
---|
65 | | - return &prop->value.u8_data; |
---|
66 | | - case DEV_PROP_U16: |
---|
67 | | - if (prop->is_array) |
---|
68 | | - return prop->pointer.u16_data; |
---|
69 | | - return &prop->value.u16_data; |
---|
70 | | - case DEV_PROP_U32: |
---|
71 | | - if (prop->is_array) |
---|
72 | | - return prop->pointer.u32_data; |
---|
73 | | - return &prop->value.u32_data; |
---|
74 | | - case DEV_PROP_U64: |
---|
75 | | - if (prop->is_array) |
---|
76 | | - return prop->pointer.u64_data; |
---|
77 | | - return &prop->value.u64_data; |
---|
78 | | - case DEV_PROP_STRING: |
---|
79 | | - if (prop->is_array) |
---|
80 | | - return prop->pointer.str; |
---|
81 | | - return &prop->value.str; |
---|
82 | | - default: |
---|
83 | | - return NULL; |
---|
84 | | - } |
---|
85 | | -} |
---|
86 | | - |
---|
87 | | -static void property_set_pointer(struct property_entry *prop, const void *pointer) |
---|
88 | | -{ |
---|
89 | | - switch (prop->type) { |
---|
90 | | - case DEV_PROP_U8: |
---|
91 | | - if (prop->is_array) |
---|
92 | | - prop->pointer.u8_data = pointer; |
---|
93 | | - else |
---|
94 | | - prop->value.u8_data = *((u8 *)pointer); |
---|
95 | | - break; |
---|
96 | | - case DEV_PROP_U16: |
---|
97 | | - if (prop->is_array) |
---|
98 | | - prop->pointer.u16_data = pointer; |
---|
99 | | - else |
---|
100 | | - prop->value.u16_data = *((u16 *)pointer); |
---|
101 | | - break; |
---|
102 | | - case DEV_PROP_U32: |
---|
103 | | - if (prop->is_array) |
---|
104 | | - prop->pointer.u32_data = pointer; |
---|
105 | | - else |
---|
106 | | - prop->value.u32_data = *((u32 *)pointer); |
---|
107 | | - break; |
---|
108 | | - case DEV_PROP_U64: |
---|
109 | | - if (prop->is_array) |
---|
110 | | - prop->pointer.u64_data = pointer; |
---|
111 | | - else |
---|
112 | | - prop->value.u64_data = *((u64 *)pointer); |
---|
113 | | - break; |
---|
114 | | - case DEV_PROP_STRING: |
---|
115 | | - if (prop->is_array) |
---|
116 | | - prop->pointer.str = pointer; |
---|
117 | | - else |
---|
118 | | - prop->value.str = pointer; |
---|
119 | | - break; |
---|
120 | | - default: |
---|
121 | | - break; |
---|
122 | | - } |
---|
123 | | -} |
---|
124 | | - |
---|
125 | | -static const void *pset_prop_find(const struct property_set *pset, |
---|
126 | | - const char *propname, size_t length) |
---|
127 | | -{ |
---|
128 | | - const struct property_entry *prop; |
---|
129 | | - const void *pointer; |
---|
130 | | - |
---|
131 | | - prop = pset_prop_get(pset, propname); |
---|
132 | | - if (!prop) |
---|
133 | | - return ERR_PTR(-EINVAL); |
---|
134 | | - pointer = property_get_pointer(prop); |
---|
135 | | - if (!pointer) |
---|
136 | | - return ERR_PTR(-ENODATA); |
---|
137 | | - if (length > prop->length) |
---|
138 | | - return ERR_PTR(-EOVERFLOW); |
---|
139 | | - return pointer; |
---|
140 | | -} |
---|
141 | | - |
---|
142 | | -static int pset_prop_read_u8_array(const struct property_set *pset, |
---|
143 | | - const char *propname, |
---|
144 | | - u8 *values, size_t nval) |
---|
145 | | -{ |
---|
146 | | - const void *pointer; |
---|
147 | | - size_t length = nval * sizeof(*values); |
---|
148 | | - |
---|
149 | | - pointer = pset_prop_find(pset, propname, length); |
---|
150 | | - if (IS_ERR(pointer)) |
---|
151 | | - return PTR_ERR(pointer); |
---|
152 | | - |
---|
153 | | - memcpy(values, pointer, length); |
---|
154 | | - return 0; |
---|
155 | | -} |
---|
156 | | - |
---|
157 | | -static int pset_prop_read_u16_array(const struct property_set *pset, |
---|
158 | | - const char *propname, |
---|
159 | | - u16 *values, size_t nval) |
---|
160 | | -{ |
---|
161 | | - const void *pointer; |
---|
162 | | - size_t length = nval * sizeof(*values); |
---|
163 | | - |
---|
164 | | - pointer = pset_prop_find(pset, propname, length); |
---|
165 | | - if (IS_ERR(pointer)) |
---|
166 | | - return PTR_ERR(pointer); |
---|
167 | | - |
---|
168 | | - memcpy(values, pointer, length); |
---|
169 | | - return 0; |
---|
170 | | -} |
---|
171 | | - |
---|
172 | | -static int pset_prop_read_u32_array(const struct property_set *pset, |
---|
173 | | - const char *propname, |
---|
174 | | - u32 *values, size_t nval) |
---|
175 | | -{ |
---|
176 | | - const void *pointer; |
---|
177 | | - size_t length = nval * sizeof(*values); |
---|
178 | | - |
---|
179 | | - pointer = pset_prop_find(pset, propname, length); |
---|
180 | | - if (IS_ERR(pointer)) |
---|
181 | | - return PTR_ERR(pointer); |
---|
182 | | - |
---|
183 | | - memcpy(values, pointer, length); |
---|
184 | | - return 0; |
---|
185 | | -} |
---|
186 | | - |
---|
187 | | -static int pset_prop_read_u64_array(const struct property_set *pset, |
---|
188 | | - const char *propname, |
---|
189 | | - u64 *values, size_t nval) |
---|
190 | | -{ |
---|
191 | | - const void *pointer; |
---|
192 | | - size_t length = nval * sizeof(*values); |
---|
193 | | - |
---|
194 | | - pointer = pset_prop_find(pset, propname, length); |
---|
195 | | - if (IS_ERR(pointer)) |
---|
196 | | - return PTR_ERR(pointer); |
---|
197 | | - |
---|
198 | | - memcpy(values, pointer, length); |
---|
199 | | - return 0; |
---|
200 | | -} |
---|
201 | | - |
---|
202 | | -static int pset_prop_count_elems_of_size(const struct property_set *pset, |
---|
203 | | - const char *propname, size_t length) |
---|
204 | | -{ |
---|
205 | | - const struct property_entry *prop; |
---|
206 | | - |
---|
207 | | - prop = pset_prop_get(pset, propname); |
---|
208 | | - if (!prop) |
---|
209 | | - return -EINVAL; |
---|
210 | | - |
---|
211 | | - return prop->length / length; |
---|
212 | | -} |
---|
213 | | - |
---|
214 | | -static int pset_prop_read_string_array(const struct property_set *pset, |
---|
215 | | - const char *propname, |
---|
216 | | - const char **strings, size_t nval) |
---|
217 | | -{ |
---|
218 | | - const struct property_entry *prop; |
---|
219 | | - const void *pointer; |
---|
220 | | - size_t array_len, length; |
---|
221 | | - |
---|
222 | | - /* Find out the array length. */ |
---|
223 | | - prop = pset_prop_get(pset, propname); |
---|
224 | | - if (!prop) |
---|
225 | | - return -EINVAL; |
---|
226 | | - |
---|
227 | | - if (!prop->is_array) |
---|
228 | | - /* The array length for a non-array string property is 1. */ |
---|
229 | | - array_len = 1; |
---|
230 | | - else |
---|
231 | | - /* Find the length of an array. */ |
---|
232 | | - array_len = pset_prop_count_elems_of_size(pset, propname, |
---|
233 | | - sizeof(const char *)); |
---|
234 | | - |
---|
235 | | - /* Return how many there are if strings is NULL. */ |
---|
236 | | - if (!strings) |
---|
237 | | - return array_len; |
---|
238 | | - |
---|
239 | | - array_len = min(nval, array_len); |
---|
240 | | - length = array_len * sizeof(*strings); |
---|
241 | | - |
---|
242 | | - pointer = pset_prop_find(pset, propname, length); |
---|
243 | | - if (IS_ERR(pointer)) |
---|
244 | | - return PTR_ERR(pointer); |
---|
245 | | - |
---|
246 | | - memcpy(strings, pointer, length); |
---|
247 | | - |
---|
248 | | - return array_len; |
---|
249 | | -} |
---|
250 | | - |
---|
251 | 21 | struct fwnode_handle *dev_fwnode(struct device *dev) |
---|
252 | 22 | { |
---|
253 | 23 | return IS_ENABLED(CONFIG_OF) && dev->of_node ? |
---|
254 | 24 | &dev->of_node->fwnode : dev->fwnode; |
---|
255 | 25 | } |
---|
256 | 26 | EXPORT_SYMBOL_GPL(dev_fwnode); |
---|
257 | | - |
---|
258 | | -static bool pset_fwnode_property_present(const struct fwnode_handle *fwnode, |
---|
259 | | - const char *propname) |
---|
260 | | -{ |
---|
261 | | - return !!pset_prop_get(to_pset_node(fwnode), propname); |
---|
262 | | -} |
---|
263 | | - |
---|
264 | | -static int pset_fwnode_read_int_array(const struct fwnode_handle *fwnode, |
---|
265 | | - const char *propname, |
---|
266 | | - unsigned int elem_size, void *val, |
---|
267 | | - size_t nval) |
---|
268 | | -{ |
---|
269 | | - const struct property_set *node = to_pset_node(fwnode); |
---|
270 | | - |
---|
271 | | - if (!val) |
---|
272 | | - return pset_prop_count_elems_of_size(node, propname, elem_size); |
---|
273 | | - |
---|
274 | | - switch (elem_size) { |
---|
275 | | - case sizeof(u8): |
---|
276 | | - return pset_prop_read_u8_array(node, propname, val, nval); |
---|
277 | | - case sizeof(u16): |
---|
278 | | - return pset_prop_read_u16_array(node, propname, val, nval); |
---|
279 | | - case sizeof(u32): |
---|
280 | | - return pset_prop_read_u32_array(node, propname, val, nval); |
---|
281 | | - case sizeof(u64): |
---|
282 | | - return pset_prop_read_u64_array(node, propname, val, nval); |
---|
283 | | - } |
---|
284 | | - |
---|
285 | | - return -ENXIO; |
---|
286 | | -} |
---|
287 | | - |
---|
288 | | -static int |
---|
289 | | -pset_fwnode_property_read_string_array(const struct fwnode_handle *fwnode, |
---|
290 | | - const char *propname, |
---|
291 | | - const char **val, size_t nval) |
---|
292 | | -{ |
---|
293 | | - return pset_prop_read_string_array(to_pset_node(fwnode), propname, |
---|
294 | | - val, nval); |
---|
295 | | -} |
---|
296 | | - |
---|
297 | | -static const struct fwnode_operations pset_fwnode_ops = { |
---|
298 | | - .property_present = pset_fwnode_property_present, |
---|
299 | | - .property_read_int_array = pset_fwnode_read_int_array, |
---|
300 | | - .property_read_string_array = pset_fwnode_property_read_string_array, |
---|
301 | | -}; |
---|
302 | 27 | |
---|
303 | 28 | /** |
---|
304 | 29 | * device_property_present - check if a property of a device is present |
---|
.. | .. |
---|
759 | 484 | } |
---|
760 | 485 | EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); |
---|
761 | 486 | |
---|
762 | | -static void property_entry_free_data(const struct property_entry *p) |
---|
763 | | -{ |
---|
764 | | - const void *pointer = property_get_pointer(p); |
---|
765 | | - size_t i, nval; |
---|
766 | | - |
---|
767 | | - if (p->is_array) { |
---|
768 | | - if (p->type == DEV_PROP_STRING && p->pointer.str) { |
---|
769 | | - nval = p->length / sizeof(const char *); |
---|
770 | | - for (i = 0; i < nval; i++) |
---|
771 | | - kfree(p->pointer.str[i]); |
---|
772 | | - } |
---|
773 | | - kfree(pointer); |
---|
774 | | - } else if (p->type == DEV_PROP_STRING) { |
---|
775 | | - kfree(p->value.str); |
---|
776 | | - } |
---|
777 | | - kfree(p->name); |
---|
778 | | -} |
---|
779 | | - |
---|
780 | | -static int property_copy_string_array(struct property_entry *dst, |
---|
781 | | - const struct property_entry *src) |
---|
782 | | -{ |
---|
783 | | - const char **d; |
---|
784 | | - size_t nval = src->length / sizeof(*d); |
---|
785 | | - int i; |
---|
786 | | - |
---|
787 | | - d = kcalloc(nval, sizeof(*d), GFP_KERNEL); |
---|
788 | | - if (!d) |
---|
789 | | - return -ENOMEM; |
---|
790 | | - |
---|
791 | | - for (i = 0; i < nval; i++) { |
---|
792 | | - d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL); |
---|
793 | | - if (!d[i] && src->pointer.str[i]) { |
---|
794 | | - while (--i >= 0) |
---|
795 | | - kfree(d[i]); |
---|
796 | | - kfree(d); |
---|
797 | | - return -ENOMEM; |
---|
798 | | - } |
---|
799 | | - } |
---|
800 | | - |
---|
801 | | - dst->pointer.str = d; |
---|
802 | | - return 0; |
---|
803 | | -} |
---|
804 | | - |
---|
805 | | -static int property_entry_copy_data(struct property_entry *dst, |
---|
806 | | - const struct property_entry *src) |
---|
807 | | -{ |
---|
808 | | - const void *pointer = property_get_pointer(src); |
---|
809 | | - const void *new; |
---|
810 | | - int error; |
---|
811 | | - |
---|
812 | | - if (src->is_array) { |
---|
813 | | - if (!src->length) |
---|
814 | | - return -ENODATA; |
---|
815 | | - |
---|
816 | | - if (src->type == DEV_PROP_STRING) { |
---|
817 | | - error = property_copy_string_array(dst, src); |
---|
818 | | - if (error) |
---|
819 | | - return error; |
---|
820 | | - new = dst->pointer.str; |
---|
821 | | - } else { |
---|
822 | | - new = kmemdup(pointer, src->length, GFP_KERNEL); |
---|
823 | | - if (!new) |
---|
824 | | - return -ENOMEM; |
---|
825 | | - } |
---|
826 | | - } else if (src->type == DEV_PROP_STRING) { |
---|
827 | | - new = kstrdup(src->value.str, GFP_KERNEL); |
---|
828 | | - if (!new && src->value.str) |
---|
829 | | - return -ENOMEM; |
---|
830 | | - } else { |
---|
831 | | - new = pointer; |
---|
832 | | - } |
---|
833 | | - |
---|
834 | | - dst->length = src->length; |
---|
835 | | - dst->is_array = src->is_array; |
---|
836 | | - dst->type = src->type; |
---|
837 | | - |
---|
838 | | - property_set_pointer(dst, new); |
---|
839 | | - |
---|
840 | | - dst->name = kstrdup(src->name, GFP_KERNEL); |
---|
841 | | - if (!dst->name) |
---|
842 | | - goto out_free_data; |
---|
843 | | - |
---|
844 | | - return 0; |
---|
845 | | - |
---|
846 | | -out_free_data: |
---|
847 | | - property_entry_free_data(dst); |
---|
848 | | - return -ENOMEM; |
---|
849 | | -} |
---|
850 | | - |
---|
851 | 487 | /** |
---|
852 | | - * property_entries_dup - duplicate array of properties |
---|
853 | | - * @properties: array of properties to copy |
---|
| 488 | + * fwnode_find_reference - Find named reference to a fwnode_handle |
---|
| 489 | + * @fwnode: Firmware node where to look for the reference |
---|
| 490 | + * @name: The name of the reference |
---|
| 491 | + * @index: Index of the reference |
---|
854 | 492 | * |
---|
855 | | - * This function creates a deep copy of the given NULL-terminated array |
---|
856 | | - * of property entries. |
---|
| 493 | + * @index can be used when the named reference holds a table of references. |
---|
| 494 | + * |
---|
| 495 | + * Returns pointer to the reference fwnode, or ERR_PTR. Caller is responsible to |
---|
| 496 | + * call fwnode_handle_put() on the returned fwnode pointer. |
---|
857 | 497 | */ |
---|
858 | | -struct property_entry * |
---|
859 | | -property_entries_dup(const struct property_entry *properties) |
---|
| 498 | +struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode, |
---|
| 499 | + const char *name, |
---|
| 500 | + unsigned int index) |
---|
860 | 501 | { |
---|
861 | | - struct property_entry *p; |
---|
862 | | - int i, n = 0; |
---|
| 502 | + struct fwnode_reference_args args; |
---|
| 503 | + int ret; |
---|
863 | 504 | |
---|
864 | | - while (properties[n].name) |
---|
865 | | - n++; |
---|
866 | | - |
---|
867 | | - p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL); |
---|
868 | | - if (!p) |
---|
869 | | - return ERR_PTR(-ENOMEM); |
---|
870 | | - |
---|
871 | | - for (i = 0; i < n; i++) { |
---|
872 | | - int ret = property_entry_copy_data(&p[i], &properties[i]); |
---|
873 | | - if (ret) { |
---|
874 | | - while (--i >= 0) |
---|
875 | | - property_entry_free_data(&p[i]); |
---|
876 | | - kfree(p); |
---|
877 | | - return ERR_PTR(ret); |
---|
878 | | - } |
---|
879 | | - } |
---|
880 | | - |
---|
881 | | - return p; |
---|
| 505 | + ret = fwnode_property_get_reference_args(fwnode, name, NULL, 0, index, |
---|
| 506 | + &args); |
---|
| 507 | + return ret ? ERR_PTR(ret) : args.fwnode; |
---|
882 | 508 | } |
---|
883 | | -EXPORT_SYMBOL_GPL(property_entries_dup); |
---|
884 | | - |
---|
885 | | -/** |
---|
886 | | - * property_entries_free - free previously allocated array of properties |
---|
887 | | - * @properties: array of properties to destroy |
---|
888 | | - * |
---|
889 | | - * This function frees given NULL-terminated array of property entries, |
---|
890 | | - * along with their data. |
---|
891 | | - */ |
---|
892 | | -void property_entries_free(const struct property_entry *properties) |
---|
893 | | -{ |
---|
894 | | - const struct property_entry *p; |
---|
895 | | - |
---|
896 | | - for (p = properties; p->name; p++) |
---|
897 | | - property_entry_free_data(p); |
---|
898 | | - |
---|
899 | | - kfree(properties); |
---|
900 | | -} |
---|
901 | | -EXPORT_SYMBOL_GPL(property_entries_free); |
---|
902 | | - |
---|
903 | | -/** |
---|
904 | | - * pset_free_set - releases memory allocated for copied property set |
---|
905 | | - * @pset: Property set to release |
---|
906 | | - * |
---|
907 | | - * Function takes previously copied property set and releases all the |
---|
908 | | - * memory allocated to it. |
---|
909 | | - */ |
---|
910 | | -static void pset_free_set(struct property_set *pset) |
---|
911 | | -{ |
---|
912 | | - if (!pset) |
---|
913 | | - return; |
---|
914 | | - |
---|
915 | | - property_entries_free(pset->properties); |
---|
916 | | - kfree(pset); |
---|
917 | | -} |
---|
918 | | - |
---|
919 | | -/** |
---|
920 | | - * pset_copy_set - copies property set |
---|
921 | | - * @pset: Property set to copy |
---|
922 | | - * |
---|
923 | | - * This function takes a deep copy of the given property set and returns |
---|
924 | | - * pointer to the copy. Call device_free_property_set() to free resources |
---|
925 | | - * allocated in this function. |
---|
926 | | - * |
---|
927 | | - * Return: Pointer to the new property set or error pointer. |
---|
928 | | - */ |
---|
929 | | -static struct property_set *pset_copy_set(const struct property_set *pset) |
---|
930 | | -{ |
---|
931 | | - struct property_entry *properties; |
---|
932 | | - struct property_set *p; |
---|
933 | | - |
---|
934 | | - p = kzalloc(sizeof(*p), GFP_KERNEL); |
---|
935 | | - if (!p) |
---|
936 | | - return ERR_PTR(-ENOMEM); |
---|
937 | | - |
---|
938 | | - properties = property_entries_dup(pset->properties); |
---|
939 | | - if (IS_ERR(properties)) { |
---|
940 | | - kfree(p); |
---|
941 | | - return ERR_CAST(properties); |
---|
942 | | - } |
---|
943 | | - |
---|
944 | | - p->properties = properties; |
---|
945 | | - return p; |
---|
946 | | -} |
---|
| 509 | +EXPORT_SYMBOL_GPL(fwnode_find_reference); |
---|
947 | 510 | |
---|
948 | 511 | /** |
---|
949 | 512 | * device_remove_properties - Remove properties from a device object. |
---|
950 | 513 | * @dev: Device whose properties to remove. |
---|
951 | 514 | * |
---|
952 | 515 | * The function removes properties previously associated to the device |
---|
953 | | - * secondary firmware node with device_add_properties(). Memory allocated |
---|
954 | | - * to the properties will also be released. |
---|
| 516 | + * firmware node with device_add_properties(). Memory allocated to the |
---|
| 517 | + * properties will also be released. |
---|
955 | 518 | */ |
---|
956 | 519 | void device_remove_properties(struct device *dev) |
---|
957 | 520 | { |
---|
958 | | - struct fwnode_handle *fwnode; |
---|
959 | | - struct property_set *pset; |
---|
| 521 | + struct fwnode_handle *fwnode = dev_fwnode(dev); |
---|
960 | 522 | |
---|
961 | | - fwnode = dev_fwnode(dev); |
---|
962 | 523 | if (!fwnode) |
---|
963 | 524 | return; |
---|
964 | | - /* |
---|
965 | | - * Pick either primary or secondary node depending which one holds |
---|
966 | | - * the pset. If there is no real firmware node (ACPI/DT) primary |
---|
967 | | - * will hold the pset. |
---|
968 | | - */ |
---|
969 | | - pset = to_pset_node(fwnode); |
---|
970 | | - if (pset) { |
---|
971 | | - set_primary_fwnode(dev, NULL); |
---|
972 | | - } else { |
---|
973 | | - pset = to_pset_node(fwnode->secondary); |
---|
974 | | - if (pset && dev == pset->dev) |
---|
975 | | - set_secondary_fwnode(dev, NULL); |
---|
| 525 | + |
---|
| 526 | + if (is_software_node(fwnode->secondary)) { |
---|
| 527 | + fwnode_remove_software_node(fwnode->secondary); |
---|
| 528 | + set_secondary_fwnode(dev, NULL); |
---|
976 | 529 | } |
---|
977 | | - if (pset && dev == pset->dev) |
---|
978 | | - pset_free_set(pset); |
---|
979 | 530 | } |
---|
980 | 531 | EXPORT_SYMBOL_GPL(device_remove_properties); |
---|
981 | 532 | |
---|
.. | .. |
---|
985 | 536 | * @properties: Collection of properties to add. |
---|
986 | 537 | * |
---|
987 | 538 | * Associate a collection of device properties represented by @properties with |
---|
988 | | - * @dev as its secondary firmware node. The function takes a copy of |
---|
989 | | - * @properties. |
---|
| 539 | + * @dev. The function takes a copy of @properties. |
---|
| 540 | + * |
---|
| 541 | + * WARNING: The callers should not use this function if it is known that there |
---|
| 542 | + * is no real firmware node associated with @dev! In that case the callers |
---|
| 543 | + * should create a software node and assign it to @dev directly. |
---|
990 | 544 | */ |
---|
991 | 545 | int device_add_properties(struct device *dev, |
---|
992 | 546 | const struct property_entry *properties) |
---|
993 | 547 | { |
---|
994 | | - struct property_set *p, pset; |
---|
| 548 | + struct fwnode_handle *fwnode; |
---|
995 | 549 | |
---|
996 | | - if (!properties) |
---|
997 | | - return -EINVAL; |
---|
| 550 | + fwnode = fwnode_create_software_node(properties, NULL); |
---|
| 551 | + if (IS_ERR(fwnode)) |
---|
| 552 | + return PTR_ERR(fwnode); |
---|
998 | 553 | |
---|
999 | | - pset.properties = properties; |
---|
1000 | | - |
---|
1001 | | - p = pset_copy_set(&pset); |
---|
1002 | | - if (IS_ERR(p)) |
---|
1003 | | - return PTR_ERR(p); |
---|
1004 | | - |
---|
1005 | | - p->fwnode.ops = &pset_fwnode_ops; |
---|
1006 | | - set_secondary_fwnode(dev, &p->fwnode); |
---|
1007 | | - p->dev = dev; |
---|
| 554 | + set_secondary_fwnode(dev, fwnode); |
---|
1008 | 555 | return 0; |
---|
1009 | 556 | } |
---|
1010 | 557 | EXPORT_SYMBOL_GPL(device_add_properties); |
---|
| 558 | + |
---|
| 559 | +/** |
---|
| 560 | + * fwnode_get_name - Return the name of a node |
---|
| 561 | + * @fwnode: The firmware node |
---|
| 562 | + * |
---|
| 563 | + * Returns a pointer to the node name. |
---|
| 564 | + */ |
---|
| 565 | +const char *fwnode_get_name(const struct fwnode_handle *fwnode) |
---|
| 566 | +{ |
---|
| 567 | + return fwnode_call_ptr_op(fwnode, get_name); |
---|
| 568 | +} |
---|
| 569 | +EXPORT_SYMBOL_GPL(fwnode_get_name); |
---|
| 570 | + |
---|
| 571 | +/** |
---|
| 572 | + * fwnode_get_name_prefix - Return the prefix of node for printing purposes |
---|
| 573 | + * @fwnode: The firmware node |
---|
| 574 | + * |
---|
| 575 | + * Returns the prefix of a node, intended to be printed right before the node. |
---|
| 576 | + * The prefix works also as a separator between the nodes. |
---|
| 577 | + */ |
---|
| 578 | +const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode) |
---|
| 579 | +{ |
---|
| 580 | + return fwnode_call_ptr_op(fwnode, get_name_prefix); |
---|
| 581 | +} |
---|
| 582 | + |
---|
| 583 | +/** |
---|
| 584 | + * fwnode_get_parent - Return parent firwmare node |
---|
| 585 | + * @fwnode: Firmware whose parent is retrieved |
---|
| 586 | + * |
---|
| 587 | + * Return parent firmware node of the given node if possible or %NULL if no |
---|
| 588 | + * parent was available. |
---|
| 589 | + */ |
---|
| 590 | +struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode) |
---|
| 591 | +{ |
---|
| 592 | + return fwnode_call_ptr_op(fwnode, get_parent); |
---|
| 593 | +} |
---|
| 594 | +EXPORT_SYMBOL_GPL(fwnode_get_parent); |
---|
1011 | 595 | |
---|
1012 | 596 | /** |
---|
1013 | 597 | * fwnode_get_next_parent - Iterate to the node's parent |
---|
.. | .. |
---|
1031 | 615 | EXPORT_SYMBOL_GPL(fwnode_get_next_parent); |
---|
1032 | 616 | |
---|
1033 | 617 | /** |
---|
1034 | | - * fwnode_get_parent - Return parent firwmare node |
---|
1035 | | - * @fwnode: Firmware whose parent is retrieved |
---|
| 618 | + * fwnode_get_next_parent_dev - Find device of closest ancestor fwnode |
---|
| 619 | + * @fwnode: firmware node |
---|
1036 | 620 | * |
---|
1037 | | - * Return parent firmware node of the given node if possible or %NULL if no |
---|
1038 | | - * parent was available. |
---|
| 621 | + * Given a firmware node (@fwnode), this function finds its closest ancestor |
---|
| 622 | + * firmware node that has a corresponding struct device and returns that struct |
---|
| 623 | + * device. |
---|
| 624 | + * |
---|
| 625 | + * The caller of this function is expected to call put_device() on the returned |
---|
| 626 | + * device when they are done. |
---|
1039 | 627 | */ |
---|
1040 | | -struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode) |
---|
| 628 | +struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode) |
---|
1041 | 629 | { |
---|
1042 | | - return fwnode_call_ptr_op(fwnode, get_parent); |
---|
| 630 | + struct device *dev = NULL; |
---|
| 631 | + |
---|
| 632 | + fwnode_handle_get(fwnode); |
---|
| 633 | + do { |
---|
| 634 | + fwnode = fwnode_get_next_parent(fwnode); |
---|
| 635 | + if (fwnode) |
---|
| 636 | + dev = get_dev_from_fwnode(fwnode); |
---|
| 637 | + } while (fwnode && !dev); |
---|
| 638 | + fwnode_handle_put(fwnode); |
---|
| 639 | + return dev; |
---|
1043 | 640 | } |
---|
1044 | | -EXPORT_SYMBOL_GPL(fwnode_get_parent); |
---|
| 641 | + |
---|
| 642 | +/** |
---|
| 643 | + * fwnode_count_parents - Return the number of parents a node has |
---|
| 644 | + * @fwnode: The node the parents of which are to be counted |
---|
| 645 | + * |
---|
| 646 | + * Returns the number of parents a node has. |
---|
| 647 | + */ |
---|
| 648 | +unsigned int fwnode_count_parents(const struct fwnode_handle *fwnode) |
---|
| 649 | +{ |
---|
| 650 | + struct fwnode_handle *__fwnode; |
---|
| 651 | + unsigned int count; |
---|
| 652 | + |
---|
| 653 | + __fwnode = fwnode_get_parent(fwnode); |
---|
| 654 | + |
---|
| 655 | + for (count = 0; __fwnode; count++) |
---|
| 656 | + __fwnode = fwnode_get_next_parent(__fwnode); |
---|
| 657 | + |
---|
| 658 | + return count; |
---|
| 659 | +} |
---|
| 660 | +EXPORT_SYMBOL_GPL(fwnode_count_parents); |
---|
| 661 | + |
---|
| 662 | +/** |
---|
| 663 | + * fwnode_get_nth_parent - Return an nth parent of a node |
---|
| 664 | + * @fwnode: The node the parent of which is requested |
---|
| 665 | + * @depth: Distance of the parent from the node |
---|
| 666 | + * |
---|
| 667 | + * Returns the nth parent of a node. If there is no parent at the requested |
---|
| 668 | + * @depth, %NULL is returned. If @depth is 0, the functionality is equivalent to |
---|
| 669 | + * fwnode_handle_get(). For @depth == 1, it is fwnode_get_parent() and so on. |
---|
| 670 | + * |
---|
| 671 | + * The caller is responsible for calling fwnode_handle_put() for the returned |
---|
| 672 | + * node. |
---|
| 673 | + */ |
---|
| 674 | +struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode, |
---|
| 675 | + unsigned int depth) |
---|
| 676 | +{ |
---|
| 677 | + unsigned int i; |
---|
| 678 | + |
---|
| 679 | + fwnode_handle_get(fwnode); |
---|
| 680 | + |
---|
| 681 | + for (i = 0; i < depth && fwnode; i++) |
---|
| 682 | + fwnode = fwnode_get_next_parent(fwnode); |
---|
| 683 | + |
---|
| 684 | + return fwnode; |
---|
| 685 | +} |
---|
| 686 | +EXPORT_SYMBOL_GPL(fwnode_get_nth_parent); |
---|
| 687 | + |
---|
| 688 | +/** |
---|
| 689 | + * fwnode_is_ancestor_of - Test if @test_ancestor is ancestor of @test_child |
---|
| 690 | + * @test_ancestor: Firmware which is tested for being an ancestor |
---|
| 691 | + * @test_child: Firmware which is tested for being the child |
---|
| 692 | + * |
---|
| 693 | + * A node is considered an ancestor of itself too. |
---|
| 694 | + * |
---|
| 695 | + * Returns true if @test_ancestor is an ancestor of @test_child. |
---|
| 696 | + * Otherwise, returns false. |
---|
| 697 | + */ |
---|
| 698 | +bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor, |
---|
| 699 | + struct fwnode_handle *test_child) |
---|
| 700 | +{ |
---|
| 701 | + if (!test_ancestor) |
---|
| 702 | + return false; |
---|
| 703 | + |
---|
| 704 | + fwnode_handle_get(test_child); |
---|
| 705 | + while (test_child) { |
---|
| 706 | + if (test_child == test_ancestor) { |
---|
| 707 | + fwnode_handle_put(test_child); |
---|
| 708 | + return true; |
---|
| 709 | + } |
---|
| 710 | + test_child = fwnode_get_next_parent(test_child); |
---|
| 711 | + } |
---|
| 712 | + return false; |
---|
| 713 | +} |
---|
1045 | 714 | |
---|
1046 | 715 | /** |
---|
1047 | 716 | * fwnode_get_next_child_node - Return the next child node handle for a node |
---|
.. | .. |
---|
1091 | 760 | struct fwnode_handle *child) |
---|
1092 | 761 | { |
---|
1093 | 762 | struct acpi_device *adev = ACPI_COMPANION(dev); |
---|
1094 | | - struct fwnode_handle *fwnode = NULL; |
---|
| 763 | + struct fwnode_handle *fwnode = NULL, *next; |
---|
1095 | 764 | |
---|
1096 | 765 | if (dev->of_node) |
---|
1097 | 766 | fwnode = &dev->of_node->fwnode; |
---|
1098 | 767 | else if (adev) |
---|
1099 | 768 | fwnode = acpi_fwnode_handle(adev); |
---|
1100 | 769 | |
---|
1101 | | - return fwnode_get_next_child_node(fwnode, child); |
---|
| 770 | + /* Try to find a child in primary fwnode */ |
---|
| 771 | + next = fwnode_get_next_child_node(fwnode, child); |
---|
| 772 | + if (next) |
---|
| 773 | + return next; |
---|
| 774 | + |
---|
| 775 | + /* When no more children in primary, continue with secondary */ |
---|
| 776 | + if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary)) |
---|
| 777 | + next = fwnode_get_next_child_node(fwnode->secondary, child); |
---|
| 778 | + |
---|
| 779 | + return next; |
---|
1102 | 780 | } |
---|
1103 | 781 | EXPORT_SYMBOL_GPL(device_get_next_child_node); |
---|
1104 | 782 | |
---|
.. | .. |
---|
1341 | 1019 | EXPORT_SYMBOL(fwnode_irq_get); |
---|
1342 | 1020 | |
---|
1343 | 1021 | /** |
---|
1344 | | - * device_graph_get_next_endpoint - Get next endpoint firmware node |
---|
| 1022 | + * fwnode_graph_get_next_endpoint - Get next endpoint firmware node |
---|
1345 | 1023 | * @fwnode: Pointer to the parent firmware node |
---|
1346 | 1024 | * @prev: Previous endpoint node or %NULL to get the first |
---|
1347 | 1025 | * |
---|
.. | .. |
---|
1461 | 1139 | EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_node); |
---|
1462 | 1140 | |
---|
1463 | 1141 | /** |
---|
| 1142 | + * fwnode_graph_get_endpoint_by_id - get endpoint by port and endpoint numbers |
---|
| 1143 | + * @fwnode: parent fwnode_handle containing the graph |
---|
| 1144 | + * @port: identifier of the port node |
---|
| 1145 | + * @endpoint: identifier of the endpoint node under the port node |
---|
| 1146 | + * @flags: fwnode lookup flags |
---|
| 1147 | + * |
---|
| 1148 | + * Return the fwnode handle of the local endpoint corresponding the port and |
---|
| 1149 | + * endpoint IDs or NULL if not found. |
---|
| 1150 | + * |
---|
| 1151 | + * If FWNODE_GRAPH_ENDPOINT_NEXT is passed in @flags and the specified endpoint |
---|
| 1152 | + * has not been found, look for the closest endpoint ID greater than the |
---|
| 1153 | + * specified one and return the endpoint that corresponds to it, if present. |
---|
| 1154 | + * |
---|
| 1155 | + * Do not return endpoints that belong to disabled devices, unless |
---|
| 1156 | + * FWNODE_GRAPH_DEVICE_DISABLED is passed in @flags. |
---|
| 1157 | + * |
---|
| 1158 | + * The returned endpoint needs to be released by calling fwnode_handle_put() on |
---|
| 1159 | + * it when it is not needed any more. |
---|
| 1160 | + */ |
---|
| 1161 | +struct fwnode_handle * |
---|
| 1162 | +fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode, |
---|
| 1163 | + u32 port, u32 endpoint, unsigned long flags) |
---|
| 1164 | +{ |
---|
| 1165 | + struct fwnode_handle *ep = NULL, *best_ep = NULL; |
---|
| 1166 | + unsigned int best_ep_id = 0; |
---|
| 1167 | + bool endpoint_next = flags & FWNODE_GRAPH_ENDPOINT_NEXT; |
---|
| 1168 | + bool enabled_only = !(flags & FWNODE_GRAPH_DEVICE_DISABLED); |
---|
| 1169 | + |
---|
| 1170 | + while ((ep = fwnode_graph_get_next_endpoint(fwnode, ep))) { |
---|
| 1171 | + struct fwnode_endpoint fwnode_ep = { 0 }; |
---|
| 1172 | + int ret; |
---|
| 1173 | + |
---|
| 1174 | + if (enabled_only) { |
---|
| 1175 | + struct fwnode_handle *dev_node; |
---|
| 1176 | + bool available; |
---|
| 1177 | + |
---|
| 1178 | + dev_node = fwnode_graph_get_remote_port_parent(ep); |
---|
| 1179 | + available = fwnode_device_is_available(dev_node); |
---|
| 1180 | + fwnode_handle_put(dev_node); |
---|
| 1181 | + if (!available) |
---|
| 1182 | + continue; |
---|
| 1183 | + } |
---|
| 1184 | + |
---|
| 1185 | + ret = fwnode_graph_parse_endpoint(ep, &fwnode_ep); |
---|
| 1186 | + if (ret < 0) |
---|
| 1187 | + continue; |
---|
| 1188 | + |
---|
| 1189 | + if (fwnode_ep.port != port) |
---|
| 1190 | + continue; |
---|
| 1191 | + |
---|
| 1192 | + if (fwnode_ep.id == endpoint) |
---|
| 1193 | + return ep; |
---|
| 1194 | + |
---|
| 1195 | + if (!endpoint_next) |
---|
| 1196 | + continue; |
---|
| 1197 | + |
---|
| 1198 | + /* |
---|
| 1199 | + * If the endpoint that has just been found is not the first |
---|
| 1200 | + * matching one and the ID of the one found previously is closer |
---|
| 1201 | + * to the requested endpoint ID, skip it. |
---|
| 1202 | + */ |
---|
| 1203 | + if (fwnode_ep.id < endpoint || |
---|
| 1204 | + (best_ep && best_ep_id < fwnode_ep.id)) |
---|
| 1205 | + continue; |
---|
| 1206 | + |
---|
| 1207 | + fwnode_handle_put(best_ep); |
---|
| 1208 | + best_ep = fwnode_handle_get(ep); |
---|
| 1209 | + best_ep_id = fwnode_ep.id; |
---|
| 1210 | + } |
---|
| 1211 | + |
---|
| 1212 | + return best_ep; |
---|
| 1213 | +} |
---|
| 1214 | +EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_by_id); |
---|
| 1215 | + |
---|
| 1216 | +/** |
---|
1464 | 1217 | * fwnode_graph_parse_endpoint - parse common endpoint node properties |
---|
1465 | 1218 | * @fwnode: pointer to endpoint fwnode_handle |
---|
1466 | 1219 | * @endpoint: pointer to the fwnode endpoint data structure |
---|
.. | .. |
---|
1483 | 1236 | return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev); |
---|
1484 | 1237 | } |
---|
1485 | 1238 | EXPORT_SYMBOL_GPL(device_get_match_data); |
---|
| 1239 | + |
---|
| 1240 | +static void * |
---|
| 1241 | +fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id, |
---|
| 1242 | + void *data, devcon_match_fn_t match) |
---|
| 1243 | +{ |
---|
| 1244 | + struct fwnode_handle *node; |
---|
| 1245 | + struct fwnode_handle *ep; |
---|
| 1246 | + void *ret; |
---|
| 1247 | + |
---|
| 1248 | + fwnode_graph_for_each_endpoint(fwnode, ep) { |
---|
| 1249 | + node = fwnode_graph_get_remote_port_parent(ep); |
---|
| 1250 | + if (!fwnode_device_is_available(node)) { |
---|
| 1251 | + fwnode_handle_put(node); |
---|
| 1252 | + continue; |
---|
| 1253 | + } |
---|
| 1254 | + |
---|
| 1255 | + ret = match(node, con_id, data); |
---|
| 1256 | + fwnode_handle_put(node); |
---|
| 1257 | + if (ret) { |
---|
| 1258 | + fwnode_handle_put(ep); |
---|
| 1259 | + return ret; |
---|
| 1260 | + } |
---|
| 1261 | + } |
---|
| 1262 | + return NULL; |
---|
| 1263 | +} |
---|
| 1264 | + |
---|
| 1265 | +static void * |
---|
| 1266 | +fwnode_devcon_match(struct fwnode_handle *fwnode, const char *con_id, |
---|
| 1267 | + void *data, devcon_match_fn_t match) |
---|
| 1268 | +{ |
---|
| 1269 | + struct fwnode_handle *node; |
---|
| 1270 | + void *ret; |
---|
| 1271 | + int i; |
---|
| 1272 | + |
---|
| 1273 | + for (i = 0; ; i++) { |
---|
| 1274 | + node = fwnode_find_reference(fwnode, con_id, i); |
---|
| 1275 | + if (IS_ERR(node)) |
---|
| 1276 | + break; |
---|
| 1277 | + |
---|
| 1278 | + ret = match(node, NULL, data); |
---|
| 1279 | + fwnode_handle_put(node); |
---|
| 1280 | + if (ret) |
---|
| 1281 | + return ret; |
---|
| 1282 | + } |
---|
| 1283 | + |
---|
| 1284 | + return NULL; |
---|
| 1285 | +} |
---|
| 1286 | + |
---|
| 1287 | +/** |
---|
| 1288 | + * fwnode_connection_find_match - Find connection from a device node |
---|
| 1289 | + * @fwnode: Device node with the connection |
---|
| 1290 | + * @con_id: Identifier for the connection |
---|
| 1291 | + * @data: Data for the match function |
---|
| 1292 | + * @match: Function to check and convert the connection description |
---|
| 1293 | + * |
---|
| 1294 | + * Find a connection with unique identifier @con_id between @fwnode and another |
---|
| 1295 | + * device node. @match will be used to convert the connection description to |
---|
| 1296 | + * data the caller is expecting to be returned. |
---|
| 1297 | + */ |
---|
| 1298 | +void *fwnode_connection_find_match(struct fwnode_handle *fwnode, |
---|
| 1299 | + const char *con_id, void *data, |
---|
| 1300 | + devcon_match_fn_t match) |
---|
| 1301 | +{ |
---|
| 1302 | + void *ret; |
---|
| 1303 | + |
---|
| 1304 | + if (!fwnode || !match) |
---|
| 1305 | + return NULL; |
---|
| 1306 | + |
---|
| 1307 | + ret = fwnode_graph_devcon_match(fwnode, con_id, data, match); |
---|
| 1308 | + if (ret) |
---|
| 1309 | + return ret; |
---|
| 1310 | + |
---|
| 1311 | + return fwnode_devcon_match(fwnode, con_id, data, match); |
---|
| 1312 | +} |
---|
| 1313 | +EXPORT_SYMBOL_GPL(fwnode_connection_find_match); |
---|