]>
Commit | Line | Data |
---|---|---|
ae6b4d85 LW |
1 | /* |
2 | * Core driver for the pin config portions of the pin control subsystem | |
3 | * | |
4 | * Copyright (C) 2011 ST-Ericsson SA | |
5 | * Written on behalf of Linaro for ST-Ericsson | |
6 | * | |
7 | * Author: Linus Walleij <linus.walleij@linaro.org> | |
8 | * | |
9 | * License terms: GNU General Public License (GPL) version 2 | |
10 | */ | |
11 | #define pr_fmt(fmt) "pinconfig core: " fmt | |
12 | ||
13 | #include <linux/kernel.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/init.h> | |
16 | #include <linux/device.h> | |
17 | #include <linux/slab.h> | |
18 | #include <linux/debugfs.h> | |
19 | #include <linux/seq_file.h> | |
20 | #include <linux/pinctrl/machine.h> | |
21 | #include <linux/pinctrl/pinctrl.h> | |
22 | #include <linux/pinctrl/pinconf.h> | |
23 | #include "core.h" | |
24 | #include "pinconf.h" | |
25 | ||
2b694250 SW |
26 | int pinconf_check_ops(struct pinctrl_dev *pctldev) |
27 | { | |
28 | const struct pinconf_ops *ops = pctldev->desc->confops; | |
29 | ||
30 | /* We must be able to read out pin status */ | |
31 | if (!ops->pin_config_get && !ops->pin_config_group_get) | |
32 | return -EINVAL; | |
33 | /* We have to be able to config the pins in SOME way */ | |
34 | if (!ops->pin_config_set && !ops->pin_config_group_set) | |
35 | return -EINVAL; | |
36 | return 0; | |
37 | } | |
38 | ||
1e2082b5 SW |
39 | int pinconf_validate_map(struct pinctrl_map const *map, int i) |
40 | { | |
41 | if (!map->data.configs.group_or_pin) { | |
42 | pr_err("failed to register map %s (%d): no group/pin given\n", | |
43 | map->name, i); | |
44 | return -EINVAL; | |
45 | } | |
46 | ||
47 | if (map->data.configs.num_configs && | |
48 | !map->data.configs.configs) { | |
49 | pr_err("failed to register map %s (%d): no configs ptr given\n", | |
50 | map->name, i); | |
51 | return -EINVAL; | |
52 | } | |
53 | ||
54 | return 0; | |
55 | } | |
56 | ||
2b694250 | 57 | static int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, |
ae6b4d85 LW |
58 | unsigned long *config) |
59 | { | |
60 | const struct pinconf_ops *ops = pctldev->desc->confops; | |
61 | ||
62 | if (!ops || !ops->pin_config_get) { | |
51cd24ee | 63 | dev_err(pctldev->dev, "cannot get pin configuration, missing " |
ae6b4d85 LW |
64 | "pin_config_get() function in driver\n"); |
65 | return -EINVAL; | |
66 | } | |
67 | ||
68 | return ops->pin_config_get(pctldev, pin, config); | |
69 | } | |
70 | ||
71 | /** | |
72 | * pin_config_get() - get the configuration of a single pin parameter | |
43699dea | 73 | * @dev_name: name of the pin controller device for this pin |
ae6b4d85 LW |
74 | * @name: name of the pin to get the config for |
75 | * @config: the config pointed to by this argument will be filled in with the | |
76 | * current pin state, it can be used directly by drivers as a numeral, or | |
77 | * it can be dereferenced to any struct. | |
78 | */ | |
43699dea | 79 | int pin_config_get(const char *dev_name, const char *name, |
ae6b4d85 LW |
80 | unsigned long *config) |
81 | { | |
43699dea | 82 | struct pinctrl_dev *pctldev; |
ae6b4d85 LW |
83 | int pin; |
84 | ||
57b676f9 SW |
85 | mutex_lock(&pinctrl_mutex); |
86 | ||
9dfac4fd | 87 | pctldev = get_pinctrl_dev_from_devname(dev_name); |
57b676f9 SW |
88 | if (!pctldev) { |
89 | pin = -EINVAL; | |
90 | goto unlock; | |
91 | } | |
43699dea | 92 | |
ae6b4d85 LW |
93 | pin = pin_get_from_name(pctldev, name); |
94 | if (pin < 0) | |
57b676f9 | 95 | goto unlock; |
ae6b4d85 | 96 | |
57b676f9 SW |
97 | pin = pin_config_get_for_pin(pctldev, pin, config); |
98 | ||
99 | unlock: | |
100 | mutex_unlock(&pinctrl_mutex); | |
101 | return pin; | |
ae6b4d85 LW |
102 | } |
103 | EXPORT_SYMBOL(pin_config_get); | |
104 | ||
2b694250 | 105 | static int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin, |
ae6b4d85 LW |
106 | unsigned long config) |
107 | { | |
108 | const struct pinconf_ops *ops = pctldev->desc->confops; | |
109 | int ret; | |
110 | ||
111 | if (!ops || !ops->pin_config_set) { | |
51cd24ee | 112 | dev_err(pctldev->dev, "cannot configure pin, missing " |
ae6b4d85 LW |
113 | "config function in driver\n"); |
114 | return -EINVAL; | |
115 | } | |
116 | ||
117 | ret = ops->pin_config_set(pctldev, pin, config); | |
118 | if (ret) { | |
51cd24ee | 119 | dev_err(pctldev->dev, |
ae6b4d85 LW |
120 | "unable to set pin configuration on pin %d\n", pin); |
121 | return ret; | |
122 | } | |
123 | ||
124 | return 0; | |
125 | } | |
126 | ||
127 | /** | |
128 | * pin_config_set() - set the configuration of a single pin parameter | |
43699dea | 129 | * @dev_name: name of pin controller device for this pin |
ae6b4d85 LW |
130 | * @name: name of the pin to set the config for |
131 | * @config: the config in this argument will contain the desired pin state, it | |
132 | * can be used directly by drivers as a numeral, or it can be dereferenced | |
133 | * to any struct. | |
134 | */ | |
43699dea | 135 | int pin_config_set(const char *dev_name, const char *name, |
ae6b4d85 LW |
136 | unsigned long config) |
137 | { | |
43699dea | 138 | struct pinctrl_dev *pctldev; |
57b676f9 SW |
139 | int pin, ret; |
140 | ||
141 | mutex_lock(&pinctrl_mutex); | |
ae6b4d85 | 142 | |
9dfac4fd | 143 | pctldev = get_pinctrl_dev_from_devname(dev_name); |
57b676f9 SW |
144 | if (!pctldev) { |
145 | ret = -EINVAL; | |
146 | goto unlock; | |
147 | } | |
43699dea | 148 | |
ae6b4d85 | 149 | pin = pin_get_from_name(pctldev, name); |
57b676f9 SW |
150 | if (pin < 0) { |
151 | ret = pin; | |
152 | goto unlock; | |
153 | } | |
154 | ||
155 | ret = pin_config_set_for_pin(pctldev, pin, config); | |
ae6b4d85 | 156 | |
57b676f9 SW |
157 | unlock: |
158 | mutex_unlock(&pinctrl_mutex); | |
159 | return ret; | |
ae6b4d85 LW |
160 | } |
161 | EXPORT_SYMBOL(pin_config_set); | |
162 | ||
43699dea | 163 | int pin_config_group_get(const char *dev_name, const char *pin_group, |
ae6b4d85 LW |
164 | unsigned long *config) |
165 | { | |
43699dea SW |
166 | struct pinctrl_dev *pctldev; |
167 | const struct pinconf_ops *ops; | |
57b676f9 SW |
168 | int selector, ret; |
169 | ||
170 | mutex_lock(&pinctrl_mutex); | |
ae6b4d85 | 171 | |
9dfac4fd | 172 | pctldev = get_pinctrl_dev_from_devname(dev_name); |
57b676f9 SW |
173 | if (!pctldev) { |
174 | ret = -EINVAL; | |
175 | goto unlock; | |
176 | } | |
43699dea SW |
177 | ops = pctldev->desc->confops; |
178 | ||
ae6b4d85 | 179 | if (!ops || !ops->pin_config_group_get) { |
51cd24ee | 180 | dev_err(pctldev->dev, "cannot get configuration for pin " |
ae6b4d85 LW |
181 | "group, missing group config get function in " |
182 | "driver\n"); | |
57b676f9 SW |
183 | ret = -EINVAL; |
184 | goto unlock; | |
ae6b4d85 LW |
185 | } |
186 | ||
187 | selector = pinctrl_get_group_selector(pctldev, pin_group); | |
57b676f9 SW |
188 | if (selector < 0) { |
189 | ret = selector; | |
190 | goto unlock; | |
191 | } | |
ae6b4d85 | 192 | |
57b676f9 SW |
193 | ret = ops->pin_config_group_get(pctldev, selector, config); |
194 | ||
195 | unlock: | |
196 | mutex_unlock(&pinctrl_mutex); | |
197 | return ret; | |
ae6b4d85 LW |
198 | } |
199 | EXPORT_SYMBOL(pin_config_group_get); | |
200 | ||
43699dea | 201 | int pin_config_group_set(const char *dev_name, const char *pin_group, |
ae6b4d85 LW |
202 | unsigned long config) |
203 | { | |
43699dea SW |
204 | struct pinctrl_dev *pctldev; |
205 | const struct pinconf_ops *ops; | |
206 | const struct pinctrl_ops *pctlops; | |
ae6b4d85 LW |
207 | int selector; |
208 | const unsigned *pins; | |
209 | unsigned num_pins; | |
210 | int ret; | |
211 | int i; | |
212 | ||
57b676f9 SW |
213 | mutex_lock(&pinctrl_mutex); |
214 | ||
9dfac4fd | 215 | pctldev = get_pinctrl_dev_from_devname(dev_name); |
57b676f9 SW |
216 | if (!pctldev) { |
217 | ret = -EINVAL; | |
218 | goto unlock; | |
219 | } | |
43699dea SW |
220 | ops = pctldev->desc->confops; |
221 | pctlops = pctldev->desc->pctlops; | |
222 | ||
ae6b4d85 | 223 | if (!ops || (!ops->pin_config_group_set && !ops->pin_config_set)) { |
51cd24ee | 224 | dev_err(pctldev->dev, "cannot configure pin group, missing " |
ae6b4d85 | 225 | "config function in driver\n"); |
57b676f9 SW |
226 | ret = -EINVAL; |
227 | goto unlock; | |
ae6b4d85 LW |
228 | } |
229 | ||
230 | selector = pinctrl_get_group_selector(pctldev, pin_group); | |
57b676f9 SW |
231 | if (selector < 0) { |
232 | ret = selector; | |
233 | goto unlock; | |
234 | } | |
ae6b4d85 LW |
235 | |
236 | ret = pctlops->get_group_pins(pctldev, selector, &pins, &num_pins); | |
237 | if (ret) { | |
51cd24ee | 238 | dev_err(pctldev->dev, "cannot configure pin group, error " |
ae6b4d85 | 239 | "getting pins\n"); |
57b676f9 | 240 | goto unlock; |
ae6b4d85 LW |
241 | } |
242 | ||
243 | /* | |
244 | * If the pin controller supports handling entire groups we use that | |
245 | * capability. | |
246 | */ | |
247 | if (ops->pin_config_group_set) { | |
248 | ret = ops->pin_config_group_set(pctldev, selector, config); | |
249 | /* | |
250 | * If the pin controller prefer that a certain group be handled | |
251 | * pin-by-pin as well, it returns -EAGAIN. | |
252 | */ | |
253 | if (ret != -EAGAIN) | |
57b676f9 | 254 | goto unlock; |
ae6b4d85 LW |
255 | } |
256 | ||
257 | /* | |
258 | * If the controller cannot handle entire groups, we configure each pin | |
259 | * individually. | |
260 | */ | |
57b676f9 SW |
261 | if (!ops->pin_config_set) { |
262 | ret = 0; | |
263 | goto unlock; | |
264 | } | |
ae6b4d85 LW |
265 | |
266 | for (i = 0; i < num_pins; i++) { | |
267 | ret = ops->pin_config_set(pctldev, pins[i], config); | |
268 | if (ret < 0) | |
57b676f9 | 269 | goto unlock; |
ae6b4d85 LW |
270 | } |
271 | ||
57b676f9 SW |
272 | ret = 0; |
273 | ||
274 | unlock: | |
275 | mutex_unlock(&pinctrl_mutex); | |
276 | ||
277 | return ret; | |
ae6b4d85 LW |
278 | } |
279 | EXPORT_SYMBOL(pin_config_group_set); | |
280 | ||
1e2082b5 SW |
281 | int pinconf_map_to_setting(struct pinctrl_map const *map, |
282 | struct pinctrl_setting *setting) | |
283 | { | |
284 | struct pinctrl_dev *pctldev = setting->pctldev; | |
285 | ||
286 | switch (setting->type) { | |
287 | case PIN_MAP_TYPE_CONFIGS_PIN: | |
288 | setting->data.configs.group_or_pin = | |
289 | pin_get_from_name(pctldev, | |
290 | map->data.configs.group_or_pin); | |
291 | if (setting->data.configs.group_or_pin < 0) | |
292 | return setting->data.configs.group_or_pin; | |
293 | break; | |
294 | case PIN_MAP_TYPE_CONFIGS_GROUP: | |
295 | setting->data.configs.group_or_pin = | |
296 | pinctrl_get_group_selector(pctldev, | |
297 | map->data.configs.group_or_pin); | |
298 | if (setting->data.configs.group_or_pin < 0) | |
299 | return setting->data.configs.group_or_pin; | |
300 | break; | |
301 | default: | |
302 | return -EINVAL; | |
303 | } | |
304 | ||
305 | setting->data.configs.num_configs = map->data.configs.num_configs; | |
306 | setting->data.configs.configs = map->data.configs.configs; | |
307 | ||
308 | return 0; | |
309 | } | |
310 | ||
311 | void pinconf_free_setting(struct pinctrl_setting const *setting) | |
312 | { | |
313 | } | |
314 | ||
315 | int pinconf_apply_setting(struct pinctrl_setting const *setting) | |
316 | { | |
317 | struct pinctrl_dev *pctldev = setting->pctldev; | |
318 | const struct pinconf_ops *ops = pctldev->desc->confops; | |
319 | int i, ret; | |
320 | ||
321 | if (!ops) { | |
322 | dev_err(pctldev->dev, "missing confops\n"); | |
323 | return -EINVAL; | |
324 | } | |
325 | ||
326 | switch (setting->type) { | |
327 | case PIN_MAP_TYPE_CONFIGS_PIN: | |
328 | if (!ops->pin_config_set) { | |
329 | dev_err(pctldev->dev, "missing pin_config_set op\n"); | |
330 | return -EINVAL; | |
331 | } | |
332 | for (i = 0; i < setting->data.configs.num_configs; i++) { | |
333 | ret = ops->pin_config_set(pctldev, | |
334 | setting->data.configs.group_or_pin, | |
335 | setting->data.configs.configs[i]); | |
336 | if (ret < 0) { | |
337 | dev_err(pctldev->dev, | |
338 | "pin_config_set op failed for pin %d config %08lx\n", | |
339 | setting->data.configs.group_or_pin, | |
340 | setting->data.configs.configs[i]); | |
341 | return ret; | |
342 | } | |
343 | } | |
344 | break; | |
345 | case PIN_MAP_TYPE_CONFIGS_GROUP: | |
346 | if (!ops->pin_config_group_set) { | |
347 | dev_err(pctldev->dev, | |
348 | "missing pin_config_group_set op\n"); | |
349 | return -EINVAL; | |
350 | } | |
351 | for (i = 0; i < setting->data.configs.num_configs; i++) { | |
352 | ret = ops->pin_config_group_set(pctldev, | |
353 | setting->data.configs.group_or_pin, | |
354 | setting->data.configs.configs[i]); | |
355 | if (ret < 0) { | |
356 | dev_err(pctldev->dev, | |
357 | "pin_config_group_set op failed for group %d config %08lx\n", | |
358 | setting->data.configs.group_or_pin, | |
359 | setting->data.configs.configs[i]); | |
360 | return ret; | |
361 | } | |
362 | } | |
363 | break; | |
364 | default: | |
365 | return -EINVAL; | |
366 | } | |
367 | ||
368 | return 0; | |
369 | } | |
370 | ||
ae6b4d85 LW |
371 | #ifdef CONFIG_DEBUG_FS |
372 | ||
1e2082b5 SW |
373 | void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) |
374 | { | |
375 | int i; | |
376 | ||
377 | switch (map->type) { | |
378 | case PIN_MAP_TYPE_CONFIGS_PIN: | |
379 | seq_printf(s, "pin "); | |
380 | break; | |
381 | case PIN_MAP_TYPE_CONFIGS_GROUP: | |
382 | seq_printf(s, "group "); | |
383 | break; | |
384 | default: | |
385 | break; | |
386 | } | |
387 | ||
388 | seq_printf(s, "%s\n", map->data.configs.group_or_pin); | |
389 | ||
390 | for (i = 0; i < map->data.configs.num_configs; i++) | |
391 | seq_printf(s, "config %08lx\n", map->data.configs.configs[i]); | |
392 | } | |
393 | ||
394 | void pinconf_show_setting(struct seq_file *s, | |
395 | struct pinctrl_setting const *setting) | |
396 | { | |
397 | struct pinctrl_dev *pctldev = setting->pctldev; | |
398 | const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; | |
399 | struct pin_desc *desc; | |
400 | int i; | |
401 | ||
402 | switch (setting->type) { | |
403 | case PIN_MAP_TYPE_CONFIGS_PIN: | |
404 | desc = pin_desc_get(setting->pctldev, | |
405 | setting->data.configs.group_or_pin); | |
406 | seq_printf(s, "pin %s (%d)", | |
407 | desc->name ? desc->name : "unnamed", | |
408 | setting->data.configs.group_or_pin); | |
409 | break; | |
410 | case PIN_MAP_TYPE_CONFIGS_GROUP: | |
411 | seq_printf(s, "group %s (%d)", | |
412 | pctlops->get_group_name(pctldev, | |
413 | setting->data.configs.group_or_pin), | |
414 | setting->data.configs.group_or_pin); | |
415 | break; | |
416 | default: | |
417 | break; | |
418 | } | |
419 | ||
420 | /* | |
421 | * FIXME: We should really get the pin controler to dump the config | |
422 | * values, so they can be decoded to something meaningful. | |
423 | */ | |
424 | for (i = 0; i < setting->data.configs.num_configs; i++) | |
425 | seq_printf(s, " %08lx", setting->data.configs.configs[i]); | |
426 | ||
427 | seq_printf(s, "\n"); | |
428 | } | |
429 | ||
ae6b4d85 LW |
430 | static void pinconf_dump_pin(struct pinctrl_dev *pctldev, |
431 | struct seq_file *s, int pin) | |
432 | { | |
433 | const struct pinconf_ops *ops = pctldev->desc->confops; | |
434 | ||
435 | if (ops && ops->pin_config_dbg_show) | |
436 | ops->pin_config_dbg_show(pctldev, s, pin); | |
437 | } | |
438 | ||
439 | static int pinconf_pins_show(struct seq_file *s, void *what) | |
440 | { | |
441 | struct pinctrl_dev *pctldev = s->private; | |
706e8520 | 442 | unsigned i, pin; |
ae6b4d85 LW |
443 | |
444 | seq_puts(s, "Pin config settings per pin\n"); | |
445 | seq_puts(s, "Format: pin (name): pinmux setting array\n"); | |
446 | ||
57b676f9 SW |
447 | mutex_lock(&pinctrl_mutex); |
448 | ||
706e8520 | 449 | /* The pin number can be retrived from the pin controller descriptor */ |
546edd83 | 450 | for (i = 0; i < pctldev->desc->npins; i++) { |
ae6b4d85 LW |
451 | struct pin_desc *desc; |
452 | ||
706e8520 | 453 | pin = pctldev->desc->pins[i].number; |
ae6b4d85 | 454 | desc = pin_desc_get(pctldev, pin); |
706e8520 | 455 | /* Skip if we cannot search the pin */ |
ae6b4d85 LW |
456 | if (desc == NULL) |
457 | continue; | |
458 | ||
459 | seq_printf(s, "pin %d (%s):", pin, | |
460 | desc->name ? desc->name : "unnamed"); | |
461 | ||
462 | pinconf_dump_pin(pctldev, s, pin); | |
463 | ||
464 | seq_printf(s, "\n"); | |
465 | } | |
466 | ||
57b676f9 SW |
467 | mutex_unlock(&pinctrl_mutex); |
468 | ||
ae6b4d85 LW |
469 | return 0; |
470 | } | |
471 | ||
472 | static void pinconf_dump_group(struct pinctrl_dev *pctldev, | |
473 | struct seq_file *s, unsigned selector, | |
474 | const char *gname) | |
475 | { | |
476 | const struct pinconf_ops *ops = pctldev->desc->confops; | |
477 | ||
478 | if (ops && ops->pin_config_group_dbg_show) | |
479 | ops->pin_config_group_dbg_show(pctldev, s, selector); | |
480 | } | |
481 | ||
482 | static int pinconf_groups_show(struct seq_file *s, void *what) | |
483 | { | |
484 | struct pinctrl_dev *pctldev = s->private; | |
485 | const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; | |
486 | const struct pinconf_ops *ops = pctldev->desc->confops; | |
487 | unsigned selector = 0; | |
488 | ||
489 | if (!ops || !ops->pin_config_group_get) | |
490 | return 0; | |
491 | ||
492 | seq_puts(s, "Pin config settings per pin group\n"); | |
493 | seq_puts(s, "Format: group (name): pinmux setting array\n"); | |
494 | ||
57b676f9 SW |
495 | mutex_lock(&pinctrl_mutex); |
496 | ||
ae6b4d85 LW |
497 | while (pctlops->list_groups(pctldev, selector) >= 0) { |
498 | const char *gname = pctlops->get_group_name(pctldev, selector); | |
499 | ||
500 | seq_printf(s, "%u (%s):", selector, gname); | |
501 | pinconf_dump_group(pctldev, s, selector, gname); | |
f7b9006f SW |
502 | seq_printf(s, "\n"); |
503 | ||
ae6b4d85 LW |
504 | selector++; |
505 | } | |
506 | ||
57b676f9 SW |
507 | mutex_unlock(&pinctrl_mutex); |
508 | ||
ae6b4d85 LW |
509 | return 0; |
510 | } | |
511 | ||
512 | static int pinconf_pins_open(struct inode *inode, struct file *file) | |
513 | { | |
514 | return single_open(file, pinconf_pins_show, inode->i_private); | |
515 | } | |
516 | ||
517 | static int pinconf_groups_open(struct inode *inode, struct file *file) | |
518 | { | |
519 | return single_open(file, pinconf_groups_show, inode->i_private); | |
520 | } | |
521 | ||
522 | static const struct file_operations pinconf_pins_ops = { | |
523 | .open = pinconf_pins_open, | |
524 | .read = seq_read, | |
525 | .llseek = seq_lseek, | |
526 | .release = single_release, | |
527 | }; | |
528 | ||
529 | static const struct file_operations pinconf_groups_ops = { | |
530 | .open = pinconf_groups_open, | |
531 | .read = seq_read, | |
532 | .llseek = seq_lseek, | |
533 | .release = single_release, | |
534 | }; | |
535 | ||
536 | void pinconf_init_device_debugfs(struct dentry *devroot, | |
537 | struct pinctrl_dev *pctldev) | |
538 | { | |
539 | debugfs_create_file("pinconf-pins", S_IFREG | S_IRUGO, | |
540 | devroot, pctldev, &pinconf_pins_ops); | |
541 | debugfs_create_file("pinconf-groups", S_IFREG | S_IRUGO, | |
542 | devroot, pctldev, &pinconf_groups_ops); | |
543 | } | |
544 | ||
545 | #endif |