]>
Commit | Line | Data |
---|---|---|
0e37f88d MR |
1 | /* |
2 | * Allwinner A1X SoCs pinctrl driver. | |
3 | * | |
4 | * Copyright (C) 2012 Maxime Ripard | |
5 | * | |
6 | * Maxime Ripard <maxime.ripard@free-electrons.com> | |
7 | * | |
8 | * This file is licensed under the terms of the GNU General Public | |
9 | * License version 2. This program is licensed "as is" without any | |
10 | * warranty of any kind, whether express or implied. | |
11 | */ | |
12 | ||
13 | #include <linux/io.h> | |
950707c0 | 14 | #include <linux/clk.h> |
88057d6e | 15 | #include <linux/gpio/driver.h> |
60242db1 | 16 | #include <linux/irqdomain.h> |
905a5117 | 17 | #include <linux/irqchip/chained_irq.h> |
bcc76199 | 18 | #include <linux/export.h> |
0e37f88d | 19 | #include <linux/of.h> |
10e3a88b | 20 | #include <linux/of_clk.h> |
0e37f88d MR |
21 | #include <linux/of_address.h> |
22 | #include <linux/of_device.h> | |
60242db1 | 23 | #include <linux/of_irq.h> |
0e37f88d MR |
24 | #include <linux/pinctrl/consumer.h> |
25 | #include <linux/pinctrl/machine.h> | |
26 | #include <linux/pinctrl/pinctrl.h> | |
27 | #include <linux/pinctrl/pinconf-generic.h> | |
28 | #include <linux/pinctrl/pinmux.h> | |
9a2a566a | 29 | #include <linux/regulator/consumer.h> |
0e37f88d MR |
30 | #include <linux/platform_device.h> |
31 | #include <linux/slab.h> | |
32 | ||
42676fa4 MR |
33 | #include <dt-bindings/pinctrl/sun4i-a10.h> |
34 | ||
5f910777 | 35 | #include "../core.h" |
0e37f88d | 36 | #include "pinctrl-sunxi.h" |
eaa3d848 | 37 | |
f4c51c10 HG |
38 | static struct irq_chip sunxi_pinctrl_edge_irq_chip; |
39 | static struct irq_chip sunxi_pinctrl_level_irq_chip; | |
40 | ||
0e37f88d MR |
41 | static struct sunxi_pinctrl_group * |
42 | sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group) | |
43 | { | |
44 | int i; | |
45 | ||
46 | for (i = 0; i < pctl->ngroups; i++) { | |
47 | struct sunxi_pinctrl_group *grp = pctl->groups + i; | |
48 | ||
49 | if (!strcmp(grp->name, group)) | |
50 | return grp; | |
51 | } | |
52 | ||
53 | return NULL; | |
54 | } | |
55 | ||
56 | static struct sunxi_pinctrl_function * | |
57 | sunxi_pinctrl_find_function_by_name(struct sunxi_pinctrl *pctl, | |
58 | const char *name) | |
59 | { | |
60 | struct sunxi_pinctrl_function *func = pctl->functions; | |
61 | int i; | |
62 | ||
63 | for (i = 0; i < pctl->nfunctions; i++) { | |
64 | if (!func[i].name) | |
65 | break; | |
66 | ||
67 | if (!strcmp(func[i].name, name)) | |
68 | return func + i; | |
69 | } | |
70 | ||
71 | return NULL; | |
72 | } | |
73 | ||
74 | static struct sunxi_desc_function * | |
75 | sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl, | |
76 | const char *pin_name, | |
77 | const char *func_name) | |
78 | { | |
79 | int i; | |
80 | ||
81 | for (i = 0; i < pctl->desc->npins; i++) { | |
82 | const struct sunxi_desc_pin *pin = pctl->desc->pins + i; | |
83 | ||
84 | if (!strcmp(pin->pin.name, pin_name)) { | |
85 | struct sunxi_desc_function *func = pin->functions; | |
86 | ||
87 | while (func->name) { | |
32e21f08 | 88 | if (!strcmp(func->name, func_name) && |
89 | (!func->variant || | |
90 | func->variant & pctl->variant)) | |
0e37f88d MR |
91 | return func; |
92 | ||
93 | func++; | |
94 | } | |
95 | } | |
96 | } | |
97 | ||
98 | return NULL; | |
99 | } | |
100 | ||
814d4f2e MR |
101 | static struct sunxi_desc_function * |
102 | sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl, | |
103 | const u16 pin_num, | |
104 | const char *func_name) | |
105 | { | |
106 | int i; | |
107 | ||
108 | for (i = 0; i < pctl->desc->npins; i++) { | |
109 | const struct sunxi_desc_pin *pin = pctl->desc->pins + i; | |
110 | ||
111 | if (pin->pin.number == pin_num) { | |
112 | struct sunxi_desc_function *func = pin->functions; | |
113 | ||
114 | while (func->name) { | |
115 | if (!strcmp(func->name, func_name)) | |
116 | return func; | |
117 | ||
118 | func++; | |
119 | } | |
120 | } | |
121 | } | |
122 | ||
123 | return NULL; | |
124 | } | |
125 | ||
0e37f88d MR |
126 | static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev) |
127 | { | |
128 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
129 | ||
130 | return pctl->ngroups; | |
131 | } | |
132 | ||
133 | static const char *sunxi_pctrl_get_group_name(struct pinctrl_dev *pctldev, | |
134 | unsigned group) | |
135 | { | |
136 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
137 | ||
138 | return pctl->groups[group].name; | |
139 | } | |
140 | ||
141 | static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev, | |
142 | unsigned group, | |
143 | const unsigned **pins, | |
144 | unsigned *num_pins) | |
145 | { | |
146 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
147 | ||
148 | *pins = (unsigned *)&pctl->groups[group].pin; | |
149 | *num_pins = 1; | |
150 | ||
151 | return 0; | |
152 | } | |
153 | ||
f233dbca MR |
154 | static bool sunxi_pctrl_has_bias_prop(struct device_node *node) |
155 | { | |
cefbf1a1 MR |
156 | return of_find_property(node, "bias-pull-up", NULL) || |
157 | of_find_property(node, "bias-pull-down", NULL) || | |
158 | of_find_property(node, "bias-disable", NULL) || | |
159 | of_find_property(node, "allwinner,pull", NULL); | |
f233dbca MR |
160 | } |
161 | ||
162 | static bool sunxi_pctrl_has_drive_prop(struct device_node *node) | |
163 | { | |
cefbf1a1 MR |
164 | return of_find_property(node, "drive-strength", NULL) || |
165 | of_find_property(node, "allwinner,drive", NULL); | |
f233dbca MR |
166 | } |
167 | ||
168 | static int sunxi_pctrl_parse_bias_prop(struct device_node *node) | |
169 | { | |
170 | u32 val; | |
171 | ||
cefbf1a1 MR |
172 | /* Try the new style binding */ |
173 | if (of_find_property(node, "bias-pull-up", NULL)) | |
174 | return PIN_CONFIG_BIAS_PULL_UP; | |
175 | ||
176 | if (of_find_property(node, "bias-pull-down", NULL)) | |
177 | return PIN_CONFIG_BIAS_PULL_DOWN; | |
178 | ||
179 | if (of_find_property(node, "bias-disable", NULL)) | |
180 | return PIN_CONFIG_BIAS_DISABLE; | |
181 | ||
182 | /* And fall back to the old binding */ | |
f233dbca MR |
183 | if (of_property_read_u32(node, "allwinner,pull", &val)) |
184 | return -EINVAL; | |
185 | ||
186 | switch (val) { | |
07fe64ba MR |
187 | case SUN4I_PINCTRL_NO_PULL: |
188 | return PIN_CONFIG_BIAS_DISABLE; | |
42676fa4 | 189 | case SUN4I_PINCTRL_PULL_UP: |
f233dbca | 190 | return PIN_CONFIG_BIAS_PULL_UP; |
42676fa4 | 191 | case SUN4I_PINCTRL_PULL_DOWN: |
f233dbca MR |
192 | return PIN_CONFIG_BIAS_PULL_DOWN; |
193 | } | |
194 | ||
195 | return -EINVAL; | |
196 | } | |
197 | ||
198 | static int sunxi_pctrl_parse_drive_prop(struct device_node *node) | |
199 | { | |
200 | u32 val; | |
201 | ||
cefbf1a1 MR |
202 | /* Try the new style binding */ |
203 | if (!of_property_read_u32(node, "drive-strength", &val)) { | |
204 | /* We can't go below 10mA ... */ | |
205 | if (val < 10) | |
206 | return -EINVAL; | |
207 | ||
208 | /* ... and only up to 40 mA ... */ | |
209 | if (val > 40) | |
210 | val = 40; | |
211 | ||
212 | /* by steps of 10 mA */ | |
213 | return rounddown(val, 10); | |
214 | } | |
215 | ||
216 | /* And then fall back to the old binding */ | |
f233dbca MR |
217 | if (of_property_read_u32(node, "allwinner,drive", &val)) |
218 | return -EINVAL; | |
219 | ||
220 | return (val + 1) * 10; | |
221 | } | |
222 | ||
223 | static const char *sunxi_pctrl_parse_function_prop(struct device_node *node) | |
224 | { | |
225 | const char *function; | |
226 | int ret; | |
227 | ||
cefbf1a1 MR |
228 | /* Try the generic binding */ |
229 | ret = of_property_read_string(node, "function", &function); | |
230 | if (!ret) | |
231 | return function; | |
232 | ||
233 | /* And fall back to our legacy one */ | |
f233dbca MR |
234 | ret = of_property_read_string(node, "allwinner,function", &function); |
235 | if (!ret) | |
236 | return function; | |
237 | ||
238 | return NULL; | |
239 | } | |
240 | ||
241 | static const char *sunxi_pctrl_find_pins_prop(struct device_node *node, | |
242 | int *npins) | |
243 | { | |
244 | int count; | |
245 | ||
cefbf1a1 MR |
246 | /* Try the generic binding */ |
247 | count = of_property_count_strings(node, "pins"); | |
248 | if (count > 0) { | |
249 | *npins = count; | |
250 | return "pins"; | |
251 | } | |
252 | ||
253 | /* And fall back to our legacy one */ | |
f233dbca MR |
254 | count = of_property_count_strings(node, "allwinner,pins"); |
255 | if (count > 0) { | |
256 | *npins = count; | |
257 | return "allwinner,pins"; | |
258 | } | |
259 | ||
260 | return NULL; | |
261 | } | |
262 | ||
263 | static unsigned long *sunxi_pctrl_build_pin_config(struct device_node *node, | |
264 | unsigned int *len) | |
265 | { | |
266 | unsigned long *pinconfig; | |
267 | unsigned int configlen = 0, idx = 0; | |
e11dee2e | 268 | int ret; |
f233dbca MR |
269 | |
270 | if (sunxi_pctrl_has_drive_prop(node)) | |
271 | configlen++; | |
272 | if (sunxi_pctrl_has_bias_prop(node)) | |
273 | configlen++; | |
274 | ||
e11dee2e MR |
275 | /* |
276 | * If we don't have any configuration, bail out | |
277 | */ | |
278 | if (!configlen) | |
279 | return NULL; | |
280 | ||
6396bb22 | 281 | pinconfig = kcalloc(configlen, sizeof(*pinconfig), GFP_KERNEL); |
f233dbca | 282 | if (!pinconfig) |
e11dee2e | 283 | return ERR_PTR(-ENOMEM); |
f233dbca MR |
284 | |
285 | if (sunxi_pctrl_has_drive_prop(node)) { | |
286 | int drive = sunxi_pctrl_parse_drive_prop(node); | |
e11dee2e MR |
287 | if (drive < 0) { |
288 | ret = drive; | |
f233dbca | 289 | goto err_free; |
e11dee2e | 290 | } |
f233dbca MR |
291 | |
292 | pinconfig[idx++] = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH, | |
293 | drive); | |
294 | } | |
295 | ||
296 | if (sunxi_pctrl_has_bias_prop(node)) { | |
297 | int pull = sunxi_pctrl_parse_bias_prop(node); | |
223dba00 | 298 | int arg = 0; |
e11dee2e MR |
299 | if (pull < 0) { |
300 | ret = pull; | |
f233dbca | 301 | goto err_free; |
e11dee2e | 302 | } |
f233dbca | 303 | |
223dba00 CYT |
304 | if (pull != PIN_CONFIG_BIAS_DISABLE) |
305 | arg = 1; /* hardware uses weak pull resistors */ | |
306 | ||
307 | pinconfig[idx++] = pinconf_to_config_packed(pull, arg); | |
f233dbca MR |
308 | } |
309 | ||
310 | ||
311 | *len = configlen; | |
312 | return pinconfig; | |
313 | ||
314 | err_free: | |
315 | kfree(pinconfig); | |
e11dee2e | 316 | return ERR_PTR(ret); |
f233dbca MR |
317 | } |
318 | ||
0e37f88d MR |
319 | static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, |
320 | struct device_node *node, | |
321 | struct pinctrl_map **map, | |
322 | unsigned *num_maps) | |
323 | { | |
324 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
325 | unsigned long *pinconfig; | |
326 | struct property *prop; | |
f233dbca | 327 | const char *function, *pin_prop; |
0e37f88d | 328 | const char *group; |
f233dbca | 329 | int ret, npins, nmaps, configlen = 0, i = 0; |
0e37f88d MR |
330 | |
331 | *map = NULL; | |
332 | *num_maps = 0; | |
333 | ||
f233dbca MR |
334 | function = sunxi_pctrl_parse_function_prop(node); |
335 | if (!function) { | |
94f4e54c RH |
336 | dev_err(pctl->dev, "missing function property in node %pOFn\n", |
337 | node); | |
0e37f88d MR |
338 | return -EINVAL; |
339 | } | |
340 | ||
f233dbca MR |
341 | pin_prop = sunxi_pctrl_find_pins_prop(node, &npins); |
342 | if (!pin_prop) { | |
94f4e54c RH |
343 | dev_err(pctl->dev, "missing pins property in node %pOFn\n", |
344 | node); | |
0e37f88d MR |
345 | return -EINVAL; |
346 | } | |
347 | ||
f233dbca MR |
348 | /* |
349 | * We have two maps for each pin: one for the function, one | |
e11dee2e MR |
350 | * for the configuration (bias, strength, etc). |
351 | * | |
352 | * We might be slightly overshooting, since we might not have | |
353 | * any configuration. | |
f233dbca MR |
354 | */ |
355 | nmaps = npins * 2; | |
6da2ec56 | 356 | *map = kmalloc_array(nmaps, sizeof(struct pinctrl_map), GFP_KERNEL); |
3efa921d | 357 | if (!*map) |
0e37f88d MR |
358 | return -ENOMEM; |
359 | ||
f233dbca | 360 | pinconfig = sunxi_pctrl_build_pin_config(node, &configlen); |
e11dee2e MR |
361 | if (IS_ERR(pinconfig)) { |
362 | ret = PTR_ERR(pinconfig); | |
f233dbca MR |
363 | goto err_free_map; |
364 | } | |
365 | ||
366 | of_property_for_each_string(node, pin_prop, prop, group) { | |
0e37f88d MR |
367 | struct sunxi_pinctrl_group *grp = |
368 | sunxi_pinctrl_find_group_by_name(pctl, group); | |
0e37f88d MR |
369 | |
370 | if (!grp) { | |
371 | dev_err(pctl->dev, "unknown pin %s", group); | |
372 | continue; | |
373 | } | |
374 | ||
375 | if (!sunxi_pinctrl_desc_find_function_by_name(pctl, | |
376 | grp->name, | |
377 | function)) { | |
378 | dev_err(pctl->dev, "unsupported function %s on pin %s", | |
379 | function, group); | |
380 | continue; | |
381 | } | |
382 | ||
383 | (*map)[i].type = PIN_MAP_TYPE_MUX_GROUP; | |
384 | (*map)[i].data.mux.group = group; | |
385 | (*map)[i].data.mux.function = function; | |
386 | ||
387 | i++; | |
388 | ||
e11dee2e MR |
389 | if (pinconfig) { |
390 | (*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP; | |
391 | (*map)[i].data.configs.group_or_pin = group; | |
392 | (*map)[i].data.configs.configs = pinconfig; | |
393 | (*map)[i].data.configs.num_configs = configlen; | |
394 | i++; | |
395 | } | |
0e37f88d MR |
396 | } |
397 | ||
e11dee2e MR |
398 | *num_maps = i; |
399 | ||
400 | /* | |
401 | * We know have the number of maps we need, we can resize our | |
402 | * map array | |
403 | */ | |
404 | *map = krealloc(*map, i * sizeof(struct pinctrl_map), GFP_KERNEL); | |
b3cde198 | 405 | if (!*map) |
e11dee2e | 406 | return -ENOMEM; |
0e37f88d MR |
407 | |
408 | return 0; | |
f233dbca MR |
409 | |
410 | err_free_map: | |
b3cde198 DC |
411 | kfree(*map); |
412 | *map = NULL; | |
f233dbca | 413 | return ret; |
0e37f88d MR |
414 | } |
415 | ||
416 | static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev, | |
417 | struct pinctrl_map *map, | |
418 | unsigned num_maps) | |
419 | { | |
88f01a1b CYT |
420 | int i; |
421 | ||
422 | /* pin config is never in the first map */ | |
423 | for (i = 1; i < num_maps; i++) { | |
424 | if (map[i].type != PIN_MAP_TYPE_CONFIGS_GROUP) | |
425 | continue; | |
426 | ||
427 | /* | |
428 | * All the maps share the same pin config, | |
429 | * free only the first one we find. | |
430 | */ | |
431 | kfree(map[i].data.configs.configs); | |
432 | break; | |
433 | } | |
434 | ||
0e37f88d MR |
435 | kfree(map); |
436 | } | |
437 | ||
022ab148 | 438 | static const struct pinctrl_ops sunxi_pctrl_ops = { |
0e37f88d MR |
439 | .dt_node_to_map = sunxi_pctrl_dt_node_to_map, |
440 | .dt_free_map = sunxi_pctrl_dt_free_map, | |
441 | .get_groups_count = sunxi_pctrl_get_groups_count, | |
442 | .get_group_name = sunxi_pctrl_get_group_name, | |
443 | .get_group_pins = sunxi_pctrl_get_group_pins, | |
444 | }; | |
445 | ||
c5fda170 CYT |
446 | static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param, |
447 | u32 *offset, u32 *shift, u32 *mask) | |
448 | { | |
449 | switch (param) { | |
450 | case PIN_CONFIG_DRIVE_STRENGTH: | |
451 | *offset = sunxi_dlevel_reg(pin); | |
452 | *shift = sunxi_dlevel_offset(pin); | |
453 | *mask = DLEVEL_PINS_MASK; | |
454 | break; | |
455 | ||
456 | case PIN_CONFIG_BIAS_PULL_UP: | |
457 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
458 | case PIN_CONFIG_BIAS_DISABLE: | |
459 | *offset = sunxi_pull_reg(pin); | |
460 | *shift = sunxi_pull_offset(pin); | |
461 | *mask = PULL_PINS_MASK; | |
462 | break; | |
463 | ||
464 | default: | |
465 | return -ENOTSUPP; | |
466 | } | |
467 | ||
468 | return 0; | |
469 | } | |
470 | ||
471 | static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin, | |
472 | unsigned long *config) | |
473 | { | |
474 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
475 | enum pin_config_param param = pinconf_to_config_param(*config); | |
476 | u32 offset, shift, mask, val; | |
477 | u16 arg; | |
478 | int ret; | |
479 | ||
480 | pin -= pctl->desc->pin_base; | |
481 | ||
482 | ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask); | |
483 | if (ret < 0) | |
484 | return ret; | |
485 | ||
486 | val = (readl(pctl->membase + offset) >> shift) & mask; | |
487 | ||
488 | switch (pinconf_to_config_param(*config)) { | |
489 | case PIN_CONFIG_DRIVE_STRENGTH: | |
490 | arg = (val + 1) * 10; | |
491 | break; | |
492 | ||
493 | case PIN_CONFIG_BIAS_PULL_UP: | |
494 | if (val != SUN4I_PINCTRL_PULL_UP) | |
495 | return -EINVAL; | |
496 | arg = 1; /* hardware is weak pull-up */ | |
497 | break; | |
498 | ||
499 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
500 | if (val != SUN4I_PINCTRL_PULL_DOWN) | |
501 | return -EINVAL; | |
502 | arg = 1; /* hardware is weak pull-down */ | |
503 | break; | |
504 | ||
505 | case PIN_CONFIG_BIAS_DISABLE: | |
506 | if (val != SUN4I_PINCTRL_NO_PULL) | |
507 | return -EINVAL; | |
508 | arg = 0; | |
509 | break; | |
510 | ||
511 | default: | |
512 | /* sunxi_pconf_reg should catch anything unsupported */ | |
513 | WARN_ON(1); | |
514 | return -ENOTSUPP; | |
515 | } | |
516 | ||
517 | *config = pinconf_to_config_packed(param, arg); | |
518 | ||
519 | return 0; | |
520 | } | |
521 | ||
0e37f88d MR |
522 | static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev, |
523 | unsigned group, | |
524 | unsigned long *config) | |
525 | { | |
526 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
c5fda170 | 527 | struct sunxi_pinctrl_group *g = &pctl->groups[group]; |
0e37f88d | 528 | |
c5fda170 CYT |
529 | /* We only support 1 pin per group. Chain it to the pin callback */ |
530 | return sunxi_pconf_get(pctldev, g->pin, config); | |
0e37f88d MR |
531 | } |
532 | ||
533 | static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, | |
534 | unsigned group, | |
03b054e9 SY |
535 | unsigned long *configs, |
536 | unsigned num_configs) | |
0e37f88d MR |
537 | { |
538 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
539 | struct sunxi_pinctrl_group *g = &pctl->groups[group]; | |
b4575c69 | 540 | unsigned pin = g->pin - pctl->desc->pin_base; |
03b054e9 | 541 | int i; |
0e37f88d | 542 | |
03b054e9 | 543 | for (i = 0; i < num_configs; i++) { |
51814827 CYT |
544 | enum pin_config_param param; |
545 | unsigned long flags; | |
546 | u32 offset, shift, mask, reg; | |
58957d2e | 547 | u32 arg, val; |
51814827 CYT |
548 | int ret; |
549 | ||
550 | param = pinconf_to_config_param(configs[i]); | |
551 | arg = pinconf_to_config_argument(configs[i]); | |
552 | ||
553 | ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask); | |
554 | if (ret < 0) | |
555 | return ret; | |
556 | ||
557 | switch (param) { | |
03b054e9 | 558 | case PIN_CONFIG_DRIVE_STRENGTH: |
51814827 | 559 | if (arg < 10 || arg > 40) |
03b054e9 SY |
560 | return -EINVAL; |
561 | /* | |
562 | * We convert from mA to what the register expects: | |
563 | * 0: 10mA | |
564 | * 1: 20mA | |
565 | * 2: 30mA | |
566 | * 3: 40mA | |
567 | */ | |
51814827 | 568 | val = arg / 10 - 1; |
03b054e9 | 569 | break; |
07fe64ba | 570 | case PIN_CONFIG_BIAS_DISABLE: |
ac059e2a PL |
571 | val = 0; |
572 | break; | |
03b054e9 | 573 | case PIN_CONFIG_BIAS_PULL_UP: |
51814827 CYT |
574 | if (arg == 0) |
575 | return -EINVAL; | |
576 | val = 1; | |
03b054e9 SY |
577 | break; |
578 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
51814827 CYT |
579 | if (arg == 0) |
580 | return -EINVAL; | |
581 | val = 2; | |
03b054e9 SY |
582 | break; |
583 | default: | |
51814827 CYT |
584 | /* sunxi_pconf_reg should catch anything unsupported */ |
585 | WARN_ON(1); | |
586 | return -ENOTSUPP; | |
03b054e9 | 587 | } |
0e37f88d | 588 | |
f658ed36 | 589 | raw_spin_lock_irqsave(&pctl->lock, flags); |
51814827 CYT |
590 | reg = readl(pctl->membase + offset); |
591 | reg &= ~(mask << shift); | |
592 | writel(reg | val << shift, pctl->membase + offset); | |
f658ed36 | 593 | raw_spin_unlock_irqrestore(&pctl->lock, flags); |
51814827 | 594 | } /* for each config */ |
0e37f88d MR |
595 | |
596 | return 0; | |
597 | } | |
598 | ||
022ab148 | 599 | static const struct pinconf_ops sunxi_pconf_ops = { |
c5fda170 CYT |
600 | .is_generic = true, |
601 | .pin_config_get = sunxi_pconf_get, | |
0e37f88d MR |
602 | .pin_config_group_get = sunxi_pconf_group_get, |
603 | .pin_config_group_set = sunxi_pconf_group_set, | |
604 | }; | |
605 | ||
606 | static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) | |
607 | { | |
608 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
609 | ||
610 | return pctl->nfunctions; | |
611 | } | |
612 | ||
613 | static const char *sunxi_pmx_get_func_name(struct pinctrl_dev *pctldev, | |
614 | unsigned function) | |
615 | { | |
616 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
617 | ||
618 | return pctl->functions[function].name; | |
619 | } | |
620 | ||
621 | static int sunxi_pmx_get_func_groups(struct pinctrl_dev *pctldev, | |
622 | unsigned function, | |
623 | const char * const **groups, | |
624 | unsigned * const num_groups) | |
625 | { | |
626 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
627 | ||
628 | *groups = pctl->functions[function].groups; | |
629 | *num_groups = pctl->functions[function].ngroups; | |
630 | ||
631 | return 0; | |
632 | } | |
633 | ||
634 | static void sunxi_pmx_set(struct pinctrl_dev *pctldev, | |
635 | unsigned pin, | |
636 | u8 config) | |
637 | { | |
638 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
1bee963d MR |
639 | unsigned long flags; |
640 | u32 val, mask; | |
641 | ||
f658ed36 | 642 | raw_spin_lock_irqsave(&pctl->lock, flags); |
0e37f88d | 643 | |
b4575c69 | 644 | pin -= pctl->desc->pin_base; |
1bee963d MR |
645 | val = readl(pctl->membase + sunxi_mux_reg(pin)); |
646 | mask = MUX_PINS_MASK << sunxi_mux_offset(pin); | |
0e37f88d MR |
647 | writel((val & ~mask) | config << sunxi_mux_offset(pin), |
648 | pctl->membase + sunxi_mux_reg(pin)); | |
1bee963d | 649 | |
f658ed36 | 650 | raw_spin_unlock_irqrestore(&pctl->lock, flags); |
0e37f88d MR |
651 | } |
652 | ||
03e9f0ca LW |
653 | static int sunxi_pmx_set_mux(struct pinctrl_dev *pctldev, |
654 | unsigned function, | |
655 | unsigned group) | |
0e37f88d MR |
656 | { |
657 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
658 | struct sunxi_pinctrl_group *g = pctl->groups + group; | |
659 | struct sunxi_pinctrl_function *func = pctl->functions + function; | |
660 | struct sunxi_desc_function *desc = | |
661 | sunxi_pinctrl_desc_find_function_by_name(pctl, | |
662 | g->name, | |
663 | func->name); | |
664 | ||
665 | if (!desc) | |
666 | return -EINVAL; | |
667 | ||
668 | sunxi_pmx_set(pctldev, g->pin, desc->muxval); | |
669 | ||
670 | return 0; | |
671 | } | |
672 | ||
08e9e614 MR |
673 | static int |
674 | sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, | |
675 | struct pinctrl_gpio_range *range, | |
676 | unsigned offset, | |
677 | bool input) | |
678 | { | |
679 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
680 | struct sunxi_desc_function *desc; | |
08e9e614 | 681 | const char *func; |
08e9e614 MR |
682 | |
683 | if (input) | |
684 | func = "gpio_in"; | |
685 | else | |
686 | func = "gpio_out"; | |
687 | ||
814d4f2e MR |
688 | desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, func); |
689 | if (!desc) | |
690 | return -EINVAL; | |
08e9e614 MR |
691 | |
692 | sunxi_pmx_set(pctldev, offset, desc->muxval); | |
693 | ||
814d4f2e | 694 | return 0; |
08e9e614 MR |
695 | } |
696 | ||
9a2a566a MR |
697 | static int sunxi_pmx_request(struct pinctrl_dev *pctldev, unsigned offset) |
698 | { | |
699 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
700 | unsigned short bank = offset / PINS_PER_BANK; | |
ca443844 CYT |
701 | unsigned short bank_offset = bank - pctl->desc->pin_base / |
702 | PINS_PER_BANK; | |
703 | struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset]; | |
dc144558 CYT |
704 | struct regulator *reg = s_reg->regulator; |
705 | char supply[16]; | |
9a2a566a MR |
706 | int ret; |
707 | ||
dc144558 | 708 | if (reg) { |
9a2a566a | 709 | refcount_inc(&s_reg->refcount); |
dc144558 CYT |
710 | return 0; |
711 | } | |
712 | ||
713 | snprintf(supply, sizeof(supply), "vcc-p%c", 'a' + bank); | |
714 | reg = regulator_get(pctl->dev, supply); | |
715 | if (IS_ERR(reg)) { | |
716 | dev_err(pctl->dev, "Couldn't get bank P%c regulator\n", | |
717 | 'A' + bank); | |
718 | return PTR_ERR(reg); | |
9a2a566a MR |
719 | } |
720 | ||
721 | ret = regulator_enable(reg); | |
722 | if (ret) { | |
723 | dev_err(pctl->dev, | |
724 | "Couldn't enable bank P%c regulator\n", 'A' + bank); | |
725 | goto out; | |
726 | } | |
727 | ||
dc144558 CYT |
728 | s_reg->regulator = reg; |
729 | refcount_set(&s_reg->refcount, 1); | |
730 | ||
9a2a566a MR |
731 | return 0; |
732 | ||
733 | out: | |
dc144558 | 734 | regulator_put(s_reg->regulator); |
9a2a566a MR |
735 | |
736 | return ret; | |
737 | } | |
738 | ||
739 | static int sunxi_pmx_free(struct pinctrl_dev *pctldev, unsigned offset) | |
740 | { | |
741 | struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | |
742 | unsigned short bank = offset / PINS_PER_BANK; | |
ca443844 CYT |
743 | unsigned short bank_offset = bank - pctl->desc->pin_base / |
744 | PINS_PER_BANK; | |
745 | struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset]; | |
9a2a566a MR |
746 | |
747 | if (!refcount_dec_and_test(&s_reg->refcount)) | |
748 | return 0; | |
749 | ||
750 | regulator_disable(s_reg->regulator); | |
751 | regulator_put(s_reg->regulator); | |
752 | s_reg->regulator = NULL; | |
753 | ||
754 | return 0; | |
755 | } | |
756 | ||
022ab148 | 757 | static const struct pinmux_ops sunxi_pmx_ops = { |
0e37f88d MR |
758 | .get_functions_count = sunxi_pmx_get_funcs_cnt, |
759 | .get_function_name = sunxi_pmx_get_func_name, | |
760 | .get_function_groups = sunxi_pmx_get_func_groups, | |
03e9f0ca | 761 | .set_mux = sunxi_pmx_set_mux, |
08e9e614 | 762 | .gpio_set_direction = sunxi_pmx_gpio_set_direction, |
9a2a566a MR |
763 | .request = sunxi_pmx_request, |
764 | .free = sunxi_pmx_free, | |
13960072 | 765 | .strict = true, |
0e37f88d MR |
766 | }; |
767 | ||
08e9e614 MR |
768 | static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip, |
769 | unsigned offset) | |
770 | { | |
771 | return pinctrl_gpio_direction_input(chip->base + offset); | |
772 | } | |
773 | ||
774 | static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset) | |
775 | { | |
88057d6e | 776 | struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); |
08e9e614 MR |
777 | u32 reg = sunxi_data_reg(offset); |
778 | u8 index = sunxi_data_offset(offset); | |
6cee3821 LW |
779 | bool set_mux = pctl->desc->irq_read_needs_mux && |
780 | gpiochip_line_is_irq(chip, offset); | |
be2d107f | 781 | u32 pin = offset + chip->base; |
ef6d24cc HG |
782 | u32 val; |
783 | ||
784 | if (set_mux) | |
be2d107f | 785 | sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT); |
ef6d24cc HG |
786 | |
787 | val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK; | |
788 | ||
789 | if (set_mux) | |
be2d107f | 790 | sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ); |
08e9e614 | 791 | |
39e24ac3 | 792 | return !!val; |
08e9e614 MR |
793 | } |
794 | ||
08e9e614 MR |
795 | static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip, |
796 | unsigned offset, int value) | |
797 | { | |
88057d6e | 798 | struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); |
08e9e614 MR |
799 | u32 reg = sunxi_data_reg(offset); |
800 | u8 index = sunxi_data_offset(offset); | |
1bee963d MR |
801 | unsigned long flags; |
802 | u32 regval; | |
803 | ||
f658ed36 | 804 | raw_spin_lock_irqsave(&pctl->lock, flags); |
1bee963d MR |
805 | |
806 | regval = readl(pctl->membase + reg); | |
08e9e614 | 807 | |
df7b34f4 MR |
808 | if (value) |
809 | regval |= BIT(index); | |
810 | else | |
811 | regval &= ~(BIT(index)); | |
08e9e614 | 812 | |
df7b34f4 | 813 | writel(regval, pctl->membase + reg); |
1bee963d | 814 | |
f658ed36 | 815 | raw_spin_unlock_irqrestore(&pctl->lock, flags); |
08e9e614 MR |
816 | } |
817 | ||
fa8cf57c CYT |
818 | static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip, |
819 | unsigned offset, int value) | |
820 | { | |
821 | sunxi_pinctrl_gpio_set(chip, offset, value); | |
822 | return pinctrl_gpio_direction_output(chip->base + offset); | |
823 | } | |
824 | ||
a0d72094 MR |
825 | static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc, |
826 | const struct of_phandle_args *gpiospec, | |
827 | u32 *flags) | |
828 | { | |
829 | int pin, base; | |
830 | ||
831 | base = PINS_PER_BANK * gpiospec->args[0]; | |
832 | pin = base + gpiospec->args[1]; | |
833 | ||
343f1327 | 834 | if (pin > gc->ngpio) |
a0d72094 MR |
835 | return -EINVAL; |
836 | ||
837 | if (flags) | |
838 | *flags = gpiospec->args[2]; | |
839 | ||
840 | return pin; | |
841 | } | |
842 | ||
60242db1 MR |
843 | static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset) |
844 | { | |
88057d6e | 845 | struct sunxi_pinctrl *pctl = gpiochip_get_data(chip); |
60242db1 | 846 | struct sunxi_desc_function *desc; |
343f1327 | 847 | unsigned pinnum = pctl->desc->pin_base + offset; |
0d3bafac | 848 | unsigned irqnum; |
60242db1 | 849 | |
c9e3b2d8 | 850 | if (offset >= chip->ngpio) |
60242db1 MR |
851 | return -ENXIO; |
852 | ||
343f1327 | 853 | desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pinnum, "irq"); |
60242db1 MR |
854 | if (!desc) |
855 | return -EINVAL; | |
856 | ||
0d3bafac CYT |
857 | irqnum = desc->irqbank * IRQ_PER_BANK + desc->irqnum; |
858 | ||
58383c78 | 859 | dev_dbg(chip->parent, "%s: request IRQ for GPIO %d, return %d\n", |
0d3bafac | 860 | chip->label, offset + chip->base, irqnum); |
60242db1 | 861 | |
0d3bafac | 862 | return irq_find_mapping(pctl->domain, irqnum); |
60242db1 MR |
863 | } |
864 | ||
fea6d8ef HG |
865 | static int sunxi_pinctrl_irq_request_resources(struct irq_data *d) |
866 | { | |
867 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | |
868 | struct sunxi_desc_function *func; | |
f83549d6 | 869 | int ret; |
fea6d8ef HG |
870 | |
871 | func = sunxi_pinctrl_desc_find_function_by_pin(pctl, | |
872 | pctl->irq_array[d->hwirq], "irq"); | |
873 | if (!func) | |
874 | return -EINVAL; | |
875 | ||
e3a2e878 | 876 | ret = gpiochip_lock_as_irq(pctl->chip, |
343f1327 | 877 | pctl->irq_array[d->hwirq] - pctl->desc->pin_base); |
f83549d6 CYT |
878 | if (ret) { |
879 | dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n", | |
880 | irqd_to_hwirq(d)); | |
881 | return ret; | |
882 | } | |
883 | ||
fea6d8ef HG |
884 | /* Change muxing to INT mode */ |
885 | sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval); | |
08e9e614 | 886 | |
fea6d8ef HG |
887 | return 0; |
888 | } | |
08e9e614 | 889 | |
f83549d6 CYT |
890 | static void sunxi_pinctrl_irq_release_resources(struct irq_data *d) |
891 | { | |
892 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | |
893 | ||
e3a2e878 AC |
894 | gpiochip_unlock_as_irq(pctl->chip, |
895 | pctl->irq_array[d->hwirq] - pctl->desc->pin_base); | |
f83549d6 CYT |
896 | } |
897 | ||
f4c51c10 | 898 | static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) |
60242db1 MR |
899 | { |
900 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | |
4b0d6c5a | 901 | u32 reg = sunxi_irq_cfg_reg(pctl->desc, d->hwirq); |
60242db1 | 902 | u8 index = sunxi_irq_cfg_offset(d->hwirq); |
1bee963d | 903 | unsigned long flags; |
2aaaddff | 904 | u32 regval; |
60242db1 MR |
905 | u8 mode; |
906 | ||
907 | switch (type) { | |
908 | case IRQ_TYPE_EDGE_RISING: | |
909 | mode = IRQ_EDGE_RISING; | |
910 | break; | |
911 | case IRQ_TYPE_EDGE_FALLING: | |
912 | mode = IRQ_EDGE_FALLING; | |
913 | break; | |
914 | case IRQ_TYPE_EDGE_BOTH: | |
915 | mode = IRQ_EDGE_BOTH; | |
916 | break; | |
917 | case IRQ_TYPE_LEVEL_HIGH: | |
918 | mode = IRQ_LEVEL_HIGH; | |
919 | break; | |
920 | case IRQ_TYPE_LEVEL_LOW: | |
921 | mode = IRQ_LEVEL_LOW; | |
922 | break; | |
923 | default: | |
924 | return -EINVAL; | |
925 | } | |
926 | ||
f658ed36 | 927 | raw_spin_lock_irqsave(&pctl->lock, flags); |
1bee963d | 928 | |
a0d6de9b | 929 | if (type & IRQ_TYPE_LEVEL_MASK) |
b9a5ec33 TG |
930 | irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_level_irq_chip, |
931 | handle_fasteoi_irq, NULL); | |
a0d6de9b | 932 | else |
b9a5ec33 TG |
933 | irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_edge_irq_chip, |
934 | handle_edge_irq, NULL); | |
a0d6de9b | 935 | |
2aaaddff | 936 | regval = readl(pctl->membase + reg); |
d82f9401 | 937 | regval &= ~(IRQ_CFG_IRQ_MASK << index); |
2aaaddff | 938 | writel(regval | (mode << index), pctl->membase + reg); |
60242db1 | 939 | |
f658ed36 | 940 | raw_spin_unlock_irqrestore(&pctl->lock, flags); |
60242db1 MR |
941 | |
942 | return 0; | |
943 | } | |
944 | ||
645ec714 | 945 | static void sunxi_pinctrl_irq_ack(struct irq_data *d) |
60242db1 MR |
946 | { |
947 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | |
4b0d6c5a | 948 | u32 status_reg = sunxi_irq_status_reg(pctl->desc, d->hwirq); |
60242db1 | 949 | u8 status_idx = sunxi_irq_status_offset(d->hwirq); |
60242db1 MR |
950 | |
951 | /* Clear the IRQ */ | |
952 | writel(1 << status_idx, pctl->membase + status_reg); | |
953 | } | |
954 | ||
955 | static void sunxi_pinctrl_irq_mask(struct irq_data *d) | |
956 | { | |
957 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | |
4b0d6c5a | 958 | u32 reg = sunxi_irq_ctrl_reg(pctl->desc, d->hwirq); |
60242db1 | 959 | u8 idx = sunxi_irq_ctrl_offset(d->hwirq); |
1bee963d | 960 | unsigned long flags; |
60242db1 MR |
961 | u32 val; |
962 | ||
f658ed36 | 963 | raw_spin_lock_irqsave(&pctl->lock, flags); |
1bee963d | 964 | |
60242db1 MR |
965 | /* Mask the IRQ */ |
966 | val = readl(pctl->membase + reg); | |
967 | writel(val & ~(1 << idx), pctl->membase + reg); | |
1bee963d | 968 | |
f658ed36 | 969 | raw_spin_unlock_irqrestore(&pctl->lock, flags); |
60242db1 MR |
970 | } |
971 | ||
972 | static void sunxi_pinctrl_irq_unmask(struct irq_data *d) | |
973 | { | |
974 | struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); | |
4b0d6c5a | 975 | u32 reg = sunxi_irq_ctrl_reg(pctl->desc, d->hwirq); |
60242db1 | 976 | u8 idx = sunxi_irq_ctrl_offset(d->hwirq); |
1bee963d | 977 | unsigned long flags; |
60242db1 MR |
978 | u32 val; |
979 | ||
f658ed36 | 980 | raw_spin_lock_irqsave(&pctl->lock, flags); |
1bee963d | 981 | |
60242db1 MR |
982 | /* Unmask the IRQ */ |
983 | val = readl(pctl->membase + reg); | |
984 | writel(val | (1 << idx), pctl->membase + reg); | |
1bee963d | 985 | |
f658ed36 | 986 | raw_spin_unlock_irqrestore(&pctl->lock, flags); |
60242db1 MR |
987 | } |
988 | ||
d61e23e5 HG |
989 | static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d) |
990 | { | |
991 | sunxi_pinctrl_irq_ack(d); | |
992 | sunxi_pinctrl_irq_unmask(d); | |
993 | } | |
994 | ||
f4c51c10 | 995 | static struct irq_chip sunxi_pinctrl_edge_irq_chip = { |
fb5b7788 | 996 | .name = "sunxi_pio_edge", |
645ec714 | 997 | .irq_ack = sunxi_pinctrl_irq_ack, |
60242db1 | 998 | .irq_mask = sunxi_pinctrl_irq_mask, |
60242db1 | 999 | .irq_unmask = sunxi_pinctrl_irq_unmask, |
fea6d8ef | 1000 | .irq_request_resources = sunxi_pinctrl_irq_request_resources, |
f83549d6 | 1001 | .irq_release_resources = sunxi_pinctrl_irq_release_resources, |
60242db1 | 1002 | .irq_set_type = sunxi_pinctrl_irq_set_type, |
578c0a87 | 1003 | .flags = IRQCHIP_SKIP_SET_WAKE, |
60242db1 MR |
1004 | }; |
1005 | ||
f4c51c10 | 1006 | static struct irq_chip sunxi_pinctrl_level_irq_chip = { |
fb5b7788 | 1007 | .name = "sunxi_pio_level", |
f4c51c10 | 1008 | .irq_eoi = sunxi_pinctrl_irq_ack, |
60242db1 | 1009 | .irq_mask = sunxi_pinctrl_irq_mask, |
60242db1 | 1010 | .irq_unmask = sunxi_pinctrl_irq_unmask, |
d61e23e5 HG |
1011 | /* Define irq_enable / disable to avoid spurious irqs for drivers |
1012 | * using these to suppress irqs while they clear the irq source */ | |
1013 | .irq_enable = sunxi_pinctrl_irq_ack_unmask, | |
1014 | .irq_disable = sunxi_pinctrl_irq_mask, | |
f4c51c10 | 1015 | .irq_request_resources = sunxi_pinctrl_irq_request_resources, |
f83549d6 | 1016 | .irq_release_resources = sunxi_pinctrl_irq_release_resources, |
60242db1 | 1017 | .irq_set_type = sunxi_pinctrl_irq_set_type, |
f4c51c10 HG |
1018 | .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_EOI_THREADED | |
1019 | IRQCHIP_EOI_IF_HANDLED, | |
60242db1 MR |
1020 | }; |
1021 | ||
d8323c6b MR |
1022 | static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d, |
1023 | struct device_node *node, | |
1024 | const u32 *intspec, | |
1025 | unsigned int intsize, | |
1026 | unsigned long *out_hwirq, | |
1027 | unsigned int *out_type) | |
1028 | { | |
8297992c | 1029 | struct sunxi_pinctrl *pctl = d->host_data; |
d8323c6b MR |
1030 | struct sunxi_desc_function *desc; |
1031 | int pin, base; | |
1032 | ||
1033 | if (intsize < 3) | |
1034 | return -EINVAL; | |
1035 | ||
1036 | base = PINS_PER_BANK * intspec[0]; | |
8297992c | 1037 | pin = pctl->desc->pin_base + base + intspec[1]; |
d8323c6b | 1038 | |
8297992c | 1039 | desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pin, "irq"); |
d8323c6b MR |
1040 | if (!desc) |
1041 | return -EINVAL; | |
1042 | ||
1043 | *out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum; | |
1044 | *out_type = intspec[2]; | |
1045 | ||
1046 | return 0; | |
1047 | } | |
1048 | ||
2421dfd6 | 1049 | static const struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = { |
d8323c6b MR |
1050 | .xlate = sunxi_pinctrl_irq_of_xlate, |
1051 | }; | |
1052 | ||
bd0b9ac4 | 1053 | static void sunxi_pinctrl_irq_handler(struct irq_desc *desc) |
60242db1 | 1054 | { |
eeef97b1 | 1055 | unsigned int irq = irq_desc_get_irq(desc); |
5663bb27 JL |
1056 | struct irq_chip *chip = irq_desc_get_chip(desc); |
1057 | struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc); | |
aebdc8ab MR |
1058 | unsigned long bank, reg, val; |
1059 | ||
1060 | for (bank = 0; bank < pctl->desc->irq_banks; bank++) | |
1061 | if (irq == pctl->irq[bank]) | |
1062 | break; | |
1063 | ||
1064 | if (bank == pctl->desc->irq_banks) | |
1065 | return; | |
60242db1 | 1066 | |
4b0d6c5a | 1067 | reg = sunxi_irq_status_reg_from_bank(pctl->desc, bank); |
aebdc8ab | 1068 | val = readl(pctl->membase + reg); |
60242db1 | 1069 | |
aebdc8ab | 1070 | if (val) { |
60242db1 MR |
1071 | int irqoffset; |
1072 | ||
905a5117 | 1073 | chained_irq_enter(chip, desc); |
aebdc8ab MR |
1074 | for_each_set_bit(irqoffset, &val, IRQ_PER_BANK) { |
1075 | int pin_irq = irq_find_mapping(pctl->domain, | |
1076 | bank * IRQ_PER_BANK + irqoffset); | |
60242db1 MR |
1077 | generic_handle_irq(pin_irq); |
1078 | } | |
905a5117 | 1079 | chained_irq_exit(chip, desc); |
60242db1 MR |
1080 | } |
1081 | } | |
1082 | ||
0e37f88d MR |
1083 | static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl, |
1084 | const char *name) | |
1085 | { | |
1086 | struct sunxi_pinctrl_function *func = pctl->functions; | |
1087 | ||
1088 | while (func->name) { | |
1089 | /* function already there */ | |
1090 | if (strcmp(func->name, name) == 0) { | |
1091 | func->ngroups++; | |
1092 | return -EEXIST; | |
1093 | } | |
1094 | func++; | |
1095 | } | |
1096 | ||
1097 | func->name = name; | |
1098 | func->ngroups = 1; | |
1099 | ||
1100 | pctl->nfunctions++; | |
1101 | ||
1102 | return 0; | |
1103 | } | |
1104 | ||
1105 | static int sunxi_pinctrl_build_state(struct platform_device *pdev) | |
1106 | { | |
1107 | struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev); | |
a93a676b | 1108 | void *ptr; |
0e37f88d MR |
1109 | int i; |
1110 | ||
578db85f MR |
1111 | /* |
1112 | * Allocate groups | |
1113 | * | |
1114 | * We assume that the number of groups is the number of pins | |
1115 | * given in the data array. | |
0e37f88d | 1116 | |
578db85f MR |
1117 | * This will not always be true, since some pins might not be |
1118 | * available in the current variant, but fortunately for us, | |
1119 | * this means that the number of pins is the maximum group | |
1120 | * number we will ever see. | |
1121 | */ | |
a86854d0 KC |
1122 | pctl->groups = devm_kcalloc(&pdev->dev, |
1123 | pctl->desc->npins, sizeof(*pctl->groups), | |
0e37f88d MR |
1124 | GFP_KERNEL); |
1125 | if (!pctl->groups) | |
1126 | return -ENOMEM; | |
1127 | ||
1128 | for (i = 0; i < pctl->desc->npins; i++) { | |
1129 | const struct sunxi_desc_pin *pin = pctl->desc->pins + i; | |
578db85f MR |
1130 | struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups; |
1131 | ||
1132 | if (pin->variant && !(pctl->variant & pin->variant)) | |
1133 | continue; | |
0e37f88d MR |
1134 | |
1135 | group->name = pin->pin.name; | |
1136 | group->pin = pin->pin.number; | |
578db85f MR |
1137 | |
1138 | /* And now we count the actual number of pins / groups */ | |
1139 | pctl->ngroups++; | |
0e37f88d MR |
1140 | } |
1141 | ||
1142 | /* | |
1143 | * We suppose that we won't have any more functions than pins, | |
1144 | * we'll reallocate that later anyway | |
1145 | */ | |
a4925311 Y |
1146 | pctl->functions = kcalloc(pctl->ngroups, |
1147 | sizeof(*pctl->functions), | |
1148 | GFP_KERNEL); | |
0e37f88d MR |
1149 | if (!pctl->functions) |
1150 | return -ENOMEM; | |
1151 | ||
1152 | /* Count functions and their associated groups */ | |
1153 | for (i = 0; i < pctl->desc->npins; i++) { | |
1154 | const struct sunxi_desc_pin *pin = pctl->desc->pins + i; | |
578db85f MR |
1155 | struct sunxi_desc_function *func; |
1156 | ||
1157 | if (pin->variant && !(pctl->variant & pin->variant)) | |
1158 | continue; | |
1159 | ||
1160 | for (func = pin->functions; func->name; func++) { | |
1161 | if (func->variant && !(pctl->variant & func->variant)) | |
1162 | continue; | |
0e37f88d | 1163 | |
d54e9a28 | 1164 | /* Create interrupt mapping while we're at it */ |
aebdc8ab MR |
1165 | if (!strcmp(func->name, "irq")) { |
1166 | int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK; | |
1167 | pctl->irq_array[irqnum] = pin->pin.number; | |
1168 | } | |
1169 | ||
0e37f88d | 1170 | sunxi_pinctrl_add_function(pctl, func->name); |
0e37f88d MR |
1171 | } |
1172 | } | |
1173 | ||
578db85f | 1174 | /* And now allocated and fill the array for real */ |
a93a676b CJ |
1175 | ptr = krealloc(pctl->functions, |
1176 | pctl->nfunctions * sizeof(*pctl->functions), | |
1177 | GFP_KERNEL); | |
1178 | if (!ptr) { | |
578db85f | 1179 | kfree(pctl->functions); |
a93a676b | 1180 | pctl->functions = NULL; |
578db85f MR |
1181 | return -ENOMEM; |
1182 | } | |
a93a676b | 1183 | pctl->functions = ptr; |
0e37f88d MR |
1184 | |
1185 | for (i = 0; i < pctl->desc->npins; i++) { | |
1186 | const struct sunxi_desc_pin *pin = pctl->desc->pins + i; | |
578db85f | 1187 | struct sunxi_desc_function *func; |
0e37f88d | 1188 | |
578db85f MR |
1189 | if (pin->variant && !(pctl->variant & pin->variant)) |
1190 | continue; | |
1191 | ||
1192 | for (func = pin->functions; func->name; func++) { | |
0e37f88d MR |
1193 | struct sunxi_pinctrl_function *func_item; |
1194 | const char **func_grp; | |
1195 | ||
578db85f MR |
1196 | if (func->variant && !(pctl->variant & func->variant)) |
1197 | continue; | |
1198 | ||
0e37f88d MR |
1199 | func_item = sunxi_pinctrl_find_function_by_name(pctl, |
1200 | func->name); | |
a4925311 Y |
1201 | if (!func_item) { |
1202 | kfree(pctl->functions); | |
0e37f88d | 1203 | return -EINVAL; |
a4925311 | 1204 | } |
0e37f88d MR |
1205 | |
1206 | if (!func_item->groups) { | |
1207 | func_item->groups = | |
a86854d0 KC |
1208 | devm_kcalloc(&pdev->dev, |
1209 | func_item->ngroups, | |
1210 | sizeof(*func_item->groups), | |
0e37f88d | 1211 | GFP_KERNEL); |
a4925311 Y |
1212 | if (!func_item->groups) { |
1213 | kfree(pctl->functions); | |
0e37f88d | 1214 | return -ENOMEM; |
a4925311 | 1215 | } |
0e37f88d MR |
1216 | } |
1217 | ||
1218 | func_grp = func_item->groups; | |
1219 | while (*func_grp) | |
1220 | func_grp++; | |
1221 | ||
1222 | *func_grp = pin->pin.name; | |
0e37f88d MR |
1223 | } |
1224 | } | |
1225 | ||
1226 | return 0; | |
1227 | } | |
1228 | ||
7c926492 MR |
1229 | static int sunxi_pinctrl_get_debounce_div(struct clk *clk, int freq, int *diff) |
1230 | { | |
1231 | unsigned long clock = clk_get_rate(clk); | |
d8a22212 | 1232 | unsigned int best_diff, best_div; |
7c926492 MR |
1233 | int i; |
1234 | ||
d8a22212 AB |
1235 | best_diff = abs(freq - clock); |
1236 | best_div = 0; | |
1237 | ||
1238 | for (i = 1; i < 8; i++) { | |
7c926492 MR |
1239 | int cur_diff = abs(freq - (clock >> i)); |
1240 | ||
1241 | if (cur_diff < best_diff) { | |
1242 | best_diff = cur_diff; | |
1243 | best_div = i; | |
1244 | } | |
1245 | } | |
1246 | ||
1247 | *diff = best_diff; | |
1248 | return best_div; | |
1249 | } | |
1250 | ||
1251 | static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl, | |
1252 | struct device_node *node) | |
1253 | { | |
1254 | unsigned int hosc_diff, losc_diff; | |
1255 | unsigned int hosc_div, losc_div; | |
1256 | struct clk *hosc, *losc; | |
1257 | u8 div, src; | |
1258 | int i, ret; | |
1259 | ||
1260 | /* Deal with old DTs that didn't have the oscillators */ | |
470b73a3 | 1261 | if (of_clk_get_parent_count(node) != 3) |
7c926492 MR |
1262 | return 0; |
1263 | ||
1264 | /* If we don't have any setup, bail out */ | |
1265 | if (!of_find_property(node, "input-debounce", NULL)) | |
1266 | return 0; | |
1267 | ||
1268 | losc = devm_clk_get(pctl->dev, "losc"); | |
1269 | if (IS_ERR(losc)) | |
1270 | return PTR_ERR(losc); | |
1271 | ||
1272 | hosc = devm_clk_get(pctl->dev, "hosc"); | |
1273 | if (IS_ERR(hosc)) | |
1274 | return PTR_ERR(hosc); | |
1275 | ||
1276 | for (i = 0; i < pctl->desc->irq_banks; i++) { | |
1277 | unsigned long debounce_freq; | |
1278 | u32 debounce; | |
1279 | ||
1280 | ret = of_property_read_u32_index(node, "input-debounce", | |
1281 | i, &debounce); | |
1282 | if (ret) | |
1283 | return ret; | |
1284 | ||
1285 | if (!debounce) | |
1286 | continue; | |
1287 | ||
1288 | debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC, debounce); | |
1289 | losc_div = sunxi_pinctrl_get_debounce_div(losc, | |
1290 | debounce_freq, | |
1291 | &losc_diff); | |
1292 | ||
1293 | hosc_div = sunxi_pinctrl_get_debounce_div(hosc, | |
1294 | debounce_freq, | |
1295 | &hosc_diff); | |
1296 | ||
1297 | if (hosc_diff < losc_diff) { | |
1298 | div = hosc_div; | |
1299 | src = 1; | |
1300 | } else { | |
1301 | div = losc_div; | |
1302 | src = 0; | |
1303 | } | |
1304 | ||
1305 | writel(src | div << 4, | |
1306 | pctl->membase + | |
4b0d6c5a | 1307 | sunxi_irq_debounce_reg_from_bank(pctl->desc, i)); |
7c926492 MR |
1308 | } |
1309 | ||
1310 | return 0; | |
1311 | } | |
1312 | ||
578db85f MR |
1313 | int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, |
1314 | const struct sunxi_pinctrl_desc *desc, | |
1315 | unsigned long variant) | |
0e37f88d MR |
1316 | { |
1317 | struct device_node *node = pdev->dev.of_node; | |
ba6764d5 | 1318 | struct pinctrl_desc *pctrl_desc; |
0e37f88d MR |
1319 | struct pinctrl_pin_desc *pins; |
1320 | struct sunxi_pinctrl *pctl; | |
aae842a3 | 1321 | struct pinmux_ops *pmxops; |
4409cafc | 1322 | struct resource *res; |
578db85f | 1323 | int i, ret, last_pin, pin_idx; |
950707c0 | 1324 | struct clk *clk; |
0e37f88d MR |
1325 | |
1326 | pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); | |
1327 | if (!pctl) | |
1328 | return -ENOMEM; | |
1329 | platform_set_drvdata(pdev, pctl); | |
1330 | ||
f658ed36 | 1331 | raw_spin_lock_init(&pctl->lock); |
1bee963d | 1332 | |
4409cafc MR |
1333 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1334 | pctl->membase = devm_ioremap_resource(&pdev->dev, res); | |
1335 | if (IS_ERR(pctl->membase)) | |
1336 | return PTR_ERR(pctl->membase); | |
0e37f88d | 1337 | |
ba6764d5 | 1338 | pctl->dev = &pdev->dev; |
2284ba6b | 1339 | pctl->desc = desc; |
578db85f | 1340 | pctl->variant = variant; |
0e37f88d | 1341 | |
aebdc8ab MR |
1342 | pctl->irq_array = devm_kcalloc(&pdev->dev, |
1343 | IRQ_PER_BANK * pctl->desc->irq_banks, | |
1344 | sizeof(*pctl->irq_array), | |
1345 | GFP_KERNEL); | |
1346 | if (!pctl->irq_array) | |
1347 | return -ENOMEM; | |
1348 | ||
0e37f88d MR |
1349 | ret = sunxi_pinctrl_build_state(pdev); |
1350 | if (ret) { | |
1351 | dev_err(&pdev->dev, "dt probe failed: %d\n", ret); | |
1352 | return ret; | |
1353 | } | |
1354 | ||
a86854d0 KC |
1355 | pins = devm_kcalloc(&pdev->dev, |
1356 | pctl->desc->npins, sizeof(*pins), | |
0e37f88d MR |
1357 | GFP_KERNEL); |
1358 | if (!pins) | |
1359 | return -ENOMEM; | |
1360 | ||
578db85f MR |
1361 | for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) { |
1362 | const struct sunxi_desc_pin *pin = pctl->desc->pins + i; | |
1363 | ||
1364 | if (pin->variant && !(pctl->variant & pin->variant)) | |
1365 | continue; | |
1366 | ||
1367 | pins[pin_idx++] = pin->pin; | |
1368 | } | |
0e37f88d | 1369 | |
ba6764d5 MR |
1370 | pctrl_desc = devm_kzalloc(&pdev->dev, |
1371 | sizeof(*pctrl_desc), | |
1372 | GFP_KERNEL); | |
1373 | if (!pctrl_desc) | |
1374 | return -ENOMEM; | |
1375 | ||
1376 | pctrl_desc->name = dev_name(&pdev->dev); | |
1377 | pctrl_desc->owner = THIS_MODULE; | |
1378 | pctrl_desc->pins = pins; | |
578db85f | 1379 | pctrl_desc->npins = pctl->ngroups; |
ba6764d5 MR |
1380 | pctrl_desc->confops = &sunxi_pconf_ops; |
1381 | pctrl_desc->pctlops = &sunxi_pctrl_ops; | |
aae842a3 MR |
1382 | |
1383 | pmxops = devm_kmemdup(&pdev->dev, &sunxi_pmx_ops, sizeof(sunxi_pmx_ops), | |
1384 | GFP_KERNEL); | |
1385 | if (!pmxops) | |
1386 | return -ENOMEM; | |
1387 | ||
1388 | if (desc->disable_strict_mode) | |
1389 | pmxops->strict = false; | |
1390 | ||
1391 | pctrl_desc->pmxops = pmxops; | |
ba6764d5 | 1392 | |
45078ea0 | 1393 | pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl); |
323de9ef | 1394 | if (IS_ERR(pctl->pctl_dev)) { |
0e37f88d | 1395 | dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); |
323de9ef | 1396 | return PTR_ERR(pctl->pctl_dev); |
0e37f88d MR |
1397 | } |
1398 | ||
08e9e614 | 1399 | pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL); |
45078ea0 LD |
1400 | if (!pctl->chip) |
1401 | return -ENOMEM; | |
08e9e614 MR |
1402 | |
1403 | last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number; | |
d83c82ce | 1404 | pctl->chip->owner = THIS_MODULE; |
98c85d58 JG |
1405 | pctl->chip->request = gpiochip_generic_request, |
1406 | pctl->chip->free = gpiochip_generic_free, | |
d83c82ce BB |
1407 | pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input, |
1408 | pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output, | |
1409 | pctl->chip->get = sunxi_pinctrl_gpio_get, | |
1410 | pctl->chip->set = sunxi_pinctrl_gpio_set, | |
1411 | pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate, | |
1412 | pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq, | |
1413 | pctl->chip->of_gpio_n_cells = 3, | |
1414 | pctl->chip->can_sleep = false, | |
1415 | pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) - | |
1416 | pctl->desc->pin_base; | |
08e9e614 | 1417 | pctl->chip->label = dev_name(&pdev->dev); |
58383c78 | 1418 | pctl->chip->parent = &pdev->dev; |
d83c82ce | 1419 | pctl->chip->base = pctl->desc->pin_base; |
08e9e614 | 1420 | |
88057d6e | 1421 | ret = gpiochip_add_data(pctl->chip, pctl); |
08e9e614 | 1422 | if (ret) |
45078ea0 | 1423 | return ret; |
08e9e614 MR |
1424 | |
1425 | for (i = 0; i < pctl->desc->npins; i++) { | |
1426 | const struct sunxi_desc_pin *pin = pctl->desc->pins + i; | |
1427 | ||
1428 | ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev), | |
343f1327 | 1429 | pin->pin.number - pctl->desc->pin_base, |
08e9e614 MR |
1430 | pin->pin.number, 1); |
1431 | if (ret) | |
1432 | goto gpiochip_error; | |
1433 | } | |
1434 | ||
10e3a88b | 1435 | ret = of_clk_get_parent_count(node); |
a34ea4b4 | 1436 | clk = devm_clk_get(&pdev->dev, ret == 1 ? NULL : "apb"); |
d72f88a4 WY |
1437 | if (IS_ERR(clk)) { |
1438 | ret = PTR_ERR(clk); | |
950707c0 | 1439 | goto gpiochip_error; |
d72f88a4 | 1440 | } |
950707c0 | 1441 | |
6415093f BB |
1442 | ret = clk_prepare_enable(clk); |
1443 | if (ret) | |
1444 | goto gpiochip_error; | |
950707c0 | 1445 | |
aebdc8ab MR |
1446 | pctl->irq = devm_kcalloc(&pdev->dev, |
1447 | pctl->desc->irq_banks, | |
1448 | sizeof(*pctl->irq), | |
1449 | GFP_KERNEL); | |
60242db1 | 1450 | if (!pctl->irq) { |
aebdc8ab | 1451 | ret = -ENOMEM; |
dc969106 | 1452 | goto clk_error; |
60242db1 MR |
1453 | } |
1454 | ||
aebdc8ab MR |
1455 | for (i = 0; i < pctl->desc->irq_banks; i++) { |
1456 | pctl->irq[i] = platform_get_irq(pdev, i); | |
1457 | if (pctl->irq[i] < 0) { | |
1458 | ret = pctl->irq[i]; | |
1459 | goto clk_error; | |
1460 | } | |
1461 | } | |
1462 | ||
1463 | pctl->domain = irq_domain_add_linear(node, | |
1464 | pctl->desc->irq_banks * IRQ_PER_BANK, | |
d8323c6b MR |
1465 | &sunxi_pinctrl_irq_domain_ops, |
1466 | pctl); | |
60242db1 MR |
1467 | if (!pctl->domain) { |
1468 | dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); | |
1469 | ret = -ENOMEM; | |
dc969106 | 1470 | goto clk_error; |
60242db1 MR |
1471 | } |
1472 | ||
aebdc8ab | 1473 | for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) { |
60242db1 MR |
1474 | int irqno = irq_create_mapping(pctl->domain, i); |
1475 | ||
f4c51c10 HG |
1476 | irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip, |
1477 | handle_edge_irq); | |
60242db1 | 1478 | irq_set_chip_data(irqno, pctl); |
5c99c0ff | 1479 | } |
60242db1 | 1480 | |
aebdc8ab | 1481 | for (i = 0; i < pctl->desc->irq_banks; i++) { |
f4c51c10 | 1482 | /* Mask and clear all IRQs before registering a handler */ |
4b0d6c5a IZ |
1483 | writel(0, pctl->membase + |
1484 | sunxi_irq_ctrl_reg_from_bank(pctl->desc, i)); | |
f4c51c10 | 1485 | writel(0xffffffff, |
4b0d6c5a IZ |
1486 | pctl->membase + |
1487 | sunxi_irq_status_reg_from_bank(pctl->desc, i)); | |
f4c51c10 | 1488 | |
ef80e87d TG |
1489 | irq_set_chained_handler_and_data(pctl->irq[i], |
1490 | sunxi_pinctrl_irq_handler, | |
1491 | pctl); | |
aebdc8ab | 1492 | } |
60242db1 | 1493 | |
7c926492 MR |
1494 | sunxi_pinctrl_setup_debounce(pctl, node); |
1495 | ||
08e9e614 | 1496 | dev_info(&pdev->dev, "initialized sunXi PIO driver\n"); |
0e37f88d MR |
1497 | |
1498 | return 0; | |
08e9e614 | 1499 | |
e2bddc6a BB |
1500 | clk_error: |
1501 | clk_disable_unprepare(clk); | |
08e9e614 | 1502 | gpiochip_error: |
b4e7c55d | 1503 | gpiochip_remove(pctl->chip); |
08e9e614 | 1504 | return ret; |
0e37f88d | 1505 | } |