Commit | Line | Data |
---|---|---|
9bf34ac5 ÁFR |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Driver for BCM6328 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 BCM6328_NUM_GPIOS 32 | |
22 | ||
23 | #define BCM6328_MODE_REG 0x18 | |
24 | #define BCM6328_MUX_HI_REG 0x1c | |
25 | #define BCM6328_MUX_LO_REG 0x20 | |
26 | #define BCM6328_MUX_OTHER_REG 0x24 | |
27 | #define BCM6328_MUX_MASK GENMASK(1, 0) | |
28 | ||
29 | struct bcm6328_pingroup { | |
30 | const char *name; | |
31 | const unsigned * const pins; | |
32 | const unsigned num_pins; | |
33 | }; | |
34 | ||
35 | struct bcm6328_function { | |
36 | const char *name; | |
37 | const char * const *groups; | |
38 | const unsigned num_groups; | |
39 | ||
40 | unsigned mode_val:1; | |
41 | unsigned mux_val:2; | |
42 | }; | |
43 | ||
44 | static const unsigned int bcm6328_mux[] = { | |
45 | BCM6328_MUX_LO_REG, | |
46 | BCM6328_MUX_HI_REG, | |
47 | BCM6328_MUX_OTHER_REG | |
48 | }; | |
49 | ||
50 | static const struct pinctrl_pin_desc bcm6328_pins[] = { | |
51 | PINCTRL_PIN(0, "gpio0"), | |
52 | PINCTRL_PIN(1, "gpio1"), | |
53 | PINCTRL_PIN(2, "gpio2"), | |
54 | PINCTRL_PIN(3, "gpio3"), | |
55 | PINCTRL_PIN(4, "gpio4"), | |
56 | PINCTRL_PIN(5, "gpio5"), | |
57 | PINCTRL_PIN(6, "gpio6"), | |
58 | PINCTRL_PIN(7, "gpio7"), | |
59 | PINCTRL_PIN(8, "gpio8"), | |
60 | PINCTRL_PIN(9, "gpio9"), | |
61 | PINCTRL_PIN(10, "gpio10"), | |
62 | PINCTRL_PIN(11, "gpio11"), | |
63 | PINCTRL_PIN(12, "gpio12"), | |
64 | PINCTRL_PIN(13, "gpio13"), | |
65 | PINCTRL_PIN(14, "gpio14"), | |
66 | PINCTRL_PIN(15, "gpio15"), | |
67 | PINCTRL_PIN(16, "gpio16"), | |
68 | PINCTRL_PIN(17, "gpio17"), | |
69 | PINCTRL_PIN(18, "gpio18"), | |
70 | PINCTRL_PIN(19, "gpio19"), | |
71 | PINCTRL_PIN(20, "gpio20"), | |
72 | PINCTRL_PIN(21, "gpio21"), | |
73 | PINCTRL_PIN(22, "gpio22"), | |
74 | PINCTRL_PIN(23, "gpio23"), | |
75 | PINCTRL_PIN(24, "gpio24"), | |
76 | PINCTRL_PIN(25, "gpio25"), | |
77 | PINCTRL_PIN(26, "gpio26"), | |
78 | PINCTRL_PIN(27, "gpio27"), | |
79 | PINCTRL_PIN(28, "gpio28"), | |
80 | PINCTRL_PIN(29, "gpio29"), | |
81 | PINCTRL_PIN(30, "gpio30"), | |
82 | PINCTRL_PIN(31, "gpio31"), | |
83 | ||
84 | /* | |
85 | * No idea where they really are; so let's put them according | |
86 | * to their mux offsets. | |
87 | */ | |
88 | PINCTRL_PIN(36, "hsspi_cs1"), | |
89 | PINCTRL_PIN(38, "usb_p2"), | |
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 | ||
125 | static unsigned hsspi_cs1_pins[] = { 36 }; | |
126 | static unsigned usb_port1_pins[] = { 38 }; | |
127 | ||
128 | #define BCM6328_GROUP(n) \ | |
129 | { \ | |
130 | .name = #n, \ | |
131 | .pins = n##_pins, \ | |
132 | .num_pins = ARRAY_SIZE(n##_pins), \ | |
133 | } | |
134 | ||
135 | static struct bcm6328_pingroup bcm6328_groups[] = { | |
136 | BCM6328_GROUP(gpio0), | |
137 | BCM6328_GROUP(gpio1), | |
138 | BCM6328_GROUP(gpio2), | |
139 | BCM6328_GROUP(gpio3), | |
140 | BCM6328_GROUP(gpio4), | |
141 | BCM6328_GROUP(gpio5), | |
142 | BCM6328_GROUP(gpio6), | |
143 | BCM6328_GROUP(gpio7), | |
144 | BCM6328_GROUP(gpio8), | |
145 | BCM6328_GROUP(gpio9), | |
146 | BCM6328_GROUP(gpio10), | |
147 | BCM6328_GROUP(gpio11), | |
148 | BCM6328_GROUP(gpio12), | |
149 | BCM6328_GROUP(gpio13), | |
150 | BCM6328_GROUP(gpio14), | |
151 | BCM6328_GROUP(gpio15), | |
152 | BCM6328_GROUP(gpio16), | |
153 | BCM6328_GROUP(gpio17), | |
154 | BCM6328_GROUP(gpio18), | |
155 | BCM6328_GROUP(gpio19), | |
156 | BCM6328_GROUP(gpio20), | |
157 | BCM6328_GROUP(gpio21), | |
158 | BCM6328_GROUP(gpio22), | |
159 | BCM6328_GROUP(gpio23), | |
160 | BCM6328_GROUP(gpio24), | |
161 | BCM6328_GROUP(gpio25), | |
162 | BCM6328_GROUP(gpio26), | |
163 | BCM6328_GROUP(gpio27), | |
164 | BCM6328_GROUP(gpio28), | |
165 | BCM6328_GROUP(gpio29), | |
166 | BCM6328_GROUP(gpio30), | |
167 | BCM6328_GROUP(gpio31), | |
168 | ||
169 | BCM6328_GROUP(hsspi_cs1), | |
170 | BCM6328_GROUP(usb_port1), | |
171 | }; | |
172 | ||
173 | /* GPIO_MODE */ | |
174 | static const char * const led_groups[] = { | |
175 | "gpio0", | |
176 | "gpio1", | |
177 | "gpio2", | |
178 | "gpio3", | |
179 | "gpio4", | |
180 | "gpio5", | |
181 | "gpio6", | |
182 | "gpio7", | |
183 | "gpio8", | |
184 | "gpio9", | |
185 | "gpio10", | |
186 | "gpio11", | |
187 | "gpio12", | |
188 | "gpio13", | |
189 | "gpio14", | |
190 | "gpio15", | |
191 | "gpio16", | |
192 | "gpio17", | |
193 | "gpio18", | |
194 | "gpio19", | |
195 | "gpio20", | |
196 | "gpio21", | |
197 | "gpio22", | |
198 | "gpio23", | |
199 | }; | |
200 | ||
201 | /* PINMUX_SEL */ | |
202 | static const char * const serial_led_data_groups[] = { | |
203 | "gpio6", | |
204 | }; | |
205 | ||
206 | static const char * const serial_led_clk_groups[] = { | |
207 | "gpio7", | |
208 | }; | |
209 | ||
210 | static const char * const inet_act_led_groups[] = { | |
211 | "gpio11", | |
212 | }; | |
213 | ||
214 | static const char * const pcie_clkreq_groups[] = { | |
215 | "gpio16", | |
216 | }; | |
217 | ||
218 | static const char * const ephy0_act_led_groups[] = { | |
219 | "gpio25", | |
220 | }; | |
221 | ||
222 | static const char * const ephy1_act_led_groups[] = { | |
223 | "gpio26", | |
224 | }; | |
225 | ||
226 | static const char * const ephy2_act_led_groups[] = { | |
227 | "gpio27", | |
228 | }; | |
229 | ||
230 | static const char * const ephy3_act_led_groups[] = { | |
231 | "gpio28", | |
232 | }; | |
233 | ||
234 | static const char * const hsspi_cs1_groups[] = { | |
235 | "hsspi_cs1" | |
236 | }; | |
237 | ||
238 | static const char * const usb_host_port_groups[] = { | |
239 | "usb_port1", | |
240 | }; | |
241 | ||
242 | static const char * const usb_device_port_groups[] = { | |
243 | "usb_port1", | |
244 | }; | |
245 | ||
246 | #define BCM6328_MODE_FUN(n) \ | |
247 | { \ | |
248 | .name = #n, \ | |
249 | .groups = n##_groups, \ | |
250 | .num_groups = ARRAY_SIZE(n##_groups), \ | |
251 | .mode_val = 1, \ | |
252 | } | |
253 | ||
254 | #define BCM6328_MUX_FUN(n, mux) \ | |
255 | { \ | |
256 | .name = #n, \ | |
257 | .groups = n##_groups, \ | |
258 | .num_groups = ARRAY_SIZE(n##_groups), \ | |
259 | .mux_val = mux, \ | |
260 | } | |
261 | ||
262 | static const struct bcm6328_function bcm6328_funcs[] = { | |
263 | BCM6328_MODE_FUN(led), | |
264 | BCM6328_MUX_FUN(serial_led_data, 2), | |
265 | BCM6328_MUX_FUN(serial_led_clk, 2), | |
266 | BCM6328_MUX_FUN(inet_act_led, 1), | |
267 | BCM6328_MUX_FUN(pcie_clkreq, 2), | |
268 | BCM6328_MUX_FUN(ephy0_act_led, 1), | |
269 | BCM6328_MUX_FUN(ephy1_act_led, 1), | |
270 | BCM6328_MUX_FUN(ephy2_act_led, 1), | |
271 | BCM6328_MUX_FUN(ephy3_act_led, 1), | |
272 | BCM6328_MUX_FUN(hsspi_cs1, 2), | |
273 | BCM6328_MUX_FUN(usb_host_port, 1), | |
274 | BCM6328_MUX_FUN(usb_device_port, 2), | |
275 | }; | |
276 | ||
277 | static inline unsigned int bcm6328_mux_off(unsigned int pin) | |
278 | { | |
279 | return bcm6328_mux[pin / 16]; | |
280 | } | |
281 | ||
282 | static int bcm6328_pinctrl_get_group_count(struct pinctrl_dev *pctldev) | |
283 | { | |
284 | return ARRAY_SIZE(bcm6328_groups); | |
285 | } | |
286 | ||
287 | static const char *bcm6328_pinctrl_get_group_name(struct pinctrl_dev *pctldev, | |
288 | unsigned group) | |
289 | { | |
290 | return bcm6328_groups[group].name; | |
291 | } | |
292 | ||
293 | static int bcm6328_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, | |
294 | unsigned group, const unsigned **pins, | |
295 | unsigned *num_pins) | |
296 | { | |
297 | *pins = bcm6328_groups[group].pins; | |
298 | *num_pins = bcm6328_groups[group].num_pins; | |
299 | ||
300 | return 0; | |
301 | } | |
302 | ||
303 | static int bcm6328_pinctrl_get_func_count(struct pinctrl_dev *pctldev) | |
304 | { | |
305 | return ARRAY_SIZE(bcm6328_funcs); | |
306 | } | |
307 | ||
308 | static const char *bcm6328_pinctrl_get_func_name(struct pinctrl_dev *pctldev, | |
309 | unsigned selector) | |
310 | { | |
311 | return bcm6328_funcs[selector].name; | |
312 | } | |
313 | ||
314 | static int bcm6328_pinctrl_get_groups(struct pinctrl_dev *pctldev, | |
315 | unsigned selector, | |
316 | const char * const **groups, | |
317 | unsigned * const num_groups) | |
318 | { | |
319 | *groups = bcm6328_funcs[selector].groups; | |
320 | *num_groups = bcm6328_funcs[selector].num_groups; | |
321 | ||
322 | return 0; | |
323 | } | |
324 | ||
325 | static void bcm6328_rmw_mux(struct bcm63xx_pinctrl *pc, unsigned pin, | |
326 | unsigned int mode, unsigned int mux) | |
327 | { | |
328 | if (pin < BCM6328_NUM_GPIOS) | |
329 | regmap_update_bits(pc->regs, BCM6328_MODE_REG, BIT(pin), | |
330 | mode ? BIT(pin) : 0); | |
331 | ||
332 | regmap_update_bits(pc->regs, bcm6328_mux_off(pin), | |
333 | BCM6328_MUX_MASK << ((pin % 16) * 2), | |
334 | mux << ((pin % 16) * 2)); | |
335 | } | |
336 | ||
337 | static int bcm6328_pinctrl_set_mux(struct pinctrl_dev *pctldev, | |
338 | unsigned selector, unsigned group) | |
339 | { | |
340 | struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); | |
341 | const struct bcm6328_pingroup *pg = &bcm6328_groups[group]; | |
342 | const struct bcm6328_function *f = &bcm6328_funcs[selector]; | |
343 | ||
344 | bcm6328_rmw_mux(pc, pg->pins[0], f->mode_val, f->mux_val); | |
345 | ||
346 | return 0; | |
347 | } | |
348 | ||
349 | static int bcm6328_gpio_request_enable(struct pinctrl_dev *pctldev, | |
350 | struct pinctrl_gpio_range *range, | |
351 | unsigned offset) | |
352 | { | |
353 | struct bcm63xx_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); | |
354 | ||
355 | /* disable all functions using this pin */ | |
356 | bcm6328_rmw_mux(pc, offset, 0, 0); | |
357 | ||
358 | return 0; | |
359 | } | |
360 | ||
d9779093 | 361 | static const struct pinctrl_ops bcm6328_pctl_ops = { |
9bf34ac5 ÁFR |
362 | .dt_free_map = pinctrl_utils_free_map, |
363 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, | |
364 | .get_group_name = bcm6328_pinctrl_get_group_name, | |
365 | .get_group_pins = bcm6328_pinctrl_get_group_pins, | |
366 | .get_groups_count = bcm6328_pinctrl_get_group_count, | |
367 | }; | |
368 | ||
0c683876 | 369 | static const struct pinmux_ops bcm6328_pmx_ops = { |
9bf34ac5 ÁFR |
370 | .get_function_groups = bcm6328_pinctrl_get_groups, |
371 | .get_function_name = bcm6328_pinctrl_get_func_name, | |
372 | .get_functions_count = bcm6328_pinctrl_get_func_count, | |
373 | .gpio_request_enable = bcm6328_gpio_request_enable, | |
374 | .set_mux = bcm6328_pinctrl_set_mux, | |
375 | .strict = true, | |
376 | }; | |
377 | ||
378 | static const struct bcm63xx_pinctrl_soc bcm6328_soc = { | |
379 | .ngpios = BCM6328_NUM_GPIOS, | |
380 | .npins = ARRAY_SIZE(bcm6328_pins), | |
381 | .pctl_ops = &bcm6328_pctl_ops, | |
382 | .pins = bcm6328_pins, | |
383 | .pmx_ops = &bcm6328_pmx_ops, | |
384 | }; | |
385 | ||
386 | static int bcm6328_pinctrl_probe(struct platform_device *pdev) | |
387 | { | |
388 | return bcm63xx_pinctrl_probe(pdev, &bcm6328_soc, NULL); | |
389 | } | |
390 | ||
391 | static const struct of_device_id bcm6328_pinctrl_match[] = { | |
392 | { .compatible = "brcm,bcm6328-pinctrl", }, | |
393 | { /* sentinel */ } | |
394 | }; | |
395 | ||
396 | static struct platform_driver bcm6328_pinctrl_driver = { | |
397 | .probe = bcm6328_pinctrl_probe, | |
398 | .driver = { | |
399 | .name = "bcm6328-pinctrl", | |
400 | .of_match_table = bcm6328_pinctrl_match, | |
401 | }, | |
402 | }; | |
403 | ||
404 | builtin_platform_driver(bcm6328_pinctrl_driver); |