1 | /* |
2 | * Driver for the Axis ARTPEC-6 pin controller |
3 | * |
4 | * Author: Chris Paterson <chris.paterson@linux.pieboy.co.uk> |
5 | * |
6 | * This file is licensed under the terms of the GNU General Public |
7 | * License version 2. This program is licensed "as is" without any |
8 | * warranty of any kind, whether express or implied. |
9 | */ |
10 | |
11 | #include <linux/device.h> |
12 | #include <linux/err.h> |
13 | #include <linux/init.h> |
14 | #include <linux/io.h> |
15 | #include <linux/of.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/pinctrl/pinctrl.h> |
18 | #include <linux/pinctrl/pinconf-generic.h> |
19 | #include <linux/pinctrl/pinconf.h> |
20 | #include <linux/pinctrl/pinmux.h> |
21 | #include <linux/slab.h> |
22 | #include "core.h" |
23 | #include "pinconf.h" |
24 | #include "pinctrl-utils.h" |
25 | |
26 | #define ARTPEC6_LAST_PIN 97 /* 97 pins in pinmux */ |
27 | #define ARTPEC6_MAX_MUXABLE 35 /* Last pin with muxable function */ |
28 | |
29 | /* Pinmux control register bit definitions */ |
30 | #define ARTPEC6_PINMUX_UDC0_MASK 0x00000001 |
31 | #define ARTPEC6_PINMUX_UDC0_SHIFT 0 |
32 | #define ARTPEC6_PINMUX_UDC1_MASK 0x00000002 |
33 | #define ARTPEC6_PINMUX_UDC1_SHIFT 1 |
34 | #define ARTPEC6_PINMUX_DRV_MASK 0x00000060 |
35 | #define ARTPEC6_PINMUX_DRV_SHIFT 5 |
36 | #define ARTPEC6_PINMUX_SEL_MASK 0x00003000 |
37 | #define ARTPEC6_PINMUX_SEL_SHIFT 12 |
38 | |
39 | /* Pinmux configurations */ |
40 | #define ARTPEC6_CONFIG_0 0 |
41 | #define ARTPEC6_CONFIG_1 1 |
42 | #define ARTPEC6_CONFIG_2 2 |
43 | #define ARTPEC6_CONFIG_3 3 |
44 | |
45 | /* Pin drive strength options */ |
46 | #define ARTPEC6_DRIVE_4mA 4 |
47 | #define ARTPEC6_DRIVE_4mA_SET 0 |
48 | #define ARTPEC6_DRIVE_6mA 6 |
49 | #define ARTPEC6_DRIVE_6mA_SET 1 |
50 | #define ARTPEC6_DRIVE_8mA 8 |
51 | #define ARTPEC6_DRIVE_8mA_SET 2 |
52 | #define ARTPEC6_DRIVE_9mA 9 |
53 | #define ARTPEC6_DRIVE_9mA_SET 3 |
54 | |
55 | struct artpec6_pmx { |
56 | struct device *dev; |
57 | struct pinctrl_dev *pctl; |
58 | void __iomem *base; |
59 | struct pinctrl_pin_desc *pins; |
60 | unsigned int num_pins; |
61 | const struct artpec6_pin_group *pin_groups; |
62 | unsigned int num_pin_groups; |
63 | const struct artpec6_pmx_func *functions; |
64 | unsigned int num_functions; |
65 | }; |
66 | |
67 | struct artpec6_pin_group { |
68 | const char *name; |
69 | const unsigned int *pins; |
70 | const unsigned int num_pins; |
71 | unsigned char config; |
72 | }; |
73 | |
74 | struct artpec6_pmx_func { |
75 | const char *name; |
76 | const char * const *groups; |
77 | const unsigned int num_groups; |
78 | }; |
79 | |
80 | /* pins */ |
81 | static struct pinctrl_pin_desc artpec6_pins[] = { |
82 | PINCTRL_PIN(0, "GPIO0" ), |
83 | PINCTRL_PIN(1, "GPIO1" ), |
84 | PINCTRL_PIN(2, "GPIO2" ), |
85 | PINCTRL_PIN(3, "GPIO3" ), |
86 | PINCTRL_PIN(4, "GPIO4" ), |
87 | PINCTRL_PIN(5, "GPIO5" ), |
88 | PINCTRL_PIN(6, "GPIO6" ), |
89 | PINCTRL_PIN(7, "GPIO7" ), |
90 | PINCTRL_PIN(8, "GPIO8" ), |
91 | PINCTRL_PIN(9, "GPIO9" ), |
92 | PINCTRL_PIN(10, "GPIO10" ), |
93 | PINCTRL_PIN(11, "GPIO11" ), |
94 | PINCTRL_PIN(12, "GPIO12" ), |
95 | PINCTRL_PIN(13, "GPIO13" ), |
96 | PINCTRL_PIN(14, "GPIO14" ), |
97 | PINCTRL_PIN(15, "GPIO15" ), |
98 | PINCTRL_PIN(16, "GPIO16" ), |
99 | PINCTRL_PIN(17, "GPIO17" ), |
100 | PINCTRL_PIN(18, "GPIO18" ), |
101 | PINCTRL_PIN(19, "GPIO19" ), |
102 | PINCTRL_PIN(20, "GPIO20" ), |
103 | PINCTRL_PIN(21, "GPIO21" ), |
104 | PINCTRL_PIN(22, "GPIO22" ), |
105 | PINCTRL_PIN(23, "GPIO23" ), |
106 | PINCTRL_PIN(24, "GPIO24" ), |
107 | PINCTRL_PIN(25, "GPIO25" ), |
108 | PINCTRL_PIN(26, "GPIO26" ), |
109 | PINCTRL_PIN(27, "GPIO27" ), |
110 | PINCTRL_PIN(28, "GPIO28" ), |
111 | PINCTRL_PIN(29, "GPIO29" ), |
112 | PINCTRL_PIN(30, "GPIO30" ), |
113 | PINCTRL_PIN(31, "GPIO31" ), |
114 | PINCTRL_PIN(32, "UART3_TXD" ), |
115 | PINCTRL_PIN(33, "UART3_RXD" ), |
116 | PINCTRL_PIN(34, "UART3_RTS" ), |
117 | PINCTRL_PIN(35, "UART3_CTS" ), |
118 | PINCTRL_PIN(36, "NF_ALE" ), |
119 | PINCTRL_PIN(37, "NF_CE0_N" ), |
120 | PINCTRL_PIN(38, "NF_CE1_N" ), |
121 | PINCTRL_PIN(39, "NF_CLE" ), |
122 | PINCTRL_PIN(40, "NF_RE_N" ), |
123 | PINCTRL_PIN(41, "NF_WE_N" ), |
124 | PINCTRL_PIN(42, "NF_WP0_N" ), |
125 | PINCTRL_PIN(43, "NF_WP1_N" ), |
126 | PINCTRL_PIN(44, "NF_IO0" ), |
127 | PINCTRL_PIN(45, "NF_IO1" ), |
128 | PINCTRL_PIN(46, "NF_IO2" ), |
129 | PINCTRL_PIN(47, "NF_IO3" ), |
130 | PINCTRL_PIN(48, "NF_IO4" ), |
131 | PINCTRL_PIN(49, "NF_IO5" ), |
132 | PINCTRL_PIN(50, "NF_IO6" ), |
133 | PINCTRL_PIN(51, "NF_IO7" ), |
134 | PINCTRL_PIN(52, "NF_RB0_N" ), |
135 | PINCTRL_PIN(53, "SDIO0_CLK" ), |
136 | PINCTRL_PIN(54, "SDIO0_CMD" ), |
137 | PINCTRL_PIN(55, "SDIO0_DAT0" ), |
138 | PINCTRL_PIN(56, "SDIO0_DAT1" ), |
139 | PINCTRL_PIN(57, "SDIO0_DAT2" ), |
140 | PINCTRL_PIN(58, "SDIO0_DAT3" ), |
141 | PINCTRL_PIN(59, "SDI0_CD" ), |
142 | PINCTRL_PIN(60, "SDI0_WP" ), |
143 | PINCTRL_PIN(61, "SDIO1_CLK" ), |
144 | PINCTRL_PIN(62, "SDIO1_CMD" ), |
145 | PINCTRL_PIN(63, "SDIO1_DAT0" ), |
146 | PINCTRL_PIN(64, "SDIO1_DAT1" ), |
147 | PINCTRL_PIN(65, "SDIO1_DAT2" ), |
148 | PINCTRL_PIN(66, "SDIO1_DAT3" ), |
149 | PINCTRL_PIN(67, "SDIO1_CD" ), |
150 | PINCTRL_PIN(68, "SDIO1_WP" ), |
151 | PINCTRL_PIN(69, "GBE_REFCLk" ), |
152 | PINCTRL_PIN(70, "GBE_GTX_CLK" ), |
153 | PINCTRL_PIN(71, "GBE_TX_CLK" ), |
154 | PINCTRL_PIN(72, "GBE_TX_EN" ), |
155 | PINCTRL_PIN(73, "GBE_TX_ER" ), |
156 | PINCTRL_PIN(74, "GBE_TXD0" ), |
157 | PINCTRL_PIN(75, "GBE_TXD1" ), |
158 | PINCTRL_PIN(76, "GBE_TXD2" ), |
159 | PINCTRL_PIN(77, "GBE_TXD3" ), |
160 | PINCTRL_PIN(78, "GBE_TXD4" ), |
161 | PINCTRL_PIN(79, "GBE_TXD5" ), |
162 | PINCTRL_PIN(80, "GBE_TXD6" ), |
163 | PINCTRL_PIN(81, "GBE_TXD7" ), |
164 | PINCTRL_PIN(82, "GBE_RX_CLK" ), |
165 | PINCTRL_PIN(83, "GBE_RX_DV" ), |
166 | PINCTRL_PIN(84, "GBE_RX_ER" ), |
167 | PINCTRL_PIN(85, "GBE_RXD0" ), |
168 | PINCTRL_PIN(86, "GBE_RXD1" ), |
169 | PINCTRL_PIN(87, "GBE_RXD2" ), |
170 | PINCTRL_PIN(88, "GBE_RXD3" ), |
171 | PINCTRL_PIN(89, "GBE_RXD4" ), |
172 | PINCTRL_PIN(90, "GBE_RXD5" ), |
173 | PINCTRL_PIN(91, "GBE_RXD6" ), |
174 | PINCTRL_PIN(92, "GBE_RXD7" ), |
175 | PINCTRL_PIN(93, "GBE_CRS" ), |
176 | PINCTRL_PIN(94, "GBE_COL" ), |
177 | PINCTRL_PIN(95, "GBE_MDC" ), |
178 | PINCTRL_PIN(96, "GBE_MDIO" ), |
179 | }; |
180 | |
181 | static const unsigned int cpuclkout_pins0[] = { 0 }; |
182 | static const unsigned int udlclkout_pins0[] = { 1 }; |
183 | static const unsigned int i2c1_pins0[] = { 2, 3 }; |
184 | static const unsigned int i2c2_pins0[] = { 4, 5 }; |
185 | static const unsigned int i2c3_pins0[] = { 6, 7 }; |
186 | static const unsigned int i2s0_pins0[] = { 8, 9, 10, 11 }; |
187 | static const unsigned int i2s1_pins0[] = { 12, 13, 14, 15 }; |
188 | static const unsigned int i2srefclk_pins0[] = { 19 }; |
189 | static const unsigned int spi0_pins0[] = { 12, 13, 14, 15 }; |
190 | static const unsigned int spi1_pins0[] = { 16, 17, 18, 19 }; |
191 | static const unsigned int pciedebug_pins0[] = { 12, 13, 14, 15 }; |
192 | static const unsigned int uart0_pins0[] = { 16, 17, 18, 19, 20, |
193 | 21, 22, 23, 24, 25 }; |
194 | static const unsigned int uart0_pins1[] = { 20, 21, 22, 23 }; |
195 | static const unsigned int uart1_pins0[] = { 24, 25, 26, 27 }; |
196 | static const unsigned int uart2_pins0[] = { 26, 27, 28, 29, 30, |
197 | 31, 32, 33, 34, 35 }; |
198 | static const unsigned int uart2_pins1[] = { 28, 29, 30, 31 }; |
199 | static const unsigned int uart3_pins0[] = { 32, 33, 34, 35 }; |
200 | static const unsigned int uart4_pins0[] = { 20, 21, 22, 23 }; |
201 | static const unsigned int uart5_pins0[] = { 28, 29, 30, 31 }; |
202 | static const unsigned int nand_pins0[] = { 36, 37, 38, 39, 40, 41, |
203 | 42, 43, 44, 45, 46, 47, |
204 | 48, 49, 50, 51, 52 }; |
205 | static const unsigned int sdio0_pins0[] = { 53, 54, 55, 56, 57, 58, 59, 60 }; |
206 | static const unsigned int sdio1_pins0[] = { 61, 62, 63, 64, 65, 66, 67, 68 }; |
207 | static const unsigned int ethernet_pins0[] = { 69, 70, 71, 72, 73, 74, 75, |
208 | 76, 77, 78, 79, 80, 81, 82, |
209 | 83, 84, 85, 86, 87, 88, 89, |
210 | 90, 91, 92, 93, 94, 95, 96 }; |
211 | |
212 | static const struct artpec6_pin_group artpec6_pin_groups[] = { |
213 | { |
214 | .name = "cpuclkoutgrp0" , |
215 | .pins = cpuclkout_pins0, |
216 | .num_pins = ARRAY_SIZE(cpuclkout_pins0), |
217 | .config = ARTPEC6_CONFIG_1, |
218 | }, |
219 | { |
220 | .name = "udlclkoutgrp0" , |
221 | .pins = udlclkout_pins0, |
222 | .num_pins = ARRAY_SIZE(udlclkout_pins0), |
223 | .config = ARTPEC6_CONFIG_1, |
224 | }, |
225 | { |
226 | .name = "i2c1grp0" , |
227 | .pins = i2c1_pins0, |
228 | .num_pins = ARRAY_SIZE(i2c1_pins0), |
229 | .config = ARTPEC6_CONFIG_1, |
230 | }, |
231 | { |
232 | .name = "i2c2grp0" , |
233 | .pins = i2c2_pins0, |
234 | .num_pins = ARRAY_SIZE(i2c2_pins0), |
235 | .config = ARTPEC6_CONFIG_1, |
236 | }, |
237 | { |
238 | .name = "i2c3grp0" , |
239 | .pins = i2c3_pins0, |
240 | .num_pins = ARRAY_SIZE(i2c3_pins0), |
241 | .config = ARTPEC6_CONFIG_1, |
242 | }, |
243 | { |
244 | .name = "i2s0grp0" , |
245 | .pins = i2s0_pins0, |
246 | .num_pins = ARRAY_SIZE(i2s0_pins0), |
247 | .config = ARTPEC6_CONFIG_1, |
248 | }, |
249 | { |
250 | .name = "i2s1grp0" , |
251 | .pins = i2s1_pins0, |
252 | .num_pins = ARRAY_SIZE(i2s1_pins0), |
253 | .config = ARTPEC6_CONFIG_1, |
254 | }, |
255 | { |
256 | .name = "i2srefclkgrp0" , |
257 | .pins = i2srefclk_pins0, |
258 | .num_pins = ARRAY_SIZE(i2srefclk_pins0), |
259 | .config = ARTPEC6_CONFIG_3, |
260 | }, |
261 | { |
262 | .name = "spi0grp0" , |
263 | .pins = spi0_pins0, |
264 | .num_pins = ARRAY_SIZE(spi0_pins0), |
265 | .config = ARTPEC6_CONFIG_2, |
266 | }, |
267 | { |
268 | .name = "spi1grp0" , |
269 | .pins = spi1_pins0, |
270 | .num_pins = ARRAY_SIZE(spi1_pins0), |
271 | .config = ARTPEC6_CONFIG_2, |
272 | }, |
273 | { |
274 | .name = "pciedebuggrp0" , |
275 | .pins = pciedebug_pins0, |
276 | .num_pins = ARRAY_SIZE(pciedebug_pins0), |
277 | .config = ARTPEC6_CONFIG_3, |
278 | }, |
279 | { |
280 | .name = "uart0grp0" , /* All pins. */ |
281 | .pins = uart0_pins0, |
282 | .num_pins = ARRAY_SIZE(uart0_pins0), |
283 | .config = ARTPEC6_CONFIG_1, |
284 | }, |
285 | { |
286 | .name = "uart0grp1" , /* RX/TX and RTS/CTS */ |
287 | .pins = uart0_pins1, |
288 | .num_pins = ARRAY_SIZE(uart0_pins1), |
289 | .config = ARTPEC6_CONFIG_1, |
290 | }, |
291 | { |
292 | .name = "uart0grp2" , /* Only RX/TX pins. */ |
293 | .pins = uart0_pins1, |
294 | .num_pins = ARRAY_SIZE(uart0_pins1) - 2, |
295 | .config = ARTPEC6_CONFIG_1, |
296 | }, |
297 | { |
298 | .name = "uart1grp0" , /* RX/TX and RTS/CTS */ |
299 | .pins = uart1_pins0, |
300 | .num_pins = ARRAY_SIZE(uart1_pins0), |
301 | .config = ARTPEC6_CONFIG_2, |
302 | }, |
303 | { |
304 | .name = "uart1grp1" , /* Only RX/TX pins. */ |
305 | .pins = uart1_pins0, |
306 | .num_pins = 2, |
307 | .config = ARTPEC6_CONFIG_2, |
308 | }, |
309 | { |
310 | .name = "uart2grp0" , /* Full pinout */ |
311 | .pins = uart2_pins0, |
312 | .num_pins = ARRAY_SIZE(uart2_pins0), |
313 | .config = ARTPEC6_CONFIG_1, |
314 | }, |
315 | { |
316 | .name = "uart2grp1" , /* RX/TX and RTS/CTS */ |
317 | .pins = uart2_pins1, |
318 | .num_pins = ARRAY_SIZE(uart2_pins1), |
319 | .config = ARTPEC6_CONFIG_1, |
320 | }, |
321 | { |
322 | .name = "uart2grp2" , /* Only RX/TX */ |
323 | .pins = uart2_pins1, |
324 | .num_pins = 2, |
325 | .config = ARTPEC6_CONFIG_1, |
326 | }, |
327 | { |
328 | .name = "uart3grp0" , /* RX/TX and CTS/RTS */ |
329 | .pins = uart3_pins0, |
330 | .num_pins = ARRAY_SIZE(uart3_pins0), |
331 | .config = ARTPEC6_CONFIG_0, |
332 | }, |
333 | { |
334 | .name = "uart3grp1" , /* Only RX/TX */ |
335 | .pins = uart3_pins0, |
336 | .num_pins = ARRAY_SIZE(uart3_pins0), |
337 | .config = ARTPEC6_CONFIG_0, |
338 | }, |
339 | { |
340 | .name = "uart4grp0" , |
341 | .pins = uart4_pins0, |
342 | .num_pins = ARRAY_SIZE(uart4_pins0), |
343 | .config = ARTPEC6_CONFIG_2, |
344 | }, |
345 | { |
346 | .name = "uart5grp0" , /* TX/RX and RTS/CTS */ |
347 | .pins = uart5_pins0, |
348 | .num_pins = ARRAY_SIZE(uart5_pins0), |
349 | .config = ARTPEC6_CONFIG_2, |
350 | }, |
351 | { |
352 | .name = "uart5grp1" , /* Only TX/RX */ |
353 | .pins = uart5_pins0, |
354 | .num_pins = 2, |
355 | .config = ARTPEC6_CONFIG_2, |
356 | }, |
357 | { |
358 | .name = "uart5nocts" , /* TX/RX/RTS */ |
359 | .pins = uart5_pins0, |
360 | .num_pins = ARRAY_SIZE(uart5_pins0) - 1, |
361 | .config = ARTPEC6_CONFIG_2, |
362 | }, |
363 | { |
364 | .name = "nandgrp0" , |
365 | .pins = nand_pins0, |
366 | .num_pins = ARRAY_SIZE(nand_pins0), |
367 | .config = ARTPEC6_CONFIG_0, |
368 | }, |
369 | { |
370 | .name = "sdio0grp0" , |
371 | .pins = sdio0_pins0, |
372 | .num_pins = ARRAY_SIZE(sdio0_pins0), |
373 | .config = ARTPEC6_CONFIG_0, |
374 | }, |
375 | { |
376 | .name = "sdio1grp0" , |
377 | .pins = sdio1_pins0, |
378 | .num_pins = ARRAY_SIZE(sdio1_pins0), |
379 | .config = ARTPEC6_CONFIG_0, |
380 | }, |
381 | { |
382 | .name = "ethernetgrp0" , |
383 | .pins = ethernet_pins0, |
384 | .num_pins = ARRAY_SIZE(ethernet_pins0), |
385 | .config = ARTPEC6_CONFIG_0, |
386 | }, |
387 | }; |
388 | |
389 | struct pin_register { |
390 | unsigned int start; |
391 | unsigned int end; |
392 | unsigned int reg_base; |
393 | }; |
394 | |
395 | /* |
396 | * The register map has two holes where the pin number |
397 | * no longer fits directly with the register offset. |
398 | * This table allows us to map this easily. |
399 | */ |
400 | static const struct pin_register pin_register[] = { |
401 | { 0, 35, 0x0 }, /* 0x0 - 0x8c */ |
402 | { 36, 52, 0x100 }, /* 0x100 - 0x140 */ |
403 | { 53, 96, 0x180 }, /* 0x180 - 0x22c */ |
404 | }; |
405 | |
406 | static unsigned int artpec6_pmx_reg_offset(unsigned int pin) |
407 | { |
408 | int i; |
409 | |
410 | for (i = 0; i < ARRAY_SIZE(pin_register); i++) { |
411 | if (pin <= pin_register[i].end) { |
412 | return (pin - pin_register[i].start) * 4 + |
413 | pin_register[i].reg_base; |
414 | } |
415 | } |
416 | /* |
417 | * Anything we return here is wrong, but we can only |
418 | * get here if pin is outside registered range. |
419 | */ |
420 | pr_err("%s: Impossible pin %d\n" , __func__, pin); |
421 | return 0; |
422 | } |
423 | |
424 | static int artpec6_get_groups_count(struct pinctrl_dev *pctldev) |
425 | { |
426 | return ARRAY_SIZE(artpec6_pin_groups); |
427 | } |
428 | |
429 | static const char *artpec6_get_group_name(struct pinctrl_dev *pctldev, |
430 | unsigned int group) |
431 | { |
432 | return artpec6_pin_groups[group].name; |
433 | } |
434 | |
435 | static int artpec6_get_group_pins(struct pinctrl_dev *pctldev, |
436 | unsigned int group, |
437 | const unsigned int **pins, |
438 | unsigned int *num_pins) |
439 | { |
440 | *pins = (unsigned int *)artpec6_pin_groups[group].pins; |
441 | *num_pins = artpec6_pin_groups[group].num_pins; |
442 | return 0; |
443 | } |
444 | |
445 | static int artpec6_pconf_drive_mA_to_field(unsigned int mA) |
446 | { |
447 | switch (mA) { |
448 | case ARTPEC6_DRIVE_4mA: |
449 | return ARTPEC6_DRIVE_4mA_SET; |
450 | case ARTPEC6_DRIVE_6mA: |
451 | return ARTPEC6_DRIVE_6mA_SET; |
452 | case ARTPEC6_DRIVE_8mA: |
453 | return ARTPEC6_DRIVE_8mA_SET; |
454 | case ARTPEC6_DRIVE_9mA: |
455 | return ARTPEC6_DRIVE_9mA_SET; |
456 | default: |
457 | return -EINVAL; |
458 | } |
459 | } |
460 | |
461 | static unsigned int artpec6_pconf_drive_field_to_mA(int field) |
462 | { |
463 | switch (field) { |
464 | case ARTPEC6_DRIVE_4mA_SET: |
465 | return ARTPEC6_DRIVE_4mA; |
466 | case ARTPEC6_DRIVE_6mA_SET: |
467 | return ARTPEC6_DRIVE_6mA; |
468 | case ARTPEC6_DRIVE_8mA_SET: |
469 | return ARTPEC6_DRIVE_8mA; |
470 | case ARTPEC6_DRIVE_9mA_SET: |
471 | return ARTPEC6_DRIVE_9mA; |
472 | default: |
473 | /* Shouldn't happen */ |
474 | return 0; |
475 | } |
476 | } |
477 | |
478 | static const struct pinctrl_ops artpec6_pctrl_ops = { |
479 | .get_group_pins = artpec6_get_group_pins, |
480 | .get_groups_count = artpec6_get_groups_count, |
481 | .get_group_name = artpec6_get_group_name, |
482 | .dt_node_to_map = pinconf_generic_dt_node_to_map_all, |
483 | .dt_free_map = pinctrl_utils_free_map, |
484 | }; |
485 | |
486 | static const char * const gpiogrps[] = { |
487 | "cpuclkoutgrp0" , "udlclkoutgrp0" , "i2c1grp0" , "i2c2grp0" , |
488 | "i2c3grp0" , "i2s0grp0" , "i2s1grp0" , "i2srefclkgrp0" , |
489 | "spi0grp0" , "spi1grp0" , "pciedebuggrp0" , "uart0grp0" , |
490 | "uart0grp1" , "uart0grp2" , "uart1grp0" , "uart1grp1" , |
491 | "uart2grp0" , "uart2grp1" , "uart2grp2" , "uart4grp0" , "uart5grp0" , |
492 | "uart5grp1" , "uart5nocts" , |
493 | }; |
494 | static const char * const cpuclkoutgrps[] = { "cpuclkoutgrp0" }; |
495 | static const char * const udlclkoutgrps[] = { "udlclkoutgrp0" }; |
496 | static const char * const i2c1grps[] = { "i2c1grp0" }; |
497 | static const char * const i2c2grps[] = { "i2c2grp0" }; |
498 | static const char * const i2c3grps[] = { "i2c3grp0" }; |
499 | static const char * const i2s0grps[] = { "i2s0grp0" }; |
500 | static const char * const i2s1grps[] = { "i2s1grp0" }; |
501 | static const char * const i2srefclkgrps[] = { "i2srefclkgrp0" }; |
502 | static const char * const spi0grps[] = { "spi0grp0" }; |
503 | static const char * const spi1grps[] = { "spi1grp0" }; |
504 | static const char * const pciedebuggrps[] = { "pciedebuggrp0" }; |
505 | static const char * const uart0grps[] = { "uart0grp0" , "uart0grp1" , |
506 | "uart0grp2" }; |
507 | static const char * const uart1grps[] = { "uart1grp0" , "uart1grp1" }; |
508 | static const char * const uart2grps[] = { "uart2grp0" , "uart2grp1" , |
509 | "uart2grp2" }; |
510 | static const char * const uart3grps[] = { "uart3grp0" }; |
511 | static const char * const uart4grps[] = { "uart4grp0" , "uart4grp1" }; |
512 | static const char * const uart5grps[] = { "uart5grp0" , "uart5grp1" , |
513 | "uart5nocts" }; |
514 | static const char * const nandgrps[] = { "nandgrp0" }; |
515 | static const char * const sdio0grps[] = { "sdio0grp0" }; |
516 | static const char * const sdio1grps[] = { "sdio1grp0" }; |
517 | static const char * const ethernetgrps[] = { "ethernetgrp0" }; |
518 | |
519 | static const struct artpec6_pmx_func artpec6_pmx_functions[] = { |
520 | { |
521 | .name = "gpio" , |
522 | .groups = gpiogrps, |
523 | .num_groups = ARRAY_SIZE(gpiogrps), |
524 | }, |
525 | { |
526 | .name = "cpuclkout" , |
527 | .groups = cpuclkoutgrps, |
528 | .num_groups = ARRAY_SIZE(cpuclkoutgrps), |
529 | }, |
530 | { |
531 | .name = "udlclkout" , |
532 | .groups = udlclkoutgrps, |
533 | .num_groups = ARRAY_SIZE(udlclkoutgrps), |
534 | }, |
535 | { |
536 | .name = "i2c1" , |
537 | .groups = i2c1grps, |
538 | .num_groups = ARRAY_SIZE(i2c1grps), |
539 | }, |
540 | { |
541 | .name = "i2c2" , |
542 | .groups = i2c2grps, |
543 | .num_groups = ARRAY_SIZE(i2c2grps), |
544 | }, |
545 | { |
546 | .name = "i2c3" , |
547 | .groups = i2c3grps, |
548 | .num_groups = ARRAY_SIZE(i2c3grps), |
549 | }, |
550 | { |
551 | .name = "i2s0" , |
552 | .groups = i2s0grps, |
553 | .num_groups = ARRAY_SIZE(i2s0grps), |
554 | }, |
555 | { |
556 | .name = "i2s1" , |
557 | .groups = i2s1grps, |
558 | .num_groups = ARRAY_SIZE(i2s1grps), |
559 | }, |
560 | { |
561 | .name = "i2srefclk" , |
562 | .groups = i2srefclkgrps, |
563 | .num_groups = ARRAY_SIZE(i2srefclkgrps), |
564 | }, |
565 | { |
566 | .name = "spi0" , |
567 | .groups = spi0grps, |
568 | .num_groups = ARRAY_SIZE(spi0grps), |
569 | }, |
570 | { |
571 | .name = "spi1" , |
572 | .groups = spi1grps, |
573 | .num_groups = ARRAY_SIZE(spi1grps), |
574 | }, |
575 | { |
576 | .name = "pciedebug" , |
577 | .groups = pciedebuggrps, |
578 | .num_groups = ARRAY_SIZE(pciedebuggrps), |
579 | }, |
580 | { |
581 | .name = "uart0" , |
582 | .groups = uart0grps, |
583 | .num_groups = ARRAY_SIZE(uart0grps), |
584 | }, |
585 | { |
586 | .name = "uart1" , |
587 | .groups = uart1grps, |
588 | .num_groups = ARRAY_SIZE(uart1grps), |
589 | }, |
590 | { |
591 | .name = "uart2" , |
592 | .groups = uart2grps, |
593 | .num_groups = ARRAY_SIZE(uart2grps), |
594 | }, |
595 | { |
596 | .name = "uart3" , |
597 | .groups = uart3grps, |
598 | .num_groups = ARRAY_SIZE(uart3grps), |
599 | }, |
600 | { |
601 | .name = "uart4" , |
602 | .groups = uart4grps, |
603 | .num_groups = ARRAY_SIZE(uart4grps), |
604 | }, |
605 | { |
606 | .name = "uart5" , |
607 | .groups = uart5grps, |
608 | .num_groups = ARRAY_SIZE(uart5grps), |
609 | }, |
610 | { |
611 | .name = "nand" , |
612 | .groups = nandgrps, |
613 | .num_groups = ARRAY_SIZE(nandgrps), |
614 | }, |
615 | { |
616 | .name = "sdio0" , |
617 | .groups = sdio0grps, |
618 | .num_groups = ARRAY_SIZE(sdio0grps), |
619 | }, |
620 | { |
621 | .name = "sdio1" , |
622 | .groups = sdio1grps, |
623 | .num_groups = ARRAY_SIZE(sdio1grps), |
624 | }, |
625 | { |
626 | .name = "ethernet" , |
627 | .groups = ethernetgrps, |
628 | .num_groups = ARRAY_SIZE(ethernetgrps), |
629 | }, |
630 | }; |
631 | |
632 | static int artpec6_pmx_get_functions_count(struct pinctrl_dev *pctldev) |
633 | { |
634 | return ARRAY_SIZE(artpec6_pmx_functions); |
635 | } |
636 | |
637 | static const char *artpec6_pmx_get_fname(struct pinctrl_dev *pctldev, |
638 | unsigned int function) |
639 | { |
640 | return artpec6_pmx_functions[function].name; |
641 | } |
642 | |
643 | static int artpec6_pmx_get_fgroups(struct pinctrl_dev *pctldev, |
644 | unsigned int function, |
645 | const char * const **groups, |
646 | unsigned int * const num_groups) |
647 | { |
648 | *groups = artpec6_pmx_functions[function].groups; |
649 | *num_groups = artpec6_pmx_functions[function].num_groups; |
650 | return 0; |
651 | } |
652 | |
653 | static void artpec6_pmx_select_func(struct pinctrl_dev *pctldev, |
654 | unsigned int function, unsigned int group, |
655 | bool enable) |
656 | { |
657 | unsigned int regval, val; |
658 | unsigned int reg; |
659 | int i; |
660 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); |
661 | |
662 | for (i = 0; i < artpec6_pin_groups[group].num_pins; i++) { |
663 | /* |
664 | * Registers for pins above a ARTPEC6_MAX_MUXABLE |
665 | * do not have a SEL field and are always selected. |
666 | */ |
667 | if (artpec6_pin_groups[group].pins[i] > ARTPEC6_MAX_MUXABLE) |
668 | continue; |
669 | |
670 | if (!strcmp(artpec6_pmx_get_fname(pctldev, function), "gpio" )) { |
671 | /* GPIO is always config 0 */ |
672 | val = ARTPEC6_CONFIG_0 << ARTPEC6_PINMUX_SEL_SHIFT; |
673 | } else { |
674 | if (enable) |
675 | val = artpec6_pin_groups[group].config |
676 | << ARTPEC6_PINMUX_SEL_SHIFT; |
677 | else |
678 | val = ARTPEC6_CONFIG_0 |
679 | << ARTPEC6_PINMUX_SEL_SHIFT; |
680 | } |
681 | |
682 | reg = artpec6_pmx_reg_offset(pin: artpec6_pin_groups[group].pins[i]); |
683 | |
684 | regval = readl(addr: pmx->base + reg); |
685 | regval &= ~ARTPEC6_PINMUX_SEL_MASK; |
686 | regval |= val; |
687 | writel(val: regval, addr: pmx->base + reg); |
688 | } |
689 | } |
690 | |
691 | static int artpec6_pmx_set(struct pinctrl_dev *pctldev, |
692 | unsigned int function, |
693 | unsigned int group) |
694 | { |
695 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); |
696 | |
697 | dev_dbg(pmx->dev, "enabling %s function for pin group %s\n" , |
698 | artpec6_pmx_get_fname(pctldev, function), |
699 | artpec6_get_group_name(pctldev, group)); |
700 | |
701 | artpec6_pmx_select_func(pctldev, function, group, enable: true); |
702 | |
703 | return 0; |
704 | } |
705 | |
706 | static int artpec6_pmx_request_gpio(struct pinctrl_dev *pctldev, |
707 | struct pinctrl_gpio_range *range, |
708 | unsigned int pin) |
709 | { |
710 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); |
711 | unsigned int reg = artpec6_pmx_reg_offset(pin); |
712 | u32 val; |
713 | |
714 | if (pin >= 32) |
715 | return -EINVAL; |
716 | |
717 | val = readl_relaxed(pmx->base + reg); |
718 | val &= ~ARTPEC6_PINMUX_SEL_MASK; |
719 | val |= ARTPEC6_CONFIG_0 << ARTPEC6_PINMUX_SEL_SHIFT; |
720 | writel_relaxed(val, pmx->base + reg); |
721 | |
722 | return 0; |
723 | } |
724 | |
725 | static const struct pinmux_ops artpec6_pmx_ops = { |
726 | .get_functions_count = artpec6_pmx_get_functions_count, |
727 | .get_function_name = artpec6_pmx_get_fname, |
728 | .get_function_groups = artpec6_pmx_get_fgroups, |
729 | .set_mux = artpec6_pmx_set, |
730 | .gpio_request_enable = artpec6_pmx_request_gpio, |
731 | }; |
732 | |
733 | static int artpec6_pconf_get(struct pinctrl_dev *pctldev, unsigned int pin, |
734 | unsigned long *config) |
735 | { |
736 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); |
737 | enum pin_config_param param = pinconf_to_config_param(config: *config); |
738 | unsigned int regval; |
739 | |
740 | /* Check for valid pin */ |
741 | if (pin >= pmx->num_pins) { |
742 | dev_dbg(pmx->dev, "pinconf is not supported for pin %s\n" , |
743 | pmx->pins[pin].name); |
744 | return -ENOTSUPP; |
745 | } |
746 | |
747 | dev_dbg(pmx->dev, "getting configuration for pin %s\n" , |
748 | pmx->pins[pin].name); |
749 | |
750 | /* Read pin register values */ |
751 | regval = readl(addr: pmx->base + artpec6_pmx_reg_offset(pin)); |
752 | |
753 | /* If valid, get configuration for parameter */ |
754 | switch (param) { |
755 | case PIN_CONFIG_BIAS_DISABLE: |
756 | if (!(regval & ARTPEC6_PINMUX_UDC1_MASK)) |
757 | return -EINVAL; |
758 | break; |
759 | |
760 | case PIN_CONFIG_BIAS_PULL_UP: |
761 | case PIN_CONFIG_BIAS_PULL_DOWN: |
762 | if (regval & ARTPEC6_PINMUX_UDC1_MASK) |
763 | return -EINVAL; |
764 | |
765 | regval = regval & ARTPEC6_PINMUX_UDC0_MASK; |
766 | if ((param == PIN_CONFIG_BIAS_PULL_UP && !regval) || |
767 | (param == PIN_CONFIG_BIAS_PULL_DOWN && regval)) |
768 | return -EINVAL; |
769 | break; |
770 | case PIN_CONFIG_DRIVE_STRENGTH: |
771 | regval = (regval & ARTPEC6_PINMUX_DRV_MASK) |
772 | >> ARTPEC6_PINMUX_DRV_SHIFT; |
773 | regval = artpec6_pconf_drive_field_to_mA(field: regval); |
774 | *config = pinconf_to_config_packed(param, argument: regval); |
775 | break; |
776 | default: |
777 | return -ENOTSUPP; |
778 | } |
779 | |
780 | return 0; |
781 | } |
782 | |
783 | /* |
784 | * Valid combinations of param and arg: |
785 | * |
786 | * param arg |
787 | * PIN_CONFIG_BIAS_DISABLE: x (disable bias) |
788 | * PIN_CONFIG_BIAS_PULL_UP: 1 (pull up bias + enable) |
789 | * PIN_CONFIG_BIAS_PULL_DOWN: 1 (pull down bias + enable) |
790 | * PIN_CONFIG_DRIVE_STRENGTH: x (4mA, 6mA, 8mA, 9mA) |
791 | * |
792 | * All other args are invalid. All other params are not supported. |
793 | */ |
794 | static int artpec6_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin, |
795 | unsigned long *configs, unsigned int num_configs) |
796 | { |
797 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); |
798 | enum pin_config_param param; |
799 | unsigned int arg; |
800 | unsigned int regval; |
801 | void __iomem *reg; |
802 | int i; |
803 | |
804 | /* Check for valid pin */ |
805 | if (pin >= pmx->num_pins) { |
806 | dev_dbg(pmx->dev, "pinconf is not supported for pin %s\n" , |
807 | pmx->pins[pin].name); |
808 | return -ENOTSUPP; |
809 | } |
810 | |
811 | dev_dbg(pmx->dev, "setting configuration for pin %s\n" , |
812 | pmx->pins[pin].name); |
813 | |
814 | reg = pmx->base + artpec6_pmx_reg_offset(pin); |
815 | |
816 | /* For each config */ |
817 | for (i = 0; i < num_configs; i++) { |
818 | int drive; |
819 | |
820 | param = pinconf_to_config_param(config: configs[i]); |
821 | arg = pinconf_to_config_argument(config: configs[i]); |
822 | |
823 | switch (param) { |
824 | case PIN_CONFIG_BIAS_DISABLE: |
825 | regval = readl(addr: reg); |
826 | regval |= (1 << ARTPEC6_PINMUX_UDC1_SHIFT); |
827 | writel(val: regval, addr: reg); |
828 | break; |
829 | |
830 | case PIN_CONFIG_BIAS_PULL_UP: |
831 | if (arg != 1) { |
832 | dev_dbg(pctldev->dev, "%s: arg %u out of range\n" , |
833 | __func__, arg); |
834 | return -EINVAL; |
835 | } |
836 | |
837 | regval = readl(addr: reg); |
838 | regval |= (arg << ARTPEC6_PINMUX_UDC0_SHIFT); |
839 | regval &= ~ARTPEC6_PINMUX_UDC1_MASK; /* Enable */ |
840 | writel(val: regval, addr: reg); |
841 | break; |
842 | |
843 | case PIN_CONFIG_BIAS_PULL_DOWN: |
844 | if (arg != 1) { |
845 | dev_dbg(pctldev->dev, "%s: arg %u out of range\n" , |
846 | __func__, arg); |
847 | return -EINVAL; |
848 | } |
849 | |
850 | regval = readl(addr: reg); |
851 | regval &= ~(arg << ARTPEC6_PINMUX_UDC0_SHIFT); |
852 | regval &= ~ARTPEC6_PINMUX_UDC1_MASK; /* Enable */ |
853 | writel(val: regval, addr: reg); |
854 | break; |
855 | |
856 | case PIN_CONFIG_DRIVE_STRENGTH: |
857 | drive = artpec6_pconf_drive_mA_to_field(mA: arg); |
858 | if (drive < 0) { |
859 | dev_dbg(pctldev->dev, "%s: arg %u out of range\n" , |
860 | __func__, arg); |
861 | return -EINVAL; |
862 | } |
863 | |
864 | regval = readl(addr: reg); |
865 | regval &= ~ARTPEC6_PINMUX_DRV_MASK; |
866 | regval |= (drive << ARTPEC6_PINMUX_DRV_SHIFT); |
867 | writel(val: regval, addr: reg); |
868 | break; |
869 | |
870 | default: |
871 | dev_dbg(pmx->dev, "parameter not supported\n" ); |
872 | return -ENOTSUPP; |
873 | } |
874 | } |
875 | |
876 | return 0; |
877 | } |
878 | |
879 | static int artpec6_pconf_group_set(struct pinctrl_dev *pctldev, |
880 | unsigned int group, unsigned long *configs, |
881 | unsigned int num_configs) |
882 | { |
883 | unsigned int num_pins, current_pin; |
884 | int ret; |
885 | |
886 | dev_dbg(pctldev->dev, "setting group %s configuration\n" , |
887 | artpec6_get_group_name(pctldev, group)); |
888 | |
889 | num_pins = artpec6_pin_groups[group].num_pins; |
890 | |
891 | for (current_pin = 0; current_pin < num_pins; current_pin++) { |
892 | ret = artpec6_pconf_set(pctldev, |
893 | pin: artpec6_pin_groups[group].pins[current_pin], |
894 | configs, num_configs); |
895 | |
896 | if (ret < 0) |
897 | return ret; |
898 | } |
899 | |
900 | return 0; |
901 | } |
902 | |
903 | static const struct pinconf_ops artpec6_pconf_ops = { |
904 | .is_generic = true, |
905 | .pin_config_get = artpec6_pconf_get, |
906 | .pin_config_set = artpec6_pconf_set, |
907 | .pin_config_group_set = artpec6_pconf_group_set, |
908 | }; |
909 | |
910 | static struct pinctrl_desc artpec6_desc = { |
911 | .name = "artpec6-pinctrl" , |
912 | .owner = THIS_MODULE, |
913 | .pins = artpec6_pins, |
914 | .npins = ARRAY_SIZE(artpec6_pins), |
915 | .pctlops = &artpec6_pctrl_ops, |
916 | .pmxops = &artpec6_pmx_ops, |
917 | .confops = &artpec6_pconf_ops, |
918 | }; |
919 | |
920 | /* The reset values say 4mA, but we want 8mA as default. */ |
921 | static void artpec6_pmx_reset(struct artpec6_pmx *pmx) |
922 | { |
923 | void __iomem *base = pmx->base; |
924 | int i; |
925 | |
926 | for (i = 0; i < ARTPEC6_LAST_PIN; i++) { |
927 | u32 val; |
928 | |
929 | val = readl_relaxed(base + artpec6_pmx_reg_offset(i)); |
930 | val &= ~ARTPEC6_PINMUX_DRV_MASK; |
931 | val |= ARTPEC6_DRIVE_8mA_SET << ARTPEC6_PINMUX_DRV_SHIFT; |
932 | writel_relaxed(val, base + artpec6_pmx_reg_offset(i)); |
933 | } |
934 | } |
935 | |
936 | static int artpec6_pmx_probe(struct platform_device *pdev) |
937 | { |
938 | struct artpec6_pmx *pmx; |
939 | |
940 | pmx = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pmx), GFP_KERNEL); |
941 | if (!pmx) |
942 | return -ENOMEM; |
943 | |
944 | pmx->dev = &pdev->dev; |
945 | |
946 | pmx->base = devm_platform_ioremap_resource(pdev, index: 0); |
947 | |
948 | if (IS_ERR(ptr: pmx->base)) |
949 | return PTR_ERR(ptr: pmx->base); |
950 | |
951 | artpec6_pmx_reset(pmx); |
952 | |
953 | pmx->pins = artpec6_pins; |
954 | pmx->num_pins = ARRAY_SIZE(artpec6_pins); |
955 | pmx->functions = artpec6_pmx_functions; |
956 | pmx->num_functions = ARRAY_SIZE(artpec6_pmx_functions); |
957 | pmx->pin_groups = artpec6_pin_groups; |
958 | pmx->num_pin_groups = ARRAY_SIZE(artpec6_pin_groups); |
959 | pmx->pctl = pinctrl_register(pctldesc: &artpec6_desc, dev: &pdev->dev, driver_data: pmx); |
960 | |
961 | if (IS_ERR(ptr: pmx->pctl)) { |
962 | dev_err(&pdev->dev, "could not register pinctrl driver\n" ); |
963 | return PTR_ERR(ptr: pmx->pctl); |
964 | } |
965 | |
966 | platform_set_drvdata(pdev, data: pmx); |
967 | |
968 | dev_info(&pdev->dev, "initialised Axis ARTPEC-6 pinctrl driver\n" ); |
969 | |
970 | return 0; |
971 | } |
972 | |
973 | static void artpec6_pmx_remove(struct platform_device *pdev) |
974 | { |
975 | struct artpec6_pmx *pmx = platform_get_drvdata(pdev); |
976 | |
977 | pinctrl_unregister(pctldev: pmx->pctl); |
978 | } |
979 | |
980 | static const struct of_device_id artpec6_pinctrl_match[] = { |
981 | { .compatible = "axis,artpec6-pinctrl" }, |
982 | {}, |
983 | }; |
984 | |
985 | static struct platform_driver artpec6_pmx_driver = { |
986 | .driver = { |
987 | .name = "artpec6-pinctrl" , |
988 | .of_match_table = artpec6_pinctrl_match, |
989 | }, |
990 | .probe = artpec6_pmx_probe, |
991 | .remove_new = artpec6_pmx_remove, |
992 | }; |
993 | |
994 | static int __init artpec6_pmx_init(void) |
995 | { |
996 | return platform_driver_register(&artpec6_pmx_driver); |
997 | } |
998 | arch_initcall(artpec6_pmx_init); |
999 | |