diff options
author | Stephen Warren <swarren@nvidia.com> | 2012-03-02 15:05:45 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2012-03-05 05:20:50 -0500 |
commit | 7ecdb16fe63e5b356335ebdc236adfb48cef31e1 (patch) | |
tree | 036d9939c64f98e1f85343f15c12ad83c9a2a890 /drivers/pinctrl/pinmux.c | |
parent | 57b676f9c1b7cd84397fe5a86c9bd2788ac4bd32 (diff) |
pinctrl: refactor struct pinctrl handling in core.c vs pinmux.c
This change separates two aspects of struct pinctrl:
a) The data representation of the parsed mapping table, into:
1) The top-level struct pinctrl object, a single entity returned
by pinctrl_get().
2) The parsed version of each mapping table entry, struct
pinctrl_setting, of which there is one per mapping table entry.
b) The code that handles this; the code for (1) above is in core.c, and
the code to parse/execute each entry in (2) above is in pinmux.c, while
the iteration over multiple settings is lifted to core.c.
This will allow the following future changes:
1) pinctrl_get() API rework, so that struct pinctrl represents all states
for the device, and the device can select between them without calling
put()/get() again.
2) To support that, a struct pinctrl_state object will be inserted into
the data model between the struct pinctrl and struct pinctrl_setting.
3) The mapping table will be extended to allow specification of pin config
settings too. To support this, struct pinctrl_setting will be enhanced
to store either mux settings or config settings, and functions will be
added to pinconf.c to parse/execute pin configuration settings.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/pinmux.c')
-rw-r--r-- | drivers/pinctrl/pinmux.c | 402 |
1 files changed, 98 insertions, 304 deletions
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 7342c26f4246..f0fb98d252e8 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c | |||
@@ -7,6 +7,8 @@ | |||
7 | * | 7 | * |
8 | * Author: Linus Walleij <linus.walleij@linaro.org> | 8 | * Author: Linus Walleij <linus.walleij@linaro.org> |
9 | * | 9 | * |
10 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
11 | * | ||
10 | * License terms: GNU General Public License (GPL) version 2 | 12 | * License terms: GNU General Public License (GPL) version 2 |
11 | */ | 13 | */ |
12 | #define pr_fmt(fmt) "pinmux core: " fmt | 14 | #define pr_fmt(fmt) "pinmux core: " fmt |
@@ -28,19 +30,6 @@ | |||
28 | #include "core.h" | 30 | #include "core.h" |
29 | #include "pinmux.h" | 31 | #include "pinmux.h" |
30 | 32 | ||
31 | /** | ||
32 | * struct pinmux_group - group list item for pinmux groups | ||
33 | * @node: pinmux group list node | ||
34 | * @func_selector: the function selector for the pinmux device handling | ||
35 | * this pinmux | ||
36 | * @group_selector: the group selector for this group | ||
37 | */ | ||
38 | struct pinmux_group { | ||
39 | struct list_head node; | ||
40 | unsigned func_selector; | ||
41 | unsigned group_selector; | ||
42 | }; | ||
43 | |||
44 | int pinmux_check_ops(struct pinctrl_dev *pctldev) | 33 | int pinmux_check_ops(struct pinctrl_dev *pctldev) |
45 | { | 34 | { |
46 | const struct pinmux_ops *ops = pctldev->desc->pmxops; | 35 | const struct pinmux_ops *ops = pctldev->desc->pmxops; |
@@ -244,164 +233,8 @@ int pinmux_gpio_direction(struct pinctrl_dev *pctldev, | |||
244 | return ret; | 233 | return ret; |
245 | } | 234 | } |
246 | 235 | ||
247 | /** | 236 | static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev, |
248 | * acquire_pins() - acquire all the pins for a certain function on a pinmux | 237 | const char *function) |
249 | * @pctldev: the device to take the pins on | ||
250 | * @owner: a representation of the owner of this pin; typically the device | ||
251 | * name that controls its mux function | ||
252 | * @group_selector: the group selector containing the pins to acquire | ||
253 | */ | ||
254 | static int acquire_pins(struct pinctrl_dev *pctldev, | ||
255 | const char *owner, | ||
256 | unsigned group_selector) | ||
257 | { | ||
258 | const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; | ||
259 | const unsigned *pins; | ||
260 | unsigned num_pins; | ||
261 | int ret; | ||
262 | int i; | ||
263 | |||
264 | ret = pctlops->get_group_pins(pctldev, group_selector, | ||
265 | &pins, &num_pins); | ||
266 | if (ret) | ||
267 | return ret; | ||
268 | |||
269 | dev_dbg(pctldev->dev, "requesting the %u pins from group %u\n", | ||
270 | num_pins, group_selector); | ||
271 | |||
272 | /* Try to allocate all pins in this group, one by one */ | ||
273 | for (i = 0; i < num_pins; i++) { | ||
274 | ret = pin_request(pctldev, pins[i], owner, NULL); | ||
275 | if (ret) { | ||
276 | dev_err(pctldev->dev, | ||
277 | "could not get request pin %d on device %s - conflicting mux mappings?\n", | ||
278 | pins[i], | ||
279 | pinctrl_dev_get_name(pctldev)); | ||
280 | /* On error release all taken pins */ | ||
281 | i--; /* this pin just failed */ | ||
282 | for (; i >= 0; i--) | ||
283 | pin_free(pctldev, pins[i], NULL); | ||
284 | return -ENODEV; | ||
285 | } | ||
286 | } | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | /** | ||
291 | * release_pins() - release pins taken by earlier acquirement | ||
292 | * @pctldev: the device to free the pins on | ||
293 | * @group_selector: the group selector containing the pins to free | ||
294 | */ | ||
295 | static void release_pins(struct pinctrl_dev *pctldev, | ||
296 | unsigned group_selector) | ||
297 | { | ||
298 | const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; | ||
299 | const unsigned *pins; | ||
300 | unsigned num_pins; | ||
301 | int ret; | ||
302 | int i; | ||
303 | |||
304 | ret = pctlops->get_group_pins(pctldev, group_selector, | ||
305 | &pins, &num_pins); | ||
306 | if (ret) { | ||
307 | dev_err(pctldev->dev, "could not get pins to release for group selector %d\n", | ||
308 | group_selector); | ||
309 | return; | ||
310 | } | ||
311 | for (i = 0; i < num_pins; i++) | ||
312 | pin_free(pctldev, pins[i], NULL); | ||
313 | } | ||
314 | |||
315 | /** | ||
316 | * pinmux_check_pin_group() - check function and pin group combo | ||
317 | * @pctldev: device to check the pin group vs function for | ||
318 | * @func_selector: the function selector to check the pin group for, we have | ||
319 | * already looked this up in the calling function | ||
320 | * @pin_group: the pin group to match to the function | ||
321 | * | ||
322 | * This function will check that the pinmux driver can supply the | ||
323 | * selected pin group for a certain function, returns the group selector if | ||
324 | * the group and function selector will work fine together, else returns | ||
325 | * negative | ||
326 | */ | ||
327 | static int pinmux_check_pin_group(struct pinctrl_dev *pctldev, | ||
328 | unsigned func_selector, | ||
329 | const char *pin_group) | ||
330 | { | ||
331 | const struct pinmux_ops *pmxops = pctldev->desc->pmxops; | ||
332 | const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; | ||
333 | int ret; | ||
334 | |||
335 | /* | ||
336 | * If the driver does not support different pin groups for the | ||
337 | * functions, we only support group 0, and assume this exists. | ||
338 | */ | ||
339 | if (!pctlops || !pctlops->list_groups) | ||
340 | return 0; | ||
341 | |||
342 | /* | ||
343 | * Passing NULL (no specific group) will select the first and | ||
344 | * hopefully only group of pins available for this function. | ||
345 | */ | ||
346 | if (!pin_group) { | ||
347 | char const * const *groups; | ||
348 | unsigned num_groups; | ||
349 | |||
350 | ret = pmxops->get_function_groups(pctldev, func_selector, | ||
351 | &groups, &num_groups); | ||
352 | if (ret) | ||
353 | return ret; | ||
354 | if (num_groups < 1) | ||
355 | return -EINVAL; | ||
356 | ret = pinctrl_get_group_selector(pctldev, groups[0]); | ||
357 | if (ret < 0) { | ||
358 | dev_err(pctldev->dev, | ||
359 | "function %s wants group %s but the pin controller does not seem to have that group\n", | ||
360 | pmxops->get_function_name(pctldev, func_selector), | ||
361 | groups[0]); | ||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | if (num_groups > 1) | ||
366 | dev_dbg(pctldev->dev, | ||
367 | "function %s support more than one group, default-selecting first group %s (%d)\n", | ||
368 | pmxops->get_function_name(pctldev, func_selector), | ||
369 | groups[0], | ||
370 | ret); | ||
371 | |||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | dev_dbg(pctldev->dev, | ||
376 | "check if we have pin group %s on controller %s\n", | ||
377 | pin_group, pinctrl_dev_get_name(pctldev)); | ||
378 | |||
379 | ret = pinctrl_get_group_selector(pctldev, pin_group); | ||
380 | if (ret < 0) { | ||
381 | dev_dbg(pctldev->dev, | ||
382 | "%s does not support pin group %s with function %s\n", | ||
383 | pinctrl_dev_get_name(pctldev), | ||
384 | pin_group, | ||
385 | pmxops->get_function_name(pctldev, func_selector)); | ||
386 | } | ||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | /** | ||
391 | * pinmux_search_function() - check pin control driver for a certain function | ||
392 | * @pctldev: device to check for function and position | ||
393 | * @map: function map containing the function and position to look for | ||
394 | * @func_selector: returns the applicable function selector if found | ||
395 | * @group_selector: returns the applicable group selector if found | ||
396 | * | ||
397 | * This will search the pinmux driver for an applicable | ||
398 | * function with a specific pin group, returns 0 if these can be mapped | ||
399 | * negative otherwise | ||
400 | */ | ||
401 | static int pinmux_search_function(struct pinctrl_dev *pctldev, | ||
402 | struct pinctrl_map const *map, | ||
403 | unsigned *func_selector, | ||
404 | unsigned *group_selector) | ||
405 | { | 238 | { |
406 | const struct pinmux_ops *ops = pctldev->desc->pmxops; | 239 | const struct pinmux_ops *ops = pctldev->desc->pmxops; |
407 | unsigned selector = 0; | 240 | unsigned selector = 0; |
@@ -410,155 +243,128 @@ static int pinmux_search_function(struct pinctrl_dev *pctldev, | |||
410 | while (ops->list_functions(pctldev, selector) >= 0) { | 243 | while (ops->list_functions(pctldev, selector) >= 0) { |
411 | const char *fname = ops->get_function_name(pctldev, | 244 | const char *fname = ops->get_function_name(pctldev, |
412 | selector); | 245 | selector); |
413 | int ret; | ||
414 | 246 | ||
415 | if (!strcmp(map->function, fname)) { | 247 | if (!strcmp(function, fname)) |
416 | /* Found the function, check pin group */ | 248 | return selector; |
417 | ret = pinmux_check_pin_group(pctldev, selector, | ||
418 | map->group); | ||
419 | if (ret < 0) | ||
420 | return ret; | ||
421 | 249 | ||
422 | /* This function and group selector can be used */ | ||
423 | *func_selector = selector; | ||
424 | *group_selector = ret; | ||
425 | return 0; | ||
426 | |||
427 | } | ||
428 | selector++; | 250 | selector++; |
429 | } | 251 | } |
430 | 252 | ||
431 | pr_err("%s does not support function %s\n", | 253 | pr_err("%s does not support function %s\n", |
432 | pinctrl_dev_get_name(pctldev), map->function); | 254 | pinctrl_dev_get_name(pctldev), function); |
433 | return -EINVAL; | 255 | return -EINVAL; |
434 | } | 256 | } |
435 | 257 | ||
436 | /** | 258 | int pinmux_map_to_setting(struct pinctrl_map const *map, |
437 | * pinmux_enable_muxmap() - enable a map entry for a certain pinmux | 259 | struct pinctrl_setting *setting) |
438 | */ | ||
439 | static int pinmux_enable_muxmap(struct pinctrl_dev *pctldev, | ||
440 | struct pinctrl *p, | ||
441 | struct device *dev, | ||
442 | const char *devname, | ||
443 | struct pinctrl_map const *map) | ||
444 | { | 260 | { |
445 | unsigned func_selector; | 261 | struct pinctrl_dev *pctldev = setting->pctldev; |
446 | unsigned group_selector; | 262 | const struct pinmux_ops *pmxops = pctldev->desc->pmxops; |
447 | struct pinmux_group *grp; | 263 | const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; |
264 | char const * const *groups; | ||
265 | unsigned num_groups; | ||
448 | int ret; | 266 | int ret; |
267 | const char *group; | ||
268 | int i; | ||
269 | const unsigned *pins; | ||
270 | unsigned num_pins; | ||
449 | 271 | ||
450 | /* | 272 | setting->func_selector = |
451 | * Note that we're not locking the pinmux mutex here, because | 273 | pinmux_func_name_to_selector(pctldev, map->function); |
452 | * this is only called at pinmux initialization time when it | 274 | if (setting->func_selector < 0) |
453 | * has not been added to any list and thus is not reachable | 275 | return setting->func_selector; |
454 | * by anyone else. | ||
455 | */ | ||
456 | 276 | ||
457 | if (p->pctldev && p->pctldev != pctldev) { | 277 | ret = pmxops->get_function_groups(pctldev, setting->func_selector, |
458 | dev_err(pctldev->dev, | 278 | &groups, &num_groups); |
459 | "different pin control devices given for device %s, function %s\n", | 279 | if (ret < 0) |
460 | devname, map->function); | 280 | return ret; |
281 | if (!num_groups) | ||
461 | return -EINVAL; | 282 | return -EINVAL; |
283 | |||
284 | if (map->group) { | ||
285 | bool found = false; | ||
286 | group = map->group; | ||
287 | for (i = 0; i < num_groups; i++) { | ||
288 | if (!strcmp(group, groups[i])) { | ||
289 | found = true; | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | if (!found) | ||
294 | return -EINVAL; | ||
295 | } else { | ||
296 | group = groups[0]; | ||
462 | } | 297 | } |
463 | p->dev = dev; | ||
464 | p->pctldev = pctldev; | ||
465 | 298 | ||
466 | /* Now go into the driver and try to match a function and group */ | 299 | setting->group_selector = |
467 | ret = pinmux_search_function(pctldev, map, &func_selector, | 300 | pinctrl_get_group_selector(pctldev, group); |
468 | &group_selector); | 301 | if (setting->group_selector < 0) |
469 | if (ret < 0) | 302 | return setting->group_selector; |
470 | return ret; | ||
471 | 303 | ||
472 | /* Now add this group selector, we may have many of them */ | 304 | ret = pctlops->get_group_pins(pctldev, setting->group_selector, |
473 | grp = kmalloc(sizeof(*grp), GFP_KERNEL); | 305 | &pins, &num_pins); |
474 | if (!grp) | ||
475 | return -ENOMEM; | ||
476 | grp->func_selector = func_selector; | ||
477 | grp->group_selector = group_selector; | ||
478 | ret = acquire_pins(pctldev, devname, group_selector); | ||
479 | if (ret) { | 306 | if (ret) { |
480 | kfree(grp); | 307 | dev_err(pctldev->dev, |
481 | return ret; | 308 | "could not get pins for device %s group selector %d\n", |
309 | pinctrl_dev_get_name(pctldev), setting->group_selector); | ||
310 | return -ENODEV; | ||
311 | } | ||
312 | |||
313 | /* Try to allocate all pins in this group, one by one */ | ||
314 | for (i = 0; i < num_pins; i++) { | ||
315 | ret = pin_request(pctldev, pins[i], map->dev_name, NULL); | ||
316 | if (ret) { | ||
317 | dev_err(pctldev->dev, | ||
318 | "could not get request pin %d on device %s\n", | ||
319 | pins[i], pinctrl_dev_get_name(pctldev)); | ||
320 | /* On error release all taken pins */ | ||
321 | i--; /* this pin just failed */ | ||
322 | for (; i >= 0; i--) | ||
323 | pin_free(pctldev, pins[i], NULL); | ||
324 | return -ENODEV; | ||
325 | } | ||
482 | } | 326 | } |
483 | list_add_tail(&grp->node, &p->groups); | ||
484 | 327 | ||
485 | return 0; | 328 | return 0; |
486 | } | 329 | } |
487 | 330 | ||
488 | /** | 331 | void pinmux_free_setting(struct pinctrl_setting const *setting) |
489 | * pinmux_apply_muxmap() - apply a certain mux mapping entry | ||
490 | */ | ||
491 | int pinmux_apply_muxmap(struct pinctrl_dev *pctldev, | ||
492 | struct pinctrl *p, | ||
493 | struct device *dev, | ||
494 | const char *devname, | ||
495 | struct pinctrl_map const *map) | ||
496 | { | 332 | { |
333 | struct pinctrl_dev *pctldev = setting->pctldev; | ||
334 | const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; | ||
335 | const unsigned *pins; | ||
336 | unsigned num_pins; | ||
497 | int ret; | 337 | int ret; |
338 | int i; | ||
498 | 339 | ||
499 | ret = pinmux_enable_muxmap(pctldev, p, dev, | 340 | ret = pctlops->get_group_pins(pctldev, setting->group_selector, |
500 | devname, map); | 341 | &pins, &num_pins); |
501 | if (ret) { | 342 | if (ret) { |
502 | pinmux_put(p); | 343 | dev_err(pctldev->dev, |
503 | return ret; | 344 | "could not get pins for device %s group selector %d\n", |
345 | pinctrl_dev_get_name(pctldev), setting->group_selector); | ||
346 | return; | ||
504 | } | 347 | } |
505 | 348 | ||
506 | return 0; | 349 | for (i = 0; i < num_pins; i++) |
507 | } | 350 | pin_free(pctldev, pins[i], NULL); |
508 | |||
509 | /** | ||
510 | * pinmux_put() - free up the pinmux portions of a pin controller handle | ||
511 | */ | ||
512 | void pinmux_put(struct pinctrl *p) | ||
513 | { | ||
514 | struct list_head *node, *tmp; | ||
515 | |||
516 | list_for_each_safe(node, tmp, &p->groups) { | ||
517 | struct pinmux_group *grp = | ||
518 | list_entry(node, struct pinmux_group, node); | ||
519 | /* Release all pins taken by this group */ | ||
520 | release_pins(p->pctldev, grp->group_selector); | ||
521 | list_del(node); | ||
522 | kfree(grp); | ||
523 | } | ||
524 | } | 351 | } |
525 | 352 | ||
526 | /** | 353 | int pinmux_enable_setting(struct pinctrl_setting const *setting) |
527 | * pinmux_enable() - enable the pinmux portion of a pin control handle | ||
528 | */ | ||
529 | int pinmux_enable(struct pinctrl *p) | ||
530 | { | 354 | { |
531 | struct pinctrl_dev *pctldev = p->pctldev; | 355 | struct pinctrl_dev *pctldev = setting->pctldev; |
532 | const struct pinmux_ops *ops = pctldev->desc->pmxops; | 356 | const struct pinmux_ops *ops = pctldev->desc->pmxops; |
533 | struct pinmux_group *grp; | ||
534 | int ret; | ||
535 | 357 | ||
536 | list_for_each_entry(grp, &p->groups, node) { | 358 | return ops->enable(pctldev, setting->func_selector, |
537 | ret = ops->enable(pctldev, grp->func_selector, | 359 | setting->group_selector); |
538 | grp->group_selector); | ||
539 | if (ret) | ||
540 | /* | ||
541 | * TODO: call disable() on all groups we called | ||
542 | * enable() on to this point? | ||
543 | */ | ||
544 | return ret; | ||
545 | } | ||
546 | return 0; | ||
547 | } | 360 | } |
548 | 361 | ||
549 | /** | 362 | void pinmux_disable_setting(struct pinctrl_setting const *setting) |
550 | * pinmux_disable() - disable the pinmux portions of a pin control handle | ||
551 | */ | ||
552 | void pinmux_disable(struct pinctrl *p) | ||
553 | { | 363 | { |
554 | struct pinctrl_dev *pctldev = p->pctldev; | 364 | struct pinctrl_dev *pctldev = setting->pctldev; |
555 | const struct pinmux_ops *ops = pctldev->desc->pmxops; | 365 | const struct pinmux_ops *ops = pctldev->desc->pmxops; |
556 | struct pinmux_group *grp; | ||
557 | 366 | ||
558 | list_for_each_entry(grp, &p->groups, node) { | 367 | ops->disable(pctldev, setting->func_selector, setting->group_selector); |
559 | ops->disable(pctldev, grp->func_selector, | ||
560 | grp->group_selector); | ||
561 | } | ||
562 | } | 368 | } |
563 | 369 | ||
564 | #ifdef CONFIG_DEBUG_FS | 370 | #ifdef CONFIG_DEBUG_FS |
@@ -635,30 +441,18 @@ static int pinmux_pins_show(struct seq_file *s, void *what) | |||
635 | return 0; | 441 | return 0; |
636 | } | 442 | } |
637 | 443 | ||
638 | void pinmux_dbg_show(struct seq_file *s, struct pinctrl *p) | 444 | void pinmux_dbg_show(struct seq_file *s, struct pinctrl_setting const *setting) |
639 | { | 445 | { |
640 | struct pinctrl_dev *pctldev = p->pctldev; | 446 | struct pinctrl_dev *pctldev = setting->pctldev; |
641 | const struct pinmux_ops *pmxops; | 447 | const struct pinmux_ops *pmxops = pctldev->desc->pmxops; |
642 | const struct pinctrl_ops *pctlops; | 448 | const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; |
643 | struct pinmux_group *grp; | 449 | |
644 | const char *sep = ""; | 450 | seq_printf(s, "controller: %s group: %s (%u) function: %s (%u)\n", |
645 | 451 | pinctrl_dev_get_name(pctldev), | |
646 | pmxops = pctldev->desc->pmxops; | 452 | pctlops->get_group_name(pctldev, setting->group_selector), |
647 | pctlops = pctldev->desc->pctlops; | 453 | setting->group_selector, |
648 | 454 | pmxops->get_function_name(pctldev, setting->func_selector), | |
649 | seq_printf(s, " groups: ["); | 455 | setting->func_selector); |
650 | list_for_each_entry(grp, &p->groups, node) { | ||
651 | seq_printf(s, "%s%s (%u)=%s (%u)", | ||
652 | sep, | ||
653 | pctlops->get_group_name(pctldev, | ||
654 | grp->group_selector), | ||
655 | grp->group_selector, | ||
656 | pmxops->get_function_name(pctldev, | ||
657 | grp->func_selector), | ||
658 | grp->func_selector); | ||
659 | sep = ", "; | ||
660 | } | ||
661 | seq_printf(s, " ]"); | ||
662 | } | 456 | } |
663 | 457 | ||
664 | static int pinmux_functions_open(struct inode *inode, struct file *file) | 458 | static int pinmux_functions_open(struct inode *inode, struct file *file) |