1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Driver for BCM6318 GPIO unit (pinctrl + GPIO) |
4 | * |
5 | * Copyright (C) 2021 Álvaro Fernández Rojas <noltari@gmail.com> |
6 | * Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com> |
7 | */ |
8 | |
9 | #include <linux/bits.h> |
10 | #include <linux/gpio/driver.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/of.h> |
13 | #include <linux/pinctrl/pinmux.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/regmap.h> |
16 | |
17 | #include "../pinctrl-utils.h" |
18 | |
19 | #include "pinctrl-bcm63xx.h" |
20 | |
21 | #define BCM6318_NUM_GPIOS 50 |
22 | #define BCM6318_NUM_MUX 48 |
23 | |
24 | #define BCM6318_MODE_REG 0x18 |
25 | #define BCM6318_MUX_REG 0x1c |
26 | #define BCM6328_MUX_MASK GENMASK(1, 0) |
27 | #define BCM6318_PAD_REG 0x54 |
28 | #define BCM6328_PAD_MASK GENMASK(3, 0) |
29 | |
30 | struct bcm6318_function { |
31 | const char *name; |
32 | const char * const *groups; |
33 | const unsigned num_groups; |
34 | |
35 | unsigned mode_val:1; |
36 | unsigned mux_val:2; |
37 | }; |
38 | |
39 | static const struct pinctrl_pin_desc bcm6318_pins[] = { |
40 | PINCTRL_PIN(0, "gpio0" ), |
41 | PINCTRL_PIN(1, "gpio1" ), |
42 | PINCTRL_PIN(2, "gpio2" ), |
43 | PINCTRL_PIN(3, "gpio3" ), |
44 | PINCTRL_PIN(4, "gpio4" ), |
45 | PINCTRL_PIN(5, "gpio5" ), |
46 | PINCTRL_PIN(6, "gpio6" ), |
47 | PINCTRL_PIN(7, "gpio7" ), |
48 | PINCTRL_PIN(8, "gpio8" ), |
49 | PINCTRL_PIN(9, "gpio9" ), |
50 | PINCTRL_PIN(10, "gpio10" ), |
51 | PINCTRL_PIN(11, "gpio11" ), |
52 | PINCTRL_PIN(12, "gpio12" ), |
53 | PINCTRL_PIN(13, "gpio13" ), |
54 | PINCTRL_PIN(14, "gpio14" ), |
55 | PINCTRL_PIN(15, "gpio15" ), |
56 | PINCTRL_PIN(16, "gpio16" ), |
57 | PINCTRL_PIN(17, "gpio17" ), |
58 | PINCTRL_PIN(18, "gpio18" ), |
59 | PINCTRL_PIN(19, "gpio19" ), |
60 | PINCTRL_PIN(20, "gpio20" ), |
61 | PINCTRL_PIN(21, "gpio21" ), |
62 | PINCTRL_PIN(22, "gpio22" ), |
63 | PINCTRL_PIN(23, "gpio23" ), |
64 | PINCTRL_PIN(24, "gpio24" ), |
65 | PINCTRL_PIN(25, "gpio25" ), |
66 | PINCTRL_PIN(26, "gpio26" ), |
67 | PINCTRL_PIN(27, "gpio27" ), |
68 | PINCTRL_PIN(28, "gpio28" ), |
69 | PINCTRL_PIN(29, "gpio29" ), |
70 | PINCTRL_PIN(30, "gpio30" ), |
71 | PINCTRL_PIN(31, "gpio31" ), |
72 | PINCTRL_PIN(32, "gpio32" ), |
73 | PINCTRL_PIN(33, "gpio33" ), |
74 | PINCTRL_PIN(34, "gpio34" ), |
75 | PINCTRL_PIN(35, "gpio35" ), |
76 | PINCTRL_PIN(36, "gpio36" ), |
77 | PINCTRL_PIN(37, "gpio37" ), |
78 | PINCTRL_PIN(38, "gpio38" ), |
79 | PINCTRL_PIN(39, "gpio39" ), |
80 | PINCTRL_PIN(40, "gpio40" ), |
81 | PINCTRL_PIN(41, "gpio41" ), |
82 | PINCTRL_PIN(42, "gpio42" ), |
83 | PINCTRL_PIN(43, "gpio43" ), |
84 | PINCTRL_PIN(44, "gpio44" ), |
85 | PINCTRL_PIN(45, "gpio45" ), |
86 | PINCTRL_PIN(46, "gpio46" ), |
87 | PINCTRL_PIN(47, "gpio47" ), |
88 | PINCTRL_PIN(48, "gpio48" ), |
89 | PINCTRL_PIN(49, "gpio49" ), |
90 | }; |
91 | |
92 | static unsigned gpio0_pins[] = { 0 }; |
93 | static unsigned gpio1_pins[] = { 1 }; |
94 | static unsigned gpio2_pins[] = { 2 }; |
95 | static unsigned gpio3_pins[] = { 3 }; |
96 | static unsigned gpio4_pins[] = { 4 }; |
97 | static unsigned gpio5_pins[] = { 5 }; |
98 | static unsigned gpio6_pins[] = { 6 }; |
99 | static unsigned gpio7_pins[] = { 7 }; |
100 | static unsigned gpio8_pins[] = { 8 }; |
101 | static unsigned gpio9_pins[] = { 9 }; |
102 | static unsigned gpio10_pins[] = { 10 }; |
103 | static unsigned gpio11_pins[] = { 11 }; |
104 | static unsigned gpio12_pins[] = { 12 }; |
105 | static unsigned gpio13_pins[] = { 13 }; |
106 | static unsigned gpio14_pins[] = { 14 }; |
107 | static unsigned gpio15_pins[] = { 15 }; |
108 | static unsigned gpio16_pins[] = { 16 }; |
109 | static unsigned gpio17_pins[] = { 17 }; |
110 | static unsigned gpio18_pins[] = { 18 }; |
111 | static unsigned gpio19_pins[] = { 19 }; |
112 | static unsigned gpio20_pins[] = { 20 }; |
113 | static unsigned gpio21_pins[] = { 21 }; |
114 | static unsigned gpio22_pins[] = { 22 }; |
115 | static unsigned gpio23_pins[] = { 23 }; |
116 | static unsigned gpio24_pins[] = { 24 }; |
117 | static unsigned gpio25_pins[] = { 25 }; |
118 | static unsigned gpio26_pins[] = { 26 }; |
119 | static unsigned gpio27_pins[] = { 27 }; |
120 | static unsigned gpio28_pins[] = { 28 }; |
121 | static unsigned gpio29_pins[] = { 29 }; |
122 | static unsigned gpio30_pins[] = { 30 }; |
123 | static unsigned gpio31_pins[] = { 31 }; |
124 | static unsigned gpio32_pins[] = { 32 }; |
125 | static unsigned gpio33_pins[] = { 33 }; |
126 | static unsigned gpio34_pins[] = { 34 }; |
127 | static unsigned gpio35_pins[] = { 35 }; |
128 | static unsigned gpio36_pins[] = { 36 }; |
129 | static unsigned gpio37_pins[] = { 37 }; |
130 | static unsigned gpio38_pins[] = { 38 }; |
131 | static unsigned gpio39_pins[] = { 39 }; |
132 | static unsigned gpio40_pins[] = { 40 }; |
133 | static unsigned gpio41_pins[] = { 41 }; |
134 | static unsigned gpio42_pins[] = { 42 }; |
135 | static unsigned gpio43_pins[] = { 43 }; |
136 | static unsigned gpio44_pins[] = { 44 }; |
137 | static unsigned gpio45_pins[] = { 45 }; |
138 | static unsigned gpio46_pins[] = { 46 }; |
139 | static unsigned gpio47_pins[] = { 47 }; |
140 | static unsigned gpio48_pins[] = { 48 }; |
141 | static unsigned gpio49_pins[] = { 49 }; |
142 | |
143 | static struct pingroup bcm6318_groups[] = { |
144 | BCM_PIN_GROUP(gpio0), |
145 | BCM_PIN_GROUP(gpio1), |
146 | BCM_PIN_GROUP(gpio2), |
147 | BCM_PIN_GROUP(gpio3), |
148 | BCM_PIN_GROUP(gpio4), |
149 | BCM_PIN_GROUP(gpio5), |
150 | BCM_PIN_GROUP(gpio6), |
151 | BCM_PIN_GROUP(gpio7), |
152 | BCM_PIN_GROUP(gpio8), |
153 | BCM_PIN_GROUP(gpio9), |
154 | BCM_PIN_GROUP(gpio10), |
155 | BCM_PIN_GROUP(gpio11), |
156 | BCM_PIN_GROUP(gpio12), |
157 | BCM_PIN_GROUP(gpio13), |
158 | BCM_PIN_GROUP(gpio14), |
159 | BCM_PIN_GROUP(gpio15), |
160 | BCM_PIN_GROUP(gpio16), |
161 | BCM_PIN_GROUP(gpio17), |
162 | BCM_PIN_GROUP(gpio18), |
163 | BCM_PIN_GROUP(gpio19), |
164 | BCM_PIN_GROUP(gpio20), |
165 | BCM_PIN_GROUP(gpio21), |
166 | BCM_PIN_GROUP(gpio22), |
167 | BCM_PIN_GROUP(gpio23), |
168 | BCM_PIN_GROUP(gpio24), |
169 | BCM_PIN_GROUP(gpio25), |
170 | BCM_PIN_GROUP(gpio26), |
171 | BCM_PIN_GROUP(gpio27), |
172 | BCM_PIN_GROUP(gpio28), |
173 | BCM_PIN_GROUP(gpio29), |
174 | BCM_PIN_GROUP(gpio30), |
175 | BCM_PIN_GROUP(gpio31), |
176 | BCM_PIN_GROUP(gpio32), |
177 | BCM_PIN_GROUP(gpio33), |
178 | BCM_PIN_GROUP(gpio34), |
179 | BCM_PIN_GROUP(gpio35), |
180 | BCM_PIN_GROUP(gpio36), |
181 | BCM_PIN_GROUP(gpio37), |
182 | BCM_PIN_GROUP(gpio38), |
183 | BCM_PIN_GROUP(gpio39), |
184 | BCM_PIN_GROUP(gpio40), |
185 | BCM_PIN_GROUP(gpio41), |
186 | BCM_PIN_GROUP(gpio42), |
187 | BCM_PIN_GROUP(gpio43), |
188 | BCM_PIN_GROUP(gpio44), |
189 | BCM_PIN_GROUP(gpio45), |
190 | BCM_PIN_GROUP(gpio46), |
191 | BCM_PIN_GROUP(gpio47), |
192 | BCM_PIN_GROUP(gpio48), |
193 | BCM_PIN_GROUP(gpio49), |
194 | }; |
195 | |
196 | /* GPIO_MODE */ |
197 | static const char * const led_groups[] = { |
198 | "gpio0" , |
199 | "gpio1" , |
200 | "gpio2" , |
201 | "gpio3" , |
202 | "gpio4" , |
203 | "gpio5" , |
204 | "gpio6" , |
205 | "gpio7" , |
206 | "gpio8" , |
207 | "gpio9" , |
208 | "gpio10" , |
209 | "gpio11" , |
210 | "gpio12" , |
211 | "gpio13" , |
212 | "gpio14" , |
213 | "gpio15" , |
214 | "gpio16" , |
215 | "gpio17" , |
216 | "gpio18" , |
217 | "gpio19" , |
218 | "gpio20" , |
219 | "gpio21" , |
220 | "gpio22" , |
221 | "gpio23" , |
222 | }; |
223 | |
224 | /* PINMUX_SEL */ |
225 | static const char * const ephy0_spd_led_groups[] = { |
226 | "gpio0" , |
227 | }; |
228 | |
229 | static const char * const ephy1_spd_led_groups[] = { |
230 | "gpio1" , |
231 | }; |
232 | |
233 | static const char * const ephy2_spd_led_groups[] = { |
234 | "gpio2" , |
235 | }; |
236 | |
237 | static const char * const ephy3_spd_led_groups[] = { |
238 | "gpio3" , |
239 | }; |
240 | |
241 | static const char * const ephy0_act_led_groups[] = { |
242 | "gpio4" , |
243 | }; |
244 | |
245 | static const char * const ephy1_act_led_groups[] = { |
246 | "gpio5" , |
247 | }; |
248 | |
249 | static const char * const ephy2_act_led_groups[] = { |
250 | "gpio6" , |
251 | }; |
252 | |
253 | static const char * const ephy3_act_led_groups[] = { |
254 | "gpio7" , |
255 | }; |
256 | |
257 | static const char * const serial_led_data_groups[] = { |
258 | "gpio6" , |
259 | }; |
260 | |
261 | static const char * const serial_led_clk_groups[] = { |
262 | "gpio7" , |
263 | }; |
264 | |
265 | static const char * const inet_act_led_groups[] = { |
266 | "gpio8" , |
267 | }; |
268 | |
269 | static const char * const inet_fail_led_groups[] = { |
270 | "gpio9" , |
271 | }; |
272 | |
273 | static const char * const dsl_led_groups[] = { |
274 | "gpio10" , |
275 | }; |
276 | |
277 | static const char * const post_fail_led_groups[] = { |
278 | "gpio11" , |
279 | }; |
280 | |
281 | static const char * const wlan_wps_led_groups[] = { |
282 | "gpio12" , |
283 | }; |
284 | |
285 | static const char * const usb_pwron_groups[] = { |
286 | "gpio13" , |
287 | }; |
288 | |
289 | static const char * const usb_device_led_groups[] = { |
290 | "gpio13" , |
291 | }; |
292 | |
293 | static const char * const usb_active_groups[] = { |
294 | "gpio40" , |
295 | }; |
296 | |
297 | #define BCM6318_MODE_FUN(n) \ |
298 | { \ |
299 | .name = #n, \ |
300 | .groups = n##_groups, \ |
301 | .num_groups = ARRAY_SIZE(n##_groups), \ |
302 | .mode_val = 1, \ |
303 | } |
304 | |
305 | #define BCM6318_MUX_FUN(n, mux) \ |
306 | { \ |
307 | .name = #n, \ |
308 | .groups = n##_groups, \ |
309 | .num_groups = ARRAY_SIZE(n##_groups), \ |
310 | .mux_val = mux, \ |
311 | } |
312 | |
313 | static const struct bcm6318_function bcm6318_funcs[] = { |
314 | BCM6318_MODE_FUN(led), |
315 | BCM6318_MUX_FUN(ephy0_spd_led, 1), |
316 | BCM6318_MUX_FUN(ephy1_spd_led, 1), |
317 | BCM6318_MUX_FUN(ephy2_spd_led, 1), |
318 | BCM6318_MUX_FUN(ephy3_spd_led, 1), |
319 | BCM6318_MUX_FUN(ephy0_act_led, 1), |
320 | BCM6318_MUX_FUN(ephy1_act_led, 1), |
321 | BCM6318_MUX_FUN(ephy2_act_led, 1), |
322 | BCM6318_MUX_FUN(ephy3_act_led, 1), |
323 | BCM6318_MUX_FUN(serial_led_data, 3), |
324 | BCM6318_MUX_FUN(serial_led_clk, 3), |
325 | BCM6318_MUX_FUN(inet_act_led, 1), |
326 | BCM6318_MUX_FUN(inet_fail_led, 1), |
327 | BCM6318_MUX_FUN(dsl_led, 1), |
328 | BCM6318_MUX_FUN(post_fail_led, 1), |
329 | BCM6318_MUX_FUN(wlan_wps_led, 1), |
330 | BCM6318_MUX_FUN(usb_pwron, 1), |
331 | BCM6318_MUX_FUN(usb_device_led, 2), |
332 | BCM6318_MUX_FUN(usb_active, 2), |
333 | }; |
334 | |
335 | static inline unsigned int bcm6318_mux_off(unsigned int pin) |
336 | { |
337 | return BCM6318_MUX_REG + (pin / 16) * 4; |
338 | } |
339 | |
340 | static inline unsigned int bcm6318_pad_off(unsigned int pin) |
341 | { |
342 | return BCM6318_PAD_REG + (pin / 8) * 4; |
343 | } |
344 | |
345 | static int bcm6318_pinctrl_get_group_count(struct pinctrl_dev *pctldev) |
346 | { |
347 | return ARRAY_SIZE(bcm6318_groups); |
348 | } |
349 | |
350 | static const char *bcm6318_pinctrl_get_group_name(struct pinctrl_dev *pctldev, |
351 | unsigned group) |
352 | { |
353 | return bcm6318_groups[group].name; |
354 | } |
355 | |
356 | static int bcm6318_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, |
357 | unsigned group, const unsigned **pins, |
358 | unsigned *npins) |
359 | { |
360 | *pins = bcm6318_groups[group].pins; |
361 | *npins = bcm6318_groups[group].npins; |
362 | |
363 | return 0; |
364 | } |
365 | |
366 | static int bcm6318_pinctrl_get_func_count(struct pinctrl_dev *pctldev) |
367 | { |
368 | return ARRAY_SIZE(bcm6318_funcs); |
369 | } |
370 | |
371 | static const char *bcm6318_pinctrl_get_func_name(struct pinctrl_dev *pctldev, |
372 | unsigned selector) |
373 | { |
374 | return bcm6318_funcs[selector].name; |
375 | } |
376 | |
377 | static int bcm6318_pinctrl_get_groups(struct pinctrl_dev *pctldev, |
378 | unsigned selector, |
379 | const char * const **groups, |
380 | unsigned * const num_groups) |
381 | { |
382 | *groups = bcm6318_funcs[selector].groups; |
383 | *num_groups = bcm6318_funcs[selector].num_groups; |
384 | |
385 | return 0; |
386 | } |
387 | |
388 | static inline void bcm6318_rmw_mux(struct bcm63xx_pinctrl *pc, unsigned pin, |
389 | unsigned int mode, unsigned int mux) |
390 | { |
391 | if (pin < BCM63XX_BANK_GPIOS) |
392 | regmap_update_bits(map: pc->regs, BCM6318_MODE_REG, BIT(pin), |
393 | val: mode ? BIT(pin) : 0); |
394 | |
395 | if (pin < BCM6318_NUM_MUX) |
396 | regmap_update_bits(map: pc->regs, |
397 | reg: bcm6318_mux_off(pin), |
398 | BCM6328_MUX_MASK << ((pin % 16) * 2), |
399 | val: mux << ((pin % 16) * 2)); |
400 | } |
401 | |
402 | static inline void bcm6318_set_pad(struct bcm63xx_pinctrl *pc, unsigned pin, |
403 | uint8_t val) |
404 | { |
405 | regmap_update_bits(map: pc->regs, reg: bcm6318_pad_off(pin), |
406 | BCM6328_PAD_MASK << ((pin % 8) * 4), |
407 | val: val << ((pin % 8) * 4)); |
408 | } |
409 | |
410 | static int bcm6318_pinctrl_set_mux(struct pinctrl_dev *pctldev, |
411 | unsigned selector, unsigned group) |
412 | { |
413 | struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); |
414 | const struct pingroup *pg = &bcm6318_groups[group]; |
415 | const struct bcm6318_function *f = &bcm6318_funcs[selector]; |
416 | |
417 | bcm6318_rmw_mux(pc, pin: pg->pins[0], mode: f->mode_val, mux: f->mux_val); |
418 | |
419 | return 0; |
420 | } |
421 | |
422 | static int bcm6318_gpio_request_enable(struct pinctrl_dev *pctldev, |
423 | struct pinctrl_gpio_range *range, |
424 | unsigned offset) |
425 | { |
426 | struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); |
427 | |
428 | /* disable all functions using this pin */ |
429 | if (offset < 13) { |
430 | /* GPIOs 0-12 use mux 0 as GPIO function */ |
431 | bcm6318_rmw_mux(pc, pin: offset, mode: 0, mux: 0); |
432 | } else if (offset < 42) { |
433 | /* GPIOs 13-41 use mux 3 as GPIO function */ |
434 | bcm6318_rmw_mux(pc, pin: offset, mode: 0, mux: 3); |
435 | |
436 | bcm6318_set_pad(pc, pin: offset, val: 0); |
437 | } |
438 | |
439 | return 0; |
440 | } |
441 | |
442 | static const struct pinctrl_ops bcm6318_pctl_ops = { |
443 | .dt_free_map = pinctrl_utils_free_map, |
444 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, |
445 | .get_group_name = bcm6318_pinctrl_get_group_name, |
446 | .get_group_pins = bcm6318_pinctrl_get_group_pins, |
447 | .get_groups_count = bcm6318_pinctrl_get_group_count, |
448 | }; |
449 | |
450 | static const struct pinmux_ops bcm6318_pmx_ops = { |
451 | .get_function_groups = bcm6318_pinctrl_get_groups, |
452 | .get_function_name = bcm6318_pinctrl_get_func_name, |
453 | .get_functions_count = bcm6318_pinctrl_get_func_count, |
454 | .gpio_request_enable = bcm6318_gpio_request_enable, |
455 | .set_mux = bcm6318_pinctrl_set_mux, |
456 | .strict = true, |
457 | }; |
458 | |
459 | static const struct bcm63xx_pinctrl_soc bcm6318_soc = { |
460 | .ngpios = BCM6318_NUM_GPIOS, |
461 | .npins = ARRAY_SIZE(bcm6318_pins), |
462 | .pctl_ops = &bcm6318_pctl_ops, |
463 | .pins = bcm6318_pins, |
464 | .pmx_ops = &bcm6318_pmx_ops, |
465 | }; |
466 | |
467 | static int bcm6318_pinctrl_probe(struct platform_device *pdev) |
468 | { |
469 | return bcm63xx_pinctrl_probe(pdev, soc: &bcm6318_soc, NULL); |
470 | } |
471 | |
472 | static const struct of_device_id bcm6318_pinctrl_match[] = { |
473 | { .compatible = "brcm,bcm6318-pinctrl" , }, |
474 | { /* sentinel */ } |
475 | }; |
476 | |
477 | static struct platform_driver bcm6318_pinctrl_driver = { |
478 | .probe = bcm6318_pinctrl_probe, |
479 | .driver = { |
480 | .name = "bcm6318-pinctrl" , |
481 | .of_match_table = bcm6318_pinctrl_match, |
482 | }, |
483 | }; |
484 | |
485 | builtin_platform_driver(bcm6318_pinctrl_driver); |
486 | |