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_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 | |
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), |
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, |
282 | unsigned *npins) |
283 | { |
284 | *pins = bcm6328_groups[group].pins; |
285 | *npins = bcm6328_groups[group].npins; |
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(map: pc->regs, BCM6328_MODE_REG, BIT(pin), |
317 | val: mode ? BIT(pin) : 0); |
318 | |
319 | regmap_update_bits(map: pc->regs, reg: bcm6328_mux_off(pin), |
320 | BCM6328_MUX_MASK << ((pin % 16) * 2), |
321 | val: 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); |
328 | const struct pingroup *pg = &bcm6328_groups[group]; |
329 | const struct bcm6328_function *f = &bcm6328_funcs[selector]; |
330 | |
331 | bcm6328_rmw_mux(pc, pin: pg->pins[0], mode: f->mode_val, mux: 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, pin: offset, mode: 0, mux: 0); |
344 | |
345 | return 0; |
346 | } |
347 | |
348 | static const struct pinctrl_ops bcm6328_pctl_ops = { |
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 | |
356 | static const struct pinmux_ops bcm6328_pmx_ops = { |
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, soc: &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); |
392 | |