1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Driver for BCM6368 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 BCM6368_NUM_GPIOS 38 |
22 | |
23 | #define BCM6368_MODE_REG 0x18 |
24 | #define BCM6368_BASEMODE_REG 0x38 |
25 | #define BCM6368_BASEMODE_MASK 0x7 |
26 | #define BCM6368_BASEMODE_GPIO 0x0 |
27 | #define BCM6368_BASEMODE_UART1 0x1 |
28 | |
29 | struct bcm6368_function { |
30 | const char *name; |
31 | const char * const *groups; |
32 | const unsigned num_groups; |
33 | |
34 | unsigned dir_out:16; |
35 | unsigned basemode:3; |
36 | }; |
37 | |
38 | struct bcm6368_priv { |
39 | struct regmap_field *overlays; |
40 | }; |
41 | |
42 | #define BCM6368_BASEMODE_PIN(a, b) \ |
43 | { \ |
44 | .number = a, \ |
45 | .name = b, \ |
46 | .drv_data = (void *)true \ |
47 | } |
48 | |
49 | static const struct pinctrl_pin_desc bcm6368_pins[] = { |
50 | PINCTRL_PIN(0, "gpio0" ), |
51 | PINCTRL_PIN(1, "gpio1" ), |
52 | PINCTRL_PIN(2, "gpio2" ), |
53 | PINCTRL_PIN(3, "gpio3" ), |
54 | PINCTRL_PIN(4, "gpio4" ), |
55 | PINCTRL_PIN(5, "gpio5" ), |
56 | PINCTRL_PIN(6, "gpio6" ), |
57 | PINCTRL_PIN(7, "gpio7" ), |
58 | PINCTRL_PIN(8, "gpio8" ), |
59 | PINCTRL_PIN(9, "gpio9" ), |
60 | PINCTRL_PIN(10, "gpio10" ), |
61 | PINCTRL_PIN(11, "gpio11" ), |
62 | PINCTRL_PIN(12, "gpio12" ), |
63 | PINCTRL_PIN(13, "gpio13" ), |
64 | PINCTRL_PIN(14, "gpio14" ), |
65 | PINCTRL_PIN(15, "gpio15" ), |
66 | PINCTRL_PIN(16, "gpio16" ), |
67 | PINCTRL_PIN(17, "gpio17" ), |
68 | PINCTRL_PIN(18, "gpio18" ), |
69 | PINCTRL_PIN(19, "gpio19" ), |
70 | PINCTRL_PIN(20, "gpio20" ), |
71 | PINCTRL_PIN(21, "gpio21" ), |
72 | PINCTRL_PIN(22, "gpio22" ), |
73 | PINCTRL_PIN(23, "gpio23" ), |
74 | PINCTRL_PIN(24, "gpio24" ), |
75 | PINCTRL_PIN(25, "gpio25" ), |
76 | PINCTRL_PIN(26, "gpio26" ), |
77 | PINCTRL_PIN(27, "gpio27" ), |
78 | PINCTRL_PIN(28, "gpio28" ), |
79 | PINCTRL_PIN(29, "gpio29" ), |
80 | BCM6368_BASEMODE_PIN(30, "gpio30" ), |
81 | BCM6368_BASEMODE_PIN(31, "gpio31" ), |
82 | BCM6368_BASEMODE_PIN(32, "gpio32" ), |
83 | BCM6368_BASEMODE_PIN(33, "gpio33" ), |
84 | PINCTRL_PIN(34, "gpio34" ), |
85 | PINCTRL_PIN(35, "gpio35" ), |
86 | PINCTRL_PIN(36, "gpio36" ), |
87 | PINCTRL_PIN(37, "gpio37" ), |
88 | }; |
89 | |
90 | static unsigned gpio0_pins[] = { 0 }; |
91 | static unsigned gpio1_pins[] = { 1 }; |
92 | static unsigned gpio2_pins[] = { 2 }; |
93 | static unsigned gpio3_pins[] = { 3 }; |
94 | static unsigned gpio4_pins[] = { 4 }; |
95 | static unsigned gpio5_pins[] = { 5 }; |
96 | static unsigned gpio6_pins[] = { 6 }; |
97 | static unsigned gpio7_pins[] = { 7 }; |
98 | static unsigned gpio8_pins[] = { 8 }; |
99 | static unsigned gpio9_pins[] = { 9 }; |
100 | static unsigned gpio10_pins[] = { 10 }; |
101 | static unsigned gpio11_pins[] = { 11 }; |
102 | static unsigned gpio12_pins[] = { 12 }; |
103 | static unsigned gpio13_pins[] = { 13 }; |
104 | static unsigned gpio14_pins[] = { 14 }; |
105 | static unsigned gpio15_pins[] = { 15 }; |
106 | static unsigned gpio16_pins[] = { 16 }; |
107 | static unsigned gpio17_pins[] = { 17 }; |
108 | static unsigned gpio18_pins[] = { 18 }; |
109 | static unsigned gpio19_pins[] = { 19 }; |
110 | static unsigned gpio20_pins[] = { 20 }; |
111 | static unsigned gpio21_pins[] = { 21 }; |
112 | static unsigned gpio22_pins[] = { 22 }; |
113 | static unsigned gpio23_pins[] = { 23 }; |
114 | static unsigned gpio24_pins[] = { 24 }; |
115 | static unsigned gpio25_pins[] = { 25 }; |
116 | static unsigned gpio26_pins[] = { 26 }; |
117 | static unsigned gpio27_pins[] = { 27 }; |
118 | static unsigned gpio28_pins[] = { 28 }; |
119 | static unsigned gpio29_pins[] = { 29 }; |
120 | static unsigned gpio30_pins[] = { 30 }; |
121 | static unsigned gpio31_pins[] = { 31 }; |
122 | static unsigned uart1_grp_pins[] = { 30, 31, 32, 33 }; |
123 | |
124 | static struct pingroup bcm6368_groups[] = { |
125 | BCM_PIN_GROUP(gpio0), |
126 | BCM_PIN_GROUP(gpio1), |
127 | BCM_PIN_GROUP(gpio2), |
128 | BCM_PIN_GROUP(gpio3), |
129 | BCM_PIN_GROUP(gpio4), |
130 | BCM_PIN_GROUP(gpio5), |
131 | BCM_PIN_GROUP(gpio6), |
132 | BCM_PIN_GROUP(gpio7), |
133 | BCM_PIN_GROUP(gpio8), |
134 | BCM_PIN_GROUP(gpio9), |
135 | BCM_PIN_GROUP(gpio10), |
136 | BCM_PIN_GROUP(gpio11), |
137 | BCM_PIN_GROUP(gpio12), |
138 | BCM_PIN_GROUP(gpio13), |
139 | BCM_PIN_GROUP(gpio14), |
140 | BCM_PIN_GROUP(gpio15), |
141 | BCM_PIN_GROUP(gpio16), |
142 | BCM_PIN_GROUP(gpio17), |
143 | BCM_PIN_GROUP(gpio18), |
144 | BCM_PIN_GROUP(gpio19), |
145 | BCM_PIN_GROUP(gpio20), |
146 | BCM_PIN_GROUP(gpio21), |
147 | BCM_PIN_GROUP(gpio22), |
148 | BCM_PIN_GROUP(gpio23), |
149 | BCM_PIN_GROUP(gpio24), |
150 | BCM_PIN_GROUP(gpio25), |
151 | BCM_PIN_GROUP(gpio26), |
152 | BCM_PIN_GROUP(gpio27), |
153 | BCM_PIN_GROUP(gpio28), |
154 | BCM_PIN_GROUP(gpio29), |
155 | BCM_PIN_GROUP(gpio30), |
156 | BCM_PIN_GROUP(gpio31), |
157 | BCM_PIN_GROUP(uart1_grp), |
158 | }; |
159 | |
160 | static const char * const analog_afe_0_groups[] = { |
161 | "gpio0" , |
162 | }; |
163 | |
164 | static const char * const analog_afe_1_groups[] = { |
165 | "gpio1" , |
166 | }; |
167 | |
168 | static const char * const sys_irq_groups[] = { |
169 | "gpio2" , |
170 | }; |
171 | |
172 | static const char * const serial_led_data_groups[] = { |
173 | "gpio3" , |
174 | }; |
175 | |
176 | static const char * const serial_led_clk_groups[] = { |
177 | "gpio4" , |
178 | }; |
179 | |
180 | static const char * const inet_led_groups[] = { |
181 | "gpio5" , |
182 | }; |
183 | |
184 | static const char * const ephy0_led_groups[] = { |
185 | "gpio6" , |
186 | }; |
187 | |
188 | static const char * const ephy1_led_groups[] = { |
189 | "gpio7" , |
190 | }; |
191 | |
192 | static const char * const ephy2_led_groups[] = { |
193 | "gpio8" , |
194 | }; |
195 | |
196 | static const char * const ephy3_led_groups[] = { |
197 | "gpio9" , |
198 | }; |
199 | |
200 | static const char * const robosw_led_data_groups[] = { |
201 | "gpio10" , |
202 | }; |
203 | |
204 | static const char * const robosw_led_clk_groups[] = { |
205 | "gpio11" , |
206 | }; |
207 | |
208 | static const char * const robosw_led0_groups[] = { |
209 | "gpio12" , |
210 | }; |
211 | |
212 | static const char * const robosw_led1_groups[] = { |
213 | "gpio13" , |
214 | }; |
215 | |
216 | static const char * const usb_device_led_groups[] = { |
217 | "gpio14" , |
218 | }; |
219 | |
220 | static const char * const pci_req1_groups[] = { |
221 | "gpio16" , |
222 | }; |
223 | |
224 | static const char * const pci_gnt1_groups[] = { |
225 | "gpio17" , |
226 | }; |
227 | |
228 | static const char * const pci_intb_groups[] = { |
229 | "gpio18" , |
230 | }; |
231 | |
232 | static const char * const pci_req0_groups[] = { |
233 | "gpio19" , |
234 | }; |
235 | |
236 | static const char * const pci_gnt0_groups[] = { |
237 | "gpio20" , |
238 | }; |
239 | |
240 | static const char * const pcmcia_cd1_groups[] = { |
241 | "gpio22" , |
242 | }; |
243 | |
244 | static const char * const pcmcia_cd2_groups[] = { |
245 | "gpio23" , |
246 | }; |
247 | |
248 | static const char * const pcmcia_vs1_groups[] = { |
249 | "gpio24" , |
250 | }; |
251 | |
252 | static const char * const pcmcia_vs2_groups[] = { |
253 | "gpio25" , |
254 | }; |
255 | |
256 | static const char * const ebi_cs2_groups[] = { |
257 | "gpio26" , |
258 | }; |
259 | |
260 | static const char * const ebi_cs3_groups[] = { |
261 | "gpio27" , |
262 | }; |
263 | |
264 | static const char * const spi_cs2_groups[] = { |
265 | "gpio28" , |
266 | }; |
267 | |
268 | static const char * const spi_cs3_groups[] = { |
269 | "gpio29" , |
270 | }; |
271 | |
272 | static const char * const spi_cs4_groups[] = { |
273 | "gpio30" , |
274 | }; |
275 | |
276 | static const char * const spi_cs5_groups[] = { |
277 | "gpio31" , |
278 | }; |
279 | |
280 | static const char * const uart1_groups[] = { |
281 | "uart1_grp" , |
282 | }; |
283 | |
284 | #define BCM6368_FUN(n, out) \ |
285 | { \ |
286 | .name = #n, \ |
287 | .groups = n##_groups, \ |
288 | .num_groups = ARRAY_SIZE(n##_groups), \ |
289 | .dir_out = out, \ |
290 | } |
291 | |
292 | #define BCM6368_BASEMODE_FUN(n, val, out) \ |
293 | { \ |
294 | .name = #n, \ |
295 | .groups = n##_groups, \ |
296 | .num_groups = ARRAY_SIZE(n##_groups), \ |
297 | .basemode = BCM6368_BASEMODE_##val, \ |
298 | .dir_out = out, \ |
299 | } |
300 | |
301 | static const struct bcm6368_function bcm6368_funcs[] = { |
302 | BCM6368_FUN(analog_afe_0, 1), |
303 | BCM6368_FUN(analog_afe_1, 1), |
304 | BCM6368_FUN(sys_irq, 1), |
305 | BCM6368_FUN(serial_led_data, 1), |
306 | BCM6368_FUN(serial_led_clk, 1), |
307 | BCM6368_FUN(inet_led, 1), |
308 | BCM6368_FUN(ephy0_led, 1), |
309 | BCM6368_FUN(ephy1_led, 1), |
310 | BCM6368_FUN(ephy2_led, 1), |
311 | BCM6368_FUN(ephy3_led, 1), |
312 | BCM6368_FUN(robosw_led_data, 1), |
313 | BCM6368_FUN(robosw_led_clk, 1), |
314 | BCM6368_FUN(robosw_led0, 1), |
315 | BCM6368_FUN(robosw_led1, 1), |
316 | BCM6368_FUN(usb_device_led, 1), |
317 | BCM6368_FUN(pci_req1, 0), |
318 | BCM6368_FUN(pci_gnt1, 0), |
319 | BCM6368_FUN(pci_intb, 0), |
320 | BCM6368_FUN(pci_req0, 0), |
321 | BCM6368_FUN(pci_gnt0, 0), |
322 | BCM6368_FUN(pcmcia_cd1, 0), |
323 | BCM6368_FUN(pcmcia_cd2, 0), |
324 | BCM6368_FUN(pcmcia_vs1, 0), |
325 | BCM6368_FUN(pcmcia_vs2, 0), |
326 | BCM6368_FUN(ebi_cs2, 1), |
327 | BCM6368_FUN(ebi_cs3, 1), |
328 | BCM6368_FUN(spi_cs2, 1), |
329 | BCM6368_FUN(spi_cs3, 1), |
330 | BCM6368_FUN(spi_cs4, 1), |
331 | BCM6368_FUN(spi_cs5, 1), |
332 | BCM6368_BASEMODE_FUN(uart1, UART1, 0x6), |
333 | }; |
334 | |
335 | static int bcm6368_pinctrl_get_group_count(struct pinctrl_dev *pctldev) |
336 | { |
337 | return ARRAY_SIZE(bcm6368_groups); |
338 | } |
339 | |
340 | static const char *bcm6368_pinctrl_get_group_name(struct pinctrl_dev *pctldev, |
341 | unsigned group) |
342 | { |
343 | return bcm6368_groups[group].name; |
344 | } |
345 | |
346 | static int bcm6368_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, |
347 | unsigned group, const unsigned **pins, |
348 | unsigned *npins) |
349 | { |
350 | *pins = bcm6368_groups[group].pins; |
351 | *npins = bcm6368_groups[group].npins; |
352 | |
353 | return 0; |
354 | } |
355 | |
356 | static int bcm6368_pinctrl_get_func_count(struct pinctrl_dev *pctldev) |
357 | { |
358 | return ARRAY_SIZE(bcm6368_funcs); |
359 | } |
360 | |
361 | static const char *bcm6368_pinctrl_get_func_name(struct pinctrl_dev *pctldev, |
362 | unsigned selector) |
363 | { |
364 | return bcm6368_funcs[selector].name; |
365 | } |
366 | |
367 | static int bcm6368_pinctrl_get_groups(struct pinctrl_dev *pctldev, |
368 | unsigned selector, |
369 | const char * const **groups, |
370 | unsigned * const num_groups) |
371 | { |
372 | *groups = bcm6368_funcs[selector].groups; |
373 | *num_groups = bcm6368_funcs[selector].num_groups; |
374 | |
375 | return 0; |
376 | } |
377 | |
378 | static int bcm6368_pinctrl_set_mux(struct pinctrl_dev *pctldev, |
379 | unsigned selector, unsigned group) |
380 | { |
381 | struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); |
382 | struct bcm6368_priv *priv = pc->driver_data; |
383 | const struct pingroup *pg = &bcm6368_groups[group]; |
384 | const struct bcm6368_function *fun = &bcm6368_funcs[selector]; |
385 | int i, pin; |
386 | |
387 | if (fun->basemode) { |
388 | unsigned int mask = 0; |
389 | |
390 | for (i = 0; i < pg->npins; i++) { |
391 | pin = pg->pins[i]; |
392 | if (pin < BCM63XX_BANK_GPIOS) |
393 | mask |= BIT(pin); |
394 | } |
395 | |
396 | regmap_update_bits(map: pc->regs, BCM6368_MODE_REG, mask, val: 0); |
397 | regmap_field_write(field: priv->overlays, val: fun->basemode); |
398 | } else { |
399 | pin = pg->pins[0]; |
400 | |
401 | if (bcm6368_pins[pin].drv_data) |
402 | regmap_field_write(field: priv->overlays, |
403 | BCM6368_BASEMODE_GPIO); |
404 | |
405 | regmap_update_bits(map: pc->regs, BCM6368_MODE_REG, BIT(pin), |
406 | BIT(pin)); |
407 | } |
408 | |
409 | for (pin = 0; pin < pg->npins; pin++) { |
410 | struct pinctrl_gpio_range *range; |
411 | int hw_gpio = bcm6368_pins[pin].number; |
412 | |
413 | range = pinctrl_find_gpio_range_from_pin(pctldev, pin: hw_gpio); |
414 | if (range) { |
415 | struct gpio_chip *gc = range->gc; |
416 | |
417 | if (fun->dir_out & BIT(pin)) |
418 | gc->direction_output(gc, hw_gpio, 0); |
419 | else |
420 | gc->direction_input(gc, hw_gpio); |
421 | } |
422 | } |
423 | |
424 | return 0; |
425 | } |
426 | |
427 | static int bcm6368_gpio_request_enable(struct pinctrl_dev *pctldev, |
428 | struct pinctrl_gpio_range *range, |
429 | unsigned offset) |
430 | { |
431 | struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); |
432 | struct bcm6368_priv *priv = pc->driver_data; |
433 | |
434 | if (offset >= BCM63XX_BANK_GPIOS && !bcm6368_pins[offset].drv_data) |
435 | return 0; |
436 | |
437 | /* disable all functions using this pin */ |
438 | if (offset < BCM63XX_BANK_GPIOS) |
439 | regmap_update_bits(map: pc->regs, BCM6368_MODE_REG, BIT(offset), val: 0); |
440 | |
441 | if (bcm6368_pins[offset].drv_data) |
442 | regmap_field_write(field: priv->overlays, BCM6368_BASEMODE_GPIO); |
443 | |
444 | return 0; |
445 | } |
446 | |
447 | static const struct pinctrl_ops bcm6368_pctl_ops = { |
448 | .dt_free_map = pinctrl_utils_free_map, |
449 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, |
450 | .get_group_name = bcm6368_pinctrl_get_group_name, |
451 | .get_group_pins = bcm6368_pinctrl_get_group_pins, |
452 | .get_groups_count = bcm6368_pinctrl_get_group_count, |
453 | }; |
454 | |
455 | static const struct pinmux_ops bcm6368_pmx_ops = { |
456 | .get_function_groups = bcm6368_pinctrl_get_groups, |
457 | .get_function_name = bcm6368_pinctrl_get_func_name, |
458 | .get_functions_count = bcm6368_pinctrl_get_func_count, |
459 | .gpio_request_enable = bcm6368_gpio_request_enable, |
460 | .set_mux = bcm6368_pinctrl_set_mux, |
461 | .strict = true, |
462 | }; |
463 | |
464 | static const struct bcm63xx_pinctrl_soc bcm6368_soc = { |
465 | .ngpios = BCM6368_NUM_GPIOS, |
466 | .npins = ARRAY_SIZE(bcm6368_pins), |
467 | .pctl_ops = &bcm6368_pctl_ops, |
468 | .pins = bcm6368_pins, |
469 | .pmx_ops = &bcm6368_pmx_ops, |
470 | }; |
471 | |
472 | static int bcm6368_pinctrl_probe(struct platform_device *pdev) |
473 | { |
474 | struct reg_field overlays = REG_FIELD(BCM6368_BASEMODE_REG, 0, 15); |
475 | struct device *dev = &pdev->dev; |
476 | struct bcm63xx_pinctrl *pc; |
477 | struct bcm6368_priv *priv; |
478 | int err; |
479 | |
480 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
481 | if (!priv) |
482 | return -ENOMEM; |
483 | |
484 | err = bcm63xx_pinctrl_probe(pdev, soc: &bcm6368_soc, driver_data: (void *) priv); |
485 | if (err) |
486 | return err; |
487 | |
488 | pc = platform_get_drvdata(pdev); |
489 | |
490 | priv->overlays = devm_regmap_field_alloc(dev, regmap: pc->regs, reg_field: overlays); |
491 | if (IS_ERR(ptr: priv->overlays)) |
492 | return PTR_ERR(ptr: priv->overlays); |
493 | |
494 | return 0; |
495 | } |
496 | |
497 | static const struct of_device_id bcm6368_pinctrl_match[] = { |
498 | { .compatible = "brcm,bcm6368-pinctrl" , }, |
499 | { /* sentinel */ } |
500 | }; |
501 | |
502 | static struct platform_driver bcm6368_pinctrl_driver = { |
503 | .probe = bcm6368_pinctrl_probe, |
504 | .driver = { |
505 | .name = "bcm6368-pinctrl" , |
506 | .of_match_table = bcm6368_pinctrl_match, |
507 | }, |
508 | }; |
509 | |
510 | builtin_platform_driver(bcm6368_pinctrl_driver); |
511 | |