/src/u-boot/drivers/pinctrl/pinctrl-generic.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0+ |
2 | | /* |
3 | | * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> |
4 | | */ |
5 | | |
6 | | #include <dm.h> |
7 | | #include <dm/device_compat.h> |
8 | | #include <linux/compat.h> |
9 | | #include <dm/pinctrl.h> |
10 | | |
11 | | /** |
12 | | * pinctrl_pin_name_to_selector() - return the pin selector for a pin |
13 | | * |
14 | | * @dev: pin controller device |
15 | | * @pin: the pin name to look up |
16 | | * @return: pin selector, or negative error code on failure |
17 | | */ |
18 | | static int pinctrl_pin_name_to_selector(struct udevice *dev, const char *pin) |
19 | 0 | { |
20 | 0 | const struct pinctrl_ops *ops = pinctrl_get_ops(dev); |
21 | 0 | unsigned npins, selector; |
22 | |
|
23 | 0 | if (!ops->get_pins_count || !ops->get_pin_name) { |
24 | 0 | dev_dbg(dev, "get_pins_count or get_pin_name missing\n"); |
25 | 0 | return -ENOENT; |
26 | 0 | } |
27 | | |
28 | 0 | npins = ops->get_pins_count(dev); |
29 | | |
30 | | /* See if this pctldev has this pin */ |
31 | 0 | for (selector = 0; selector < npins; selector++) { |
32 | 0 | const char *pname = ops->get_pin_name(dev, selector); |
33 | |
|
34 | 0 | if (!strcmp(pin, pname)) |
35 | 0 | return selector; |
36 | 0 | } |
37 | | |
38 | 0 | return -ENOENT; |
39 | 0 | } |
40 | | |
41 | | /** |
42 | | * pinctrl_group_name_to_selector() - return the group selector for a group |
43 | | * |
44 | | * @dev: pin controller device |
45 | | * @group: the pin group name to look up |
46 | | * @return: pin group selector, or negative error code on failure |
47 | | */ |
48 | | static int pinctrl_group_name_to_selector(struct udevice *dev, |
49 | | const char *group) |
50 | 0 | { |
51 | 0 | const struct pinctrl_ops *ops = pinctrl_get_ops(dev); |
52 | 0 | unsigned ngroups, selector; |
53 | |
|
54 | 0 | if (!ops->get_groups_count || !ops->get_group_name) { |
55 | 0 | dev_dbg(dev, "get_groups_count or get_group_name missing\n"); |
56 | 0 | return -ENOENT; |
57 | 0 | } |
58 | | |
59 | 0 | ngroups = ops->get_groups_count(dev); |
60 | | |
61 | | /* See if this pctldev has this group */ |
62 | 0 | for (selector = 0; selector < ngroups; selector++) { |
63 | 0 | const char *gname = ops->get_group_name(dev, selector); |
64 | |
|
65 | 0 | if (!strcmp(group, gname)) |
66 | 0 | return selector; |
67 | 0 | } |
68 | | |
69 | 0 | return -ENOENT; |
70 | 0 | } |
71 | | |
72 | | #if CONFIG_IS_ENABLED(PINMUX) |
73 | | /** |
74 | | * pinmux_func_name_to_selector() - return the function selector for a function |
75 | | * |
76 | | * @dev: pin controller device |
77 | | * @function: the function name to look up |
78 | | * @return: function selector, or negative error code on failure |
79 | | */ |
80 | | static int pinmux_func_name_to_selector(struct udevice *dev, |
81 | | const char *function) |
82 | 0 | { |
83 | 0 | const struct pinctrl_ops *ops = pinctrl_get_ops(dev); |
84 | 0 | unsigned nfuncs, selector = 0; |
85 | |
|
86 | 0 | if (!ops->get_functions_count || !ops->get_function_name) { |
87 | 0 | dev_dbg(dev, |
88 | 0 | "get_functions_count or get_function_name missing\n"); |
89 | 0 | return -ENOENT; |
90 | 0 | } |
91 | | |
92 | 0 | nfuncs = ops->get_functions_count(dev); |
93 | | |
94 | | /* See if this pctldev has this function */ |
95 | 0 | for (selector = 0; selector < nfuncs; selector++) { |
96 | 0 | const char *fname = ops->get_function_name(dev, selector); |
97 | |
|
98 | 0 | if (!strcmp(function, fname)) |
99 | 0 | return selector; |
100 | 0 | } |
101 | | |
102 | 0 | return -ENOENT; |
103 | 0 | } |
104 | | |
105 | | /** |
106 | | * pinmux_enable_setting() - enable pin-mux setting for a certain pin/group |
107 | | * |
108 | | * @dev: pin controller device |
109 | | * @is_group: target of operation (true: pin group, false: pin) |
110 | | * @selector: pin selector or group selector, depending on @is_group |
111 | | * @func_selector: function selector |
112 | | * @return: 0 on success, or negative error code on failure |
113 | | */ |
114 | | static int pinmux_enable_setting(struct udevice *dev, bool is_group, |
115 | | unsigned selector, unsigned func_selector) |
116 | 0 | { |
117 | 0 | const struct pinctrl_ops *ops = pinctrl_get_ops(dev); |
118 | |
|
119 | 0 | if (is_group) { |
120 | 0 | if (!ops->pinmux_group_set) { |
121 | 0 | dev_dbg(dev, "pinmux_group_set op missing\n"); |
122 | 0 | return -ENOENT; |
123 | 0 | } |
124 | | |
125 | 0 | return ops->pinmux_group_set(dev, selector, func_selector); |
126 | 0 | } else { |
127 | 0 | if (!ops->pinmux_set) { |
128 | 0 | dev_dbg(dev, "pinmux_set op missing\n"); |
129 | 0 | return -ENOENT; |
130 | 0 | } |
131 | 0 | return ops->pinmux_set(dev, selector, func_selector); |
132 | 0 | } |
133 | 0 | } |
134 | | #else |
135 | | static int pinmux_func_name_to_selector(struct udevice *dev, |
136 | | const char *function) |
137 | | { |
138 | | return 0; |
139 | | } |
140 | | |
141 | | static int pinmux_enable_setting(struct udevice *dev, bool is_group, |
142 | | unsigned selector, unsigned func_selector) |
143 | | { |
144 | | return 0; |
145 | | } |
146 | | #endif |
147 | | |
148 | | #if CONFIG_IS_ENABLED(PINCONF) |
149 | | /** |
150 | | * pinconf_prop_name_to_param() - return parameter ID for a property name |
151 | | * |
152 | | * @dev: pin controller device |
153 | | * @property: property name in DTS, such as "bias-pull-up", "slew-rate", etc. |
154 | | * @default_value: return default value in case no value is specified in DTS |
155 | | * @return: return pamater ID, or negative error code on failure |
156 | | */ |
157 | | static int pinconf_prop_name_to_param(struct udevice *dev, |
158 | | const char *property, u32 *default_value) |
159 | 0 | { |
160 | 0 | const struct pinctrl_ops *ops = pinctrl_get_ops(dev); |
161 | 0 | const struct pinconf_param *p, *end; |
162 | |
|
163 | 0 | if (!ops->pinconf_num_params || !ops->pinconf_params) { |
164 | 0 | dev_dbg(dev, "pinconf_num_params or pinconf_params missing\n"); |
165 | 0 | return -ENOENT; |
166 | 0 | } |
167 | | |
168 | 0 | p = ops->pinconf_params; |
169 | 0 | end = p + ops->pinconf_num_params; |
170 | | |
171 | | /* See if this pctldev supports this parameter */ |
172 | 0 | for (; p < end; p++) { |
173 | 0 | if (!strcmp(property, p->property)) { |
174 | 0 | *default_value = p->default_value; |
175 | 0 | return p->param; |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | 0 | return -ENOENT; |
180 | 0 | } |
181 | | |
182 | | /** |
183 | | * pinconf_enable_setting() - apply pin configuration for a certain pin/group |
184 | | * |
185 | | * @dev: pin controller device |
186 | | * @is_group: target of operation (true: pin group, false: pin) |
187 | | * @selector: pin selector or group selector, depending on @is_group |
188 | | * @param: configuration paramter |
189 | | * @argument: argument taken by some configuration parameters |
190 | | * @return: 0 on success, or negative error code on failure |
191 | | */ |
192 | | static int pinconf_enable_setting(struct udevice *dev, bool is_group, |
193 | | unsigned selector, unsigned param, |
194 | | u32 argument) |
195 | 0 | { |
196 | 0 | const struct pinctrl_ops *ops = pinctrl_get_ops(dev); |
197 | |
|
198 | 0 | if (is_group) { |
199 | 0 | if (!ops->pinconf_group_set) { |
200 | 0 | dev_dbg(dev, "pinconf_group_set op missing\n"); |
201 | 0 | return -ENOENT; |
202 | 0 | } |
203 | | |
204 | 0 | return ops->pinconf_group_set(dev, selector, param, |
205 | 0 | argument); |
206 | 0 | } else { |
207 | 0 | if (!ops->pinconf_set) { |
208 | 0 | dev_dbg(dev, "pinconf_set op missing\n"); |
209 | 0 | return -ENOENT; |
210 | 0 | } |
211 | 0 | return ops->pinconf_set(dev, selector, param, argument); |
212 | 0 | } |
213 | 0 | } |
214 | | #else |
215 | | static int pinconf_prop_name_to_param(struct udevice *dev, |
216 | | const char *property, u32 *default_value) |
217 | | { |
218 | | return -ENOENT; |
219 | | } |
220 | | |
221 | | static int pinconf_enable_setting(struct udevice *dev, bool is_group, |
222 | | unsigned selector, unsigned param, |
223 | | u32 argument) |
224 | | { |
225 | | return 0; |
226 | | } |
227 | | #endif |
228 | | |
229 | | enum pinmux_subnode_type { |
230 | | PST_NONE = 0, |
231 | | PST_PIN, |
232 | | PST_GROUP, |
233 | | PST_PINMUX, |
234 | | }; |
235 | | |
236 | | static const char *alloc_name_with_prefix(const char *name, const char *prefix) |
237 | 0 | { |
238 | 0 | if (prefix) { |
239 | 0 | char *name_with_prefix = malloc(strlen(prefix) + strlen(name) + 1); |
240 | 0 | if (name_with_prefix) |
241 | 0 | sprintf(name_with_prefix, "%s%s", prefix, name); |
242 | 0 | return name_with_prefix; |
243 | 0 | } else { |
244 | 0 | return name; |
245 | 0 | } |
246 | 0 | } |
247 | | |
248 | | static void free_name_with_prefix(const char *name_with_prefix, const char *prefix) |
249 | 0 | { |
250 | 0 | if (prefix) |
251 | 0 | free((char *)name_with_prefix); |
252 | 0 | } |
253 | | |
254 | | /** |
255 | | * pinctrl_generic_set_state_one() - set state for a certain pin/group |
256 | | * Apply all pin multiplexing and pin configurations specified by @config |
257 | | * for a given pin or pin group. |
258 | | * |
259 | | * @dev: pin controller device |
260 | | * @config: pseudo device pointing to config node |
261 | | * @subnode_type: target of operation (pin, group, or pin specified by a pinmux |
262 | | * group) |
263 | | * @selector: pin selector or group selector, depending on @subnode_type |
264 | | * @return: 0 on success, or negative error code on failure |
265 | | */ |
266 | | static int pinctrl_generic_set_state_one(struct udevice *dev, |
267 | | struct udevice *config, |
268 | | const char *prefix, |
269 | | enum pinmux_subnode_type subnode_type, |
270 | | unsigned selector) |
271 | 0 | { |
272 | 0 | const char *function_propname; |
273 | 0 | const char *propname; |
274 | 0 | const void *value; |
275 | 0 | struct ofprop property; |
276 | 0 | int len, func_selector, param, ret; |
277 | 0 | u32 arg, default_val; |
278 | |
|
279 | 0 | assert(subnode_type != PST_NONE); |
280 | |
|
281 | 0 | function_propname = alloc_name_with_prefix("function", prefix); |
282 | 0 | if (!function_propname) |
283 | 0 | return -ENOMEM; |
284 | | |
285 | 0 | dev_for_each_property(property, config) { |
286 | 0 | value = dev_read_prop_by_prop(&property, &propname, &len); |
287 | 0 | if (!value) { |
288 | 0 | free_name_with_prefix(function_propname, prefix); |
289 | 0 | return -EINVAL; |
290 | 0 | } |
291 | | |
292 | | /* pinmux subnodes already have their muxing set */ |
293 | 0 | if (subnode_type != PST_PINMUX && |
294 | 0 | !strcmp(propname, function_propname)) { |
295 | 0 | func_selector = pinmux_func_name_to_selector(dev, |
296 | 0 | value); |
297 | 0 | if (func_selector < 0) { |
298 | 0 | free_name_with_prefix(function_propname, prefix); |
299 | 0 | return func_selector; |
300 | 0 | } |
301 | 0 | ret = pinmux_enable_setting(dev, |
302 | 0 | subnode_type == PST_GROUP, |
303 | 0 | selector, |
304 | 0 | func_selector); |
305 | 0 | } else { |
306 | 0 | param = pinconf_prop_name_to_param(dev, propname, |
307 | 0 | &default_val); |
308 | 0 | if (param < 0) |
309 | 0 | continue; /* just skip unknown properties */ |
310 | | |
311 | 0 | if (len >= sizeof(fdt32_t)) |
312 | 0 | arg = fdt32_to_cpu(*(fdt32_t *)value); |
313 | 0 | else |
314 | 0 | arg = default_val; |
315 | |
|
316 | 0 | ret = pinconf_enable_setting(dev, |
317 | 0 | subnode_type == PST_GROUP, |
318 | 0 | selector, param, arg); |
319 | 0 | } |
320 | | |
321 | 0 | if (ret) { |
322 | 0 | free_name_with_prefix(function_propname, prefix); |
323 | 0 | return ret; |
324 | 0 | } |
325 | 0 | } |
326 | | |
327 | 0 | free_name_with_prefix(function_propname, prefix); |
328 | 0 | return 0; |
329 | 0 | } |
330 | | |
331 | | /** |
332 | | * pinctrl_generic_get_subnode_type() - determine whether there is a valid |
333 | | * pins, groups, or pinmux property in the config node |
334 | | * |
335 | | * @dev: pin controller device |
336 | | * @config: pseudo device pointing to config node |
337 | | * @count: number of specifiers contained within the property |
338 | | * @return: the type of the subnode, or PST_NONE |
339 | | */ |
340 | | static enum pinmux_subnode_type pinctrl_generic_get_subnode_type(struct udevice *dev, |
341 | | struct udevice *config, |
342 | | const char *prefix, |
343 | | int *count) |
344 | 0 | { |
345 | 0 | const struct pinctrl_ops *ops = pinctrl_get_ops(dev); |
346 | 0 | const char *propname; |
347 | |
|
348 | 0 | propname = alloc_name_with_prefix("pins", prefix); |
349 | 0 | if (!propname) |
350 | 0 | return -ENOMEM; |
351 | 0 | *count = dev_read_string_count(config, propname); |
352 | 0 | free_name_with_prefix(propname, prefix); |
353 | 0 | if (*count >= 0) |
354 | 0 | return PST_PIN; |
355 | | |
356 | 0 | propname = alloc_name_with_prefix("groups", prefix); |
357 | 0 | if (!propname) |
358 | 0 | return -ENOMEM; |
359 | 0 | *count = dev_read_string_count(config, propname); |
360 | 0 | free_name_with_prefix(propname, prefix); |
361 | 0 | if (*count >= 0) |
362 | 0 | return PST_GROUP; |
363 | | |
364 | 0 | if (ops->pinmux_property_set) { |
365 | 0 | propname = alloc_name_with_prefix("pinmux", prefix); |
366 | 0 | if (!propname) |
367 | 0 | return -ENOMEM; |
368 | 0 | *count = dev_read_size(config, propname); |
369 | 0 | free_name_with_prefix(propname, prefix); |
370 | 0 | if (*count >= 0 && !(*count % sizeof(u32))) { |
371 | 0 | *count /= sizeof(u32); |
372 | 0 | return PST_PINMUX; |
373 | 0 | } |
374 | 0 | } |
375 | | |
376 | 0 | *count = 0; |
377 | 0 | return PST_NONE; |
378 | 0 | } |
379 | | |
380 | | /** |
381 | | * pinctrl_generic_set_state_subnode() - apply all settings in config node |
382 | | * |
383 | | * @dev: pin controller device |
384 | | * @config: pseudo device pointing to config node |
385 | | * @prefix: device tree property prefix (e.g. vendor specific) |
386 | | * @return: 0 on success, or negative error code on failure |
387 | | */ |
388 | | static int pinctrl_generic_set_state_subnode(struct udevice *dev, |
389 | | struct udevice *config, |
390 | | const char *prefix) |
391 | 0 | { |
392 | 0 | enum pinmux_subnode_type subnode_type; |
393 | 0 | const char *propname; |
394 | 0 | const char *name; |
395 | 0 | int count, selector, i, ret, scratch; |
396 | 0 | const u32 *pinmux_groups = NULL; /* prevent use-uninitialized warning */ |
397 | |
|
398 | 0 | subnode_type = pinctrl_generic_get_subnode_type(dev, config, prefix, &count); |
399 | |
|
400 | 0 | debug("%s(%s, %s): count=%d\n", __func__, dev->name, config->name, |
401 | 0 | count); |
402 | |
|
403 | 0 | if (subnode_type == PST_PINMUX) { |
404 | 0 | propname = alloc_name_with_prefix("pinmux", prefix); |
405 | 0 | if (!propname) |
406 | 0 | return -ENOMEM; |
407 | 0 | pinmux_groups = dev_read_prop(config, propname, &scratch); |
408 | 0 | free_name_with_prefix(propname, prefix); |
409 | 0 | if (!pinmux_groups) |
410 | 0 | return -EINVAL; |
411 | 0 | } |
412 | | |
413 | 0 | for (i = 0; i < count; i++) { |
414 | 0 | switch (subnode_type) { |
415 | 0 | case PST_PIN: |
416 | 0 | propname = alloc_name_with_prefix("pins", prefix); |
417 | 0 | if (!propname) |
418 | 0 | return -ENOMEM; |
419 | 0 | ret = dev_read_string_index(config, propname, i, &name); |
420 | 0 | free_name_with_prefix(propname, prefix); |
421 | 0 | if (ret) |
422 | 0 | return ret; |
423 | 0 | selector = pinctrl_pin_name_to_selector(dev, name); |
424 | 0 | break; |
425 | 0 | case PST_GROUP: |
426 | 0 | propname = alloc_name_with_prefix("groups", prefix); |
427 | 0 | if (!propname) |
428 | 0 | return -ENOMEM; |
429 | 0 | ret = dev_read_string_index(config, propname, i, &name); |
430 | 0 | free_name_with_prefix(propname, prefix); |
431 | 0 | if (ret) |
432 | 0 | return ret; |
433 | 0 | selector = pinctrl_group_name_to_selector(dev, name); |
434 | 0 | break; |
435 | 0 | case PST_PINMUX: { |
436 | 0 | const struct pinctrl_ops *ops = pinctrl_get_ops(dev); |
437 | 0 | u32 pinmux_group = fdt32_to_cpu(pinmux_groups[i]); |
438 | | |
439 | | /* Checked for in pinctrl_generic_get_subnode_type */ |
440 | 0 | selector = ops->pinmux_property_set(dev, pinmux_group); |
441 | 0 | break; |
442 | 0 | } |
443 | 0 | case PST_NONE: |
444 | 0 | default: |
445 | | /* skip this node; may contain config child nodes */ |
446 | 0 | return 0; |
447 | 0 | } |
448 | | |
449 | 0 | if (selector < 0) |
450 | 0 | return selector; |
451 | | |
452 | 0 | ret = pinctrl_generic_set_state_one(dev, config, prefix, |
453 | 0 | subnode_type, selector); |
454 | 0 | if (ret) |
455 | 0 | return ret; |
456 | 0 | } |
457 | | |
458 | 0 | return 0; |
459 | 0 | } |
460 | | |
461 | | int pinctrl_generic_set_state_prefix(struct udevice *dev, struct udevice *config, |
462 | | const char *prefix) |
463 | 0 | { |
464 | 0 | struct udevice *child; |
465 | 0 | int ret; |
466 | |
|
467 | 0 | ret = pinctrl_generic_set_state_subnode(dev, config, prefix); |
468 | 0 | if (ret) |
469 | 0 | return ret; |
470 | | |
471 | 0 | for (device_find_first_child(config, &child); |
472 | 0 | child; |
473 | 0 | device_find_next_child(&child)) { |
474 | 0 | ret = pinctrl_generic_set_state_subnode(dev, child, prefix); |
475 | 0 | if (ret) |
476 | 0 | return ret; |
477 | 0 | } |
478 | | |
479 | 0 | return 0; |
480 | 0 | } |
481 | | |
482 | | int pinctrl_generic_set_state(struct udevice *dev, struct udevice *config) |
483 | 0 | { |
484 | | return pinctrl_generic_set_state_prefix(dev, config, NULL); |
485 | 0 | } |