diff options
author | Laurent Meunier <laurent.meunier@st.com> | 2013-02-06 03:09:44 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-02-10 15:11:54 -0500 |
commit | 6f9e41f4e673bf9ae6a5c0831b1524a91ea1c440 (patch) | |
tree | 9cff86fdcbbefdbca5520cc1746163d7ad9534a6 /drivers/pinctrl | |
parent | 007cd694332e6d5f57ef76431d2372c958b85a21 (diff) |
pinctrl/pinconfig: add debug interface
This update adds a debugfs interface to modify a pin configuration
for a given state in the pinctrl map. This allows to modify the
configuration for a non-active state, typically sleep state.
This configuration is not applied right away, but only when the state
will be entered.
This solution is mandated for us by HW validation: in order
to test and verify several pin configurations during sleep without
recompiling the software.
Signed-off-by: Laurent Meunier <laurent.meunier@st.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/core.c | 18 | ||||
-rw-r--r-- | drivers/pinctrl/core.h | 19 | ||||
-rw-r--r-- | drivers/pinctrl/pinconf.c | 207 |
3 files changed, 227 insertions, 17 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index b0a8e9a38393..b0de6e7f1fdb 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c | |||
@@ -32,17 +32,6 @@ | |||
32 | #include "pinmux.h" | 32 | #include "pinmux.h" |
33 | #include "pinconf.h" | 33 | #include "pinconf.h" |
34 | 34 | ||
35 | /** | ||
36 | * struct pinctrl_maps - a list item containing part of the mapping table | ||
37 | * @node: mapping table list node | ||
38 | * @maps: array of mapping table entries | ||
39 | * @num_maps: the number of entries in @maps | ||
40 | */ | ||
41 | struct pinctrl_maps { | ||
42 | struct list_head node; | ||
43 | struct pinctrl_map const *maps; | ||
44 | unsigned num_maps; | ||
45 | }; | ||
46 | 35 | ||
47 | static bool pinctrl_dummy_state; | 36 | static bool pinctrl_dummy_state; |
48 | 37 | ||
@@ -56,13 +45,8 @@ LIST_HEAD(pinctrldev_list); | |||
56 | static LIST_HEAD(pinctrl_list); | 45 | static LIST_HEAD(pinctrl_list); |
57 | 46 | ||
58 | /* List of pinctrl maps (struct pinctrl_maps) */ | 47 | /* List of pinctrl maps (struct pinctrl_maps) */ |
59 | static LIST_HEAD(pinctrl_maps); | 48 | LIST_HEAD(pinctrl_maps); |
60 | 49 | ||
61 | #define for_each_maps(_maps_node_, _i_, _map_) \ | ||
62 | list_for_each_entry(_maps_node_, &pinctrl_maps, node) \ | ||
63 | for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \ | ||
64 | _i_ < _maps_node_->num_maps; \ | ||
65 | _i_++, _map_ = &_maps_node_->maps[_i_]) | ||
66 | 50 | ||
67 | /** | 51 | /** |
68 | * pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support | 52 | * pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support |
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index fdd350d639f6..ee72f1f6d862 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h | |||
@@ -155,6 +155,18 @@ struct pin_desc { | |||
155 | #endif | 155 | #endif |
156 | }; | 156 | }; |
157 | 157 | ||
158 | /** | ||
159 | * struct pinctrl_maps - a list item containing part of the mapping table | ||
160 | * @node: mapping table list node | ||
161 | * @maps: array of mapping table entries | ||
162 | * @num_maps: the number of entries in @maps | ||
163 | */ | ||
164 | struct pinctrl_maps { | ||
165 | struct list_head node; | ||
166 | struct pinctrl_map const *maps; | ||
167 | unsigned num_maps; | ||
168 | }; | ||
169 | |||
158 | struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); | 170 | struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); |
159 | int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name); | 171 | int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name); |
160 | const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin); | 172 | const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin); |
@@ -176,3 +188,10 @@ extern int pinctrl_force_default(struct pinctrl_dev *pctldev); | |||
176 | 188 | ||
177 | extern struct mutex pinctrl_mutex; | 189 | extern struct mutex pinctrl_mutex; |
178 | extern struct list_head pinctrldev_list; | 190 | extern struct list_head pinctrldev_list; |
191 | extern struct list_head pinctrl_maps; | ||
192 | |||
193 | #define for_each_maps(_maps_node_, _i_, _map_) \ | ||
194 | list_for_each_entry(_maps_node_, &pinctrl_maps, node) \ | ||
195 | for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \ | ||
196 | _i_ < _maps_node_->num_maps; \ | ||
197 | _i_++, _map_ = &_maps_node_->maps[_i_]) | ||
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index baee2cc46a17..ac8d382a79bb 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c | |||
@@ -574,6 +574,207 @@ static const struct file_operations pinconf_groups_ops = { | |||
574 | .release = single_release, | 574 | .release = single_release, |
575 | }; | 575 | }; |
576 | 576 | ||
577 | /* 32bit read/write ressources */ | ||
578 | #define MAX_NAME_LEN 16 | ||
579 | char dbg_pinname[MAX_NAME_LEN]; /* shared: name of the state of the pin*/ | ||
580 | char dbg_state_name[MAX_NAME_LEN]; /* shared: state of the pin*/ | ||
581 | static u32 dbg_config; /* shared: config to be read/set for the pin & state*/ | ||
582 | |||
583 | static int pinconf_dbg_pinname_print(struct seq_file *s, void *d) | ||
584 | { | ||
585 | if (strlen(dbg_pinname)) | ||
586 | seq_printf(s, "%s\n", dbg_pinname); | ||
587 | else | ||
588 | seq_printf(s, "No pin name set\n"); | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int pinconf_dbg_pinname_open(struct inode *inode, struct file *file) | ||
593 | { | ||
594 | return single_open(file, pinconf_dbg_pinname_print, inode->i_private); | ||
595 | } | ||
596 | |||
597 | static int pinconf_dbg_pinname_write(struct file *file, | ||
598 | const char __user *user_buf, size_t count, loff_t *ppos) | ||
599 | { | ||
600 | int err; | ||
601 | |||
602 | if (count > MAX_NAME_LEN) | ||
603 | return -EINVAL; | ||
604 | |||
605 | err = sscanf(user_buf, "%15s", dbg_pinname); | ||
606 | |||
607 | if (err != 1) | ||
608 | return -EINVAL; | ||
609 | |||
610 | return count; | ||
611 | } | ||
612 | |||
613 | static const struct file_operations pinconf_dbg_pinname_fops = { | ||
614 | .open = pinconf_dbg_pinname_open, | ||
615 | .write = pinconf_dbg_pinname_write, | ||
616 | .read = seq_read, | ||
617 | .llseek = seq_lseek, | ||
618 | .release = single_release, | ||
619 | .owner = THIS_MODULE, | ||
620 | }; | ||
621 | |||
622 | static int pinconf_dbg_state_print(struct seq_file *s, void *d) | ||
623 | { | ||
624 | if (strlen(dbg_state_name)) | ||
625 | seq_printf(s, "%s\n", dbg_pinname); | ||
626 | else | ||
627 | seq_printf(s, "No pin state set\n"); | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static int pinconf_dbg_state_open(struct inode *inode, struct file *file) | ||
632 | { | ||
633 | return single_open(file, pinconf_dbg_state_print, inode->i_private); | ||
634 | } | ||
635 | |||
636 | static int pinconf_dbg_state_write(struct file *file, | ||
637 | const char __user *user_buf, size_t count, loff_t *ppos) | ||
638 | { | ||
639 | int err; | ||
640 | |||
641 | if (count > MAX_NAME_LEN) | ||
642 | return -EINVAL; | ||
643 | |||
644 | err = sscanf(user_buf, "%15s", dbg_state_name); | ||
645 | |||
646 | if (err != 1) | ||
647 | return -EINVAL; | ||
648 | |||
649 | return count; | ||
650 | } | ||
651 | |||
652 | static const struct file_operations pinconf_dbg_pinstate_fops = { | ||
653 | .open = pinconf_dbg_state_open, | ||
654 | .write = pinconf_dbg_state_write, | ||
655 | .read = seq_read, | ||
656 | .llseek = seq_lseek, | ||
657 | .release = single_release, | ||
658 | .owner = THIS_MODULE, | ||
659 | }; | ||
660 | |||
661 | /** | ||
662 | * pinconf_dbg_config_print() - display the pinctrl config from the pinctrl | ||
663 | * map, of a pin/state pair based on pinname and state that have been | ||
664 | * selected with the debugfs entries pinconf-name and pinconf-state | ||
665 | * @s: contains the 32bits config to be written | ||
666 | * @d: not used | ||
667 | */ | ||
668 | static int pinconf_dbg_config_print(struct seq_file *s, void *d) | ||
669 | { | ||
670 | struct pinctrl_maps *maps_node; | ||
671 | struct pinctrl_map const *map; | ||
672 | struct pinctrl_dev *pctldev = NULL; | ||
673 | struct pinconf_ops *confops = NULL; | ||
674 | int i, j; | ||
675 | bool found = false; | ||
676 | |||
677 | mutex_lock(&pinctrl_mutex); | ||
678 | |||
679 | /* Parse the pinctrl map and look for the elected pin/state */ | ||
680 | for_each_maps(maps_node, i, map) { | ||
681 | if (map->type != PIN_MAP_TYPE_CONFIGS_PIN) | ||
682 | continue; | ||
683 | |||
684 | if (strncmp(map->name, dbg_state_name, MAX_NAME_LEN) > 0) | ||
685 | continue; | ||
686 | |||
687 | for (j = 0; j < map->data.configs.num_configs; j++) { | ||
688 | if (0 == strncmp(map->data.configs.group_or_pin, | ||
689 | dbg_pinname, MAX_NAME_LEN)) { | ||
690 | /* We found the right pin / state, read the | ||
691 | * config and store the pctldev */ | ||
692 | dbg_config = map->data.configs.configs[j]; | ||
693 | pctldev = get_pinctrl_dev_from_devname | ||
694 | (map->ctrl_dev_name); | ||
695 | found = true; | ||
696 | break; | ||
697 | } | ||
698 | } | ||
699 | } | ||
700 | |||
701 | mutex_unlock(&pinctrl_mutex); | ||
702 | |||
703 | if (found) { | ||
704 | seq_printf(s, "Config of %s in state %s: 0x%08X\n", dbg_pinname, | ||
705 | dbg_state_name, dbg_config); | ||
706 | |||
707 | if (pctldev) | ||
708 | confops = pctldev->desc->confops; | ||
709 | |||
710 | if (confops && confops->pin_config_config_dbg_show) | ||
711 | confops->pin_config_config_dbg_show(pctldev, | ||
712 | s, dbg_config); | ||
713 | } else { | ||
714 | seq_printf(s, "No pin found for defined name/state\n"); | ||
715 | } | ||
716 | |||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | static int pinconf_dbg_config_open(struct inode *inode, struct file *file) | ||
721 | { | ||
722 | return single_open(file, pinconf_dbg_config_print, inode->i_private); | ||
723 | } | ||
724 | |||
725 | /** | ||
726 | * pinconf_dbg_config_write() - overwrite the pinctrl config in thepinctrl | ||
727 | * map, of a pin/state pair based on pinname and state that have been | ||
728 | * selected with the debugfs entries pinconf-name and pinconf-state | ||
729 | */ | ||
730 | static int pinconf_dbg_config_write(struct file *file, | ||
731 | const char __user *user_buf, size_t count, loff_t *ppos) | ||
732 | { | ||
733 | int err; | ||
734 | unsigned long config; | ||
735 | struct pinctrl_maps *maps_node; | ||
736 | struct pinctrl_map const *map; | ||
737 | int i, j; | ||
738 | |||
739 | err = kstrtoul_from_user(user_buf, count, 0, &config); | ||
740 | |||
741 | if (err) | ||
742 | return err; | ||
743 | |||
744 | dbg_config = config; | ||
745 | |||
746 | mutex_lock(&pinctrl_mutex); | ||
747 | |||
748 | /* Parse the pinctrl map and look for the selected pin/state */ | ||
749 | for_each_maps(maps_node, i, map) { | ||
750 | if (map->type != PIN_MAP_TYPE_CONFIGS_PIN) | ||
751 | continue; | ||
752 | |||
753 | if (strncmp(map->name, dbg_state_name, MAX_NAME_LEN) > 0) | ||
754 | continue; | ||
755 | |||
756 | /* we found the right pin / state, so overwrite config */ | ||
757 | for (j = 0; j < map->data.configs.num_configs; j++) { | ||
758 | if (strncmp(map->data.configs.group_or_pin, dbg_pinname, | ||
759 | MAX_NAME_LEN) == 0) | ||
760 | map->data.configs.configs[j] = dbg_config; | ||
761 | } | ||
762 | } | ||
763 | |||
764 | mutex_unlock(&pinctrl_mutex); | ||
765 | |||
766 | return count; | ||
767 | } | ||
768 | |||
769 | static const struct file_operations pinconf_dbg_pinconfig_fops = { | ||
770 | .open = pinconf_dbg_config_open, | ||
771 | .write = pinconf_dbg_config_write, | ||
772 | .read = seq_read, | ||
773 | .llseek = seq_lseek, | ||
774 | .release = single_release, | ||
775 | .owner = THIS_MODULE, | ||
776 | }; | ||
777 | |||
577 | void pinconf_init_device_debugfs(struct dentry *devroot, | 778 | void pinconf_init_device_debugfs(struct dentry *devroot, |
578 | struct pinctrl_dev *pctldev) | 779 | struct pinctrl_dev *pctldev) |
579 | { | 780 | { |
@@ -581,6 +782,12 @@ void pinconf_init_device_debugfs(struct dentry *devroot, | |||
581 | devroot, pctldev, &pinconf_pins_ops); | 782 | devroot, pctldev, &pinconf_pins_ops); |
582 | debugfs_create_file("pinconf-groups", S_IFREG | S_IRUGO, | 783 | debugfs_create_file("pinconf-groups", S_IFREG | S_IRUGO, |
583 | devroot, pctldev, &pinconf_groups_ops); | 784 | devroot, pctldev, &pinconf_groups_ops); |
785 | debugfs_create_file("pinconf-name", (S_IRUGO | S_IWUSR | S_IWGRP), | ||
786 | devroot, pctldev, &pinconf_dbg_pinname_fops); | ||
787 | debugfs_create_file("pinconf-state", (S_IRUGO | S_IWUSR | S_IWGRP), | ||
788 | devroot, pctldev, &pinconf_dbg_pinstate_fops); | ||
789 | debugfs_create_file("pinconf-config", (S_IRUGO | S_IWUSR | S_IWGRP), | ||
790 | devroot, pctldev, &pinconf_dbg_pinconfig_fops); | ||
584 | } | 791 | } |
585 | 792 | ||
586 | #endif | 793 | #endif |