1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com> |
4 | * Copyright (c) 2020 Western Digital Corporation or its affiliates. |
5 | */ |
6 | #include <linux/bitfield.h> |
7 | #include <linux/clk.h> |
8 | #include <linux/io.h> |
9 | #include <linux/mfd/syscon.h> |
10 | #include <linux/of.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/regmap.h> |
13 | #include <linux/seq_file.h> |
14 | #include <linux/slab.h> |
15 | |
16 | #include <linux/pinctrl/pinconf-generic.h> |
17 | #include <linux/pinctrl/pinconf.h> |
18 | #include <linux/pinctrl/pinctrl.h> |
19 | #include <linux/pinctrl/pinmux.h> |
20 | |
21 | #include <dt-bindings/pinctrl/k210-fpioa.h> |
22 | |
23 | #include "core.h" |
24 | #include "pinconf.h" |
25 | #include "pinctrl-utils.h" |
26 | |
27 | /* |
28 | * The K210 only implements 8 drive levels, even though |
29 | * there is register space for 16 |
30 | */ |
31 | #define K210_PC_DRIVE_MASK GENMASK(11, 8) |
32 | #define K210_PC_DRIVE_SHIFT 8 |
33 | #define K210_PC_DRIVE_0 (0 << K210_PC_DRIVE_SHIFT) |
34 | #define K210_PC_DRIVE_1 (1 << K210_PC_DRIVE_SHIFT) |
35 | #define K210_PC_DRIVE_2 (2 << K210_PC_DRIVE_SHIFT) |
36 | #define K210_PC_DRIVE_3 (3 << K210_PC_DRIVE_SHIFT) |
37 | #define K210_PC_DRIVE_4 (4 << K210_PC_DRIVE_SHIFT) |
38 | #define K210_PC_DRIVE_5 (5 << K210_PC_DRIVE_SHIFT) |
39 | #define K210_PC_DRIVE_6 (6 << K210_PC_DRIVE_SHIFT) |
40 | #define K210_PC_DRIVE_7 (7 << K210_PC_DRIVE_SHIFT) |
41 | #define K210_PC_DRIVE_MAX 7 |
42 | #define K210_PC_MODE_MASK GENMASK(23, 12) |
43 | |
44 | /* |
45 | * output enabled == PC_OE & (PC_OE_INV ^ FUNCTION_OE) |
46 | * where FUNCTION_OE is a physical signal from the function. |
47 | */ |
48 | #define K210_PC_OE BIT(12) /* Output Enable */ |
49 | #define K210_PC_OE_INV BIT(13) /* INVert Output Enable */ |
50 | #define K210_PC_DO_OE BIT(14) /* set Data Out to Output Enable sig */ |
51 | #define K210_PC_DO_INV BIT(15) /* INVert final Data Output */ |
52 | #define K210_PC_PU BIT(16) /* Pull Up */ |
53 | #define K210_PC_PD BIT(17) /* Pull Down */ |
54 | /* Strong pull up not implemented on K210 */ |
55 | #define K210_PC_SL BIT(19) /* reduce SLew rate */ |
56 | /* Same semantics as OE above */ |
57 | #define K210_PC_IE BIT(20) /* Input Enable */ |
58 | #define K210_PC_IE_INV BIT(21) /* INVert Input Enable */ |
59 | #define K210_PC_DI_INV BIT(22) /* INVert Data Input */ |
60 | #define K210_PC_ST BIT(23) /* Schmitt Trigger */ |
61 | #define K210_PC_DI BIT(31) /* raw Data Input */ |
62 | |
63 | #define K210_PC_BIAS_MASK (K210_PC_PU & K210_PC_PD) |
64 | |
65 | #define K210_PC_MODE_IN (K210_PC_IE | K210_PC_ST) |
66 | #define K210_PC_MODE_OUT (K210_PC_DRIVE_7 | K210_PC_OE) |
67 | #define K210_PC_MODE_I2C (K210_PC_MODE_IN | K210_PC_SL | \ |
68 | K210_PC_OE | K210_PC_PU) |
69 | #define K210_PC_MODE_SCCB (K210_PC_MODE_I2C | \ |
70 | K210_PC_OE_INV | K210_PC_IE_INV) |
71 | #define K210_PC_MODE_SPI (K210_PC_MODE_IN | K210_PC_IE_INV | \ |
72 | K210_PC_MODE_OUT | K210_PC_OE_INV) |
73 | #define K210_PC_MODE_GPIO (K210_PC_MODE_IN | K210_PC_MODE_OUT) |
74 | |
75 | #define K210_PG_FUNC GENMASK(7, 0) |
76 | #define K210_PG_DO BIT(8) |
77 | #define K210_PG_PIN GENMASK(22, 16) |
78 | |
79 | /* |
80 | * struct k210_fpioa: Kendryte K210 FPIOA memory mapped registers |
81 | * @pins: 48 32-bits IO pin registers |
82 | * @tie_en: 256 (one per function) input tie enable bits |
83 | * @tie_val: 256 (one per function) input tie value bits |
84 | */ |
85 | struct k210_fpioa { |
86 | u32 pins[48]; |
87 | u32 tie_en[8]; |
88 | u32 tie_val[8]; |
89 | }; |
90 | |
91 | struct k210_fpioa_data { |
92 | |
93 | struct device *dev; |
94 | struct pinctrl_dev *pctl; |
95 | |
96 | struct k210_fpioa __iomem *fpioa; |
97 | struct regmap *sysctl_map; |
98 | u32 power_offset; |
99 | struct clk *clk; |
100 | struct clk *pclk; |
101 | }; |
102 | |
103 | #define K210_PIN_NAME(i) ("IO_" #i) |
104 | #define K210_PIN(i) [(i)] = PINCTRL_PIN((i), K210_PIN_NAME(i)) |
105 | |
106 | static const struct pinctrl_pin_desc k210_pins[] = { |
107 | K210_PIN(0), K210_PIN(1), K210_PIN(2), |
108 | K210_PIN(3), K210_PIN(4), K210_PIN(5), |
109 | K210_PIN(6), K210_PIN(7), K210_PIN(8), |
110 | K210_PIN(9), K210_PIN(10), K210_PIN(11), |
111 | K210_PIN(12), K210_PIN(13), K210_PIN(14), |
112 | K210_PIN(15), K210_PIN(16), K210_PIN(17), |
113 | K210_PIN(18), K210_PIN(19), K210_PIN(20), |
114 | K210_PIN(21), K210_PIN(22), K210_PIN(23), |
115 | K210_PIN(24), K210_PIN(25), K210_PIN(26), |
116 | K210_PIN(27), K210_PIN(28), K210_PIN(29), |
117 | K210_PIN(30), K210_PIN(31), K210_PIN(32), |
118 | K210_PIN(33), K210_PIN(34), K210_PIN(35), |
119 | K210_PIN(36), K210_PIN(37), K210_PIN(38), |
120 | K210_PIN(39), K210_PIN(40), K210_PIN(41), |
121 | K210_PIN(42), K210_PIN(43), K210_PIN(44), |
122 | K210_PIN(45), K210_PIN(46), K210_PIN(47) |
123 | }; |
124 | |
125 | #define K210_NPINS ARRAY_SIZE(k210_pins) |
126 | |
127 | /* |
128 | * Pin groups: each of the 48 programmable pins is a group. |
129 | * To this are added 8 power domain groups, which for the purposes of |
130 | * the pin subsystem, contain no pins. The power domain groups only exist |
131 | * to set the power level. The id should never be used (since there are |
132 | * no pins 48-55). |
133 | */ |
134 | static const char *const k210_group_names[] = { |
135 | /* The first 48 groups are for pins, one each */ |
136 | K210_PIN_NAME(0), K210_PIN_NAME(1), K210_PIN_NAME(2), |
137 | K210_PIN_NAME(3), K210_PIN_NAME(4), K210_PIN_NAME(5), |
138 | K210_PIN_NAME(6), K210_PIN_NAME(7), K210_PIN_NAME(8), |
139 | K210_PIN_NAME(9), K210_PIN_NAME(10), K210_PIN_NAME(11), |
140 | K210_PIN_NAME(12), K210_PIN_NAME(13), K210_PIN_NAME(14), |
141 | K210_PIN_NAME(15), K210_PIN_NAME(16), K210_PIN_NAME(17), |
142 | K210_PIN_NAME(18), K210_PIN_NAME(19), K210_PIN_NAME(20), |
143 | K210_PIN_NAME(21), K210_PIN_NAME(22), K210_PIN_NAME(23), |
144 | K210_PIN_NAME(24), K210_PIN_NAME(25), K210_PIN_NAME(26), |
145 | K210_PIN_NAME(27), K210_PIN_NAME(28), K210_PIN_NAME(29), |
146 | K210_PIN_NAME(30), K210_PIN_NAME(31), K210_PIN_NAME(32), |
147 | K210_PIN_NAME(33), K210_PIN_NAME(34), K210_PIN_NAME(35), |
148 | K210_PIN_NAME(36), K210_PIN_NAME(37), K210_PIN_NAME(38), |
149 | K210_PIN_NAME(39), K210_PIN_NAME(40), K210_PIN_NAME(41), |
150 | K210_PIN_NAME(42), K210_PIN_NAME(43), K210_PIN_NAME(44), |
151 | K210_PIN_NAME(45), K210_PIN_NAME(46), K210_PIN_NAME(47), |
152 | [48] = "A0" , [49] = "A1" , [50] = "A2" , |
153 | [51] = "B3" , [52] = "B4" , [53] = "B5" , |
154 | [54] = "C6" , [55] = "C7" |
155 | }; |
156 | |
157 | #define K210_NGROUPS ARRAY_SIZE(k210_group_names) |
158 | |
159 | enum k210_pinctrl_mode_id { |
160 | K210_PC_DEFAULT_DISABLED, |
161 | K210_PC_DEFAULT_IN, |
162 | K210_PC_DEFAULT_IN_TIE, |
163 | K210_PC_DEFAULT_OUT, |
164 | K210_PC_DEFAULT_I2C, |
165 | K210_PC_DEFAULT_SCCB, |
166 | K210_PC_DEFAULT_SPI, |
167 | K210_PC_DEFAULT_GPIO, |
168 | K210_PC_DEFAULT_INT13, |
169 | }; |
170 | |
171 | #define K210_PC_DEFAULT(mode) \ |
172 | [K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode |
173 | |
174 | static const u32 k210_pinconf_mode_id_to_mode[] = { |
175 | [K210_PC_DEFAULT_DISABLED] = 0, |
176 | K210_PC_DEFAULT(IN), |
177 | [K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN, |
178 | K210_PC_DEFAULT(OUT), |
179 | K210_PC_DEFAULT(I2C), |
180 | K210_PC_DEFAULT(SCCB), |
181 | K210_PC_DEFAULT(SPI), |
182 | K210_PC_DEFAULT(GPIO), |
183 | [K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU, |
184 | }; |
185 | |
186 | #undef DEFAULT |
187 | |
188 | /* |
189 | * Pin functions configuration information. |
190 | */ |
191 | struct k210_pcf_info { |
192 | char name[15]; |
193 | u8 mode_id; |
194 | }; |
195 | |
196 | #define K210_FUNC(id, mode) \ |
197 | [K210_PCF_##id] = { \ |
198 | .name = #id, \ |
199 | .mode_id = K210_PC_DEFAULT_##mode \ |
200 | } |
201 | |
202 | static const struct k210_pcf_info k210_pcf_infos[] = { |
203 | K210_FUNC(JTAG_TCLK, IN), |
204 | K210_FUNC(JTAG_TDI, IN), |
205 | K210_FUNC(JTAG_TMS, IN), |
206 | K210_FUNC(JTAG_TDO, OUT), |
207 | K210_FUNC(SPI0_D0, SPI), |
208 | K210_FUNC(SPI0_D1, SPI), |
209 | K210_FUNC(SPI0_D2, SPI), |
210 | K210_FUNC(SPI0_D3, SPI), |
211 | K210_FUNC(SPI0_D4, SPI), |
212 | K210_FUNC(SPI0_D5, SPI), |
213 | K210_FUNC(SPI0_D6, SPI), |
214 | K210_FUNC(SPI0_D7, SPI), |
215 | K210_FUNC(SPI0_SS0, OUT), |
216 | K210_FUNC(SPI0_SS1, OUT), |
217 | K210_FUNC(SPI0_SS2, OUT), |
218 | K210_FUNC(SPI0_SS3, OUT), |
219 | K210_FUNC(SPI0_ARB, IN_TIE), |
220 | K210_FUNC(SPI0_SCLK, OUT), |
221 | K210_FUNC(UARTHS_RX, IN), |
222 | K210_FUNC(UARTHS_TX, OUT), |
223 | K210_FUNC(RESV6, IN), |
224 | K210_FUNC(RESV7, IN), |
225 | K210_FUNC(CLK_SPI1, OUT), |
226 | K210_FUNC(CLK_I2C1, OUT), |
227 | K210_FUNC(GPIOHS0, GPIO), |
228 | K210_FUNC(GPIOHS1, GPIO), |
229 | K210_FUNC(GPIOHS2, GPIO), |
230 | K210_FUNC(GPIOHS3, GPIO), |
231 | K210_FUNC(GPIOHS4, GPIO), |
232 | K210_FUNC(GPIOHS5, GPIO), |
233 | K210_FUNC(GPIOHS6, GPIO), |
234 | K210_FUNC(GPIOHS7, GPIO), |
235 | K210_FUNC(GPIOHS8, GPIO), |
236 | K210_FUNC(GPIOHS9, GPIO), |
237 | K210_FUNC(GPIOHS10, GPIO), |
238 | K210_FUNC(GPIOHS11, GPIO), |
239 | K210_FUNC(GPIOHS12, GPIO), |
240 | K210_FUNC(GPIOHS13, GPIO), |
241 | K210_FUNC(GPIOHS14, GPIO), |
242 | K210_FUNC(GPIOHS15, GPIO), |
243 | K210_FUNC(GPIOHS16, GPIO), |
244 | K210_FUNC(GPIOHS17, GPIO), |
245 | K210_FUNC(GPIOHS18, GPIO), |
246 | K210_FUNC(GPIOHS19, GPIO), |
247 | K210_FUNC(GPIOHS20, GPIO), |
248 | K210_FUNC(GPIOHS21, GPIO), |
249 | K210_FUNC(GPIOHS22, GPIO), |
250 | K210_FUNC(GPIOHS23, GPIO), |
251 | K210_FUNC(GPIOHS24, GPIO), |
252 | K210_FUNC(GPIOHS25, GPIO), |
253 | K210_FUNC(GPIOHS26, GPIO), |
254 | K210_FUNC(GPIOHS27, GPIO), |
255 | K210_FUNC(GPIOHS28, GPIO), |
256 | K210_FUNC(GPIOHS29, GPIO), |
257 | K210_FUNC(GPIOHS30, GPIO), |
258 | K210_FUNC(GPIOHS31, GPIO), |
259 | K210_FUNC(GPIO0, GPIO), |
260 | K210_FUNC(GPIO1, GPIO), |
261 | K210_FUNC(GPIO2, GPIO), |
262 | K210_FUNC(GPIO3, GPIO), |
263 | K210_FUNC(GPIO4, GPIO), |
264 | K210_FUNC(GPIO5, GPIO), |
265 | K210_FUNC(GPIO6, GPIO), |
266 | K210_FUNC(GPIO7, GPIO), |
267 | K210_FUNC(UART1_RX, IN), |
268 | K210_FUNC(UART1_TX, OUT), |
269 | K210_FUNC(UART2_RX, IN), |
270 | K210_FUNC(UART2_TX, OUT), |
271 | K210_FUNC(UART3_RX, IN), |
272 | K210_FUNC(UART3_TX, OUT), |
273 | K210_FUNC(SPI1_D0, SPI), |
274 | K210_FUNC(SPI1_D1, SPI), |
275 | K210_FUNC(SPI1_D2, SPI), |
276 | K210_FUNC(SPI1_D3, SPI), |
277 | K210_FUNC(SPI1_D4, SPI), |
278 | K210_FUNC(SPI1_D5, SPI), |
279 | K210_FUNC(SPI1_D6, SPI), |
280 | K210_FUNC(SPI1_D7, SPI), |
281 | K210_FUNC(SPI1_SS0, OUT), |
282 | K210_FUNC(SPI1_SS1, OUT), |
283 | K210_FUNC(SPI1_SS2, OUT), |
284 | K210_FUNC(SPI1_SS3, OUT), |
285 | K210_FUNC(SPI1_ARB, IN_TIE), |
286 | K210_FUNC(SPI1_SCLK, OUT), |
287 | K210_FUNC(SPI2_D0, SPI), |
288 | K210_FUNC(SPI2_SS, IN), |
289 | K210_FUNC(SPI2_SCLK, IN), |
290 | K210_FUNC(I2S0_MCLK, OUT), |
291 | K210_FUNC(I2S0_SCLK, OUT), |
292 | K210_FUNC(I2S0_WS, OUT), |
293 | K210_FUNC(I2S0_IN_D0, IN), |
294 | K210_FUNC(I2S0_IN_D1, IN), |
295 | K210_FUNC(I2S0_IN_D2, IN), |
296 | K210_FUNC(I2S0_IN_D3, IN), |
297 | K210_FUNC(I2S0_OUT_D0, OUT), |
298 | K210_FUNC(I2S0_OUT_D1, OUT), |
299 | K210_FUNC(I2S0_OUT_D2, OUT), |
300 | K210_FUNC(I2S0_OUT_D3, OUT), |
301 | K210_FUNC(I2S1_MCLK, OUT), |
302 | K210_FUNC(I2S1_SCLK, OUT), |
303 | K210_FUNC(I2S1_WS, OUT), |
304 | K210_FUNC(I2S1_IN_D0, IN), |
305 | K210_FUNC(I2S1_IN_D1, IN), |
306 | K210_FUNC(I2S1_IN_D2, IN), |
307 | K210_FUNC(I2S1_IN_D3, IN), |
308 | K210_FUNC(I2S1_OUT_D0, OUT), |
309 | K210_FUNC(I2S1_OUT_D1, OUT), |
310 | K210_FUNC(I2S1_OUT_D2, OUT), |
311 | K210_FUNC(I2S1_OUT_D3, OUT), |
312 | K210_FUNC(I2S2_MCLK, OUT), |
313 | K210_FUNC(I2S2_SCLK, OUT), |
314 | K210_FUNC(I2S2_WS, OUT), |
315 | K210_FUNC(I2S2_IN_D0, IN), |
316 | K210_FUNC(I2S2_IN_D1, IN), |
317 | K210_FUNC(I2S2_IN_D2, IN), |
318 | K210_FUNC(I2S2_IN_D3, IN), |
319 | K210_FUNC(I2S2_OUT_D0, OUT), |
320 | K210_FUNC(I2S2_OUT_D1, OUT), |
321 | K210_FUNC(I2S2_OUT_D2, OUT), |
322 | K210_FUNC(I2S2_OUT_D3, OUT), |
323 | K210_FUNC(RESV0, DISABLED), |
324 | K210_FUNC(RESV1, DISABLED), |
325 | K210_FUNC(RESV2, DISABLED), |
326 | K210_FUNC(RESV3, DISABLED), |
327 | K210_FUNC(RESV4, DISABLED), |
328 | K210_FUNC(RESV5, DISABLED), |
329 | K210_FUNC(I2C0_SCLK, I2C), |
330 | K210_FUNC(I2C0_SDA, I2C), |
331 | K210_FUNC(I2C1_SCLK, I2C), |
332 | K210_FUNC(I2C1_SDA, I2C), |
333 | K210_FUNC(I2C2_SCLK, I2C), |
334 | K210_FUNC(I2C2_SDA, I2C), |
335 | K210_FUNC(DVP_XCLK, OUT), |
336 | K210_FUNC(DVP_RST, OUT), |
337 | K210_FUNC(DVP_PWDN, OUT), |
338 | K210_FUNC(DVP_VSYNC, IN), |
339 | K210_FUNC(DVP_HSYNC, IN), |
340 | K210_FUNC(DVP_PCLK, IN), |
341 | K210_FUNC(DVP_D0, IN), |
342 | K210_FUNC(DVP_D1, IN), |
343 | K210_FUNC(DVP_D2, IN), |
344 | K210_FUNC(DVP_D3, IN), |
345 | K210_FUNC(DVP_D4, IN), |
346 | K210_FUNC(DVP_D5, IN), |
347 | K210_FUNC(DVP_D6, IN), |
348 | K210_FUNC(DVP_D7, IN), |
349 | K210_FUNC(SCCB_SCLK, SCCB), |
350 | K210_FUNC(SCCB_SDA, SCCB), |
351 | K210_FUNC(UART1_CTS, IN), |
352 | K210_FUNC(UART1_DSR, IN), |
353 | K210_FUNC(UART1_DCD, IN), |
354 | K210_FUNC(UART1_RI, IN), |
355 | K210_FUNC(UART1_SIR_IN, IN), |
356 | K210_FUNC(UART1_DTR, OUT), |
357 | K210_FUNC(UART1_RTS, OUT), |
358 | K210_FUNC(UART1_OUT2, OUT), |
359 | K210_FUNC(UART1_OUT1, OUT), |
360 | K210_FUNC(UART1_SIR_OUT, OUT), |
361 | K210_FUNC(UART1_BAUD, OUT), |
362 | K210_FUNC(UART1_RE, OUT), |
363 | K210_FUNC(UART1_DE, OUT), |
364 | K210_FUNC(UART1_RS485_EN, OUT), |
365 | K210_FUNC(UART2_CTS, IN), |
366 | K210_FUNC(UART2_DSR, IN), |
367 | K210_FUNC(UART2_DCD, IN), |
368 | K210_FUNC(UART2_RI, IN), |
369 | K210_FUNC(UART2_SIR_IN, IN), |
370 | K210_FUNC(UART2_DTR, OUT), |
371 | K210_FUNC(UART2_RTS, OUT), |
372 | K210_FUNC(UART2_OUT2, OUT), |
373 | K210_FUNC(UART2_OUT1, OUT), |
374 | K210_FUNC(UART2_SIR_OUT, OUT), |
375 | K210_FUNC(UART2_BAUD, OUT), |
376 | K210_FUNC(UART2_RE, OUT), |
377 | K210_FUNC(UART2_DE, OUT), |
378 | K210_FUNC(UART2_RS485_EN, OUT), |
379 | K210_FUNC(UART3_CTS, IN), |
380 | K210_FUNC(UART3_DSR, IN), |
381 | K210_FUNC(UART3_DCD, IN), |
382 | K210_FUNC(UART3_RI, IN), |
383 | K210_FUNC(UART3_SIR_IN, IN), |
384 | K210_FUNC(UART3_DTR, OUT), |
385 | K210_FUNC(UART3_RTS, OUT), |
386 | K210_FUNC(UART3_OUT2, OUT), |
387 | K210_FUNC(UART3_OUT1, OUT), |
388 | K210_FUNC(UART3_SIR_OUT, OUT), |
389 | K210_FUNC(UART3_BAUD, OUT), |
390 | K210_FUNC(UART3_RE, OUT), |
391 | K210_FUNC(UART3_DE, OUT), |
392 | K210_FUNC(UART3_RS485_EN, OUT), |
393 | K210_FUNC(TIMER0_TOGGLE1, OUT), |
394 | K210_FUNC(TIMER0_TOGGLE2, OUT), |
395 | K210_FUNC(TIMER0_TOGGLE3, OUT), |
396 | K210_FUNC(TIMER0_TOGGLE4, OUT), |
397 | K210_FUNC(TIMER1_TOGGLE1, OUT), |
398 | K210_FUNC(TIMER1_TOGGLE2, OUT), |
399 | K210_FUNC(TIMER1_TOGGLE3, OUT), |
400 | K210_FUNC(TIMER1_TOGGLE4, OUT), |
401 | K210_FUNC(TIMER2_TOGGLE1, OUT), |
402 | K210_FUNC(TIMER2_TOGGLE2, OUT), |
403 | K210_FUNC(TIMER2_TOGGLE3, OUT), |
404 | K210_FUNC(TIMER2_TOGGLE4, OUT), |
405 | K210_FUNC(CLK_SPI2, OUT), |
406 | K210_FUNC(CLK_I2C2, OUT), |
407 | K210_FUNC(INTERNAL0, OUT), |
408 | K210_FUNC(INTERNAL1, OUT), |
409 | K210_FUNC(INTERNAL2, OUT), |
410 | K210_FUNC(INTERNAL3, OUT), |
411 | K210_FUNC(INTERNAL4, OUT), |
412 | K210_FUNC(INTERNAL5, OUT), |
413 | K210_FUNC(INTERNAL6, OUT), |
414 | K210_FUNC(INTERNAL7, OUT), |
415 | K210_FUNC(INTERNAL8, OUT), |
416 | K210_FUNC(INTERNAL9, IN), |
417 | K210_FUNC(INTERNAL10, IN), |
418 | K210_FUNC(INTERNAL11, IN), |
419 | K210_FUNC(INTERNAL12, IN), |
420 | K210_FUNC(INTERNAL13, INT13), |
421 | K210_FUNC(INTERNAL14, I2C), |
422 | K210_FUNC(INTERNAL15, IN), |
423 | K210_FUNC(INTERNAL16, IN), |
424 | K210_FUNC(INTERNAL17, IN), |
425 | K210_FUNC(CONSTANT, DISABLED), |
426 | K210_FUNC(INTERNAL18, IN), |
427 | K210_FUNC(DEBUG0, OUT), |
428 | K210_FUNC(DEBUG1, OUT), |
429 | K210_FUNC(DEBUG2, OUT), |
430 | K210_FUNC(DEBUG3, OUT), |
431 | K210_FUNC(DEBUG4, OUT), |
432 | K210_FUNC(DEBUG5, OUT), |
433 | K210_FUNC(DEBUG6, OUT), |
434 | K210_FUNC(DEBUG7, OUT), |
435 | K210_FUNC(DEBUG8, OUT), |
436 | K210_FUNC(DEBUG9, OUT), |
437 | K210_FUNC(DEBUG10, OUT), |
438 | K210_FUNC(DEBUG11, OUT), |
439 | K210_FUNC(DEBUG12, OUT), |
440 | K210_FUNC(DEBUG13, OUT), |
441 | K210_FUNC(DEBUG14, OUT), |
442 | K210_FUNC(DEBUG15, OUT), |
443 | K210_FUNC(DEBUG16, OUT), |
444 | K210_FUNC(DEBUG17, OUT), |
445 | K210_FUNC(DEBUG18, OUT), |
446 | K210_FUNC(DEBUG19, OUT), |
447 | K210_FUNC(DEBUG20, OUT), |
448 | K210_FUNC(DEBUG21, OUT), |
449 | K210_FUNC(DEBUG22, OUT), |
450 | K210_FUNC(DEBUG23, OUT), |
451 | K210_FUNC(DEBUG24, OUT), |
452 | K210_FUNC(DEBUG25, OUT), |
453 | K210_FUNC(DEBUG26, OUT), |
454 | K210_FUNC(DEBUG27, OUT), |
455 | K210_FUNC(DEBUG28, OUT), |
456 | K210_FUNC(DEBUG29, OUT), |
457 | K210_FUNC(DEBUG30, OUT), |
458 | K210_FUNC(DEBUG31, OUT), |
459 | }; |
460 | |
461 | #define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1) |
462 | #define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2) |
463 | |
464 | static const struct pinconf_generic_params k210_pinconf_custom_params[] = { |
465 | { "output-polarity-invert" , PIN_CONFIG_OUTPUT_INVERT, 1 }, |
466 | { "input-polarity-invert" , PIN_CONFIG_INPUT_INVERT, 1 }, |
467 | }; |
468 | |
469 | /* |
470 | * Max drive strength in uA. |
471 | */ |
472 | static const int k210_pinconf_drive_strength[] = { |
473 | [0] = 11200, |
474 | [1] = 16800, |
475 | [2] = 22300, |
476 | [3] = 27800, |
477 | [4] = 33300, |
478 | [5] = 38700, |
479 | [6] = 44100, |
480 | [7] = 49500, |
481 | }; |
482 | |
483 | static int k210_pinconf_get_drive(unsigned int max_strength_ua) |
484 | { |
485 | int i; |
486 | |
487 | for (i = K210_PC_DRIVE_MAX; i >= 0; i--) { |
488 | if (k210_pinconf_drive_strength[i] <= max_strength_ua) |
489 | return i; |
490 | } |
491 | |
492 | return -EINVAL; |
493 | } |
494 | |
495 | static void k210_pinmux_set_pin_function(struct pinctrl_dev *pctldev, |
496 | u32 pin, u32 func) |
497 | { |
498 | struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); |
499 | const struct k210_pcf_info *info = &k210_pcf_infos[func]; |
500 | u32 mode = k210_pinconf_mode_id_to_mode[info->mode_id]; |
501 | u32 val = func | mode; |
502 | |
503 | dev_dbg(pdata->dev, "set pin %u function %s (%u) -> 0x%08x\n" , |
504 | pin, info->name, func, val); |
505 | |
506 | writel(val, addr: &pdata->fpioa->pins[pin]); |
507 | } |
508 | |
509 | static int k210_pinconf_set_param(struct pinctrl_dev *pctldev, |
510 | unsigned int pin, |
511 | unsigned int param, unsigned int arg) |
512 | { |
513 | struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); |
514 | u32 val = readl(addr: &pdata->fpioa->pins[pin]); |
515 | int drive; |
516 | |
517 | dev_dbg(pdata->dev, "set pin %u param %u, arg 0x%x\n" , |
518 | pin, param, arg); |
519 | |
520 | switch (param) { |
521 | case PIN_CONFIG_BIAS_DISABLE: |
522 | val &= ~K210_PC_BIAS_MASK; |
523 | break; |
524 | case PIN_CONFIG_BIAS_PULL_DOWN: |
525 | if (!arg) |
526 | return -EINVAL; |
527 | val |= K210_PC_PD; |
528 | break; |
529 | case PIN_CONFIG_BIAS_PULL_UP: |
530 | if (!arg) |
531 | return -EINVAL; |
532 | val |= K210_PC_PU; |
533 | break; |
534 | case PIN_CONFIG_DRIVE_STRENGTH: |
535 | arg *= 1000; |
536 | fallthrough; |
537 | case PIN_CONFIG_DRIVE_STRENGTH_UA: |
538 | drive = k210_pinconf_get_drive(max_strength_ua: arg); |
539 | if (drive < 0) |
540 | return drive; |
541 | val &= ~K210_PC_DRIVE_MASK; |
542 | val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive); |
543 | break; |
544 | case PIN_CONFIG_INPUT_ENABLE: |
545 | if (arg) |
546 | val |= K210_PC_IE; |
547 | else |
548 | val &= ~K210_PC_IE; |
549 | break; |
550 | case PIN_CONFIG_INPUT_SCHMITT_ENABLE: |
551 | if (arg) |
552 | val |= K210_PC_ST; |
553 | else |
554 | val &= ~K210_PC_ST; |
555 | break; |
556 | case PIN_CONFIG_OUTPUT: |
557 | k210_pinmux_set_pin_function(pctldev, pin, K210_PCF_CONSTANT); |
558 | val = readl(addr: &pdata->fpioa->pins[pin]); |
559 | val |= K210_PC_MODE_OUT; |
560 | if (!arg) |
561 | val |= K210_PC_DO_INV; |
562 | break; |
563 | case PIN_CONFIG_OUTPUT_ENABLE: |
564 | if (arg) |
565 | val |= K210_PC_OE; |
566 | else |
567 | val &= ~K210_PC_OE; |
568 | break; |
569 | case PIN_CONFIG_SLEW_RATE: |
570 | if (arg) |
571 | val |= K210_PC_SL; |
572 | else |
573 | val &= ~K210_PC_SL; |
574 | break; |
575 | case PIN_CONFIG_OUTPUT_INVERT: |
576 | if (arg) |
577 | val |= K210_PC_DO_INV; |
578 | else |
579 | val &= ~K210_PC_DO_INV; |
580 | break; |
581 | case PIN_CONFIG_INPUT_INVERT: |
582 | if (arg) |
583 | val |= K210_PC_DI_INV; |
584 | else |
585 | val &= ~K210_PC_DI_INV; |
586 | break; |
587 | default: |
588 | return -EINVAL; |
589 | } |
590 | |
591 | writel(val, addr: &pdata->fpioa->pins[pin]); |
592 | |
593 | return 0; |
594 | } |
595 | |
596 | static int k210_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, |
597 | unsigned long *configs, unsigned int num_configs) |
598 | { |
599 | unsigned int param, arg; |
600 | int i, ret; |
601 | |
602 | if (WARN_ON(pin >= K210_NPINS)) |
603 | return -EINVAL; |
604 | |
605 | for (i = 0; i < num_configs; i++) { |
606 | param = pinconf_to_config_param(config: configs[i]); |
607 | arg = pinconf_to_config_argument(config: configs[i]); |
608 | ret = k210_pinconf_set_param(pctldev, pin, param, arg); |
609 | if (ret) |
610 | return ret; |
611 | } |
612 | |
613 | return 0; |
614 | } |
615 | |
616 | static void k210_pinconf_dbg_show(struct pinctrl_dev *pctldev, |
617 | struct seq_file *s, unsigned int pin) |
618 | { |
619 | struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); |
620 | |
621 | seq_printf(m: s, fmt: "%#x" , readl(addr: &pdata->fpioa->pins[pin])); |
622 | } |
623 | |
624 | static int k210_pinconf_group_set(struct pinctrl_dev *pctldev, |
625 | unsigned int selector, unsigned long *configs, |
626 | unsigned int num_configs) |
627 | { |
628 | struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); |
629 | unsigned int param, arg; |
630 | u32 bit; |
631 | int i; |
632 | |
633 | /* Pins should be configured with pinmux, not groups*/ |
634 | if (selector < K210_NPINS) |
635 | return -EINVAL; |
636 | |
637 | /* Otherwise it's a power domain */ |
638 | for (i = 0; i < num_configs; i++) { |
639 | param = pinconf_to_config_param(config: configs[i]); |
640 | if (param != PIN_CONFIG_POWER_SOURCE) |
641 | return -EINVAL; |
642 | |
643 | arg = pinconf_to_config_argument(config: configs[i]); |
644 | bit = BIT(selector - K210_NPINS); |
645 | regmap_update_bits(map: pdata->sysctl_map, |
646 | reg: pdata->power_offset, |
647 | mask: bit, val: arg ? bit : 0); |
648 | } |
649 | |
650 | return 0; |
651 | } |
652 | |
653 | static void k210_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, |
654 | struct seq_file *s, |
655 | unsigned int selector) |
656 | { |
657 | struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); |
658 | int ret; |
659 | u32 val; |
660 | |
661 | if (selector < K210_NPINS) |
662 | return k210_pinconf_dbg_show(pctldev, s, pin: selector); |
663 | |
664 | ret = regmap_read(map: pdata->sysctl_map, reg: pdata->power_offset, val: &val); |
665 | if (ret) { |
666 | dev_err(pdata->dev, "Failed to read power reg\n" ); |
667 | return; |
668 | } |
669 | |
670 | seq_printf(m: s, fmt: "%s: %s V" , k210_group_names[selector], |
671 | val & BIT(selector - K210_NPINS) ? "1.8" : "3.3" ); |
672 | } |
673 | |
674 | static const struct pinconf_ops k210_pinconf_ops = { |
675 | .is_generic = true, |
676 | .pin_config_set = k210_pinconf_set, |
677 | .pin_config_group_set = k210_pinconf_group_set, |
678 | .pin_config_dbg_show = k210_pinconf_dbg_show, |
679 | .pin_config_group_dbg_show = k210_pinconf_group_dbg_show, |
680 | }; |
681 | |
682 | static int k210_pinmux_get_function_count(struct pinctrl_dev *pctldev) |
683 | { |
684 | return ARRAY_SIZE(k210_pcf_infos); |
685 | } |
686 | |
687 | static const char *k210_pinmux_get_function_name(struct pinctrl_dev *pctldev, |
688 | unsigned int selector) |
689 | { |
690 | return k210_pcf_infos[selector].name; |
691 | } |
692 | |
693 | static int k210_pinmux_get_function_groups(struct pinctrl_dev *pctldev, |
694 | unsigned int selector, |
695 | const char * const **groups, |
696 | unsigned int * const num_groups) |
697 | { |
698 | /* Any function can be mapped to any pin */ |
699 | *groups = k210_group_names; |
700 | *num_groups = K210_NPINS; |
701 | |
702 | return 0; |
703 | } |
704 | |
705 | static int k210_pinmux_set_mux(struct pinctrl_dev *pctldev, |
706 | unsigned int function, |
707 | unsigned int group) |
708 | { |
709 | /* Can't mux power domains */ |
710 | if (group >= K210_NPINS) |
711 | return -EINVAL; |
712 | |
713 | k210_pinmux_set_pin_function(pctldev, pin: group, func: function); |
714 | |
715 | return 0; |
716 | } |
717 | |
718 | static const struct pinmux_ops k210_pinmux_ops = { |
719 | .get_functions_count = k210_pinmux_get_function_count, |
720 | .get_function_name = k210_pinmux_get_function_name, |
721 | .get_function_groups = k210_pinmux_get_function_groups, |
722 | .set_mux = k210_pinmux_set_mux, |
723 | .strict = true, |
724 | }; |
725 | |
726 | static int k210_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) |
727 | { |
728 | return K210_NGROUPS; |
729 | } |
730 | |
731 | static const char *k210_pinctrl_get_group_name(struct pinctrl_dev *pctldev, |
732 | unsigned int group) |
733 | { |
734 | return k210_group_names[group]; |
735 | } |
736 | |
737 | static int k210_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, |
738 | unsigned int group, |
739 | const unsigned int **pins, |
740 | unsigned int *npins) |
741 | { |
742 | if (group >= K210_NPINS) { |
743 | *pins = NULL; |
744 | *npins = 0; |
745 | return 0; |
746 | } |
747 | |
748 | *pins = &k210_pins[group].number; |
749 | *npins = 1; |
750 | |
751 | return 0; |
752 | } |
753 | |
754 | static void k210_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, |
755 | struct seq_file *s, unsigned int offset) |
756 | { |
757 | seq_printf(m: s, fmt: "%s" , dev_name(dev: pctldev->dev)); |
758 | } |
759 | |
760 | static int k210_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, |
761 | struct device_node *np, |
762 | struct pinctrl_map **map, |
763 | unsigned int *reserved_maps, |
764 | unsigned int *num_maps) |
765 | { |
766 | struct property *prop; |
767 | const __be32 *p; |
768 | int ret, pinmux_groups; |
769 | u32 pinmux_group; |
770 | unsigned long *configs = NULL; |
771 | unsigned int num_configs = 0; |
772 | unsigned int reserve = 0; |
773 | |
774 | ret = of_property_count_strings(np, propname: "groups" ); |
775 | if (!ret) |
776 | return pinconf_generic_dt_subnode_to_map(pctldev, np, map, |
777 | reserved_maps, num_maps, |
778 | type: PIN_MAP_TYPE_CONFIGS_GROUP); |
779 | |
780 | pinmux_groups = of_property_count_u32_elems(np, propname: "pinmux" ); |
781 | if (pinmux_groups <= 0) { |
782 | /* Ignore this node */ |
783 | return 0; |
784 | } |
785 | |
786 | ret = pinconf_generic_parse_dt_config(np, pctldev, configs: &configs, |
787 | nconfigs: &num_configs); |
788 | if (ret < 0) { |
789 | dev_err(pctldev->dev, "%pOF: could not parse node property\n" , |
790 | np); |
791 | return ret; |
792 | } |
793 | |
794 | reserve = pinmux_groups * (1 + num_configs); |
795 | ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, |
796 | reserve); |
797 | if (ret < 0) |
798 | goto exit; |
799 | |
800 | of_property_for_each_u32(np, "pinmux" , prop, p, pinmux_group) { |
801 | const char *group_name, *func_name; |
802 | u32 pin = FIELD_GET(K210_PG_PIN, pinmux_group); |
803 | u32 func = FIELD_GET(K210_PG_FUNC, pinmux_group); |
804 | |
805 | if (pin >= K210_NPINS) { |
806 | ret = -EINVAL; |
807 | goto exit; |
808 | } |
809 | |
810 | group_name = k210_group_names[pin]; |
811 | func_name = k210_pcf_infos[func].name; |
812 | |
813 | dev_dbg(pctldev->dev, "Pinmux %s: pin %u func %s\n" , |
814 | np->name, pin, func_name); |
815 | |
816 | ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, |
817 | num_maps, group: group_name, |
818 | function: func_name); |
819 | if (ret < 0) { |
820 | dev_err(pctldev->dev, "%pOF add mux map failed %d\n" , |
821 | np, ret); |
822 | goto exit; |
823 | } |
824 | |
825 | if (num_configs) { |
826 | ret = pinctrl_utils_add_map_configs(pctldev, map, |
827 | reserved_maps, num_maps, group: group_name, |
828 | configs, num_configs, |
829 | type: PIN_MAP_TYPE_CONFIGS_PIN); |
830 | if (ret < 0) { |
831 | dev_err(pctldev->dev, |
832 | "%pOF add configs map failed %d\n" , |
833 | np, ret); |
834 | goto exit; |
835 | } |
836 | } |
837 | } |
838 | |
839 | ret = 0; |
840 | |
841 | exit: |
842 | kfree(objp: configs); |
843 | return ret; |
844 | } |
845 | |
846 | static int k210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, |
847 | struct device_node *np_config, |
848 | struct pinctrl_map **map, |
849 | unsigned int *num_maps) |
850 | { |
851 | unsigned int reserved_maps; |
852 | struct device_node *np; |
853 | int ret; |
854 | |
855 | reserved_maps = 0; |
856 | *map = NULL; |
857 | *num_maps = 0; |
858 | |
859 | ret = k210_pinctrl_dt_subnode_to_map(pctldev, np: np_config, map, |
860 | reserved_maps: &reserved_maps, num_maps); |
861 | if (ret < 0) |
862 | goto err; |
863 | |
864 | for_each_available_child_of_node(np_config, np) { |
865 | ret = k210_pinctrl_dt_subnode_to_map(pctldev, np, map, |
866 | reserved_maps: &reserved_maps, num_maps); |
867 | if (ret < 0) { |
868 | of_node_put(node: np); |
869 | goto err; |
870 | } |
871 | } |
872 | return 0; |
873 | |
874 | err: |
875 | pinctrl_utils_free_map(pctldev, map: *map, num_maps: *num_maps); |
876 | return ret; |
877 | } |
878 | |
879 | |
880 | static const struct pinctrl_ops k210_pinctrl_ops = { |
881 | .get_groups_count = k210_pinctrl_get_groups_count, |
882 | .get_group_name = k210_pinctrl_get_group_name, |
883 | .get_group_pins = k210_pinctrl_get_group_pins, |
884 | .pin_dbg_show = k210_pinctrl_pin_dbg_show, |
885 | .dt_node_to_map = k210_pinctrl_dt_node_to_map, |
886 | .dt_free_map = pinconf_generic_dt_free_map, |
887 | }; |
888 | |
889 | static struct pinctrl_desc k210_pinctrl_desc = { |
890 | .name = "k210-pinctrl" , |
891 | .pins = k210_pins, |
892 | .npins = K210_NPINS, |
893 | .pctlops = &k210_pinctrl_ops, |
894 | .pmxops = &k210_pinmux_ops, |
895 | .confops = &k210_pinconf_ops, |
896 | .custom_params = k210_pinconf_custom_params, |
897 | .num_custom_params = ARRAY_SIZE(k210_pinconf_custom_params), |
898 | }; |
899 | |
900 | static void k210_fpioa_init_ties(struct k210_fpioa_data *pdata) |
901 | { |
902 | struct k210_fpioa __iomem *fpioa = pdata->fpioa; |
903 | u32 val; |
904 | int i, j; |
905 | |
906 | dev_dbg(pdata->dev, "Init pin ties\n" ); |
907 | |
908 | /* Init pin functions input ties */ |
909 | for (i = 0; i < ARRAY_SIZE(fpioa->tie_en); i++) { |
910 | val = 0; |
911 | for (j = 0; j < 32; j++) { |
912 | if (k210_pcf_infos[i * 32 + j].mode_id == |
913 | K210_PC_DEFAULT_IN_TIE) { |
914 | dev_dbg(pdata->dev, |
915 | "tie_en function %d (%s)\n" , |
916 | i * 32 + j, |
917 | k210_pcf_infos[i * 32 + j].name); |
918 | val |= BIT(j); |
919 | } |
920 | } |
921 | |
922 | /* Set value before enable */ |
923 | writel(val, addr: &fpioa->tie_val[i]); |
924 | writel(val, addr: &fpioa->tie_en[i]); |
925 | } |
926 | } |
927 | |
928 | static int k210_fpioa_probe(struct platform_device *pdev) |
929 | { |
930 | struct device *dev = &pdev->dev; |
931 | struct device_node *np = dev->of_node; |
932 | struct k210_fpioa_data *pdata; |
933 | int ret; |
934 | |
935 | dev_info(dev, "K210 FPIOA pin controller\n" ); |
936 | |
937 | pdata = devm_kzalloc(dev, size: sizeof(*pdata), GFP_KERNEL); |
938 | if (!pdata) |
939 | return -ENOMEM; |
940 | |
941 | pdata->dev = dev; |
942 | platform_set_drvdata(pdev, data: pdata); |
943 | |
944 | pdata->fpioa = devm_platform_ioremap_resource(pdev, index: 0); |
945 | if (IS_ERR(ptr: pdata->fpioa)) |
946 | return PTR_ERR(ptr: pdata->fpioa); |
947 | |
948 | pdata->clk = devm_clk_get(dev, id: "ref" ); |
949 | if (IS_ERR(ptr: pdata->clk)) |
950 | return PTR_ERR(ptr: pdata->clk); |
951 | |
952 | ret = clk_prepare_enable(clk: pdata->clk); |
953 | if (ret) |
954 | return ret; |
955 | |
956 | pdata->pclk = devm_clk_get_optional(dev, id: "pclk" ); |
957 | if (!IS_ERR(ptr: pdata->pclk)) { |
958 | ret = clk_prepare_enable(clk: pdata->pclk); |
959 | if (ret) |
960 | goto disable_clk; |
961 | } |
962 | |
963 | pdata->sysctl_map = |
964 | syscon_regmap_lookup_by_phandle_args(np, |
965 | property: "canaan,k210-sysctl-power" , |
966 | arg_count: 1, out_args: &pdata->power_offset); |
967 | if (IS_ERR(ptr: pdata->sysctl_map)) { |
968 | ret = PTR_ERR(ptr: pdata->sysctl_map); |
969 | goto disable_pclk; |
970 | } |
971 | |
972 | k210_fpioa_init_ties(pdata); |
973 | |
974 | pdata->pctl = pinctrl_register(pctldesc: &k210_pinctrl_desc, dev, driver_data: (void *)pdata); |
975 | if (IS_ERR(ptr: pdata->pctl)) { |
976 | ret = PTR_ERR(ptr: pdata->pctl); |
977 | goto disable_pclk; |
978 | } |
979 | |
980 | return 0; |
981 | |
982 | disable_pclk: |
983 | clk_disable_unprepare(clk: pdata->pclk); |
984 | disable_clk: |
985 | clk_disable_unprepare(clk: pdata->clk); |
986 | |
987 | return ret; |
988 | } |
989 | |
990 | static const struct of_device_id k210_fpioa_dt_ids[] = { |
991 | { .compatible = "canaan,k210-fpioa" }, |
992 | { /* sentinel */ }, |
993 | }; |
994 | |
995 | static struct platform_driver k210_fpioa_driver = { |
996 | .probe = k210_fpioa_probe, |
997 | .driver = { |
998 | .name = "k210-fpioa" , |
999 | .of_match_table = k210_fpioa_dt_ids, |
1000 | }, |
1001 | }; |
1002 | builtin_platform_driver(k210_fpioa_driver); |
1003 | |