diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2013-06-17 14:50:02 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-06-18 04:57:51 -0400 |
commit | fe1c9a822ce72c6ec8476a2501c412265ee2172c (patch) | |
tree | 743e3e67152fd5883e02a4eded386787d7fa8be5 /drivers/pinctrl/sh-pfc/pinctrl.c | |
parent | 3a7f520e63727e14de9567515d8727c2c01fedb4 (diff) |
sh-pfc: Add DT support
Support device instantiation through the device tree. The compatible
property is used to select the SoC pinmux information.
Set the gpio_chip device field to the PFC device to enable automatic
GPIO OF support.
Cc: devicetree-discuss@lists.ozlabs.org
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Acked-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/sh-pfc/pinctrl.c')
-rw-r--r-- | drivers/pinctrl/sh-pfc/pinctrl.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index 3492ec9a33b7..7e32bb8c08dd 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c | |||
@@ -14,7 +14,9 @@ | |||
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/of.h> | ||
17 | #include <linux/pinctrl/consumer.h> | 18 | #include <linux/pinctrl/consumer.h> |
19 | #include <linux/pinctrl/machine.h> | ||
18 | #include <linux/pinctrl/pinconf.h> | 20 | #include <linux/pinctrl/pinconf.h> |
19 | #include <linux/pinctrl/pinconf-generic.h> | 21 | #include <linux/pinctrl/pinconf-generic.h> |
20 | #include <linux/pinctrl/pinctrl.h> | 22 | #include <linux/pinctrl/pinctrl.h> |
@@ -72,11 +74,125 @@ static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, | |||
72 | seq_printf(s, "%s", DRV_NAME); | 74 | seq_printf(s, "%s", DRV_NAME); |
73 | } | 75 | } |
74 | 76 | ||
77 | static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, | ||
78 | struct pinctrl_map **map, | ||
79 | unsigned int *num_maps, unsigned int *index) | ||
80 | { | ||
81 | struct pinctrl_map *maps = *map; | ||
82 | unsigned int nmaps = *num_maps; | ||
83 | unsigned int idx = *index; | ||
84 | const char *function = NULL; | ||
85 | struct property *prop; | ||
86 | const char *group; | ||
87 | int ret; | ||
88 | |||
89 | /* Parse the function and configuration properties. At least a function | ||
90 | * or one configuration must be specified. | ||
91 | */ | ||
92 | ret = of_property_read_string(np, "renesas,function", &function); | ||
93 | if (ret < 0 && ret != -EINVAL) { | ||
94 | dev_err(dev, "Invalid function in DT\n"); | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | if (!function) { | ||
99 | dev_err(dev, "DT node must contain at least one function\n"); | ||
100 | goto done; | ||
101 | } | ||
102 | |||
103 | /* Count the number of groups and reallocate mappings. */ | ||
104 | ret = of_property_count_strings(np, "renesas,groups"); | ||
105 | if (ret < 0 && ret != -EINVAL) { | ||
106 | dev_err(dev, "Invalid pin groups list in DT\n"); | ||
107 | goto done; | ||
108 | } | ||
109 | |||
110 | if (!ret) { | ||
111 | dev_err(dev, "No group provided in DT node\n"); | ||
112 | ret = -ENODEV; | ||
113 | goto done; | ||
114 | } | ||
115 | |||
116 | nmaps += ret; | ||
117 | |||
118 | maps = krealloc(maps, sizeof(*maps) * nmaps, GFP_KERNEL); | ||
119 | if (maps == NULL) { | ||
120 | ret = -ENOMEM; | ||
121 | goto done; | ||
122 | } | ||
123 | |||
124 | *map = maps; | ||
125 | *num_maps = nmaps; | ||
126 | |||
127 | /* Iterate over pins and groups and create the mappings. */ | ||
128 | of_property_for_each_string(np, "renesas,groups", prop, group) { | ||
129 | maps[idx].type = PIN_MAP_TYPE_MUX_GROUP; | ||
130 | maps[idx].data.mux.group = group; | ||
131 | maps[idx].data.mux.function = function; | ||
132 | idx++; | ||
133 | } | ||
134 | |||
135 | ret = 0; | ||
136 | |||
137 | done: | ||
138 | *index = idx; | ||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | static void sh_pfc_dt_free_map(struct pinctrl_dev *pctldev, | ||
143 | struct pinctrl_map *map, unsigned num_maps) | ||
144 | { | ||
145 | kfree(map); | ||
146 | } | ||
147 | |||
148 | static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev, | ||
149 | struct device_node *np, | ||
150 | struct pinctrl_map **map, unsigned *num_maps) | ||
151 | { | ||
152 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); | ||
153 | struct device *dev = pmx->pfc->dev; | ||
154 | struct device_node *child; | ||
155 | unsigned int index; | ||
156 | int ret; | ||
157 | |||
158 | *map = NULL; | ||
159 | *num_maps = 0; | ||
160 | index = 0; | ||
161 | |||
162 | for_each_child_of_node(np, child) { | ||
163 | ret = sh_pfc_dt_subnode_to_map(dev, child, map, num_maps, | ||
164 | &index); | ||
165 | if (ret < 0) | ||
166 | goto done; | ||
167 | } | ||
168 | |||
169 | /* If no mapping has been found in child nodes try the config node. */ | ||
170 | if (*num_maps == 0) { | ||
171 | ret = sh_pfc_dt_subnode_to_map(dev, np, map, num_maps, &index); | ||
172 | if (ret < 0) | ||
173 | goto done; | ||
174 | } | ||
175 | |||
176 | if (*num_maps) | ||
177 | return 0; | ||
178 | |||
179 | dev_err(dev, "no mapping found in node %s\n", np->full_name); | ||
180 | ret = -EINVAL; | ||
181 | |||
182 | done: | ||
183 | if (ret < 0) | ||
184 | sh_pfc_dt_free_map(pctldev, *map, *num_maps); | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | |||
75 | static const struct pinctrl_ops sh_pfc_pinctrl_ops = { | 189 | static const struct pinctrl_ops sh_pfc_pinctrl_ops = { |
76 | .get_groups_count = sh_pfc_get_groups_count, | 190 | .get_groups_count = sh_pfc_get_groups_count, |
77 | .get_group_name = sh_pfc_get_group_name, | 191 | .get_group_name = sh_pfc_get_group_name, |
78 | .get_group_pins = sh_pfc_get_group_pins, | 192 | .get_group_pins = sh_pfc_get_group_pins, |
79 | .pin_dbg_show = sh_pfc_pin_dbg_show, | 193 | .pin_dbg_show = sh_pfc_pin_dbg_show, |
194 | .dt_node_to_map = sh_pfc_dt_node_to_map, | ||
195 | .dt_free_map = sh_pfc_dt_free_map, | ||
80 | }; | 196 | }; |
81 | 197 | ||
82 | static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev) | 198 | static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev) |