1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // Copyright (C) 2015-2017 Socionext Inc. |
4 | // Author: Masahiro Yamada <yamada.masahiro@socionext.com> |
5 | |
6 | #include <linux/list.h> |
7 | #include <linux/mfd/syscon.h> |
8 | #include <linux/of.h> |
9 | #include <linux/platform_device.h> |
10 | #include <linux/regmap.h> |
11 | #include <linux/seq_file.h> |
12 | |
13 | #include <linux/pinctrl/pinconf-generic.h> |
14 | #include <linux/pinctrl/pinconf.h> |
15 | #include <linux/pinctrl/pinctrl.h> |
16 | #include <linux/pinctrl/pinmux.h> |
17 | |
18 | #include "../core.h" |
19 | #include "../pinctrl-utils.h" |
20 | #include "pinctrl-uniphier.h" |
21 | |
22 | #define UNIPHIER_PINCTRL_PINMUX_BASE 0x1000 |
23 | #define UNIPHIER_PINCTRL_LOAD_PINMUX 0x1700 |
24 | #define UNIPHIER_PINCTRL_DRVCTRL_BASE 0x1800 |
25 | #define UNIPHIER_PINCTRL_DRV2CTRL_BASE 0x1900 |
26 | #define UNIPHIER_PINCTRL_DRV3CTRL_BASE 0x1980 |
27 | #define UNIPHIER_PINCTRL_PUPDCTRL_BASE 0x1a00 |
28 | #define UNIPHIER_PINCTRL_IECTRL_BASE 0x1d00 |
29 | |
30 | struct uniphier_pinctrl_reg_region { |
31 | struct list_head node; |
32 | unsigned int base; |
33 | unsigned int nregs; |
34 | u32 vals[] __counted_by(nregs); |
35 | }; |
36 | |
37 | struct uniphier_pinctrl_priv { |
38 | struct pinctrl_desc pctldesc; |
39 | struct pinctrl_dev *pctldev; |
40 | struct regmap *regmap; |
41 | const struct uniphier_pinctrl_socdata *socdata; |
42 | struct list_head reg_regions; |
43 | }; |
44 | |
45 | static int uniphier_pctl_get_groups_count(struct pinctrl_dev *pctldev) |
46 | { |
47 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
48 | |
49 | return priv->socdata->groups_count; |
50 | } |
51 | |
52 | static const char *uniphier_pctl_get_group_name(struct pinctrl_dev *pctldev, |
53 | unsigned selector) |
54 | { |
55 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
56 | |
57 | return priv->socdata->groups[selector].name; |
58 | } |
59 | |
60 | static int uniphier_pctl_get_group_pins(struct pinctrl_dev *pctldev, |
61 | unsigned selector, |
62 | const unsigned **pins, |
63 | unsigned *num_pins) |
64 | { |
65 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
66 | |
67 | *pins = priv->socdata->groups[selector].pins; |
68 | *num_pins = priv->socdata->groups[selector].num_pins; |
69 | |
70 | return 0; |
71 | } |
72 | |
73 | #ifdef CONFIG_DEBUG_FS |
74 | static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, |
75 | struct seq_file *s, unsigned offset) |
76 | { |
77 | const struct pin_desc *desc = pin_desc_get(pctldev, pin: offset); |
78 | const char *pull_dir, *drv_type; |
79 | |
80 | switch (uniphier_pin_get_pull_dir(drv_data: desc->drv_data)) { |
81 | case UNIPHIER_PIN_PULL_UP: |
82 | pull_dir = "UP" ; |
83 | break; |
84 | case UNIPHIER_PIN_PULL_DOWN: |
85 | pull_dir = "DOWN" ; |
86 | break; |
87 | case UNIPHIER_PIN_PULL_UP_FIXED: |
88 | pull_dir = "UP(FIXED)" ; |
89 | break; |
90 | case UNIPHIER_PIN_PULL_DOWN_FIXED: |
91 | pull_dir = "DOWN(FIXED)" ; |
92 | break; |
93 | case UNIPHIER_PIN_PULL_NONE: |
94 | pull_dir = "NONE" ; |
95 | break; |
96 | default: |
97 | BUG(); |
98 | } |
99 | |
100 | switch (uniphier_pin_get_drv_type(drv_data: desc->drv_data)) { |
101 | case UNIPHIER_PIN_DRV_1BIT: |
102 | drv_type = "4/8(mA)" ; |
103 | break; |
104 | case UNIPHIER_PIN_DRV_2BIT: |
105 | drv_type = "8/12/16/20(mA)" ; |
106 | break; |
107 | case UNIPHIER_PIN_DRV_3BIT: |
108 | drv_type = "4/5/7/9/11/12/14/16(mA)" ; |
109 | break; |
110 | case UNIPHIER_PIN_DRV_FIXED4: |
111 | drv_type = "4(mA)" ; |
112 | break; |
113 | case UNIPHIER_PIN_DRV_FIXED5: |
114 | drv_type = "5(mA)" ; |
115 | break; |
116 | case UNIPHIER_PIN_DRV_FIXED8: |
117 | drv_type = "8(mA)" ; |
118 | break; |
119 | case UNIPHIER_PIN_DRV_NONE: |
120 | drv_type = "NONE" ; |
121 | break; |
122 | default: |
123 | BUG(); |
124 | } |
125 | |
126 | seq_printf(m: s, fmt: " PULL_DIR=%s DRV_TYPE=%s" , pull_dir, drv_type); |
127 | } |
128 | #endif |
129 | |
130 | static const struct pinctrl_ops uniphier_pctlops = { |
131 | .get_groups_count = uniphier_pctl_get_groups_count, |
132 | .get_group_name = uniphier_pctl_get_group_name, |
133 | .get_group_pins = uniphier_pctl_get_group_pins, |
134 | #ifdef CONFIG_DEBUG_FS |
135 | .pin_dbg_show = uniphier_pctl_pin_dbg_show, |
136 | #endif |
137 | .dt_node_to_map = pinconf_generic_dt_node_to_map_all, |
138 | .dt_free_map = pinctrl_utils_free_map, |
139 | }; |
140 | |
141 | static const unsigned int uniphier_conf_drv_strengths_1bit[] = {4, 8}; |
142 | static const unsigned int uniphier_conf_drv_strengths_2bit[] = {8, 12, 16, 20}; |
143 | static const unsigned int uniphier_conf_drv_strengths_3bit[] = {4, 5, 7, 9, 11, |
144 | 12, 14, 16}; |
145 | static const unsigned int uniphier_conf_drv_strengths_fixed4[] = {4}; |
146 | static const unsigned int uniphier_conf_drv_strengths_fixed5[] = {5}; |
147 | static const unsigned int uniphier_conf_drv_strengths_fixed8[] = {8}; |
148 | |
149 | static int uniphier_conf_get_drvctrl_data(struct pinctrl_dev *pctldev, |
150 | unsigned int pin, unsigned int *reg, |
151 | unsigned int *shift, |
152 | unsigned int *mask, |
153 | const unsigned int **strengths) |
154 | { |
155 | const struct pin_desc *desc = pin_desc_get(pctldev, pin); |
156 | enum uniphier_pin_drv_type type = |
157 | uniphier_pin_get_drv_type(drv_data: desc->drv_data); |
158 | unsigned int base = 0; |
159 | unsigned int stride = 0; |
160 | unsigned int width = 0; |
161 | unsigned int drvctrl; |
162 | |
163 | switch (type) { |
164 | case UNIPHIER_PIN_DRV_1BIT: |
165 | *strengths = uniphier_conf_drv_strengths_1bit; |
166 | base = UNIPHIER_PINCTRL_DRVCTRL_BASE; |
167 | stride = 1; |
168 | width = 1; |
169 | break; |
170 | case UNIPHIER_PIN_DRV_2BIT: |
171 | *strengths = uniphier_conf_drv_strengths_2bit; |
172 | base = UNIPHIER_PINCTRL_DRV2CTRL_BASE; |
173 | stride = 2; |
174 | width = 2; |
175 | break; |
176 | case UNIPHIER_PIN_DRV_3BIT: |
177 | *strengths = uniphier_conf_drv_strengths_3bit; |
178 | base = UNIPHIER_PINCTRL_DRV3CTRL_BASE; |
179 | stride = 4; |
180 | width = 3; |
181 | break; |
182 | case UNIPHIER_PIN_DRV_FIXED4: |
183 | *strengths = uniphier_conf_drv_strengths_fixed4; |
184 | break; |
185 | case UNIPHIER_PIN_DRV_FIXED5: |
186 | *strengths = uniphier_conf_drv_strengths_fixed5; |
187 | break; |
188 | case UNIPHIER_PIN_DRV_FIXED8: |
189 | *strengths = uniphier_conf_drv_strengths_fixed8; |
190 | break; |
191 | default: |
192 | /* drive strength control is not supported for this pin */ |
193 | return -EINVAL; |
194 | } |
195 | |
196 | drvctrl = uniphier_pin_get_drvctrl(drv_data: desc->drv_data); |
197 | drvctrl *= stride; |
198 | |
199 | *reg = base + drvctrl / 32 * 4; |
200 | *shift = drvctrl % 32; |
201 | *mask = (1U << width) - 1; |
202 | |
203 | return 0; |
204 | } |
205 | |
206 | static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev, |
207 | unsigned int pin, |
208 | enum pin_config_param param) |
209 | { |
210 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
211 | const struct pin_desc *desc = pin_desc_get(pctldev, pin); |
212 | enum uniphier_pin_pull_dir pull_dir = |
213 | uniphier_pin_get_pull_dir(drv_data: desc->drv_data); |
214 | unsigned int pupdctrl, reg, shift, val; |
215 | unsigned int expected = 1; |
216 | int ret; |
217 | |
218 | switch (param) { |
219 | case PIN_CONFIG_BIAS_DISABLE: |
220 | if (pull_dir == UNIPHIER_PIN_PULL_NONE) |
221 | return 0; |
222 | if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || |
223 | pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) |
224 | return -EINVAL; |
225 | expected = 0; |
226 | break; |
227 | case PIN_CONFIG_BIAS_PULL_UP: |
228 | if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED) |
229 | return 0; |
230 | if (pull_dir != UNIPHIER_PIN_PULL_UP) |
231 | return -EINVAL; |
232 | break; |
233 | case PIN_CONFIG_BIAS_PULL_DOWN: |
234 | if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) |
235 | return 0; |
236 | if (pull_dir != UNIPHIER_PIN_PULL_DOWN) |
237 | return -EINVAL; |
238 | break; |
239 | default: |
240 | BUG(); |
241 | } |
242 | |
243 | pupdctrl = uniphier_pin_get_pupdctrl(drv_data: desc->drv_data); |
244 | |
245 | reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; |
246 | shift = pupdctrl % 32; |
247 | |
248 | ret = regmap_read(map: priv->regmap, reg, val: &val); |
249 | if (ret) |
250 | return ret; |
251 | |
252 | val = (val >> shift) & 1; |
253 | |
254 | return (val == expected) ? 0 : -EINVAL; |
255 | } |
256 | |
257 | static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev, |
258 | unsigned int pin, u32 *strength) |
259 | { |
260 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
261 | unsigned int reg, shift, mask, val; |
262 | const unsigned int *strengths; |
263 | int ret; |
264 | |
265 | ret = uniphier_conf_get_drvctrl_data(pctldev, pin, reg: ®, shift: &shift, |
266 | mask: &mask, strengths: &strengths); |
267 | if (ret) |
268 | return ret; |
269 | |
270 | if (mask) { |
271 | ret = regmap_read(map: priv->regmap, reg, val: &val); |
272 | if (ret) |
273 | return ret; |
274 | } else { |
275 | val = 0; |
276 | } |
277 | |
278 | *strength = strengths[(val >> shift) & mask]; |
279 | |
280 | return 0; |
281 | } |
282 | |
283 | static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev, |
284 | unsigned int pin) |
285 | { |
286 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
287 | const struct pin_desc *desc = pin_desc_get(pctldev, pin); |
288 | unsigned int iectrl = uniphier_pin_get_iectrl(drv_data: desc->drv_data); |
289 | unsigned int reg, mask, val; |
290 | int ret; |
291 | |
292 | if (iectrl == UNIPHIER_PIN_IECTRL_NONE) |
293 | /* This pin is always input-enabled. */ |
294 | return 0; |
295 | |
296 | if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) |
297 | iectrl = pin; |
298 | |
299 | reg = UNIPHIER_PINCTRL_IECTRL_BASE + iectrl / 32 * 4; |
300 | mask = BIT(iectrl % 32); |
301 | |
302 | ret = regmap_read(map: priv->regmap, reg, val: &val); |
303 | if (ret) |
304 | return ret; |
305 | |
306 | return val & mask ? 0 : -EINVAL; |
307 | } |
308 | |
309 | static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev, |
310 | unsigned pin, |
311 | unsigned long *configs) |
312 | { |
313 | enum pin_config_param param = pinconf_to_config_param(config: *configs); |
314 | bool has_arg = false; |
315 | u32 arg; |
316 | int ret; |
317 | |
318 | switch (param) { |
319 | case PIN_CONFIG_BIAS_DISABLE: |
320 | case PIN_CONFIG_BIAS_PULL_UP: |
321 | case PIN_CONFIG_BIAS_PULL_DOWN: |
322 | ret = uniphier_conf_pin_bias_get(pctldev, pin, param); |
323 | break; |
324 | case PIN_CONFIG_DRIVE_STRENGTH: |
325 | ret = uniphier_conf_pin_drive_get(pctldev, pin, strength: &arg); |
326 | has_arg = true; |
327 | break; |
328 | case PIN_CONFIG_INPUT_ENABLE: |
329 | ret = uniphier_conf_pin_input_enable_get(pctldev, pin); |
330 | break; |
331 | default: |
332 | /* unsupported parameter */ |
333 | ret = -EINVAL; |
334 | break; |
335 | } |
336 | |
337 | if (ret == 0 && has_arg) |
338 | *configs = pinconf_to_config_packed(param, argument: arg); |
339 | |
340 | return ret; |
341 | } |
342 | |
343 | static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, |
344 | unsigned int pin, |
345 | enum pin_config_param param, u32 arg) |
346 | { |
347 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
348 | const struct pin_desc *desc = pin_desc_get(pctldev, pin); |
349 | enum uniphier_pin_pull_dir pull_dir = |
350 | uniphier_pin_get_pull_dir(drv_data: desc->drv_data); |
351 | unsigned int pupdctrl, reg, shift; |
352 | unsigned int val = 1; |
353 | |
354 | switch (param) { |
355 | case PIN_CONFIG_BIAS_DISABLE: |
356 | if (pull_dir == UNIPHIER_PIN_PULL_NONE) |
357 | return 0; |
358 | if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || |
359 | pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) { |
360 | dev_err(pctldev->dev, |
361 | "can not disable pull register for pin %s\n" , |
362 | desc->name); |
363 | return -EINVAL; |
364 | } |
365 | val = 0; |
366 | break; |
367 | case PIN_CONFIG_BIAS_PULL_UP: |
368 | if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED && arg != 0) |
369 | return 0; |
370 | if (pull_dir != UNIPHIER_PIN_PULL_UP) { |
371 | dev_err(pctldev->dev, |
372 | "pull-up is unsupported for pin %s\n" , |
373 | desc->name); |
374 | return -EINVAL; |
375 | } |
376 | if (arg == 0) { |
377 | dev_err(pctldev->dev, "pull-up can not be total\n" ); |
378 | return -EINVAL; |
379 | } |
380 | break; |
381 | case PIN_CONFIG_BIAS_PULL_DOWN: |
382 | if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED && arg != 0) |
383 | return 0; |
384 | if (pull_dir != UNIPHIER_PIN_PULL_DOWN) { |
385 | dev_err(pctldev->dev, |
386 | "pull-down is unsupported for pin %s\n" , |
387 | desc->name); |
388 | return -EINVAL; |
389 | } |
390 | if (arg == 0) { |
391 | dev_err(pctldev->dev, "pull-down can not be total\n" ); |
392 | return -EINVAL; |
393 | } |
394 | break; |
395 | case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: |
396 | if (pull_dir == UNIPHIER_PIN_PULL_NONE) { |
397 | dev_err(pctldev->dev, |
398 | "pull-up/down is unsupported for pin %s\n" , |
399 | desc->name); |
400 | return -EINVAL; |
401 | } |
402 | |
403 | if (arg == 0) |
404 | return 0; /* configuration ingored */ |
405 | break; |
406 | default: |
407 | BUG(); |
408 | } |
409 | |
410 | pupdctrl = uniphier_pin_get_pupdctrl(drv_data: desc->drv_data); |
411 | |
412 | reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; |
413 | shift = pupdctrl % 32; |
414 | |
415 | return regmap_update_bits(map: priv->regmap, reg, mask: 1 << shift, val: val << shift); |
416 | } |
417 | |
418 | static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev, |
419 | unsigned int pin, u32 strength) |
420 | { |
421 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
422 | const struct pin_desc *desc = pin_desc_get(pctldev, pin); |
423 | unsigned int reg, shift, mask, val; |
424 | const unsigned int *strengths; |
425 | int ret; |
426 | |
427 | ret = uniphier_conf_get_drvctrl_data(pctldev, pin, reg: ®, shift: &shift, |
428 | mask: &mask, strengths: &strengths); |
429 | if (ret) { |
430 | dev_err(pctldev->dev, "cannot set drive strength for pin %s\n" , |
431 | desc->name); |
432 | return ret; |
433 | } |
434 | |
435 | for (val = 0; val <= mask; val++) { |
436 | if (strengths[val] > strength) |
437 | break; |
438 | } |
439 | |
440 | if (val == 0) { |
441 | dev_err(pctldev->dev, |
442 | "unsupported drive strength %u mA for pin %s\n" , |
443 | strength, desc->name); |
444 | return -EINVAL; |
445 | } |
446 | |
447 | if (!mask) |
448 | return 0; |
449 | |
450 | val--; |
451 | |
452 | return regmap_update_bits(map: priv->regmap, reg, |
453 | mask: mask << shift, val: val << shift); |
454 | } |
455 | |
456 | static int uniphier_conf_pin_input_enable(struct pinctrl_dev *pctldev, |
457 | unsigned int pin, u32 enable) |
458 | { |
459 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
460 | const struct pin_desc *desc = pin_desc_get(pctldev, pin); |
461 | unsigned int iectrl = uniphier_pin_get_iectrl(drv_data: desc->drv_data); |
462 | unsigned int reg, mask; |
463 | |
464 | /* |
465 | * Multiple pins share one input enable, per-pin disabling is |
466 | * impossible. |
467 | */ |
468 | if (!(priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) && |
469 | !enable) |
470 | return -EINVAL; |
471 | |
472 | /* UNIPHIER_PIN_IECTRL_NONE means the pin is always input-enabled */ |
473 | if (iectrl == UNIPHIER_PIN_IECTRL_NONE) |
474 | return enable ? 0 : -EINVAL; |
475 | |
476 | if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) |
477 | iectrl = pin; |
478 | |
479 | reg = UNIPHIER_PINCTRL_IECTRL_BASE + iectrl / 32 * 4; |
480 | mask = BIT(iectrl % 32); |
481 | |
482 | return regmap_update_bits(map: priv->regmap, reg, mask, val: enable ? mask : 0); |
483 | } |
484 | |
485 | static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev, |
486 | unsigned pin, |
487 | unsigned long *configs, |
488 | unsigned num_configs) |
489 | { |
490 | int i, ret; |
491 | |
492 | for (i = 0; i < num_configs; i++) { |
493 | enum pin_config_param param = |
494 | pinconf_to_config_param(config: configs[i]); |
495 | u32 arg = pinconf_to_config_argument(config: configs[i]); |
496 | |
497 | switch (param) { |
498 | case PIN_CONFIG_BIAS_DISABLE: |
499 | case PIN_CONFIG_BIAS_PULL_UP: |
500 | case PIN_CONFIG_BIAS_PULL_DOWN: |
501 | case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: |
502 | ret = uniphier_conf_pin_bias_set(pctldev, pin, |
503 | param, arg); |
504 | break; |
505 | case PIN_CONFIG_DRIVE_STRENGTH: |
506 | ret = uniphier_conf_pin_drive_set(pctldev, pin, strength: arg); |
507 | break; |
508 | case PIN_CONFIG_INPUT_ENABLE: |
509 | ret = uniphier_conf_pin_input_enable(pctldev, pin, enable: arg); |
510 | break; |
511 | default: |
512 | dev_err(pctldev->dev, |
513 | "unsupported configuration parameter %u\n" , |
514 | param); |
515 | return -EINVAL; |
516 | } |
517 | |
518 | if (ret) |
519 | return ret; |
520 | } |
521 | |
522 | return 0; |
523 | } |
524 | |
525 | static int uniphier_conf_pin_config_group_set(struct pinctrl_dev *pctldev, |
526 | unsigned selector, |
527 | unsigned long *configs, |
528 | unsigned num_configs) |
529 | { |
530 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
531 | const unsigned *pins = priv->socdata->groups[selector].pins; |
532 | unsigned num_pins = priv->socdata->groups[selector].num_pins; |
533 | int i, ret; |
534 | |
535 | for (i = 0; i < num_pins; i++) { |
536 | ret = uniphier_conf_pin_config_set(pctldev, pin: pins[i], |
537 | configs, num_configs); |
538 | if (ret) |
539 | return ret; |
540 | } |
541 | |
542 | return 0; |
543 | } |
544 | |
545 | static const struct pinconf_ops uniphier_confops = { |
546 | .is_generic = true, |
547 | .pin_config_get = uniphier_conf_pin_config_get, |
548 | .pin_config_set = uniphier_conf_pin_config_set, |
549 | .pin_config_group_set = uniphier_conf_pin_config_group_set, |
550 | }; |
551 | |
552 | static int uniphier_pmx_get_functions_count(struct pinctrl_dev *pctldev) |
553 | { |
554 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
555 | |
556 | return priv->socdata->functions_count; |
557 | } |
558 | |
559 | static const char *uniphier_pmx_get_function_name(struct pinctrl_dev *pctldev, |
560 | unsigned selector) |
561 | { |
562 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
563 | |
564 | return priv->socdata->functions[selector].name; |
565 | } |
566 | |
567 | static int uniphier_pmx_get_function_groups(struct pinctrl_dev *pctldev, |
568 | unsigned selector, |
569 | const char * const **groups, |
570 | unsigned *num_groups) |
571 | { |
572 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
573 | |
574 | *groups = priv->socdata->functions[selector].groups; |
575 | *num_groups = priv->socdata->functions[selector].num_groups; |
576 | |
577 | return 0; |
578 | } |
579 | |
580 | static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin, |
581 | int muxval) |
582 | { |
583 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
584 | unsigned int mux_bits, reg_stride, reg, reg_end, shift, mask; |
585 | bool load_pinctrl; |
586 | int ret; |
587 | |
588 | /* some pins need input-enabling */ |
589 | ret = uniphier_conf_pin_input_enable(pctldev, pin, enable: 1); |
590 | if (ret) |
591 | return ret; |
592 | |
593 | if (muxval < 0) |
594 | return 0; /* dedicated pin; nothing to do for pin-mux */ |
595 | |
596 | if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) { |
597 | /* |
598 | * Mode reg_offset bit_position |
599 | * Normal 4 * n shift+3:shift |
600 | * Debug 4 * n shift+7:shift+4 |
601 | */ |
602 | mux_bits = 4; |
603 | reg_stride = 8; |
604 | load_pinctrl = true; |
605 | } else { |
606 | /* |
607 | * Mode reg_offset bit_position |
608 | * Normal 8 * n shift+3:shift |
609 | * Debug 8 * n + 4 shift+3:shift |
610 | */ |
611 | mux_bits = 8; |
612 | reg_stride = 4; |
613 | load_pinctrl = false; |
614 | } |
615 | |
616 | reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride; |
617 | reg_end = reg + reg_stride; |
618 | shift = pin * mux_bits % 32; |
619 | mask = (1U << mux_bits) - 1; |
620 | |
621 | /* |
622 | * If reg_stride is greater than 4, the MSB of each pinsel shall be |
623 | * stored in the offset+4. |
624 | */ |
625 | for (; reg < reg_end; reg += 4) { |
626 | ret = regmap_update_bits(map: priv->regmap, reg, |
627 | mask: mask << shift, val: muxval << shift); |
628 | if (ret) |
629 | return ret; |
630 | muxval >>= mux_bits; |
631 | } |
632 | |
633 | if (load_pinctrl) { |
634 | ret = regmap_write(map: priv->regmap, |
635 | UNIPHIER_PINCTRL_LOAD_PINMUX, val: 1); |
636 | if (ret) |
637 | return ret; |
638 | } |
639 | |
640 | return 0; |
641 | } |
642 | |
643 | static int uniphier_pmx_set_mux(struct pinctrl_dev *pctldev, |
644 | unsigned func_selector, |
645 | unsigned group_selector) |
646 | { |
647 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
648 | const struct uniphier_pinctrl_group *grp = |
649 | &priv->socdata->groups[group_selector]; |
650 | int i; |
651 | int ret; |
652 | |
653 | for (i = 0; i < grp->num_pins; i++) { |
654 | ret = uniphier_pmx_set_one_mux(pctldev, pin: grp->pins[i], |
655 | muxval: grp->muxvals[i]); |
656 | if (ret) |
657 | return ret; |
658 | } |
659 | |
660 | return 0; |
661 | } |
662 | |
663 | static int uniphier_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, |
664 | struct pinctrl_gpio_range *range, |
665 | unsigned offset) |
666 | { |
667 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); |
668 | unsigned int gpio_offset; |
669 | int muxval, i; |
670 | |
671 | if (range->pins) { |
672 | for (i = 0; i < range->npins; i++) |
673 | if (range->pins[i] == offset) |
674 | break; |
675 | |
676 | if (WARN_ON(i == range->npins)) |
677 | return -EINVAL; |
678 | |
679 | gpio_offset = i; |
680 | } else { |
681 | gpio_offset = offset - range->pin_base; |
682 | } |
683 | |
684 | gpio_offset += range->id; |
685 | |
686 | muxval = priv->socdata->get_gpio_muxval(offset, gpio_offset); |
687 | |
688 | return uniphier_pmx_set_one_mux(pctldev, pin: offset, muxval); |
689 | } |
690 | |
691 | static const struct pinmux_ops uniphier_pmxops = { |
692 | .get_functions_count = uniphier_pmx_get_functions_count, |
693 | .get_function_name = uniphier_pmx_get_function_name, |
694 | .get_function_groups = uniphier_pmx_get_function_groups, |
695 | .set_mux = uniphier_pmx_set_mux, |
696 | .gpio_request_enable = uniphier_pmx_gpio_request_enable, |
697 | .strict = true, |
698 | }; |
699 | |
700 | #ifdef CONFIG_PM_SLEEP |
701 | static int uniphier_pinctrl_suspend(struct device *dev) |
702 | { |
703 | struct uniphier_pinctrl_priv *priv = dev_get_drvdata(dev); |
704 | struct uniphier_pinctrl_reg_region *r; |
705 | int ret; |
706 | |
707 | list_for_each_entry(r, &priv->reg_regions, node) { |
708 | ret = regmap_bulk_read(map: priv->regmap, reg: r->base, val: r->vals, |
709 | val_count: r->nregs); |
710 | if (ret) |
711 | return ret; |
712 | } |
713 | |
714 | return 0; |
715 | } |
716 | |
717 | static int uniphier_pinctrl_resume(struct device *dev) |
718 | { |
719 | struct uniphier_pinctrl_priv *priv = dev_get_drvdata(dev); |
720 | struct uniphier_pinctrl_reg_region *r; |
721 | int ret; |
722 | |
723 | list_for_each_entry(r, &priv->reg_regions, node) { |
724 | ret = regmap_bulk_write(map: priv->regmap, reg: r->base, val: r->vals, |
725 | val_count: r->nregs); |
726 | if (ret) |
727 | return ret; |
728 | } |
729 | |
730 | if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) { |
731 | ret = regmap_write(map: priv->regmap, |
732 | UNIPHIER_PINCTRL_LOAD_PINMUX, val: 1); |
733 | if (ret) |
734 | return ret; |
735 | } |
736 | |
737 | return 0; |
738 | } |
739 | |
740 | static int uniphier_pinctrl_add_reg_region(struct device *dev, |
741 | struct uniphier_pinctrl_priv *priv, |
742 | unsigned int base, |
743 | unsigned int count, |
744 | unsigned int width) |
745 | { |
746 | struct uniphier_pinctrl_reg_region *region; |
747 | unsigned int nregs; |
748 | |
749 | if (!count) |
750 | return 0; |
751 | |
752 | nregs = DIV_ROUND_UP(count * width, 32); |
753 | |
754 | region = devm_kzalloc(dev, struct_size(region, vals, nregs), |
755 | GFP_KERNEL); |
756 | if (!region) |
757 | return -ENOMEM; |
758 | |
759 | region->base = base; |
760 | region->nregs = nregs; |
761 | |
762 | list_add_tail(new: ®ion->node, head: &priv->reg_regions); |
763 | |
764 | return 0; |
765 | } |
766 | #endif |
767 | |
768 | static int uniphier_pinctrl_pm_init(struct device *dev, |
769 | struct uniphier_pinctrl_priv *priv) |
770 | { |
771 | #ifdef CONFIG_PM_SLEEP |
772 | const struct uniphier_pinctrl_socdata *socdata = priv->socdata; |
773 | unsigned int num_drvctrl = 0; |
774 | unsigned int num_drv2ctrl = 0; |
775 | unsigned int num_drv3ctrl = 0; |
776 | unsigned int num_pupdctrl = 0; |
777 | unsigned int num_iectrl = 0; |
778 | unsigned int iectrl, drvctrl, pupdctrl; |
779 | enum uniphier_pin_drv_type drv_type; |
780 | enum uniphier_pin_pull_dir pull_dir; |
781 | int i, ret; |
782 | |
783 | for (i = 0; i < socdata->npins; i++) { |
784 | void *drv_data = socdata->pins[i].drv_data; |
785 | |
786 | drvctrl = uniphier_pin_get_drvctrl(drv_data); |
787 | drv_type = uniphier_pin_get_drv_type(drv_data); |
788 | pupdctrl = uniphier_pin_get_pupdctrl(drv_data); |
789 | pull_dir = uniphier_pin_get_pull_dir(drv_data); |
790 | iectrl = uniphier_pin_get_iectrl(drv_data); |
791 | |
792 | switch (drv_type) { |
793 | case UNIPHIER_PIN_DRV_1BIT: |
794 | num_drvctrl = max(num_drvctrl, drvctrl + 1); |
795 | break; |
796 | case UNIPHIER_PIN_DRV_2BIT: |
797 | num_drv2ctrl = max(num_drv2ctrl, drvctrl + 1); |
798 | break; |
799 | case UNIPHIER_PIN_DRV_3BIT: |
800 | num_drv3ctrl = max(num_drv3ctrl, drvctrl + 1); |
801 | break; |
802 | default: |
803 | break; |
804 | } |
805 | |
806 | if (pull_dir == UNIPHIER_PIN_PULL_UP || |
807 | pull_dir == UNIPHIER_PIN_PULL_DOWN) |
808 | num_pupdctrl = max(num_pupdctrl, pupdctrl + 1); |
809 | |
810 | if (iectrl != UNIPHIER_PIN_IECTRL_NONE) { |
811 | if (socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) |
812 | iectrl = i; |
813 | num_iectrl = max(num_iectrl, iectrl + 1); |
814 | } |
815 | } |
816 | |
817 | INIT_LIST_HEAD(list: &priv->reg_regions); |
818 | |
819 | ret = uniphier_pinctrl_add_reg_region(dev, priv, |
820 | UNIPHIER_PINCTRL_PINMUX_BASE, |
821 | count: socdata->npins, width: 8); |
822 | if (ret) |
823 | return ret; |
824 | |
825 | ret = uniphier_pinctrl_add_reg_region(dev, priv, |
826 | UNIPHIER_PINCTRL_DRVCTRL_BASE, |
827 | count: num_drvctrl, width: 1); |
828 | if (ret) |
829 | return ret; |
830 | |
831 | ret = uniphier_pinctrl_add_reg_region(dev, priv, |
832 | UNIPHIER_PINCTRL_DRV2CTRL_BASE, |
833 | count: num_drv2ctrl, width: 2); |
834 | if (ret) |
835 | return ret; |
836 | |
837 | ret = uniphier_pinctrl_add_reg_region(dev, priv, |
838 | UNIPHIER_PINCTRL_DRV3CTRL_BASE, |
839 | count: num_drv3ctrl, width: 3); |
840 | if (ret) |
841 | return ret; |
842 | |
843 | ret = uniphier_pinctrl_add_reg_region(dev, priv, |
844 | UNIPHIER_PINCTRL_PUPDCTRL_BASE, |
845 | count: num_pupdctrl, width: 1); |
846 | if (ret) |
847 | return ret; |
848 | |
849 | ret = uniphier_pinctrl_add_reg_region(dev, priv, |
850 | UNIPHIER_PINCTRL_IECTRL_BASE, |
851 | count: num_iectrl, width: 1); |
852 | if (ret) |
853 | return ret; |
854 | #endif |
855 | return 0; |
856 | } |
857 | |
858 | const struct dev_pm_ops uniphier_pinctrl_pm_ops = { |
859 | SET_LATE_SYSTEM_SLEEP_PM_OPS(uniphier_pinctrl_suspend, |
860 | uniphier_pinctrl_resume) |
861 | }; |
862 | |
863 | int uniphier_pinctrl_probe(struct platform_device *pdev, |
864 | const struct uniphier_pinctrl_socdata *socdata) |
865 | { |
866 | struct device *dev = &pdev->dev; |
867 | struct uniphier_pinctrl_priv *priv; |
868 | struct device_node *parent; |
869 | int ret; |
870 | |
871 | if (!socdata || |
872 | !socdata->pins || !socdata->npins || |
873 | !socdata->groups || !socdata->groups_count || |
874 | !socdata->functions || !socdata->functions_count) { |
875 | dev_err(dev, "pinctrl socdata lacks necessary members\n" ); |
876 | return -EINVAL; |
877 | } |
878 | |
879 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
880 | if (!priv) |
881 | return -ENOMEM; |
882 | |
883 | parent = of_get_parent(node: dev->of_node); |
884 | priv->regmap = syscon_node_to_regmap(np: parent); |
885 | of_node_put(node: parent); |
886 | |
887 | if (IS_ERR(ptr: priv->regmap)) { |
888 | dev_err(dev, "failed to get regmap\n" ); |
889 | return PTR_ERR(ptr: priv->regmap); |
890 | } |
891 | |
892 | priv->socdata = socdata; |
893 | priv->pctldesc.name = dev->driver->name; |
894 | priv->pctldesc.pins = socdata->pins; |
895 | priv->pctldesc.npins = socdata->npins; |
896 | priv->pctldesc.pctlops = &uniphier_pctlops; |
897 | priv->pctldesc.pmxops = &uniphier_pmxops; |
898 | priv->pctldesc.confops = &uniphier_confops; |
899 | priv->pctldesc.owner = dev->driver->owner; |
900 | |
901 | ret = uniphier_pinctrl_pm_init(dev, priv); |
902 | if (ret) |
903 | return ret; |
904 | |
905 | priv->pctldev = devm_pinctrl_register(dev, pctldesc: &priv->pctldesc, driver_data: priv); |
906 | if (IS_ERR(ptr: priv->pctldev)) { |
907 | dev_err(dev, "failed to register UniPhier pinctrl driver\n" ); |
908 | return PTR_ERR(ptr: priv->pctldev); |
909 | } |
910 | |
911 | platform_set_drvdata(pdev, data: priv); |
912 | |
913 | return 0; |
914 | } |
915 | |