]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
7e8d9415 SH |
2 | /* |
3 | * Marvell MVEBU pinctrl core driver | |
4 | * | |
5 | * Authors: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | |
6 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | |
7e8d9415 SH |
7 | */ |
8 | ||
9 | #include <linux/platform_device.h> | |
7e8d9415 SH |
10 | #include <linux/slab.h> |
11 | #include <linux/io.h> | |
12 | #include <linux/of.h> | |
13 | #include <linux/of_address.h> | |
14 | #include <linux/of_platform.h> | |
15 | #include <linux/err.h> | |
1c5fb66a | 16 | #include <linux/gpio/driver.h> |
7e8d9415 SH |
17 | #include <linux/pinctrl/machine.h> |
18 | #include <linux/pinctrl/pinconf.h> | |
19 | #include <linux/pinctrl/pinctrl.h> | |
20 | #include <linux/pinctrl/pinmux.h> | |
d068b098 RK |
21 | #include <linux/mfd/syscon.h> |
22 | #include <linux/regmap.h> | |
7e8d9415 | 23 | |
7e8d9415 SH |
24 | #include "pinctrl-mvebu.h" |
25 | ||
26 | #define MPPS_PER_REG 8 | |
27 | #define MPP_BITS 4 | |
28 | #define MPP_MASK 0xf | |
29 | ||
30 | struct mvebu_pinctrl_function { | |
31 | const char *name; | |
32 | const char **groups; | |
33 | unsigned num_groups; | |
34 | }; | |
35 | ||
36 | struct mvebu_pinctrl_group { | |
37 | const char *name; | |
30be3fb9 | 38 | const struct mvebu_mpp_ctrl *ctrl; |
20955c5f | 39 | struct mvebu_mpp_ctrl_data *data; |
7e8d9415 SH |
40 | struct mvebu_mpp_ctrl_setting *settings; |
41 | unsigned num_settings; | |
42 | unsigned gid; | |
43 | unsigned *pins; | |
44 | unsigned npins; | |
45 | }; | |
46 | ||
47 | struct mvebu_pinctrl { | |
48 | struct device *dev; | |
49 | struct pinctrl_dev *pctldev; | |
50 | struct pinctrl_desc desc; | |
7e8d9415 SH |
51 | struct mvebu_pinctrl_group *groups; |
52 | unsigned num_groups; | |
53 | struct mvebu_pinctrl_function *functions; | |
54 | unsigned num_functions; | |
55 | u8 variant; | |
56 | }; | |
57 | ||
44aa9d06 RK |
58 | int mvebu_mmio_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, |
59 | unsigned int pid, unsigned long *config) | |
60 | { | |
61 | unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; | |
62 | unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; | |
63 | ||
64 | *config = (readl(data->base + off) >> shift) & MVEBU_MPP_MASK; | |
65 | ||
66 | return 0; | |
67 | } | |
68 | ||
69 | int mvebu_mmio_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, | |
70 | unsigned int pid, unsigned long config) | |
71 | { | |
72 | unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; | |
73 | unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; | |
74 | unsigned long reg; | |
75 | ||
76 | reg = readl(data->base + off) & ~(MVEBU_MPP_MASK << shift); | |
77 | writel(reg | (config << shift), data->base + off); | |
78 | ||
79 | return 0; | |
80 | } | |
81 | ||
7e8d9415 SH |
82 | static struct mvebu_pinctrl_group *mvebu_pinctrl_find_group_by_pid( |
83 | struct mvebu_pinctrl *pctl, unsigned pid) | |
84 | { | |
85 | unsigned n; | |
86 | for (n = 0; n < pctl->num_groups; n++) { | |
87 | if (pid >= pctl->groups[n].pins[0] && | |
88 | pid < pctl->groups[n].pins[0] + | |
89 | pctl->groups[n].npins) | |
90 | return &pctl->groups[n]; | |
91 | } | |
92 | return NULL; | |
93 | } | |
94 | ||
95 | static struct mvebu_pinctrl_group *mvebu_pinctrl_find_group_by_name( | |
96 | struct mvebu_pinctrl *pctl, const char *name) | |
97 | { | |
98 | unsigned n; | |
99 | for (n = 0; n < pctl->num_groups; n++) { | |
100 | if (strcmp(name, pctl->groups[n].name) == 0) | |
101 | return &pctl->groups[n]; | |
102 | } | |
103 | return NULL; | |
104 | } | |
105 | ||
106 | static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_val( | |
107 | struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp, | |
108 | unsigned long config) | |
109 | { | |
110 | unsigned n; | |
111 | for (n = 0; n < grp->num_settings; n++) { | |
112 | if (config == grp->settings[n].val) { | |
113 | if (!pctl->variant || (pctl->variant & | |
114 | grp->settings[n].variant)) | |
115 | return &grp->settings[n]; | |
116 | } | |
117 | } | |
118 | return NULL; | |
119 | } | |
120 | ||
121 | static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_name( | |
122 | struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp, | |
123 | const char *name) | |
124 | { | |
125 | unsigned n; | |
126 | for (n = 0; n < grp->num_settings; n++) { | |
127 | if (strcmp(name, grp->settings[n].name) == 0) { | |
128 | if (!pctl->variant || (pctl->variant & | |
129 | grp->settings[n].variant)) | |
130 | return &grp->settings[n]; | |
131 | } | |
132 | } | |
133 | return NULL; | |
134 | } | |
135 | ||
136 | static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_gpio_setting( | |
137 | struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp) | |
138 | { | |
139 | unsigned n; | |
140 | for (n = 0; n < grp->num_settings; n++) { | |
141 | if (grp->settings[n].flags & | |
142 | (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) { | |
143 | if (!pctl->variant || (pctl->variant & | |
144 | grp->settings[n].variant)) | |
145 | return &grp->settings[n]; | |
146 | } | |
147 | } | |
148 | return NULL; | |
149 | } | |
150 | ||
151 | static struct mvebu_pinctrl_function *mvebu_pinctrl_find_function_by_name( | |
152 | struct mvebu_pinctrl *pctl, const char *name) | |
153 | { | |
154 | unsigned n; | |
155 | for (n = 0; n < pctl->num_functions; n++) { | |
156 | if (strcmp(name, pctl->functions[n].name) == 0) | |
157 | return &pctl->functions[n]; | |
158 | } | |
159 | return NULL; | |
160 | } | |
161 | ||
7e8d9415 SH |
162 | static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev, |
163 | unsigned gid, unsigned long *config) | |
164 | { | |
165 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
166 | struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; | |
167 | ||
168 | if (!grp->ctrl) | |
169 | return -EINVAL; | |
170 | ||
20955c5f | 171 | return grp->ctrl->mpp_get(grp->data, grp->pins[0], config); |
7e8d9415 SH |
172 | } |
173 | ||
174 | static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev, | |
03b054e9 SY |
175 | unsigned gid, unsigned long *configs, |
176 | unsigned num_configs) | |
7e8d9415 SH |
177 | { |
178 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
179 | struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; | |
03b054e9 | 180 | int i, ret; |
7e8d9415 SH |
181 | |
182 | if (!grp->ctrl) | |
183 | return -EINVAL; | |
184 | ||
03b054e9 | 185 | for (i = 0; i < num_configs; i++) { |
20955c5f | 186 | ret = grp->ctrl->mpp_set(grp->data, grp->pins[0], configs[i]); |
03b054e9 SY |
187 | if (ret) |
188 | return ret; | |
189 | } /* for each config */ | |
190 | ||
191 | return 0; | |
7e8d9415 SH |
192 | } |
193 | ||
194 | static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, | |
195 | struct seq_file *s, unsigned gid) | |
196 | { | |
197 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
198 | struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; | |
199 | struct mvebu_mpp_ctrl_setting *curr; | |
200 | unsigned long config; | |
201 | unsigned n; | |
202 | ||
203 | if (mvebu_pinconf_group_get(pctldev, gid, &config)) | |
204 | return; | |
205 | ||
206 | curr = mvebu_pinctrl_find_setting_by_val(pctl, grp, config); | |
207 | ||
208 | if (curr) { | |
209 | seq_printf(s, "current: %s", curr->name); | |
210 | if (curr->subname) | |
211 | seq_printf(s, "(%s)", curr->subname); | |
212 | if (curr->flags & (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) { | |
a61266eb | 213 | seq_putc(s, '('); |
7e8d9415 | 214 | if (curr->flags & MVEBU_SETTING_GPI) |
a61266eb | 215 | seq_putc(s, 'i'); |
7e8d9415 | 216 | if (curr->flags & MVEBU_SETTING_GPO) |
a61266eb ME |
217 | seq_putc(s, 'o'); |
218 | seq_putc(s, ')'); | |
7e8d9415 | 219 | } |
420dc616 ME |
220 | } else { |
221 | seq_puts(s, "current: UNKNOWN"); | |
222 | } | |
7e8d9415 SH |
223 | |
224 | if (grp->num_settings > 1) { | |
420dc616 | 225 | seq_puts(s, ", available = ["); |
7e8d9415 SH |
226 | for (n = 0; n < grp->num_settings; n++) { |
227 | if (curr == &grp->settings[n]) | |
228 | continue; | |
229 | ||
230 | /* skip unsupported settings for this variant */ | |
231 | if (pctl->variant && | |
232 | !(pctl->variant & grp->settings[n].variant)) | |
233 | continue; | |
234 | ||
235 | seq_printf(s, " %s", grp->settings[n].name); | |
236 | if (grp->settings[n].subname) | |
237 | seq_printf(s, "(%s)", grp->settings[n].subname); | |
238 | if (grp->settings[n].flags & | |
239 | (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) { | |
a61266eb | 240 | seq_putc(s, '('); |
7e8d9415 | 241 | if (grp->settings[n].flags & MVEBU_SETTING_GPI) |
a61266eb | 242 | seq_putc(s, 'i'); |
7e8d9415 | 243 | if (grp->settings[n].flags & MVEBU_SETTING_GPO) |
a61266eb ME |
244 | seq_putc(s, 'o'); |
245 | seq_putc(s, ')'); | |
7e8d9415 SH |
246 | } |
247 | } | |
420dc616 | 248 | seq_puts(s, " ]"); |
7e8d9415 | 249 | } |
7e8d9415 SH |
250 | } |
251 | ||
022ab148 | 252 | static const struct pinconf_ops mvebu_pinconf_ops = { |
7e8d9415 SH |
253 | .pin_config_group_get = mvebu_pinconf_group_get, |
254 | .pin_config_group_set = mvebu_pinconf_group_set, | |
255 | .pin_config_group_dbg_show = mvebu_pinconf_group_dbg_show, | |
256 | }; | |
257 | ||
258 | static int mvebu_pinmux_get_funcs_count(struct pinctrl_dev *pctldev) | |
259 | { | |
260 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
261 | ||
262 | return pctl->num_functions; | |
263 | } | |
264 | ||
265 | static const char *mvebu_pinmux_get_func_name(struct pinctrl_dev *pctldev, | |
266 | unsigned fid) | |
267 | { | |
268 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
269 | ||
270 | return pctl->functions[fid].name; | |
271 | } | |
272 | ||
273 | static int mvebu_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned fid, | |
274 | const char * const **groups, | |
275 | unsigned * const num_groups) | |
276 | { | |
277 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
278 | ||
279 | *groups = pctl->functions[fid].groups; | |
280 | *num_groups = pctl->functions[fid].num_groups; | |
281 | return 0; | |
282 | } | |
283 | ||
03e9f0ca LW |
284 | static int mvebu_pinmux_set(struct pinctrl_dev *pctldev, unsigned fid, |
285 | unsigned gid) | |
7e8d9415 SH |
286 | { |
287 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
288 | struct mvebu_pinctrl_function *func = &pctl->functions[fid]; | |
289 | struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; | |
290 | struct mvebu_mpp_ctrl_setting *setting; | |
291 | int ret; | |
03b054e9 | 292 | unsigned long config; |
7e8d9415 SH |
293 | |
294 | setting = mvebu_pinctrl_find_setting_by_name(pctl, grp, | |
295 | func->name); | |
296 | if (!setting) { | |
297 | dev_err(pctl->dev, | |
298 | "unable to find setting %s in group %s\n", | |
299 | func->name, func->groups[gid]); | |
300 | return -EINVAL; | |
301 | } | |
302 | ||
03b054e9 SY |
303 | config = setting->val; |
304 | ret = mvebu_pinconf_group_set(pctldev, grp->gid, &config, 1); | |
7e8d9415 SH |
305 | if (ret) { |
306 | dev_err(pctl->dev, "cannot set group %s to %s\n", | |
307 | func->groups[gid], func->name); | |
308 | return ret; | |
309 | } | |
310 | ||
311 | return 0; | |
312 | } | |
313 | ||
314 | static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, | |
315 | struct pinctrl_gpio_range *range, unsigned offset) | |
316 | { | |
317 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
318 | struct mvebu_pinctrl_group *grp; | |
319 | struct mvebu_mpp_ctrl_setting *setting; | |
03b054e9 | 320 | unsigned long config; |
7e8d9415 SH |
321 | |
322 | grp = mvebu_pinctrl_find_group_by_pid(pctl, offset); | |
323 | if (!grp) | |
324 | return -EINVAL; | |
325 | ||
326 | if (grp->ctrl->mpp_gpio_req) | |
20955c5f | 327 | return grp->ctrl->mpp_gpio_req(grp->data, offset); |
7e8d9415 SH |
328 | |
329 | setting = mvebu_pinctrl_find_gpio_setting(pctl, grp); | |
330 | if (!setting) | |
331 | return -ENOTSUPP; | |
332 | ||
03b054e9 SY |
333 | config = setting->val; |
334 | ||
335 | return mvebu_pinconf_group_set(pctldev, grp->gid, &config, 1); | |
7e8d9415 SH |
336 | } |
337 | ||
338 | static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | |
339 | struct pinctrl_gpio_range *range, unsigned offset, bool input) | |
340 | { | |
341 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
342 | struct mvebu_pinctrl_group *grp; | |
343 | struct mvebu_mpp_ctrl_setting *setting; | |
344 | ||
345 | grp = mvebu_pinctrl_find_group_by_pid(pctl, offset); | |
346 | if (!grp) | |
347 | return -EINVAL; | |
348 | ||
349 | if (grp->ctrl->mpp_gpio_dir) | |
20955c5f | 350 | return grp->ctrl->mpp_gpio_dir(grp->data, offset, input); |
7e8d9415 SH |
351 | |
352 | setting = mvebu_pinctrl_find_gpio_setting(pctl, grp); | |
353 | if (!setting) | |
354 | return -ENOTSUPP; | |
355 | ||
356 | if ((input && (setting->flags & MVEBU_SETTING_GPI)) || | |
357 | (!input && (setting->flags & MVEBU_SETTING_GPO))) | |
358 | return 0; | |
359 | ||
360 | return -ENOTSUPP; | |
361 | } | |
362 | ||
022ab148 | 363 | static const struct pinmux_ops mvebu_pinmux_ops = { |
7e8d9415 SH |
364 | .get_functions_count = mvebu_pinmux_get_funcs_count, |
365 | .get_function_name = mvebu_pinmux_get_func_name, | |
366 | .get_function_groups = mvebu_pinmux_get_groups, | |
367 | .gpio_request_enable = mvebu_pinmux_gpio_request_enable, | |
368 | .gpio_set_direction = mvebu_pinmux_gpio_set_direction, | |
03e9f0ca | 369 | .set_mux = mvebu_pinmux_set, |
7e8d9415 SH |
370 | }; |
371 | ||
372 | static int mvebu_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) | |
373 | { | |
374 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
375 | return pctl->num_groups; | |
376 | } | |
377 | ||
378 | static const char *mvebu_pinctrl_get_group_name(struct pinctrl_dev *pctldev, | |
379 | unsigned gid) | |
380 | { | |
381 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
382 | return pctl->groups[gid].name; | |
383 | } | |
384 | ||
385 | static int mvebu_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, | |
386 | unsigned gid, const unsigned **pins, | |
387 | unsigned *num_pins) | |
388 | { | |
389 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
390 | *pins = pctl->groups[gid].pins; | |
391 | *num_pins = pctl->groups[gid].npins; | |
392 | return 0; | |
393 | } | |
394 | ||
395 | static int mvebu_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, | |
396 | struct device_node *np, | |
397 | struct pinctrl_map **map, | |
398 | unsigned *num_maps) | |
399 | { | |
400 | struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
401 | struct property *prop; | |
402 | const char *function; | |
403 | const char *group; | |
404 | int ret, nmaps, n; | |
405 | ||
406 | *map = NULL; | |
407 | *num_maps = 0; | |
408 | ||
409 | ret = of_property_read_string(np, "marvell,function", &function); | |
410 | if (ret) { | |
411 | dev_err(pctl->dev, | |
94f4e54c | 412 | "missing marvell,function in node %pOFn\n", np); |
7e8d9415 SH |
413 | return 0; |
414 | } | |
415 | ||
416 | nmaps = of_property_count_strings(np, "marvell,pins"); | |
417 | if (nmaps < 0) { | |
418 | dev_err(pctl->dev, | |
94f4e54c | 419 | "missing marvell,pins in node %pOFn\n", np); |
7e8d9415 SH |
420 | return 0; |
421 | } | |
422 | ||
e6e965ce | 423 | *map = kmalloc_array(nmaps, sizeof(**map), GFP_KERNEL); |
77d3d2e2 | 424 | if (!*map) |
7e8d9415 | 425 | return -ENOMEM; |
7e8d9415 SH |
426 | |
427 | n = 0; | |
428 | of_property_for_each_string(np, "marvell,pins", prop, group) { | |
429 | struct mvebu_pinctrl_group *grp = | |
430 | mvebu_pinctrl_find_group_by_name(pctl, group); | |
431 | ||
432 | if (!grp) { | |
433 | dev_err(pctl->dev, "unknown pin %s", group); | |
434 | continue; | |
435 | } | |
436 | ||
437 | if (!mvebu_pinctrl_find_setting_by_name(pctl, grp, function)) { | |
438 | dev_err(pctl->dev, "unsupported function %s on pin %s", | |
439 | function, group); | |
440 | continue; | |
441 | } | |
442 | ||
443 | (*map)[n].type = PIN_MAP_TYPE_MUX_GROUP; | |
444 | (*map)[n].data.mux.group = group; | |
445 | (*map)[n].data.mux.function = function; | |
446 | n++; | |
447 | } | |
448 | ||
449 | *num_maps = nmaps; | |
450 | ||
451 | return 0; | |
452 | } | |
453 | ||
454 | static void mvebu_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, | |
455 | struct pinctrl_map *map, unsigned num_maps) | |
456 | { | |
457 | kfree(map); | |
458 | } | |
459 | ||
022ab148 | 460 | static const struct pinctrl_ops mvebu_pinctrl_ops = { |
7e8d9415 SH |
461 | .get_groups_count = mvebu_pinctrl_get_groups_count, |
462 | .get_group_name = mvebu_pinctrl_get_group_name, | |
463 | .get_group_pins = mvebu_pinctrl_get_group_pins, | |
464 | .dt_node_to_map = mvebu_pinctrl_dt_node_to_map, | |
465 | .dt_free_map = mvebu_pinctrl_dt_free_map, | |
466 | }; | |
467 | ||
aaed651f DW |
468 | static int _add_function(struct mvebu_pinctrl_function *funcs, int *funcsize, |
469 | const char *name) | |
7e8d9415 | 470 | { |
aaed651f DW |
471 | if (*funcsize <= 0) |
472 | return -EOVERFLOW; | |
473 | ||
7e8d9415 SH |
474 | while (funcs->num_groups) { |
475 | /* function already there */ | |
476 | if (strcmp(funcs->name, name) == 0) { | |
477 | funcs->num_groups++; | |
478 | return -EEXIST; | |
479 | } | |
480 | funcs++; | |
481 | } | |
aaed651f DW |
482 | |
483 | /* append new unique function */ | |
7e8d9415 SH |
484 | funcs->name = name; |
485 | funcs->num_groups = 1; | |
aaed651f DW |
486 | (*funcsize)--; |
487 | ||
7e8d9415 SH |
488 | return 0; |
489 | } | |
490 | ||
150632b0 GKH |
491 | static int mvebu_pinctrl_build_functions(struct platform_device *pdev, |
492 | struct mvebu_pinctrl *pctl) | |
7e8d9415 SH |
493 | { |
494 | struct mvebu_pinctrl_function *funcs; | |
aaed651f | 495 | int num = 0, funcsize = pctl->desc.npins; |
7e8d9415 SH |
496 | int n, s; |
497 | ||
498 | /* we allocate functions for number of pins and hope | |
aaed651f | 499 | * there are fewer unique functions than pins available */ |
a86854d0 KC |
500 | funcs = devm_kcalloc(&pdev->dev, |
501 | funcsize, sizeof(struct mvebu_pinctrl_function), | |
502 | GFP_KERNEL); | |
7e8d9415 SH |
503 | if (!funcs) |
504 | return -ENOMEM; | |
505 | ||
506 | for (n = 0; n < pctl->num_groups; n++) { | |
507 | struct mvebu_pinctrl_group *grp = &pctl->groups[n]; | |
508 | for (s = 0; s < grp->num_settings; s++) { | |
aaed651f DW |
509 | int ret; |
510 | ||
7e8d9415 SH |
511 | /* skip unsupported settings on this variant */ |
512 | if (pctl->variant && | |
513 | !(pctl->variant & grp->settings[s].variant)) | |
514 | continue; | |
515 | ||
516 | /* check for unique functions and count groups */ | |
aaed651f DW |
517 | ret = _add_function(funcs, &funcsize, |
518 | grp->settings[s].name); | |
519 | if (ret == -EOVERFLOW) | |
520 | dev_err(&pdev->dev, | |
521 | "More functions than pins(%d)\n", | |
522 | pctl->desc.npins); | |
523 | if (ret < 0) | |
7e8d9415 SH |
524 | continue; |
525 | ||
526 | num++; | |
527 | } | |
528 | } | |
529 | ||
7e8d9415 SH |
530 | pctl->num_functions = num; |
531 | pctl->functions = funcs; | |
532 | ||
533 | for (n = 0; n < pctl->num_groups; n++) { | |
534 | struct mvebu_pinctrl_group *grp = &pctl->groups[n]; | |
535 | for (s = 0; s < grp->num_settings; s++) { | |
536 | struct mvebu_pinctrl_function *f; | |
537 | const char **groups; | |
538 | ||
539 | /* skip unsupported settings on this variant */ | |
540 | if (pctl->variant && | |
541 | !(pctl->variant & grp->settings[s].variant)) | |
542 | continue; | |
543 | ||
544 | f = mvebu_pinctrl_find_function_by_name(pctl, | |
545 | grp->settings[s].name); | |
546 | ||
547 | /* allocate group name array if not done already */ | |
548 | if (!f->groups) { | |
a86854d0 KC |
549 | f->groups = devm_kcalloc(&pdev->dev, |
550 | f->num_groups, | |
551 | sizeof(char *), | |
7e8d9415 SH |
552 | GFP_KERNEL); |
553 | if (!f->groups) | |
554 | return -ENOMEM; | |
555 | } | |
556 | ||
557 | /* find next free group name and assign current name */ | |
558 | groups = f->groups; | |
559 | while (*groups) | |
560 | groups++; | |
561 | *groups = grp->name; | |
562 | } | |
563 | } | |
564 | ||
565 | return 0; | |
566 | } | |
567 | ||
150632b0 | 568 | int mvebu_pinctrl_probe(struct platform_device *pdev) |
7e8d9415 SH |
569 | { |
570 | struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev); | |
7e8d9415 | 571 | struct mvebu_pinctrl *pctl; |
7e8d9415 SH |
572 | struct pinctrl_pin_desc *pdesc; |
573 | unsigned gid, n, k; | |
8d898fd5 SH |
574 | unsigned size, noname = 0; |
575 | char *noname_buf; | |
576 | void *p; | |
7e8d9415 SH |
577 | int ret; |
578 | ||
579 | if (!soc || !soc->controls || !soc->modes) { | |
580 | dev_err(&pdev->dev, "wrong pinctrl soc info\n"); | |
581 | return -EINVAL; | |
582 | } | |
583 | ||
7e8d9415 SH |
584 | pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl), |
585 | GFP_KERNEL); | |
77d3d2e2 | 586 | if (!pctl) |
7e8d9415 | 587 | return -ENOMEM; |
7e8d9415 SH |
588 | |
589 | pctl->desc.name = dev_name(&pdev->dev); | |
590 | pctl->desc.owner = THIS_MODULE; | |
591 | pctl->desc.pctlops = &mvebu_pinctrl_ops; | |
592 | pctl->desc.pmxops = &mvebu_pinmux_ops; | |
593 | pctl->desc.confops = &mvebu_pinconf_ops; | |
594 | pctl->variant = soc->variant; | |
7e8d9415 SH |
595 | pctl->dev = &pdev->dev; |
596 | platform_set_drvdata(pdev, pctl); | |
597 | ||
598 | /* count controls and create names for mvebu generic | |
599 | register controls; also does sanity checks */ | |
600 | pctl->num_groups = 0; | |
601 | pctl->desc.npins = 0; | |
602 | for (n = 0; n < soc->ncontrols; n++) { | |
30be3fb9 | 603 | const struct mvebu_mpp_ctrl *ctrl = &soc->controls[n]; |
7e8d9415 SH |
604 | |
605 | pctl->desc.npins += ctrl->npins; | |
e310b745 | 606 | /* initialize control's pins[] array */ |
7e8d9415 SH |
607 | for (k = 0; k < ctrl->npins; k++) |
608 | ctrl->pins[k] = ctrl->pid + k; | |
609 | ||
e310b745 SH |
610 | /* |
611 | * We allow to pass controls with NULL name that we treat | |
612 | * as a range of one-pin groups with generic mvebu register | |
613 | * controls. | |
614 | */ | |
615 | if (!ctrl->name) { | |
616 | pctl->num_groups += ctrl->npins; | |
617 | noname += ctrl->npins; | |
618 | } else { | |
7e8d9415 | 619 | pctl->num_groups += 1; |
7e8d9415 | 620 | } |
7e8d9415 SH |
621 | } |
622 | ||
a86854d0 KC |
623 | pdesc = devm_kcalloc(&pdev->dev, |
624 | pctl->desc.npins, | |
625 | sizeof(struct pinctrl_pin_desc), | |
626 | GFP_KERNEL); | |
77d3d2e2 | 627 | if (!pdesc) |
7e8d9415 | 628 | return -ENOMEM; |
7e8d9415 SH |
629 | |
630 | for (n = 0; n < pctl->desc.npins; n++) | |
631 | pdesc[n].number = n; | |
632 | pctl->desc.pins = pdesc; | |
633 | ||
8d898fd5 SH |
634 | /* |
635 | * allocate groups and name buffers for unnamed groups. | |
636 | */ | |
637 | size = pctl->num_groups * sizeof(*pctl->groups) + noname * 8; | |
638 | p = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); | |
bca50ce0 | 639 | if (!p) |
7e8d9415 | 640 | return -ENOMEM; |
bca50ce0 | 641 | |
8d898fd5 SH |
642 | pctl->groups = p; |
643 | noname_buf = p + pctl->num_groups * sizeof(*pctl->groups); | |
7e8d9415 SH |
644 | |
645 | /* assign mpp controls to groups */ | |
646 | gid = 0; | |
647 | for (n = 0; n < soc->ncontrols; n++) { | |
30be3fb9 | 648 | const struct mvebu_mpp_ctrl *ctrl = &soc->controls[n]; |
20955c5f RK |
649 | struct mvebu_mpp_ctrl_data *data = soc->control_data ? |
650 | &soc->control_data[n] : NULL; | |
651 | ||
7e8d9415 SH |
652 | pctl->groups[gid].gid = gid; |
653 | pctl->groups[gid].ctrl = ctrl; | |
20955c5f | 654 | pctl->groups[gid].data = data; |
7e8d9415 SH |
655 | pctl->groups[gid].name = ctrl->name; |
656 | pctl->groups[gid].pins = ctrl->pins; | |
657 | pctl->groups[gid].npins = ctrl->npins; | |
658 | ||
e310b745 SH |
659 | /* |
660 | * We treat unnamed controls as a range of one-pin groups | |
661 | * with generic mvebu register controls. Use one group for | |
662 | * each in this range and assign a default group name. | |
663 | */ | |
664 | if (!ctrl->name) { | |
8d898fd5 | 665 | pctl->groups[gid].name = noname_buf; |
7e8d9415 | 666 | pctl->groups[gid].npins = 1; |
8d898fd5 SH |
667 | sprintf(noname_buf, "mpp%d", ctrl->pid+0); |
668 | noname_buf += 8; | |
7e8d9415 SH |
669 | |
670 | for (k = 1; k < ctrl->npins; k++) { | |
671 | gid++; | |
672 | pctl->groups[gid].gid = gid; | |
673 | pctl->groups[gid].ctrl = ctrl; | |
20955c5f | 674 | pctl->groups[gid].data = data; |
8d898fd5 | 675 | pctl->groups[gid].name = noname_buf; |
7e8d9415 SH |
676 | pctl->groups[gid].pins = &ctrl->pins[k]; |
677 | pctl->groups[gid].npins = 1; | |
8d898fd5 SH |
678 | sprintf(noname_buf, "mpp%d", ctrl->pid+k); |
679 | noname_buf += 8; | |
7e8d9415 SH |
680 | } |
681 | } | |
682 | gid++; | |
683 | } | |
684 | ||
685 | /* assign mpp modes to groups */ | |
686 | for (n = 0; n < soc->nmodes; n++) { | |
687 | struct mvebu_mpp_mode *mode = &soc->modes[n]; | |
0581b16b SH |
688 | struct mvebu_mpp_ctrl_setting *set = &mode->settings[0]; |
689 | struct mvebu_pinctrl_group *grp; | |
7e8d9415 | 690 | unsigned num_settings; |
7864d926 | 691 | unsigned supp_settings; |
7e8d9415 | 692 | |
7864d926 | 693 | for (num_settings = 0, supp_settings = 0; ; set++) { |
7e8d9415 SH |
694 | if (!set->name) |
695 | break; | |
7e8d9415 | 696 | |
7864d926 SH |
697 | num_settings++; |
698 | ||
7e8d9415 SH |
699 | /* skip unsupported settings for this variant */ |
700 | if (pctl->variant && !(pctl->variant & set->variant)) | |
701 | continue; | |
702 | ||
7864d926 | 703 | supp_settings++; |
0581b16b | 704 | |
7e8d9415 SH |
705 | /* find gpio/gpo/gpi settings */ |
706 | if (strcmp(set->name, "gpio") == 0) | |
707 | set->flags = MVEBU_SETTING_GPI | | |
708 | MVEBU_SETTING_GPO; | |
709 | else if (strcmp(set->name, "gpo") == 0) | |
710 | set->flags = MVEBU_SETTING_GPO; | |
711 | else if (strcmp(set->name, "gpi") == 0) | |
712 | set->flags = MVEBU_SETTING_GPI; | |
713 | } | |
714 | ||
0581b16b | 715 | /* skip modes with no settings for this variant */ |
7864d926 | 716 | if (!supp_settings) |
0581b16b SH |
717 | continue; |
718 | ||
719 | grp = mvebu_pinctrl_find_group_by_pid(pctl, mode->pid); | |
720 | if (!grp) { | |
721 | dev_warn(&pdev->dev, "unknown pinctrl group %d\n", | |
722 | mode->pid); | |
723 | continue; | |
724 | } | |
725 | ||
7e8d9415 SH |
726 | grp->settings = mode->settings; |
727 | grp->num_settings = num_settings; | |
728 | } | |
729 | ||
730 | ret = mvebu_pinctrl_build_functions(pdev, pctl); | |
731 | if (ret) { | |
732 | dev_err(&pdev->dev, "unable to build functions\n"); | |
733 | return ret; | |
734 | } | |
735 | ||
699097a9 | 736 | pctl->pctldev = devm_pinctrl_register(&pdev->dev, &pctl->desc, pctl); |
323de9ef | 737 | if (IS_ERR(pctl->pctldev)) { |
7e8d9415 | 738 | dev_err(&pdev->dev, "unable to register pinctrl driver\n"); |
323de9ef | 739 | return PTR_ERR(pctl->pctldev); |
7e8d9415 SH |
740 | } |
741 | ||
742 | dev_info(&pdev->dev, "registered pinctrl driver\n"); | |
743 | ||
744 | /* register gpio ranges */ | |
745 | for (n = 0; n < soc->ngpioranges; n++) | |
746 | pinctrl_add_gpio_range(pctl->pctldev, &soc->gpioranges[n]); | |
747 | ||
748 | return 0; | |
749 | } | |
44aa9d06 RK |
750 | |
751 | /* | |
752 | * mvebu_pinctrl_simple_mmio_probe - probe a simple mmio pinctrl | |
753 | * @pdev: platform device (with platform data already attached) | |
754 | * | |
755 | * Initialise a simple (single base address) mmio pinctrl driver, | |
756 | * assigning the MMIO base address to all mvebu mpp ctrl instances. | |
757 | */ | |
758 | int mvebu_pinctrl_simple_mmio_probe(struct platform_device *pdev) | |
759 | { | |
760 | struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev); | |
761 | struct mvebu_mpp_ctrl_data *mpp_data; | |
762 | struct resource *res; | |
763 | void __iomem *base; | |
764 | int i; | |
765 | ||
766 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
767 | base = devm_ioremap_resource(&pdev->dev, res); | |
768 | if (IS_ERR(base)) | |
769 | return PTR_ERR(base); | |
770 | ||
771 | mpp_data = devm_kcalloc(&pdev->dev, soc->ncontrols, sizeof(*mpp_data), | |
772 | GFP_KERNEL); | |
773 | if (!mpp_data) | |
774 | return -ENOMEM; | |
775 | ||
776 | for (i = 0; i < soc->ncontrols; i++) | |
777 | mpp_data[i].base = base; | |
778 | ||
779 | soc->control_data = mpp_data; | |
780 | ||
781 | return mvebu_pinctrl_probe(pdev); | |
782 | } | |
d068b098 RK |
783 | |
784 | int mvebu_regmap_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, | |
785 | unsigned int pid, unsigned long *config) | |
786 | { | |
787 | unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; | |
788 | unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; | |
789 | unsigned int val; | |
790 | int err; | |
791 | ||
792 | err = regmap_read(data->regmap.map, data->regmap.offset + off, &val); | |
793 | if (err) | |
794 | return err; | |
795 | ||
796 | *config = (val >> shift) & MVEBU_MPP_MASK; | |
797 | ||
798 | return 0; | |
799 | } | |
800 | ||
801 | int mvebu_regmap_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, | |
802 | unsigned int pid, unsigned long config) | |
803 | { | |
804 | unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; | |
805 | unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; | |
806 | ||
807 | return regmap_update_bits(data->regmap.map, data->regmap.offset + off, | |
808 | MVEBU_MPP_MASK << shift, config << shift); | |
809 | } | |
810 | ||
811 | int mvebu_pinctrl_simple_regmap_probe(struct platform_device *pdev, | |
ef088187 | 812 | struct device *syscon_dev, u32 offset) |
d068b098 RK |
813 | { |
814 | struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev); | |
815 | struct mvebu_mpp_ctrl_data *mpp_data; | |
816 | struct regmap *regmap; | |
d068b098 RK |
817 | int i; |
818 | ||
819 | regmap = syscon_node_to_regmap(syscon_dev->of_node); | |
820 | if (IS_ERR(regmap)) | |
821 | return PTR_ERR(regmap); | |
822 | ||
d068b098 RK |
823 | mpp_data = devm_kcalloc(&pdev->dev, soc->ncontrols, sizeof(*mpp_data), |
824 | GFP_KERNEL); | |
825 | if (!mpp_data) | |
826 | return -ENOMEM; | |
827 | ||
828 | for (i = 0; i < soc->ncontrols; i++) { | |
829 | mpp_data[i].regmap.map = regmap; | |
830 | mpp_data[i].regmap.offset = offset; | |
831 | } | |
832 | ||
833 | soc->control_data = mpp_data; | |
834 | ||
835 | return mvebu_pinctrl_probe(pdev); | |
836 | } |