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/core.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/core.c')
-rw-r--r-- | drivers/pinctrl/core.c | 105 |
1 files changed, 66 insertions, 39 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index aefc3394db91..535f8d53c289 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c | |||
@@ -460,14 +460,15 @@ EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output); | |||
460 | 460 | ||
461 | static struct pinctrl *pinctrl_get_locked(struct device *dev, const char *name) | 461 | static struct pinctrl *pinctrl_get_locked(struct device *dev, const char *name) |
462 | { | 462 | { |
463 | struct pinctrl_dev *pctldev = NULL; | 463 | struct pinctrl_dev *pctldev; |
464 | const char *devname; | 464 | const char *devname; |
465 | struct pinctrl *p; | 465 | struct pinctrl *p; |
466 | unsigned num_maps = 0; | 466 | unsigned num_maps = 0; |
467 | int ret = -ENODEV; | 467 | int ret; |
468 | struct pinctrl_maps *maps_node; | 468 | struct pinctrl_maps *maps_node; |
469 | int i; | 469 | int i; |
470 | struct pinctrl_map const *map; | 470 | struct pinctrl_map const *map; |
471 | struct pinctrl_setting *setting; | ||
471 | 472 | ||
472 | /* We must have both a dev and state name */ | 473 | /* We must have both a dev and state name */ |
473 | if (WARN_ON(!dev || !name)) | 474 | if (WARN_ON(!dev || !name)) |
@@ -487,39 +488,50 @@ static struct pinctrl *pinctrl_get_locked(struct device *dev, const char *name) | |||
487 | dev_err(dev, "failed to alloc struct pinctrl\n"); | 488 | dev_err(dev, "failed to alloc struct pinctrl\n"); |
488 | return ERR_PTR(-ENOMEM); | 489 | return ERR_PTR(-ENOMEM); |
489 | } | 490 | } |
490 | pinmux_init_pinctrl_handle(p); | 491 | p->dev = dev; |
492 | p->state = name; | ||
493 | INIT_LIST_HEAD(&p->settings); | ||
491 | 494 | ||
492 | /* Iterate over the pin control maps to locate the right ones */ | 495 | /* Iterate over the pin control maps to locate the right ones */ |
493 | for_each_maps(maps_node, i, map) { | 496 | for_each_maps(maps_node, i, map) { |
497 | /* Map must be for this device */ | ||
498 | if (strcmp(map->dev_name, devname)) | ||
499 | continue; | ||
500 | |||
501 | /* State name must be the one we're looking for */ | ||
502 | if (strcmp(map->name, name)) | ||
503 | continue; | ||
504 | |||
494 | /* | 505 | /* |
495 | * First, try to find the pctldev given in the map | 506 | * Try to find the pctldev given in the map |
496 | */ | 507 | */ |
497 | pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); | 508 | pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); |
498 | if (!pctldev) { | 509 | if (!pctldev) { |
499 | dev_err(dev, "unknown pinctrl device %s in map entry", | 510 | dev_err(dev, "unknown pinctrl device %s in map entry", |
500 | map->ctrl_dev_name); | 511 | map->ctrl_dev_name); |
501 | pinmux_put(p); | ||
502 | kfree(p); | ||
503 | /* Eventually, this should trigger deferred probe */ | 512 | /* Eventually, this should trigger deferred probe */ |
504 | return ERR_PTR(-ENODEV); | 513 | ret = -ENODEV; |
514 | goto error; | ||
505 | } | 515 | } |
506 | 516 | ||
507 | dev_dbg(dev, "in map, found pctldev %s to handle function %s", | 517 | dev_dbg(dev, "in map, found pctldev %s to handle function %s", |
508 | dev_name(pctldev->dev), map->function); | 518 | dev_name(pctldev->dev), map->function); |
509 | 519 | ||
510 | /* Map must be for this device */ | 520 | setting = kzalloc(sizeof(*setting), GFP_KERNEL); |
511 | if (strcmp(map->dev_name, devname)) | 521 | if (setting == NULL) { |
512 | continue; | 522 | dev_err(dev, |
523 | "failed to alloc struct pinctrl_setting\n"); | ||
524 | ret = -ENOMEM; | ||
525 | goto error; | ||
526 | } | ||
513 | 527 | ||
514 | /* State name must be the one we're looking for */ | 528 | setting->pctldev = pctldev; |
515 | if (strcmp(map->name, name)) | 529 | ret = pinmux_map_to_setting(map, setting); |
516 | continue; | 530 | if (ret < 0) |
531 | goto error; | ||
532 | |||
533 | list_add_tail(&setting->node, &p->settings); | ||
517 | 534 | ||
518 | ret = pinmux_apply_muxmap(pctldev, p, dev, devname, map); | ||
519 | if (ret) { | ||
520 | kfree(p); | ||
521 | return ERR_PTR(ret); | ||
522 | } | ||
523 | num_maps++; | 535 | num_maps++; |
524 | } | 536 | } |
525 | 537 | ||
@@ -541,6 +553,14 @@ static struct pinctrl *pinctrl_get_locked(struct device *dev, const char *name) | |||
541 | list_add_tail(&p->node, &pinctrl_list); | 553 | list_add_tail(&p->node, &pinctrl_list); |
542 | 554 | ||
543 | return p; | 555 | return p; |
556 | |||
557 | error: | ||
558 | list_for_each_entry(setting, &p->settings, node) | ||
559 | pinmux_free_setting(setting); | ||
560 | |||
561 | kfree(p); | ||
562 | |||
563 | return ERR_PTR(ret); | ||
544 | } | 564 | } |
545 | 565 | ||
546 | /** | 566 | /** |
@@ -564,13 +584,18 @@ EXPORT_SYMBOL_GPL(pinctrl_get); | |||
564 | 584 | ||
565 | static void pinctrl_put_locked(struct pinctrl *p) | 585 | static void pinctrl_put_locked(struct pinctrl *p) |
566 | { | 586 | { |
587 | struct pinctrl_setting *setting, *n; | ||
588 | |||
567 | if (p == NULL) | 589 | if (p == NULL) |
568 | return; | 590 | return; |
569 | 591 | ||
570 | if (p->usecount) | 592 | if (p->usecount) |
571 | pr_warn("releasing pin control handle with active users!\n"); | 593 | pr_warn("releasing pin control handle with active users!\n"); |
572 | /* Free the groups and all acquired pins */ | 594 | list_for_each_entry_safe(setting, n, &p->settings, node) { |
573 | pinmux_put(p); | 595 | pinmux_free_setting(setting); |
596 | list_del(&setting->node); | ||
597 | kfree(setting); | ||
598 | } | ||
574 | 599 | ||
575 | /* Remove from list */ | 600 | /* Remove from list */ |
576 | list_del(&p->node); | 601 | list_del(&p->node); |
@@ -592,18 +617,24 @@ EXPORT_SYMBOL_GPL(pinctrl_put); | |||
592 | 617 | ||
593 | static int pinctrl_enable_locked(struct pinctrl *p) | 618 | static int pinctrl_enable_locked(struct pinctrl *p) |
594 | { | 619 | { |
595 | int ret = 0; | 620 | struct pinctrl_setting *setting; |
621 | int ret; | ||
596 | 622 | ||
597 | if (p == NULL) | 623 | if (p == NULL) |
598 | return -EINVAL; | 624 | return -EINVAL; |
599 | 625 | ||
600 | if (p->usecount++ == 0) { | 626 | if (p->usecount++ == 0) { |
601 | ret = pinmux_enable(p); | 627 | list_for_each_entry(setting, &p->settings, node) { |
602 | if (ret) | 628 | ret = pinmux_enable_setting(setting); |
603 | p->usecount--; | 629 | if (ret < 0) { |
630 | /* FIXME: Difficult to return to prev state */ | ||
631 | p->usecount--; | ||
632 | return ret; | ||
633 | } | ||
634 | } | ||
604 | } | 635 | } |
605 | 636 | ||
606 | return ret; | 637 | return 0; |
607 | } | 638 | } |
608 | 639 | ||
609 | /** | 640 | /** |
@@ -622,11 +653,14 @@ EXPORT_SYMBOL_GPL(pinctrl_enable); | |||
622 | 653 | ||
623 | static void pinctrl_disable_locked(struct pinctrl *p) | 654 | static void pinctrl_disable_locked(struct pinctrl *p) |
624 | { | 655 | { |
656 | struct pinctrl_setting *setting; | ||
657 | |||
625 | if (p == NULL) | 658 | if (p == NULL) |
626 | return; | 659 | return; |
627 | 660 | ||
628 | if (--p->usecount == 0) { | 661 | if (--p->usecount == 0) { |
629 | pinmux_disable(p); | 662 | list_for_each_entry(setting, &p->settings, node) |
663 | pinmux_disable_setting(setting); | ||
630 | } | 664 | } |
631 | } | 665 | } |
632 | 666 | ||
@@ -857,27 +891,20 @@ static int pinctrl_maps_show(struct seq_file *s, void *what) | |||
857 | static int pinctrl_show(struct seq_file *s, void *what) | 891 | static int pinctrl_show(struct seq_file *s, void *what) |
858 | { | 892 | { |
859 | struct pinctrl *p; | 893 | struct pinctrl *p; |
894 | struct pinctrl_setting *setting; | ||
860 | 895 | ||
861 | seq_puts(s, "Requested pin control handlers their pinmux maps:\n"); | 896 | seq_puts(s, "Requested pin control handlers their pinmux maps:\n"); |
862 | 897 | ||
863 | mutex_lock(&pinctrl_mutex); | 898 | mutex_lock(&pinctrl_mutex); |
864 | 899 | ||
865 | list_for_each_entry(p, &pinctrl_list, node) { | 900 | list_for_each_entry(p, &pinctrl_list, node) { |
866 | struct pinctrl_dev *pctldev = p->pctldev; | 901 | seq_printf(s, "device: %s state: %s users: %u\n", |
902 | dev_name(p->dev), p->state, p->usecount); | ||
867 | 903 | ||
868 | if (!pctldev) { | 904 | list_for_each_entry(setting, &p->settings, node) { |
869 | seq_puts(s, "NO PIN CONTROLLER DEVICE\n"); | 905 | seq_printf(s, " "); |
870 | continue; | 906 | pinmux_dbg_show(s, setting); |
871 | } | 907 | } |
872 | |||
873 | seq_printf(s, "device: %s", | ||
874 | pinctrl_dev_get_name(p->pctldev)); | ||
875 | |||
876 | pinmux_dbg_show(s, p); | ||
877 | |||
878 | seq_printf(s, " users: %u map-> %s\n", | ||
879 | p->usecount, | ||
880 | p->dev ? dev_name(p->dev) : "(system)"); | ||
881 | } | 908 | } |
882 | 909 | ||
883 | mutex_unlock(&pinctrl_mutex); | 910 | mutex_unlock(&pinctrl_mutex); |