]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
d90a5a30 MY |
2 | /* |
3 | * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> | |
d90a5a30 MY |
4 | */ |
5 | ||
b953ec2b PD |
6 | #define LOG_CATEGORY UCLASS_PINCTRL |
7 | ||
d678a59d | 8 | #include <common.h> |
336d4615 | 9 | #include <malloc.h> |
401d1c4f | 10 | #include <asm/global_data.h> |
336d4615 | 11 | #include <dm/device_compat.h> |
b08c8c48 | 12 | #include <linux/libfdt.h> |
d90a5a30 MY |
13 | #include <linux/err.h> |
14 | #include <linux/list.h> | |
9d922450 | 15 | #include <dm.h> |
d90a5a30 MY |
16 | #include <dm/lists.h> |
17 | #include <dm/pinctrl.h> | |
27326c7e | 18 | #include <dm/util.h> |
1e656ad0 | 19 | #include <dm/of_access.h> |
d90a5a30 MY |
20 | |
21 | DECLARE_GLOBAL_DATA_PTR; | |
22 | ||
d90a5a30 MY |
23 | /** |
24 | * pinctrl_config_one() - apply pinctrl settings for a single node | |
25 | * | |
26 | * @config: pin configuration node | |
27 | * @return: 0 on success, or negative error code on failure | |
28 | */ | |
29 | static int pinctrl_config_one(struct udevice *config) | |
30 | { | |
31 | struct udevice *pctldev; | |
32 | const struct pinctrl_ops *ops; | |
33 | ||
34 | pctldev = config; | |
35 | for (;;) { | |
36 | pctldev = dev_get_parent(pctldev); | |
37 | if (!pctldev) { | |
38 | dev_err(config, "could not find pctldev\n"); | |
39 | return -EINVAL; | |
40 | } | |
41 | if (pctldev->uclass->uc_drv->id == UCLASS_PINCTRL) | |
42 | break; | |
43 | } | |
44 | ||
45 | ops = pinctrl_get_ops(pctldev); | |
46 | return ops->set_state(pctldev, config); | |
47 | } | |
48 | ||
49 | /** | |
50 | * pinctrl_select_state_full() - full implementation of pinctrl_select_state | |
51 | * | |
52 | * @dev: peripheral device | |
53 | * @statename: state name, like "default" | |
54 | * @return: 0 on success, or negative error code on failure | |
55 | */ | |
56 | static int pinctrl_select_state_full(struct udevice *dev, const char *statename) | |
57 | { | |
d90a5a30 MY |
58 | char propname[32]; /* long enough */ |
59 | const fdt32_t *list; | |
60 | uint32_t phandle; | |
d90a5a30 MY |
61 | struct udevice *config; |
62 | int state, size, i, ret; | |
63 | ||
1e656ad0 | 64 | state = dev_read_stringlist_search(dev, "pinctrl-names", statename); |
d90a5a30 MY |
65 | if (state < 0) { |
66 | char *end; | |
67 | /* | |
68 | * If statename is not found in "pinctrl-names", | |
69 | * assume statename is just the integer state ID. | |
70 | */ | |
0b1284eb | 71 | state = dectoul(statename, &end); |
d90a5a30 | 72 | if (*end) |
72b8c6d1 | 73 | return -ENOSYS; |
d90a5a30 MY |
74 | } |
75 | ||
76 | snprintf(propname, sizeof(propname), "pinctrl-%d", state); | |
1e656ad0 | 77 | list = dev_read_prop(dev, propname, &size); |
d90a5a30 | 78 | if (!list) |
72b8c6d1 | 79 | return -ENOSYS; |
d90a5a30 MY |
80 | |
81 | size /= sizeof(*list); | |
82 | for (i = 0; i < size; i++) { | |
83 | phandle = fdt32_to_cpu(*list++); | |
1e656ad0 KY |
84 | ret = uclass_get_device_by_phandle_id(UCLASS_PINCONFIG, phandle, |
85 | &config); | |
36a90eda MT |
86 | if (ret) { |
87 | dev_warn(dev, "%s: uclass_get_device_by_phandle_id: err=%d\n", | |
88 | __func__, ret); | |
89 | continue; | |
90 | } | |
d90a5a30 MY |
91 | |
92 | ret = pinctrl_config_one(config); | |
36a90eda MT |
93 | if (ret) { |
94 | dev_warn(dev, "%s: pinctrl_config_one: err=%d\n", | |
95 | __func__, ret); | |
96 | continue; | |
97 | } | |
d90a5a30 MY |
98 | } |
99 | ||
100 | return 0; | |
101 | } | |
102 | ||
1d01440b JK |
103 | static bool ofnode_pre_reloc_recursive(ofnode parent) |
104 | { | |
105 | ofnode child; | |
106 | ||
107 | if (ofnode_pre_reloc(parent)) | |
108 | return true; | |
109 | ||
110 | if (CONFIG_IS_ENABLED(PINCONF_RECURSIVE)) { | |
111 | ofnode_for_each_subnode(child, parent) | |
112 | if (ofnode_pre_reloc_recursive(child)) | |
113 | return true; | |
114 | } | |
115 | ||
116 | return false; | |
117 | } | |
118 | ||
d90a5a30 | 119 | /** |
f835706c | 120 | * pinconfig_post_bind() - post binding for PINCONFIG uclass |
d90a5a30 MY |
121 | * Recursively bind its children as pinconfig devices. |
122 | * | |
123 | * @dev: pinconfig device | |
124 | * @return: 0 on success, or negative error code on failure | |
125 | */ | |
126 | static int pinconfig_post_bind(struct udevice *dev) | |
127 | { | |
5589a818 | 128 | bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC); |
d90a5a30 | 129 | const char *name; |
45a26867 | 130 | ofnode node; |
d90a5a30 MY |
131 | int ret; |
132 | ||
7d14ee44 | 133 | if (!dev_has_ofnode(dev)) |
63402831 UR |
134 | return 0; |
135 | ||
45a26867 | 136 | dev_for_each_subnode(node, dev) { |
b6a6238f | 137 | if (pre_reloc_only && |
1d01440b | 138 | !ofnode_pre_reloc_recursive(node)) |
5589a818 | 139 | continue; |
d90a5a30 MY |
140 | /* |
141 | * If this node has "compatible" property, this is not | |
142 | * a pin configuration node, but a normal device. skip. | |
143 | */ | |
61e51bab | 144 | ofnode_get_property(node, "compatible", &ret); |
d90a5a30 MY |
145 | if (ret >= 0) |
146 | continue; | |
d39e2bd0 PD |
147 | /* If this node has "gpio-controller" property, skip */ |
148 | if (ofnode_read_bool(node, "gpio-controller")) | |
149 | continue; | |
d90a5a30 MY |
150 | |
151 | if (ret != -FDT_ERR_NOTFOUND) | |
152 | return ret; | |
153 | ||
45a26867 | 154 | name = ofnode_get_name(node); |
d90a5a30 MY |
155 | if (!name) |
156 | return -EINVAL; | |
157 | ret = device_bind_driver_to_node(dev, "pinconfig", name, | |
45a26867 | 158 | node, NULL); |
d90a5a30 MY |
159 | if (ret) |
160 | return ret; | |
161 | } | |
162 | ||
163 | return 0; | |
164 | } | |
165 | ||
75013fa7 | 166 | #if CONFIG_IS_ENABLED(PINCTRL_FULL) |
d90a5a30 MY |
167 | UCLASS_DRIVER(pinconfig) = { |
168 | .id = UCLASS_PINCONFIG, | |
44510dae | 169 | #if CONFIG_IS_ENABLED(PINCONF_RECURSIVE) |
d90a5a30 | 170 | .post_bind = pinconfig_post_bind, |
c20851b3 | 171 | #endif |
d90a5a30 MY |
172 | .name = "pinconfig", |
173 | }; | |
174 | ||
175 | U_BOOT_DRIVER(pinconfig_generic) = { | |
176 | .name = "pinconfig", | |
177 | .id = UCLASS_PINCONFIG, | |
178 | }; | |
d90a5a30 MY |
179 | #endif |
180 | ||
ae59d7ca MV |
181 | static int |
182 | pinctrl_gpio_get_pinctrl_and_offset(struct udevice *dev, unsigned offset, | |
183 | struct udevice **pctldev, | |
184 | unsigned int *pin_selector) | |
185 | { | |
186 | struct ofnode_phandle_args args; | |
187 | unsigned gpio_offset, pfc_base, pfc_pins; | |
d0bb00ad QW |
188 | int ret = 0; |
189 | int i = 0; | |
ae59d7ca | 190 | |
d0bb00ad QW |
191 | while (ret == 0) { |
192 | ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, | |
193 | i++, &args); | |
194 | if (ret) { | |
195 | dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n", | |
196 | __func__, ret); | |
197 | return ret; | |
198 | } | |
ae59d7ca | 199 | |
d0bb00ad QW |
200 | ret = uclass_get_device_by_ofnode(UCLASS_PINCTRL, |
201 | args.node, pctldev); | |
202 | if (ret) { | |
203 | dev_dbg(dev, | |
204 | "%s: uclass_get_device_by_of_offset failed: err=%d\n", | |
205 | __func__, ret); | |
206 | return ret; | |
207 | } | |
ae59d7ca | 208 | |
d0bb00ad QW |
209 | gpio_offset = args.args[0]; |
210 | pfc_base = args.args[1]; | |
211 | pfc_pins = args.args[2]; | |
ae59d7ca | 212 | |
d0bb00ad QW |
213 | if (offset >= gpio_offset && offset <= gpio_offset + pfc_pins) |
214 | break; | |
ae59d7ca MV |
215 | } |
216 | ||
217 | offset -= gpio_offset; | |
218 | offset += pfc_base; | |
219 | *pin_selector = offset; | |
220 | ||
221 | return 0; | |
222 | } | |
223 | ||
224 | /** | |
225 | * pinctrl_gpio_request() - request a single pin to be used as GPIO | |
226 | * | |
227 | * @dev: GPIO peripheral device | |
228 | * @offset: the GPIO pin offset from the GPIO controller | |
a1de1035 | 229 | * @label: the GPIO pin label |
ae59d7ca MV |
230 | * @return: 0 on success, or negative error code on failure |
231 | */ | |
a1de1035 | 232 | int pinctrl_gpio_request(struct udevice *dev, unsigned offset, const char *label) |
ae59d7ca MV |
233 | { |
234 | const struct pinctrl_ops *ops; | |
235 | struct udevice *pctldev; | |
236 | unsigned int pin_selector; | |
237 | int ret; | |
238 | ||
239 | ret = pinctrl_gpio_get_pinctrl_and_offset(dev, offset, | |
240 | &pctldev, &pin_selector); | |
241 | if (ret) | |
242 | return ret; | |
243 | ||
244 | ops = pinctrl_get_ops(pctldev); | |
bddac45d SG |
245 | assert(ops); |
246 | if (!ops->gpio_request_enable) | |
247 | return -ENOSYS; | |
ae59d7ca MV |
248 | |
249 | return ops->gpio_request_enable(pctldev, pin_selector); | |
250 | } | |
251 | ||
252 | /** | |
253 | * pinctrl_gpio_free() - free a single pin used as GPIO | |
254 | * | |
255 | * @dev: GPIO peripheral device | |
256 | * @offset: the GPIO pin offset from the GPIO controller | |
257 | * @return: 0 on success, or negative error code on failure | |
258 | */ | |
259 | int pinctrl_gpio_free(struct udevice *dev, unsigned offset) | |
260 | { | |
261 | const struct pinctrl_ops *ops; | |
262 | struct udevice *pctldev; | |
263 | unsigned int pin_selector; | |
264 | int ret; | |
265 | ||
266 | ret = pinctrl_gpio_get_pinctrl_and_offset(dev, offset, | |
267 | &pctldev, &pin_selector); | |
268 | if (ret) | |
269 | return ret; | |
270 | ||
271 | ops = pinctrl_get_ops(pctldev); | |
bddac45d SG |
272 | assert(ops); |
273 | if (!ops->gpio_disable_free) | |
274 | return -ENOSYS; | |
ae59d7ca MV |
275 | |
276 | return ops->gpio_disable_free(pctldev, pin_selector); | |
277 | } | |
278 | ||
d90a5a30 MY |
279 | /** |
280 | * pinctrl_select_state_simple() - simple implementation of pinctrl_select_state | |
281 | * | |
282 | * @dev: peripheral device | |
283 | * @return: 0 on success, or negative error code on failure | |
284 | */ | |
285 | static int pinctrl_select_state_simple(struct udevice *dev) | |
286 | { | |
287 | struct udevice *pctldev; | |
288 | struct pinctrl_ops *ops; | |
289 | int ret; | |
290 | ||
291 | /* | |
dce406e0 PC |
292 | * For most system, there is only one pincontroller device. But in |
293 | * case of multiple pincontroller devices, probe the one with sequence | |
294 | * number 0 (defined by alias) to avoid race condition. | |
d90a5a30 | 295 | */ |
dce406e0 PC |
296 | ret = uclass_get_device_by_seq(UCLASS_PINCTRL, 0, &pctldev); |
297 | if (ret) | |
298 | /* if not found, get the first one */ | |
299 | ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev); | |
d90a5a30 MY |
300 | if (ret) |
301 | return ret; | |
302 | ||
303 | ops = pinctrl_get_ops(pctldev); | |
304 | if (!ops->set_state_simple) { | |
305 | dev_dbg(dev, "set_state_simple op missing\n"); | |
306 | return -ENOSYS; | |
307 | } | |
308 | ||
309 | return ops->set_state_simple(pctldev, dev); | |
310 | } | |
311 | ||
312 | int pinctrl_select_state(struct udevice *dev, const char *statename) | |
313 | { | |
f717b4c8 KY |
314 | /* |
315 | * Some device which is logical like mmc.blk, do not have | |
316 | * a valid ofnode. | |
317 | */ | |
c23405f8 | 318 | if (!dev_has_ofnode(dev)) |
f717b4c8 | 319 | return 0; |
d90a5a30 MY |
320 | /* |
321 | * Try full-implemented pinctrl first. | |
322 | * If it fails or is not implemented, try simple one. | |
323 | */ | |
72b8c6d1 MW |
324 | if (CONFIG_IS_ENABLED(PINCTRL_FULL)) |
325 | return pinctrl_select_state_full(dev, statename); | |
d90a5a30 | 326 | |
72b8c6d1 | 327 | return pinctrl_select_state_simple(dev); |
d90a5a30 MY |
328 | } |
329 | ||
c5acf4a2 SG |
330 | int pinctrl_request(struct udevice *dev, int func, int flags) |
331 | { | |
332 | struct pinctrl_ops *ops = pinctrl_get_ops(dev); | |
333 | ||
334 | if (!ops->request) | |
335 | return -ENOSYS; | |
336 | ||
337 | return ops->request(dev, func, flags); | |
338 | } | |
339 | ||
340 | int pinctrl_request_noflags(struct udevice *dev, int func) | |
341 | { | |
342 | return pinctrl_request(dev, func, 0); | |
343 | } | |
344 | ||
345 | int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph) | |
346 | { | |
347 | struct pinctrl_ops *ops = pinctrl_get_ops(dev); | |
348 | ||
349 | if (!ops->get_periph_id) | |
350 | return -ENOSYS; | |
351 | ||
352 | return ops->get_periph_id(dev, periph); | |
353 | } | |
354 | ||
77eaa19e SG |
355 | int pinctrl_get_gpio_mux(struct udevice *dev, int banknum, int index) |
356 | { | |
357 | struct pinctrl_ops *ops = pinctrl_get_ops(dev); | |
358 | ||
359 | if (!ops->get_gpio_mux) | |
360 | return -ENOSYS; | |
361 | ||
362 | return ops->get_gpio_mux(dev, banknum, index); | |
363 | } | |
364 | ||
8bbb5b20 PC |
365 | int pinctrl_get_pins_count(struct udevice *dev) |
366 | { | |
367 | struct pinctrl_ops *ops = pinctrl_get_ops(dev); | |
368 | ||
369 | if (!ops->get_pins_count) | |
370 | return -ENOSYS; | |
371 | ||
372 | return ops->get_pins_count(dev); | |
373 | } | |
374 | ||
375 | int pinctrl_get_pin_name(struct udevice *dev, int selector, char *buf, | |
376 | int size) | |
377 | { | |
378 | struct pinctrl_ops *ops = pinctrl_get_ops(dev); | |
379 | ||
380 | if (!ops->get_pin_name) | |
381 | return -ENOSYS; | |
382 | ||
383 | snprintf(buf, size, ops->get_pin_name(dev, selector)); | |
384 | ||
385 | return 0; | |
386 | } | |
387 | ||
f55a0c0a PC |
388 | int pinctrl_get_pin_muxing(struct udevice *dev, int selector, char *buf, |
389 | int size) | |
390 | { | |
391 | struct pinctrl_ops *ops = pinctrl_get_ops(dev); | |
392 | ||
393 | if (!ops->get_pin_muxing) | |
394 | return -ENOSYS; | |
395 | ||
396 | return ops->get_pin_muxing(dev, selector, buf, size); | |
397 | } | |
398 | ||
d90a5a30 | 399 | /** |
e71505fc | 400 | * pinctrl_post_bind() - post binding for PINCTRL uclass |
d90a5a30 MY |
401 | * Recursively bind child nodes as pinconfig devices in case of full pinctrl. |
402 | * | |
403 | * @dev: pinctrl device | |
404 | * @return: 0 on success, or negative error code on failure | |
405 | */ | |
e878b53a | 406 | static int __maybe_unused pinctrl_post_bind(struct udevice *dev) |
d90a5a30 MY |
407 | { |
408 | const struct pinctrl_ops *ops = pinctrl_get_ops(dev); | |
409 | ||
410 | if (!ops) { | |
411 | dev_dbg(dev, "ops is not set. Do not bind.\n"); | |
412 | return -EINVAL; | |
413 | } | |
414 | ||
415 | /* | |
75013fa7 MW |
416 | * If the pinctrl driver has the full implementation, its child nodes |
417 | * should be bound so that peripheral devices can easily search in | |
418 | * parent devices during later DT-parsing. | |
d90a5a30 | 419 | */ |
75013fa7 | 420 | if (CONFIG_IS_ENABLED(PINCTRL_FULL)) |
8a5f6129 MY |
421 | return pinconfig_post_bind(dev); |
422 | ||
423 | return 0; | |
d90a5a30 MY |
424 | } |
425 | ||
426 | UCLASS_DRIVER(pinctrl) = { | |
427 | .id = UCLASS_PINCTRL, | |
95397385 | 428 | #if CONFIG_IS_ENABLED(OF_REAL) |
d90a5a30 | 429 | .post_bind = pinctrl_post_bind, |
c8fbf308 | 430 | #endif |
ac985273 | 431 | .flags = DM_UC_FLAG_SEQ_ALIAS, |
d90a5a30 MY |
432 | .name = "pinctrl", |
433 | }; |