1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * MediaTek Pinctrl Moore Driver, which implement the generic dt-binding |
4 | * pinctrl-bindings.txt for MediaTek SoC. |
5 | * |
6 | * Copyright (C) 2017-2018 MediaTek Inc. |
7 | * Author: Sean Wang <sean.wang@mediatek.com> |
8 | * |
9 | */ |
10 | |
11 | #include <dt-bindings/pinctrl/mt65xx.h> |
12 | #include <linux/gpio/driver.h> |
13 | |
14 | #include <linux/pinctrl/consumer.h> |
15 | |
16 | #include "pinctrl-moore.h" |
17 | |
18 | #define PINCTRL_PINCTRL_DEV KBUILD_MODNAME |
19 | |
20 | /* Custom pinconf parameters */ |
21 | #define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) |
22 | #define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) |
23 | #define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3) |
24 | #define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4) |
25 | |
26 | static const struct pinconf_generic_params mtk_custom_bindings[] = { |
27 | {"mediatek,tdsel" , MTK_PIN_CONFIG_TDSEL, 0}, |
28 | {"mediatek,rdsel" , MTK_PIN_CONFIG_RDSEL, 0}, |
29 | {"mediatek,pull-up-adv" , MTK_PIN_CONFIG_PU_ADV, 1}, |
30 | {"mediatek,pull-down-adv" , MTK_PIN_CONFIG_PD_ADV, 1}, |
31 | }; |
32 | |
33 | #ifdef CONFIG_DEBUG_FS |
34 | static const struct pin_config_item mtk_conf_items[] = { |
35 | PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel" , NULL, true), |
36 | PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel" , NULL, true), |
37 | PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv" , NULL, true), |
38 | PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv" , NULL, true), |
39 | }; |
40 | #endif |
41 | |
42 | static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev, |
43 | unsigned int selector, unsigned int group) |
44 | { |
45 | struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); |
46 | struct function_desc *func; |
47 | struct group_desc *grp; |
48 | int i, err; |
49 | |
50 | func = pinmux_generic_get_function(pctldev, selector); |
51 | if (!func) |
52 | return -EINVAL; |
53 | |
54 | grp = pinctrl_generic_get_group(pctldev, group_selector: group); |
55 | if (!grp) |
56 | return -EINVAL; |
57 | |
58 | dev_dbg(pctldev->dev, "enable function %s group %s\n" , |
59 | func->name, grp->grp.name); |
60 | |
61 | for (i = 0; i < grp->grp.npins; i++) { |
62 | const struct mtk_pin_desc *desc; |
63 | int *pin_modes = grp->data; |
64 | int pin = grp->grp.pins[i]; |
65 | |
66 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; |
67 | if (!desc->name) |
68 | return -ENOTSUPP; |
69 | |
70 | err = mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_MODE, |
71 | value: pin_modes[i]); |
72 | |
73 | if (err) |
74 | return err; |
75 | } |
76 | |
77 | return 0; |
78 | } |
79 | |
80 | static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, |
81 | struct pinctrl_gpio_range *range, |
82 | unsigned int pin) |
83 | { |
84 | struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); |
85 | const struct mtk_pin_desc *desc; |
86 | |
87 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; |
88 | if (!desc->name) |
89 | return -ENOTSUPP; |
90 | |
91 | return mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_MODE, |
92 | value: hw->soc->gpio_m); |
93 | } |
94 | |
95 | static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, |
96 | struct pinctrl_gpio_range *range, |
97 | unsigned int pin, bool input) |
98 | { |
99 | struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); |
100 | const struct mtk_pin_desc *desc; |
101 | |
102 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; |
103 | if (!desc->name) |
104 | return -ENOTSUPP; |
105 | |
106 | /* hardware would take 0 as input direction */ |
107 | return mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_DIR, value: !input); |
108 | } |
109 | |
110 | static int mtk_pinconf_get(struct pinctrl_dev *pctldev, |
111 | unsigned int pin, unsigned long *config) |
112 | { |
113 | struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); |
114 | u32 param = pinconf_to_config_param(config: *config); |
115 | int val, val2, err, pullup, reg, ret = 1; |
116 | const struct mtk_pin_desc *desc; |
117 | |
118 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; |
119 | if (!desc->name) |
120 | return -ENOTSUPP; |
121 | |
122 | switch (param) { |
123 | case PIN_CONFIG_BIAS_DISABLE: |
124 | if (hw->soc->bias_get_combo) { |
125 | err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); |
126 | if (err) |
127 | return err; |
128 | if (ret != MTK_PUPD_SET_R1R0_00 && ret != MTK_DISABLE) |
129 | return -EINVAL; |
130 | } else if (hw->soc->bias_disable_get) { |
131 | err = hw->soc->bias_disable_get(hw, desc, &ret); |
132 | if (err) |
133 | return err; |
134 | } else { |
135 | return -ENOTSUPP; |
136 | } |
137 | break; |
138 | case PIN_CONFIG_BIAS_PULL_UP: |
139 | if (hw->soc->bias_get_combo) { |
140 | err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); |
141 | if (err) |
142 | return err; |
143 | if (ret == MTK_PUPD_SET_R1R0_00 || ret == MTK_DISABLE) |
144 | return -EINVAL; |
145 | if (!pullup) |
146 | return -EINVAL; |
147 | } else if (hw->soc->bias_get) { |
148 | err = hw->soc->bias_get(hw, desc, 1, &ret); |
149 | if (err) |
150 | return err; |
151 | } else { |
152 | return -ENOTSUPP; |
153 | } |
154 | break; |
155 | case PIN_CONFIG_BIAS_PULL_DOWN: |
156 | if (hw->soc->bias_get_combo) { |
157 | err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); |
158 | if (err) |
159 | return err; |
160 | if (ret == MTK_PUPD_SET_R1R0_00 || ret == MTK_DISABLE) |
161 | return -EINVAL; |
162 | if (pullup) |
163 | return -EINVAL; |
164 | } else if (hw->soc->bias_get) { |
165 | err = hw->soc->bias_get(hw, desc, 0, &ret); |
166 | if (err) |
167 | return err; |
168 | } else { |
169 | return -ENOTSUPP; |
170 | } |
171 | break; |
172 | case PIN_CONFIG_SLEW_RATE: |
173 | err = mtk_hw_get_value(hw, desc, field: PINCTRL_PIN_REG_SR, value: &val); |
174 | if (err) |
175 | return err; |
176 | |
177 | if (!val) |
178 | return -EINVAL; |
179 | |
180 | break; |
181 | case PIN_CONFIG_INPUT_ENABLE: |
182 | case PIN_CONFIG_OUTPUT_ENABLE: |
183 | err = mtk_hw_get_value(hw, desc, field: PINCTRL_PIN_REG_DIR, value: &val); |
184 | if (err) |
185 | return err; |
186 | |
187 | /* HW takes input mode as zero; output mode as non-zero */ |
188 | if ((val && param == PIN_CONFIG_INPUT_ENABLE) || |
189 | (!val && param == PIN_CONFIG_OUTPUT_ENABLE)) |
190 | return -EINVAL; |
191 | |
192 | break; |
193 | case PIN_CONFIG_INPUT_SCHMITT_ENABLE: |
194 | err = mtk_hw_get_value(hw, desc, field: PINCTRL_PIN_REG_DIR, value: &val); |
195 | if (err) |
196 | return err; |
197 | |
198 | err = mtk_hw_get_value(hw, desc, field: PINCTRL_PIN_REG_SMT, value: &val2); |
199 | if (err) |
200 | return err; |
201 | |
202 | if (val || !val2) |
203 | return -EINVAL; |
204 | |
205 | break; |
206 | case PIN_CONFIG_DRIVE_STRENGTH: |
207 | if (hw->soc->drive_get) { |
208 | err = hw->soc->drive_get(hw, desc, &ret); |
209 | if (err) |
210 | return err; |
211 | } else { |
212 | err = -ENOTSUPP; |
213 | } |
214 | break; |
215 | case MTK_PIN_CONFIG_TDSEL: |
216 | case MTK_PIN_CONFIG_RDSEL: |
217 | reg = (param == MTK_PIN_CONFIG_TDSEL) ? |
218 | PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; |
219 | |
220 | err = mtk_hw_get_value(hw, desc, field: reg, value: &val); |
221 | if (err) |
222 | return err; |
223 | |
224 | ret = val; |
225 | |
226 | break; |
227 | case MTK_PIN_CONFIG_PU_ADV: |
228 | case MTK_PIN_CONFIG_PD_ADV: |
229 | if (hw->soc->adv_pull_get) { |
230 | bool pullup; |
231 | |
232 | pullup = param == MTK_PIN_CONFIG_PU_ADV; |
233 | err = hw->soc->adv_pull_get(hw, desc, pullup, &ret); |
234 | if (err) |
235 | return err; |
236 | } else { |
237 | return -ENOTSUPP; |
238 | } |
239 | break; |
240 | default: |
241 | return -ENOTSUPP; |
242 | } |
243 | |
244 | *config = pinconf_to_config_packed(param, argument: ret); |
245 | |
246 | return 0; |
247 | } |
248 | |
249 | static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, |
250 | unsigned long *configs, unsigned int num_configs) |
251 | { |
252 | struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); |
253 | const struct mtk_pin_desc *desc; |
254 | u32 reg, param, arg; |
255 | int cfg, err = 0; |
256 | |
257 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; |
258 | if (!desc->name) |
259 | return -ENOTSUPP; |
260 | |
261 | for (cfg = 0; cfg < num_configs; cfg++) { |
262 | param = pinconf_to_config_param(config: configs[cfg]); |
263 | arg = pinconf_to_config_argument(config: configs[cfg]); |
264 | |
265 | switch (param) { |
266 | case PIN_CONFIG_BIAS_DISABLE: |
267 | if (hw->soc->bias_set_combo) { |
268 | err = hw->soc->bias_set_combo(hw, desc, 0, MTK_DISABLE); |
269 | if (err) |
270 | return err; |
271 | } else if (hw->soc->bias_disable_set) { |
272 | err = hw->soc->bias_disable_set(hw, desc); |
273 | if (err) |
274 | return err; |
275 | } else { |
276 | return -ENOTSUPP; |
277 | } |
278 | break; |
279 | case PIN_CONFIG_BIAS_PULL_UP: |
280 | if (hw->soc->bias_set_combo) { |
281 | err = hw->soc->bias_set_combo(hw, desc, 1, arg); |
282 | if (err) |
283 | return err; |
284 | } else if (hw->soc->bias_set) { |
285 | err = hw->soc->bias_set(hw, desc, 1); |
286 | if (err) |
287 | return err; |
288 | } else { |
289 | return -ENOTSUPP; |
290 | } |
291 | break; |
292 | case PIN_CONFIG_BIAS_PULL_DOWN: |
293 | if (hw->soc->bias_set_combo) { |
294 | err = hw->soc->bias_set_combo(hw, desc, 0, arg); |
295 | if (err) |
296 | return err; |
297 | } else if (hw->soc->bias_set) { |
298 | err = hw->soc->bias_set(hw, desc, 0); |
299 | if (err) |
300 | return err; |
301 | } else { |
302 | return -ENOTSUPP; |
303 | } |
304 | break; |
305 | case PIN_CONFIG_OUTPUT_ENABLE: |
306 | err = mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_SMT, |
307 | MTK_DISABLE); |
308 | if (err) |
309 | goto err; |
310 | |
311 | err = mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_DIR, |
312 | MTK_OUTPUT); |
313 | if (err) |
314 | goto err; |
315 | break; |
316 | case PIN_CONFIG_INPUT_ENABLE: |
317 | |
318 | if (hw->soc->ies_present) { |
319 | mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_IES, |
320 | MTK_ENABLE); |
321 | } |
322 | |
323 | err = mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_DIR, |
324 | MTK_INPUT); |
325 | if (err) |
326 | goto err; |
327 | break; |
328 | case PIN_CONFIG_SLEW_RATE: |
329 | err = mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_SR, |
330 | value: arg); |
331 | if (err) |
332 | goto err; |
333 | |
334 | break; |
335 | case PIN_CONFIG_OUTPUT: |
336 | err = mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_DIR, |
337 | MTK_OUTPUT); |
338 | if (err) |
339 | goto err; |
340 | |
341 | err = mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_DO, |
342 | value: arg); |
343 | if (err) |
344 | goto err; |
345 | break; |
346 | case PIN_CONFIG_INPUT_SCHMITT_ENABLE: |
347 | /* arg = 1: Input mode & SMT enable ; |
348 | * arg = 0: Output mode & SMT disable |
349 | */ |
350 | arg = arg ? 2 : 1; |
351 | err = mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_DIR, |
352 | value: arg & 1); |
353 | if (err) |
354 | goto err; |
355 | |
356 | err = mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_SMT, |
357 | value: !!(arg & 2)); |
358 | if (err) |
359 | goto err; |
360 | break; |
361 | case PIN_CONFIG_DRIVE_STRENGTH: |
362 | if (hw->soc->drive_set) { |
363 | err = hw->soc->drive_set(hw, desc, arg); |
364 | if (err) |
365 | return err; |
366 | } else { |
367 | err = -ENOTSUPP; |
368 | } |
369 | break; |
370 | case MTK_PIN_CONFIG_TDSEL: |
371 | case MTK_PIN_CONFIG_RDSEL: |
372 | reg = (param == MTK_PIN_CONFIG_TDSEL) ? |
373 | PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; |
374 | |
375 | err = mtk_hw_set_value(hw, desc, field: reg, value: arg); |
376 | if (err) |
377 | goto err; |
378 | break; |
379 | case MTK_PIN_CONFIG_PU_ADV: |
380 | case MTK_PIN_CONFIG_PD_ADV: |
381 | if (hw->soc->adv_pull_set) { |
382 | bool pullup; |
383 | |
384 | pullup = param == MTK_PIN_CONFIG_PU_ADV; |
385 | err = hw->soc->adv_pull_set(hw, desc, pullup, |
386 | arg); |
387 | if (err) |
388 | return err; |
389 | } else { |
390 | return -ENOTSUPP; |
391 | } |
392 | break; |
393 | default: |
394 | err = -ENOTSUPP; |
395 | } |
396 | } |
397 | err: |
398 | return err; |
399 | } |
400 | |
401 | static int mtk_pinconf_group_get(struct pinctrl_dev *pctldev, |
402 | unsigned int group, unsigned long *config) |
403 | { |
404 | const unsigned int *pins; |
405 | unsigned int i, npins, old = 0; |
406 | int ret; |
407 | |
408 | ret = pinctrl_generic_get_group_pins(pctldev, group_selector: group, pins: &pins, npins: &npins); |
409 | if (ret) |
410 | return ret; |
411 | |
412 | for (i = 0; i < npins; i++) { |
413 | if (mtk_pinconf_get(pctldev, pin: pins[i], config)) |
414 | return -ENOTSUPP; |
415 | |
416 | /* configs do not match between two pins */ |
417 | if (i && old != *config) |
418 | return -ENOTSUPP; |
419 | |
420 | old = *config; |
421 | } |
422 | |
423 | return 0; |
424 | } |
425 | |
426 | static int mtk_pinconf_group_set(struct pinctrl_dev *pctldev, |
427 | unsigned int group, unsigned long *configs, |
428 | unsigned int num_configs) |
429 | { |
430 | const unsigned int *pins; |
431 | unsigned int i, npins; |
432 | int ret; |
433 | |
434 | ret = pinctrl_generic_get_group_pins(pctldev, group_selector: group, pins: &pins, npins: &npins); |
435 | if (ret) |
436 | return ret; |
437 | |
438 | for (i = 0; i < npins; i++) { |
439 | ret = mtk_pinconf_set(pctldev, pin: pins[i], configs, num_configs); |
440 | if (ret) |
441 | return ret; |
442 | } |
443 | |
444 | return 0; |
445 | } |
446 | |
447 | static const struct pinctrl_ops mtk_pctlops = { |
448 | .get_groups_count = pinctrl_generic_get_group_count, |
449 | .get_group_name = pinctrl_generic_get_group_name, |
450 | .get_group_pins = pinctrl_generic_get_group_pins, |
451 | .dt_node_to_map = pinconf_generic_dt_node_to_map_all, |
452 | .dt_free_map = pinconf_generic_dt_free_map, |
453 | }; |
454 | |
455 | static const struct pinmux_ops mtk_pmxops = { |
456 | .get_functions_count = pinmux_generic_get_function_count, |
457 | .get_function_name = pinmux_generic_get_function_name, |
458 | .get_function_groups = pinmux_generic_get_function_groups, |
459 | .set_mux = mtk_pinmux_set_mux, |
460 | .gpio_request_enable = mtk_pinmux_gpio_request_enable, |
461 | .gpio_set_direction = mtk_pinmux_gpio_set_direction, |
462 | .strict = true, |
463 | }; |
464 | |
465 | static const struct pinconf_ops mtk_confops = { |
466 | .is_generic = true, |
467 | .pin_config_get = mtk_pinconf_get, |
468 | .pin_config_set = mtk_pinconf_set, |
469 | .pin_config_group_get = mtk_pinconf_group_get, |
470 | .pin_config_group_set = mtk_pinconf_group_set, |
471 | .pin_config_config_dbg_show = pinconf_generic_dump_config, |
472 | }; |
473 | |
474 | static struct pinctrl_desc mtk_desc = { |
475 | .name = PINCTRL_PINCTRL_DEV, |
476 | .pctlops = &mtk_pctlops, |
477 | .pmxops = &mtk_pmxops, |
478 | .confops = &mtk_confops, |
479 | .owner = THIS_MODULE, |
480 | }; |
481 | |
482 | static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) |
483 | { |
484 | struct mtk_pinctrl *hw = gpiochip_get_data(gc: chip); |
485 | const struct mtk_pin_desc *desc; |
486 | int value, err; |
487 | |
488 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; |
489 | if (!desc->name) |
490 | return -ENOTSUPP; |
491 | |
492 | err = mtk_hw_get_value(hw, desc, field: PINCTRL_PIN_REG_DI, value: &value); |
493 | if (err) |
494 | return err; |
495 | |
496 | return !!value; |
497 | } |
498 | |
499 | static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) |
500 | { |
501 | struct mtk_pinctrl *hw = gpiochip_get_data(gc: chip); |
502 | const struct mtk_pin_desc *desc; |
503 | |
504 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; |
505 | if (!desc->name) { |
506 | dev_err(hw->dev, "Failed to set gpio %d\n" , gpio); |
507 | return; |
508 | } |
509 | |
510 | mtk_hw_set_value(hw, desc, field: PINCTRL_PIN_REG_DO, value: !!value); |
511 | } |
512 | |
513 | static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, |
514 | int value) |
515 | { |
516 | mtk_gpio_set(chip, gpio, value); |
517 | |
518 | return pinctrl_gpio_direction_output(gc: chip, offset: gpio); |
519 | } |
520 | |
521 | static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) |
522 | { |
523 | struct mtk_pinctrl *hw = gpiochip_get_data(gc: chip); |
524 | const struct mtk_pin_desc *desc; |
525 | |
526 | if (!hw->eint) |
527 | return -ENOTSUPP; |
528 | |
529 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; |
530 | |
531 | if (desc->eint.eint_n == (u16)EINT_NA) |
532 | return -ENOTSUPP; |
533 | |
534 | return mtk_eint_find_irq(eint: hw->eint, eint_n: desc->eint.eint_n); |
535 | } |
536 | |
537 | static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, |
538 | unsigned long config) |
539 | { |
540 | struct mtk_pinctrl *hw = gpiochip_get_data(gc: chip); |
541 | const struct mtk_pin_desc *desc; |
542 | u32 debounce; |
543 | |
544 | desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; |
545 | if (!desc->name) |
546 | return -ENOTSUPP; |
547 | |
548 | if (!hw->eint || |
549 | pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE || |
550 | desc->eint.eint_n == (u16)EINT_NA) |
551 | return -ENOTSUPP; |
552 | |
553 | debounce = pinconf_to_config_argument(config); |
554 | |
555 | return mtk_eint_set_debounce(eint: hw->eint, eint_n: desc->eint.eint_n, debounce); |
556 | } |
557 | |
558 | static int mtk_build_gpiochip(struct mtk_pinctrl *hw) |
559 | { |
560 | struct gpio_chip *chip = &hw->chip; |
561 | int ret; |
562 | |
563 | chip->label = PINCTRL_PINCTRL_DEV; |
564 | chip->parent = hw->dev; |
565 | chip->request = gpiochip_generic_request; |
566 | chip->free = gpiochip_generic_free; |
567 | chip->direction_input = pinctrl_gpio_direction_input; |
568 | chip->direction_output = mtk_gpio_direction_output; |
569 | chip->get = mtk_gpio_get; |
570 | chip->set = mtk_gpio_set; |
571 | chip->to_irq = mtk_gpio_to_irq; |
572 | chip->set_config = mtk_gpio_set_config; |
573 | chip->base = -1; |
574 | chip->ngpio = hw->soc->npins; |
575 | |
576 | ret = gpiochip_add_data(chip, hw); |
577 | if (ret < 0) |
578 | return ret; |
579 | |
580 | /* Just for backward compatible for these old pinctrl nodes without |
581 | * "gpio-ranges" property. Otherwise, called directly from a |
582 | * DeviceTree-supported pinctrl driver is DEPRECATED. |
583 | * Please see Section 2.1 of |
584 | * Documentation/devicetree/bindings/gpio/gpio.txt on how to |
585 | * bind pinctrl and gpio drivers via the "gpio-ranges" property. |
586 | */ |
587 | if (!of_property_present(np: hw->dev->of_node, propname: "gpio-ranges" )) { |
588 | ret = gpiochip_add_pin_range(gc: chip, pinctl_name: dev_name(dev: hw->dev), gpio_offset: 0, pin_offset: 0, |
589 | npins: chip->ngpio); |
590 | if (ret < 0) { |
591 | gpiochip_remove(gc: chip); |
592 | return ret; |
593 | } |
594 | } |
595 | |
596 | return 0; |
597 | } |
598 | |
599 | static int mtk_build_groups(struct mtk_pinctrl *hw) |
600 | { |
601 | int err, i; |
602 | |
603 | for (i = 0; i < hw->soc->ngrps; i++) { |
604 | const struct group_desc *group = hw->soc->grps + i; |
605 | const struct pingroup *grp = &group->grp; |
606 | |
607 | err = pinctrl_generic_add_group(pctldev: hw->pctrl, name: grp->name, pins: grp->pins, num_pins: grp->npins, |
608 | data: group->data); |
609 | if (err < 0) { |
610 | dev_err(hw->dev, "Failed to register group %s\n" , grp->name); |
611 | return err; |
612 | } |
613 | } |
614 | |
615 | return 0; |
616 | } |
617 | |
618 | static int mtk_build_functions(struct mtk_pinctrl *hw) |
619 | { |
620 | int i, err; |
621 | |
622 | for (i = 0; i < hw->soc->nfuncs ; i++) { |
623 | const struct function_desc *func = hw->soc->funcs + i; |
624 | |
625 | err = pinmux_generic_add_function(pctldev: hw->pctrl, name: func->name, |
626 | groups: func->group_names, |
627 | num_groups: func->num_group_names, |
628 | data: func->data); |
629 | if (err < 0) { |
630 | dev_err(hw->dev, "Failed to register function %s\n" , |
631 | func->name); |
632 | return err; |
633 | } |
634 | } |
635 | |
636 | return 0; |
637 | } |
638 | |
639 | int mtk_moore_pinctrl_probe(struct platform_device *pdev, |
640 | const struct mtk_pin_soc *soc) |
641 | { |
642 | struct device *dev = &pdev->dev; |
643 | struct pinctrl_pin_desc *pins; |
644 | struct mtk_pinctrl *hw; |
645 | int err, i; |
646 | |
647 | hw = devm_kzalloc(dev: &pdev->dev, size: sizeof(*hw), GFP_KERNEL); |
648 | if (!hw) |
649 | return -ENOMEM; |
650 | |
651 | hw->soc = soc; |
652 | hw->dev = &pdev->dev; |
653 | |
654 | if (!hw->soc->nbase_names) |
655 | return dev_err_probe(dev, err: -EINVAL, |
656 | fmt: "SoC should be assigned at least one register base\n" ); |
657 | |
658 | hw->base = devm_kmalloc_array(dev: &pdev->dev, n: hw->soc->nbase_names, |
659 | size: sizeof(*hw->base), GFP_KERNEL); |
660 | if (!hw->base) |
661 | return -ENOMEM; |
662 | |
663 | for (i = 0; i < hw->soc->nbase_names; i++) { |
664 | hw->base[i] = devm_platform_ioremap_resource_byname(pdev, |
665 | name: hw->soc->base_names[i]); |
666 | if (IS_ERR(ptr: hw->base[i])) |
667 | return PTR_ERR(ptr: hw->base[i]); |
668 | } |
669 | |
670 | hw->nbase = hw->soc->nbase_names; |
671 | |
672 | spin_lock_init(&hw->lock); |
673 | |
674 | /* Copy from internal struct mtk_pin_desc to register to the core */ |
675 | pins = devm_kmalloc_array(dev: &pdev->dev, n: hw->soc->npins, size: sizeof(*pins), |
676 | GFP_KERNEL); |
677 | if (!pins) |
678 | return -ENOMEM; |
679 | |
680 | for (i = 0; i < hw->soc->npins; i++) { |
681 | pins[i].number = hw->soc->pins[i].number; |
682 | pins[i].name = hw->soc->pins[i].name; |
683 | } |
684 | |
685 | /* Setup pins descriptions per SoC types */ |
686 | mtk_desc.pins = (const struct pinctrl_pin_desc *)pins; |
687 | mtk_desc.npins = hw->soc->npins; |
688 | mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); |
689 | mtk_desc.custom_params = mtk_custom_bindings; |
690 | #ifdef CONFIG_DEBUG_FS |
691 | mtk_desc.custom_conf_items = mtk_conf_items; |
692 | #endif |
693 | |
694 | err = devm_pinctrl_register_and_init(dev: &pdev->dev, pctldesc: &mtk_desc, driver_data: hw, |
695 | pctldev: &hw->pctrl); |
696 | if (err) |
697 | return err; |
698 | |
699 | /* Setup groups descriptions per SoC types */ |
700 | err = mtk_build_groups(hw); |
701 | if (err) |
702 | return dev_err_probe(dev, err, fmt: "Failed to build groups\n" ); |
703 | |
704 | /* Setup functions descriptions per SoC types */ |
705 | err = mtk_build_functions(hw); |
706 | if (err) |
707 | return dev_err_probe(dev, err, fmt: "Failed to build functions\n" ); |
708 | |
709 | /* For able to make pinctrl_claim_hogs, we must not enable pinctrl |
710 | * until all groups and functions are being added one. |
711 | */ |
712 | err = pinctrl_enable(pctldev: hw->pctrl); |
713 | if (err) |
714 | return err; |
715 | |
716 | err = mtk_build_eint(hw, pdev); |
717 | if (err) |
718 | dev_warn(&pdev->dev, |
719 | "Failed to add EINT, but pinctrl still can work\n" ); |
720 | |
721 | /* Build gpiochip should be after pinctrl_enable is done */ |
722 | err = mtk_build_gpiochip(hw); |
723 | if (err) |
724 | return dev_err_probe(dev, err, fmt: "Failed to add gpio_chip\n" ); |
725 | |
726 | platform_set_drvdata(pdev, data: hw); |
727 | |
728 | return 0; |
729 | } |
730 | |