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