1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Abilis Systems TB10x pin control driver |
4 | * |
5 | * Copyright (C) Abilis Systems 2012 |
6 | * |
7 | * Author: Christian Ruppert <christian.ruppert@abilis.com> |
8 | */ |
9 | |
10 | #include <linux/stringify.h> |
11 | #include <linux/pinctrl/pinctrl.h> |
12 | #include <linux/pinctrl/pinmux.h> |
13 | #include <linux/pinctrl/machine.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/module.h> |
16 | #include <linux/mutex.h> |
17 | #include <linux/err.h> |
18 | #include <linux/io.h> |
19 | #include <linux/of.h> |
20 | #include <linux/slab.h> |
21 | |
22 | #include "pinctrl-utils.h" |
23 | |
24 | #define TB10X_PORT1 (0) |
25 | #define TB10X_PORT2 (16) |
26 | #define TB10X_PORT3 (32) |
27 | #define TB10X_PORT4 (48) |
28 | #define TB10X_PORT5 (128) |
29 | #define TB10X_PORT6 (64) |
30 | #define TB10X_PORT7 (80) |
31 | #define TB10X_PORT8 (96) |
32 | #define TB10X_PORT9 (112) |
33 | #define TB10X_GPIOS (256) |
34 | |
35 | #define PCFG_PORT_BITWIDTH (2) |
36 | #define PCFG_PORT_MASK(PORT) \ |
37 | (((1 << PCFG_PORT_BITWIDTH) - 1) << (PCFG_PORT_BITWIDTH * (PORT))) |
38 | |
39 | static const struct pinctrl_pin_desc tb10x_pins[] = { |
40 | /* Port 1 */ |
41 | PINCTRL_PIN(TB10X_PORT1 + 0, "MICLK_S0" ), |
42 | PINCTRL_PIN(TB10X_PORT1 + 1, "MISTRT_S0" ), |
43 | PINCTRL_PIN(TB10X_PORT1 + 2, "MIVAL_S0" ), |
44 | PINCTRL_PIN(TB10X_PORT1 + 3, "MDI_S0" ), |
45 | PINCTRL_PIN(TB10X_PORT1 + 4, "GPIOA0" ), |
46 | PINCTRL_PIN(TB10X_PORT1 + 5, "GPIOA1" ), |
47 | PINCTRL_PIN(TB10X_PORT1 + 6, "GPIOA2" ), |
48 | PINCTRL_PIN(TB10X_PORT1 + 7, "MDI_S1" ), |
49 | PINCTRL_PIN(TB10X_PORT1 + 8, "MIVAL_S1" ), |
50 | PINCTRL_PIN(TB10X_PORT1 + 9, "MISTRT_S1" ), |
51 | PINCTRL_PIN(TB10X_PORT1 + 10, "MICLK_S1" ), |
52 | /* Port 2 */ |
53 | PINCTRL_PIN(TB10X_PORT2 + 0, "MICLK_S2" ), |
54 | PINCTRL_PIN(TB10X_PORT2 + 1, "MISTRT_S2" ), |
55 | PINCTRL_PIN(TB10X_PORT2 + 2, "MIVAL_S2" ), |
56 | PINCTRL_PIN(TB10X_PORT2 + 3, "MDI_S2" ), |
57 | PINCTRL_PIN(TB10X_PORT2 + 4, "GPIOC0" ), |
58 | PINCTRL_PIN(TB10X_PORT2 + 5, "GPIOC1" ), |
59 | PINCTRL_PIN(TB10X_PORT2 + 6, "GPIOC2" ), |
60 | PINCTRL_PIN(TB10X_PORT2 + 7, "MDI_S3" ), |
61 | PINCTRL_PIN(TB10X_PORT2 + 8, "MIVAL_S3" ), |
62 | PINCTRL_PIN(TB10X_PORT2 + 9, "MISTRT_S3" ), |
63 | PINCTRL_PIN(TB10X_PORT2 + 10, "MICLK_S3" ), |
64 | /* Port 3 */ |
65 | PINCTRL_PIN(TB10X_PORT3 + 0, "MICLK_S4" ), |
66 | PINCTRL_PIN(TB10X_PORT3 + 1, "MISTRT_S4" ), |
67 | PINCTRL_PIN(TB10X_PORT3 + 2, "MIVAL_S4" ), |
68 | PINCTRL_PIN(TB10X_PORT3 + 3, "MDI_S4" ), |
69 | PINCTRL_PIN(TB10X_PORT3 + 4, "GPIOE0" ), |
70 | PINCTRL_PIN(TB10X_PORT3 + 5, "GPIOE1" ), |
71 | PINCTRL_PIN(TB10X_PORT3 + 6, "GPIOE2" ), |
72 | PINCTRL_PIN(TB10X_PORT3 + 7, "MDI_S5" ), |
73 | PINCTRL_PIN(TB10X_PORT3 + 8, "MIVAL_S5" ), |
74 | PINCTRL_PIN(TB10X_PORT3 + 9, "MISTRT_S5" ), |
75 | PINCTRL_PIN(TB10X_PORT3 + 10, "MICLK_S5" ), |
76 | /* Port 4 */ |
77 | PINCTRL_PIN(TB10X_PORT4 + 0, "MICLK_S6" ), |
78 | PINCTRL_PIN(TB10X_PORT4 + 1, "MISTRT_S6" ), |
79 | PINCTRL_PIN(TB10X_PORT4 + 2, "MIVAL_S6" ), |
80 | PINCTRL_PIN(TB10X_PORT4 + 3, "MDI_S6" ), |
81 | PINCTRL_PIN(TB10X_PORT4 + 4, "GPIOG0" ), |
82 | PINCTRL_PIN(TB10X_PORT4 + 5, "GPIOG1" ), |
83 | PINCTRL_PIN(TB10X_PORT4 + 6, "GPIOG2" ), |
84 | PINCTRL_PIN(TB10X_PORT4 + 7, "MDI_S7" ), |
85 | PINCTRL_PIN(TB10X_PORT4 + 8, "MIVAL_S7" ), |
86 | PINCTRL_PIN(TB10X_PORT4 + 9, "MISTRT_S7" ), |
87 | PINCTRL_PIN(TB10X_PORT4 + 10, "MICLK_S7" ), |
88 | /* Port 5 */ |
89 | PINCTRL_PIN(TB10X_PORT5 + 0, "PC_CE1N" ), |
90 | PINCTRL_PIN(TB10X_PORT5 + 1, "PC_CE2N" ), |
91 | PINCTRL_PIN(TB10X_PORT5 + 2, "PC_REGN" ), |
92 | PINCTRL_PIN(TB10X_PORT5 + 3, "PC_INPACKN" ), |
93 | PINCTRL_PIN(TB10X_PORT5 + 4, "PC_OEN" ), |
94 | PINCTRL_PIN(TB10X_PORT5 + 5, "PC_WEN" ), |
95 | PINCTRL_PIN(TB10X_PORT5 + 6, "PC_IORDN" ), |
96 | PINCTRL_PIN(TB10X_PORT5 + 7, "PC_IOWRN" ), |
97 | PINCTRL_PIN(TB10X_PORT5 + 8, "PC_RDYIRQN" ), |
98 | PINCTRL_PIN(TB10X_PORT5 + 9, "PC_WAITN" ), |
99 | PINCTRL_PIN(TB10X_PORT5 + 10, "PC_A0" ), |
100 | PINCTRL_PIN(TB10X_PORT5 + 11, "PC_A1" ), |
101 | PINCTRL_PIN(TB10X_PORT5 + 12, "PC_A2" ), |
102 | PINCTRL_PIN(TB10X_PORT5 + 13, "PC_A3" ), |
103 | PINCTRL_PIN(TB10X_PORT5 + 14, "PC_A4" ), |
104 | PINCTRL_PIN(TB10X_PORT5 + 15, "PC_A5" ), |
105 | PINCTRL_PIN(TB10X_PORT5 + 16, "PC_A6" ), |
106 | PINCTRL_PIN(TB10X_PORT5 + 17, "PC_A7" ), |
107 | PINCTRL_PIN(TB10X_PORT5 + 18, "PC_A8" ), |
108 | PINCTRL_PIN(TB10X_PORT5 + 19, "PC_A9" ), |
109 | PINCTRL_PIN(TB10X_PORT5 + 20, "PC_A10" ), |
110 | PINCTRL_PIN(TB10X_PORT5 + 21, "PC_A11" ), |
111 | PINCTRL_PIN(TB10X_PORT5 + 22, "PC_A12" ), |
112 | PINCTRL_PIN(TB10X_PORT5 + 23, "PC_A13" ), |
113 | PINCTRL_PIN(TB10X_PORT5 + 24, "PC_A14" ), |
114 | PINCTRL_PIN(TB10X_PORT5 + 25, "PC_D0" ), |
115 | PINCTRL_PIN(TB10X_PORT5 + 26, "PC_D1" ), |
116 | PINCTRL_PIN(TB10X_PORT5 + 27, "PC_D2" ), |
117 | PINCTRL_PIN(TB10X_PORT5 + 28, "PC_D3" ), |
118 | PINCTRL_PIN(TB10X_PORT5 + 29, "PC_D4" ), |
119 | PINCTRL_PIN(TB10X_PORT5 + 30, "PC_D5" ), |
120 | PINCTRL_PIN(TB10X_PORT5 + 31, "PC_D6" ), |
121 | PINCTRL_PIN(TB10X_PORT5 + 32, "PC_D7" ), |
122 | PINCTRL_PIN(TB10X_PORT5 + 33, "PC_MOSTRT" ), |
123 | PINCTRL_PIN(TB10X_PORT5 + 34, "PC_MOVAL" ), |
124 | PINCTRL_PIN(TB10X_PORT5 + 35, "PC_MDO0" ), |
125 | PINCTRL_PIN(TB10X_PORT5 + 36, "PC_MDO1" ), |
126 | PINCTRL_PIN(TB10X_PORT5 + 37, "PC_MDO2" ), |
127 | PINCTRL_PIN(TB10X_PORT5 + 38, "PC_MDO3" ), |
128 | PINCTRL_PIN(TB10X_PORT5 + 39, "PC_MDO4" ), |
129 | PINCTRL_PIN(TB10X_PORT5 + 40, "PC_MDO5" ), |
130 | PINCTRL_PIN(TB10X_PORT5 + 41, "PC_MDO6" ), |
131 | PINCTRL_PIN(TB10X_PORT5 + 42, "PC_MDO7" ), |
132 | PINCTRL_PIN(TB10X_PORT5 + 43, "PC_MISTRT" ), |
133 | PINCTRL_PIN(TB10X_PORT5 + 44, "PC_MIVAL" ), |
134 | PINCTRL_PIN(TB10X_PORT5 + 45, "PC_MDI0" ), |
135 | PINCTRL_PIN(TB10X_PORT5 + 46, "PC_MDI1" ), |
136 | PINCTRL_PIN(TB10X_PORT5 + 47, "PC_MDI2" ), |
137 | PINCTRL_PIN(TB10X_PORT5 + 48, "PC_MDI3" ), |
138 | PINCTRL_PIN(TB10X_PORT5 + 49, "PC_MDI4" ), |
139 | PINCTRL_PIN(TB10X_PORT5 + 50, "PC_MDI5" ), |
140 | PINCTRL_PIN(TB10X_PORT5 + 51, "PC_MDI6" ), |
141 | PINCTRL_PIN(TB10X_PORT5 + 52, "PC_MDI7" ), |
142 | PINCTRL_PIN(TB10X_PORT5 + 53, "PC_MICLK" ), |
143 | /* Port 6 */ |
144 | PINCTRL_PIN(TB10X_PORT6 + 0, "T_MOSTRT_S0" ), |
145 | PINCTRL_PIN(TB10X_PORT6 + 1, "T_MOVAL_S0" ), |
146 | PINCTRL_PIN(TB10X_PORT6 + 2, "T_MDO_S0" ), |
147 | PINCTRL_PIN(TB10X_PORT6 + 3, "T_MOSTRT_S1" ), |
148 | PINCTRL_PIN(TB10X_PORT6 + 4, "T_MOVAL_S1" ), |
149 | PINCTRL_PIN(TB10X_PORT6 + 5, "T_MDO_S1" ), |
150 | PINCTRL_PIN(TB10X_PORT6 + 6, "T_MOSTRT_S2" ), |
151 | PINCTRL_PIN(TB10X_PORT6 + 7, "T_MOVAL_S2" ), |
152 | PINCTRL_PIN(TB10X_PORT6 + 8, "T_MDO_S2" ), |
153 | PINCTRL_PIN(TB10X_PORT6 + 9, "T_MOSTRT_S3" ), |
154 | /* Port 7 */ |
155 | PINCTRL_PIN(TB10X_PORT7 + 0, "UART0_TXD" ), |
156 | PINCTRL_PIN(TB10X_PORT7 + 1, "UART0_RXD" ), |
157 | PINCTRL_PIN(TB10X_PORT7 + 2, "UART0_CTS" ), |
158 | PINCTRL_PIN(TB10X_PORT7 + 3, "UART0_RTS" ), |
159 | PINCTRL_PIN(TB10X_PORT7 + 4, "UART1_TXD" ), |
160 | PINCTRL_PIN(TB10X_PORT7 + 5, "UART1_RXD" ), |
161 | PINCTRL_PIN(TB10X_PORT7 + 6, "UART1_CTS" ), |
162 | PINCTRL_PIN(TB10X_PORT7 + 7, "UART1_RTS" ), |
163 | /* Port 8 */ |
164 | PINCTRL_PIN(TB10X_PORT8 + 0, "SPI3_CLK" ), |
165 | PINCTRL_PIN(TB10X_PORT8 + 1, "SPI3_MISO" ), |
166 | PINCTRL_PIN(TB10X_PORT8 + 2, "SPI3_MOSI" ), |
167 | PINCTRL_PIN(TB10X_PORT8 + 3, "SPI3_SSN" ), |
168 | /* Port 9 */ |
169 | PINCTRL_PIN(TB10X_PORT9 + 0, "SPI1_CLK" ), |
170 | PINCTRL_PIN(TB10X_PORT9 + 1, "SPI1_MISO" ), |
171 | PINCTRL_PIN(TB10X_PORT9 + 2, "SPI1_MOSI" ), |
172 | PINCTRL_PIN(TB10X_PORT9 + 3, "SPI1_SSN0" ), |
173 | PINCTRL_PIN(TB10X_PORT9 + 4, "SPI1_SSN1" ), |
174 | /* Unmuxed GPIOs */ |
175 | PINCTRL_PIN(TB10X_GPIOS + 0, "GPIOB0" ), |
176 | PINCTRL_PIN(TB10X_GPIOS + 1, "GPIOB1" ), |
177 | |
178 | PINCTRL_PIN(TB10X_GPIOS + 2, "GPIOD0" ), |
179 | PINCTRL_PIN(TB10X_GPIOS + 3, "GPIOD1" ), |
180 | |
181 | PINCTRL_PIN(TB10X_GPIOS + 4, "GPIOF0" ), |
182 | PINCTRL_PIN(TB10X_GPIOS + 5, "GPIOF1" ), |
183 | |
184 | PINCTRL_PIN(TB10X_GPIOS + 6, "GPIOH0" ), |
185 | PINCTRL_PIN(TB10X_GPIOS + 7, "GPIOH1" ), |
186 | |
187 | PINCTRL_PIN(TB10X_GPIOS + 8, "GPIOI0" ), |
188 | PINCTRL_PIN(TB10X_GPIOS + 9, "GPIOI1" ), |
189 | PINCTRL_PIN(TB10X_GPIOS + 10, "GPIOI2" ), |
190 | PINCTRL_PIN(TB10X_GPIOS + 11, "GPIOI3" ), |
191 | PINCTRL_PIN(TB10X_GPIOS + 12, "GPIOI4" ), |
192 | PINCTRL_PIN(TB10X_GPIOS + 13, "GPIOI5" ), |
193 | PINCTRL_PIN(TB10X_GPIOS + 14, "GPIOI6" ), |
194 | PINCTRL_PIN(TB10X_GPIOS + 15, "GPIOI7" ), |
195 | PINCTRL_PIN(TB10X_GPIOS + 16, "GPIOI8" ), |
196 | PINCTRL_PIN(TB10X_GPIOS + 17, "GPIOI9" ), |
197 | PINCTRL_PIN(TB10X_GPIOS + 18, "GPIOI10" ), |
198 | PINCTRL_PIN(TB10X_GPIOS + 19, "GPIOI11" ), |
199 | |
200 | PINCTRL_PIN(TB10X_GPIOS + 20, "GPION0" ), |
201 | PINCTRL_PIN(TB10X_GPIOS + 21, "GPION1" ), |
202 | PINCTRL_PIN(TB10X_GPIOS + 22, "GPION2" ), |
203 | PINCTRL_PIN(TB10X_GPIOS + 23, "GPION3" ), |
204 | #define MAX_PIN (TB10X_GPIOS + 24) |
205 | PINCTRL_PIN(MAX_PIN, "GPION4" ), |
206 | }; |
207 | |
208 | |
209 | /* Port 1 */ |
210 | static const unsigned mis0_pins[] = { TB10X_PORT1 + 0, TB10X_PORT1 + 1, |
211 | TB10X_PORT1 + 2, TB10X_PORT1 + 3}; |
212 | static const unsigned gpioa_pins[] = { TB10X_PORT1 + 4, TB10X_PORT1 + 5, |
213 | TB10X_PORT1 + 6}; |
214 | static const unsigned mis1_pins[] = { TB10X_PORT1 + 7, TB10X_PORT1 + 8, |
215 | TB10X_PORT1 + 9, TB10X_PORT1 + 10}; |
216 | static const unsigned mip1_pins[] = { TB10X_PORT1 + 0, TB10X_PORT1 + 1, |
217 | TB10X_PORT1 + 2, TB10X_PORT1 + 3, |
218 | TB10X_PORT1 + 4, TB10X_PORT1 + 5, |
219 | TB10X_PORT1 + 6, TB10X_PORT1 + 7, |
220 | TB10X_PORT1 + 8, TB10X_PORT1 + 9, |
221 | TB10X_PORT1 + 10}; |
222 | |
223 | /* Port 2 */ |
224 | static const unsigned mis2_pins[] = { TB10X_PORT2 + 0, TB10X_PORT2 + 1, |
225 | TB10X_PORT2 + 2, TB10X_PORT2 + 3}; |
226 | static const unsigned gpioc_pins[] = { TB10X_PORT2 + 4, TB10X_PORT2 + 5, |
227 | TB10X_PORT2 + 6}; |
228 | static const unsigned mis3_pins[] = { TB10X_PORT2 + 7, TB10X_PORT2 + 8, |
229 | TB10X_PORT2 + 9, TB10X_PORT2 + 10}; |
230 | static const unsigned mip3_pins[] = { TB10X_PORT2 + 0, TB10X_PORT2 + 1, |
231 | TB10X_PORT2 + 2, TB10X_PORT2 + 3, |
232 | TB10X_PORT2 + 4, TB10X_PORT2 + 5, |
233 | TB10X_PORT2 + 6, TB10X_PORT2 + 7, |
234 | TB10X_PORT2 + 8, TB10X_PORT2 + 9, |
235 | TB10X_PORT2 + 10}; |
236 | |
237 | /* Port 3 */ |
238 | static const unsigned mis4_pins[] = { TB10X_PORT3 + 0, TB10X_PORT3 + 1, |
239 | TB10X_PORT3 + 2, TB10X_PORT3 + 3}; |
240 | static const unsigned gpioe_pins[] = { TB10X_PORT3 + 4, TB10X_PORT3 + 5, |
241 | TB10X_PORT3 + 6}; |
242 | static const unsigned mis5_pins[] = { TB10X_PORT3 + 7, TB10X_PORT3 + 8, |
243 | TB10X_PORT3 + 9, TB10X_PORT3 + 10}; |
244 | static const unsigned mip5_pins[] = { TB10X_PORT3 + 0, TB10X_PORT3 + 1, |
245 | TB10X_PORT3 + 2, TB10X_PORT3 + 3, |
246 | TB10X_PORT3 + 4, TB10X_PORT3 + 5, |
247 | TB10X_PORT3 + 6, TB10X_PORT3 + 7, |
248 | TB10X_PORT3 + 8, TB10X_PORT3 + 9, |
249 | TB10X_PORT3 + 10}; |
250 | |
251 | /* Port 4 */ |
252 | static const unsigned mis6_pins[] = { TB10X_PORT4 + 0, TB10X_PORT4 + 1, |
253 | TB10X_PORT4 + 2, TB10X_PORT4 + 3}; |
254 | static const unsigned gpiog_pins[] = { TB10X_PORT4 + 4, TB10X_PORT4 + 5, |
255 | TB10X_PORT4 + 6}; |
256 | static const unsigned mis7_pins[] = { TB10X_PORT4 + 7, TB10X_PORT4 + 8, |
257 | TB10X_PORT4 + 9, TB10X_PORT4 + 10}; |
258 | static const unsigned mip7_pins[] = { TB10X_PORT4 + 0, TB10X_PORT4 + 1, |
259 | TB10X_PORT4 + 2, TB10X_PORT4 + 3, |
260 | TB10X_PORT4 + 4, TB10X_PORT4 + 5, |
261 | TB10X_PORT4 + 6, TB10X_PORT4 + 7, |
262 | TB10X_PORT4 + 8, TB10X_PORT4 + 9, |
263 | TB10X_PORT4 + 10}; |
264 | |
265 | /* Port 6 */ |
266 | static const unsigned mop_pins[] = { TB10X_PORT6 + 0, TB10X_PORT6 + 1, |
267 | TB10X_PORT6 + 2, TB10X_PORT6 + 3, |
268 | TB10X_PORT6 + 4, TB10X_PORT6 + 5, |
269 | TB10X_PORT6 + 6, TB10X_PORT6 + 7, |
270 | TB10X_PORT6 + 8, TB10X_PORT6 + 9}; |
271 | static const unsigned mos0_pins[] = { TB10X_PORT6 + 0, TB10X_PORT6 + 1, |
272 | TB10X_PORT6 + 2}; |
273 | static const unsigned mos1_pins[] = { TB10X_PORT6 + 3, TB10X_PORT6 + 4, |
274 | TB10X_PORT6 + 5}; |
275 | static const unsigned mos2_pins[] = { TB10X_PORT6 + 6, TB10X_PORT6 + 7, |
276 | TB10X_PORT6 + 8}; |
277 | static const unsigned mos3_pins[] = { TB10X_PORT6 + 9}; |
278 | |
279 | /* Port 7 */ |
280 | static const unsigned uart0_pins[] = { TB10X_PORT7 + 0, TB10X_PORT7 + 1, |
281 | TB10X_PORT7 + 2, TB10X_PORT7 + 3}; |
282 | static const unsigned uart1_pins[] = { TB10X_PORT7 + 4, TB10X_PORT7 + 5, |
283 | TB10X_PORT7 + 6, TB10X_PORT7 + 7}; |
284 | static const unsigned gpiol_pins[] = { TB10X_PORT7 + 0, TB10X_PORT7 + 1, |
285 | TB10X_PORT7 + 2, TB10X_PORT7 + 3}; |
286 | static const unsigned gpiom_pins[] = { TB10X_PORT7 + 4, TB10X_PORT7 + 5, |
287 | TB10X_PORT7 + 6, TB10X_PORT7 + 7}; |
288 | |
289 | /* Port 8 */ |
290 | static const unsigned spi3_pins[] = { TB10X_PORT8 + 0, TB10X_PORT8 + 1, |
291 | TB10X_PORT8 + 2, TB10X_PORT8 + 3}; |
292 | static const unsigned jtag_pins[] = { TB10X_PORT8 + 0, TB10X_PORT8 + 1, |
293 | TB10X_PORT8 + 2, TB10X_PORT8 + 3}; |
294 | |
295 | /* Port 9 */ |
296 | static const unsigned spi1_pins[] = { TB10X_PORT9 + 0, TB10X_PORT9 + 1, |
297 | TB10X_PORT9 + 2, TB10X_PORT9 + 3, |
298 | TB10X_PORT9 + 4}; |
299 | static const unsigned gpion_pins[] = { TB10X_PORT9 + 0, TB10X_PORT9 + 1, |
300 | TB10X_PORT9 + 2, TB10X_PORT9 + 3, |
301 | TB10X_PORT9 + 4}; |
302 | |
303 | /* Port 5 */ |
304 | static const unsigned gpioj_pins[] = { TB10X_PORT5 + 0, TB10X_PORT5 + 1, |
305 | TB10X_PORT5 + 2, TB10X_PORT5 + 3, |
306 | TB10X_PORT5 + 4, TB10X_PORT5 + 5, |
307 | TB10X_PORT5 + 6, TB10X_PORT5 + 7, |
308 | TB10X_PORT5 + 8, TB10X_PORT5 + 9, |
309 | TB10X_PORT5 + 10, TB10X_PORT5 + 11, |
310 | TB10X_PORT5 + 12, TB10X_PORT5 + 13, |
311 | TB10X_PORT5 + 14, TB10X_PORT5 + 15, |
312 | TB10X_PORT5 + 16, TB10X_PORT5 + 17, |
313 | TB10X_PORT5 + 18, TB10X_PORT5 + 19, |
314 | TB10X_PORT5 + 20, TB10X_PORT5 + 21, |
315 | TB10X_PORT5 + 22, TB10X_PORT5 + 23, |
316 | TB10X_PORT5 + 24, TB10X_PORT5 + 25, |
317 | TB10X_PORT5 + 26, TB10X_PORT5 + 27, |
318 | TB10X_PORT5 + 28, TB10X_PORT5 + 29, |
319 | TB10X_PORT5 + 30, TB10X_PORT5 + 31}; |
320 | static const unsigned gpiok_pins[] = { TB10X_PORT5 + 32, TB10X_PORT5 + 33, |
321 | TB10X_PORT5 + 34, TB10X_PORT5 + 35, |
322 | TB10X_PORT5 + 36, TB10X_PORT5 + 37, |
323 | TB10X_PORT5 + 38, TB10X_PORT5 + 39, |
324 | TB10X_PORT5 + 40, TB10X_PORT5 + 41, |
325 | TB10X_PORT5 + 42, TB10X_PORT5 + 43, |
326 | TB10X_PORT5 + 44, TB10X_PORT5 + 45, |
327 | TB10X_PORT5 + 46, TB10X_PORT5 + 47, |
328 | TB10X_PORT5 + 48, TB10X_PORT5 + 49, |
329 | TB10X_PORT5 + 50, TB10X_PORT5 + 51, |
330 | TB10X_PORT5 + 52, TB10X_PORT5 + 53}; |
331 | static const unsigned ciplus_pins[] = { TB10X_PORT5 + 0, TB10X_PORT5 + 1, |
332 | TB10X_PORT5 + 2, TB10X_PORT5 + 3, |
333 | TB10X_PORT5 + 4, TB10X_PORT5 + 5, |
334 | TB10X_PORT5 + 6, TB10X_PORT5 + 7, |
335 | TB10X_PORT5 + 8, TB10X_PORT5 + 9, |
336 | TB10X_PORT5 + 10, TB10X_PORT5 + 11, |
337 | TB10X_PORT5 + 12, TB10X_PORT5 + 13, |
338 | TB10X_PORT5 + 14, TB10X_PORT5 + 15, |
339 | TB10X_PORT5 + 16, TB10X_PORT5 + 17, |
340 | TB10X_PORT5 + 18, TB10X_PORT5 + 19, |
341 | TB10X_PORT5 + 20, TB10X_PORT5 + 21, |
342 | TB10X_PORT5 + 22, TB10X_PORT5 + 23, |
343 | TB10X_PORT5 + 24, TB10X_PORT5 + 25, |
344 | TB10X_PORT5 + 26, TB10X_PORT5 + 27, |
345 | TB10X_PORT5 + 28, TB10X_PORT5 + 29, |
346 | TB10X_PORT5 + 30, TB10X_PORT5 + 31, |
347 | TB10X_PORT5 + 32, TB10X_PORT5 + 33, |
348 | TB10X_PORT5 + 34, TB10X_PORT5 + 35, |
349 | TB10X_PORT5 + 36, TB10X_PORT5 + 37, |
350 | TB10X_PORT5 + 38, TB10X_PORT5 + 39, |
351 | TB10X_PORT5 + 40, TB10X_PORT5 + 41, |
352 | TB10X_PORT5 + 42, TB10X_PORT5 + 43, |
353 | TB10X_PORT5 + 44, TB10X_PORT5 + 45, |
354 | TB10X_PORT5 + 46, TB10X_PORT5 + 47, |
355 | TB10X_PORT5 + 48, TB10X_PORT5 + 49, |
356 | TB10X_PORT5 + 50, TB10X_PORT5 + 51, |
357 | TB10X_PORT5 + 52, TB10X_PORT5 + 53}; |
358 | static const unsigned mcard_pins[] = { TB10X_PORT5 + 3, TB10X_PORT5 + 10, |
359 | TB10X_PORT5 + 11, TB10X_PORT5 + 12, |
360 | TB10X_PORT5 + 22, TB10X_PORT5 + 23, |
361 | TB10X_PORT5 + 33, TB10X_PORT5 + 35, |
362 | TB10X_PORT5 + 36, TB10X_PORT5 + 37, |
363 | TB10X_PORT5 + 38, TB10X_PORT5 + 39, |
364 | TB10X_PORT5 + 40, TB10X_PORT5 + 41, |
365 | TB10X_PORT5 + 42, TB10X_PORT5 + 43, |
366 | TB10X_PORT5 + 45, TB10X_PORT5 + 46, |
367 | TB10X_PORT5 + 47, TB10X_PORT5 + 48, |
368 | TB10X_PORT5 + 49, TB10X_PORT5 + 50, |
369 | TB10X_PORT5 + 51, TB10X_PORT5 + 52, |
370 | TB10X_PORT5 + 53}; |
371 | static const unsigned stc0_pins[] = { TB10X_PORT5 + 34, TB10X_PORT5 + 35, |
372 | TB10X_PORT5 + 36, TB10X_PORT5 + 37, |
373 | TB10X_PORT5 + 38, TB10X_PORT5 + 39, |
374 | TB10X_PORT5 + 40}; |
375 | static const unsigned stc1_pins[] = { TB10X_PORT5 + 25, TB10X_PORT5 + 26, |
376 | TB10X_PORT5 + 27, TB10X_PORT5 + 28, |
377 | TB10X_PORT5 + 29, TB10X_PORT5 + 30, |
378 | TB10X_PORT5 + 44}; |
379 | |
380 | /* Unmuxed GPIOs */ |
381 | static const unsigned gpiob_pins[] = { TB10X_GPIOS + 0, TB10X_GPIOS + 1}; |
382 | static const unsigned gpiod_pins[] = { TB10X_GPIOS + 2, TB10X_GPIOS + 3}; |
383 | static const unsigned gpiof_pins[] = { TB10X_GPIOS + 4, TB10X_GPIOS + 5}; |
384 | static const unsigned gpioh_pins[] = { TB10X_GPIOS + 6, TB10X_GPIOS + 7}; |
385 | static const unsigned gpioi_pins[] = { TB10X_GPIOS + 8, TB10X_GPIOS + 9, |
386 | TB10X_GPIOS + 10, TB10X_GPIOS + 11, |
387 | TB10X_GPIOS + 12, TB10X_GPIOS + 13, |
388 | TB10X_GPIOS + 14, TB10X_GPIOS + 15, |
389 | TB10X_GPIOS + 16, TB10X_GPIOS + 17, |
390 | TB10X_GPIOS + 18, TB10X_GPIOS + 19}; |
391 | |
392 | struct tb10x_pinfuncgrp { |
393 | const char *name; |
394 | const unsigned int *pins; |
395 | const unsigned int pincnt; |
396 | const int port; |
397 | const unsigned int mode; |
398 | const int isgpio; |
399 | }; |
400 | #define DEFPINFUNCGRP(NAME, PORT, MODE, ISGPIO) { \ |
401 | .name = __stringify(NAME), \ |
402 | .pins = NAME##_pins, .pincnt = ARRAY_SIZE(NAME##_pins), \ |
403 | .port = (PORT), .mode = (MODE), \ |
404 | .isgpio = (ISGPIO), \ |
405 | } |
406 | static const struct tb10x_pinfuncgrp tb10x_pingroups[] = { |
407 | DEFPINFUNCGRP(mis0, 0, 0, 0), |
408 | DEFPINFUNCGRP(gpioa, 0, 0, 1), |
409 | DEFPINFUNCGRP(mis1, 0, 0, 0), |
410 | DEFPINFUNCGRP(mip1, 0, 1, 0), |
411 | DEFPINFUNCGRP(mis2, 1, 0, 0), |
412 | DEFPINFUNCGRP(gpioc, 1, 0, 1), |
413 | DEFPINFUNCGRP(mis3, 1, 0, 0), |
414 | DEFPINFUNCGRP(mip3, 1, 1, 0), |
415 | DEFPINFUNCGRP(mis4, 2, 0, 0), |
416 | DEFPINFUNCGRP(gpioe, 2, 0, 1), |
417 | DEFPINFUNCGRP(mis5, 2, 0, 0), |
418 | DEFPINFUNCGRP(mip5, 2, 1, 0), |
419 | DEFPINFUNCGRP(mis6, 3, 0, 0), |
420 | DEFPINFUNCGRP(gpiog, 3, 0, 1), |
421 | DEFPINFUNCGRP(mis7, 3, 0, 0), |
422 | DEFPINFUNCGRP(mip7, 3, 1, 0), |
423 | DEFPINFUNCGRP(gpioj, 4, 0, 1), |
424 | DEFPINFUNCGRP(gpiok, 4, 0, 1), |
425 | DEFPINFUNCGRP(ciplus, 4, 1, 0), |
426 | DEFPINFUNCGRP(mcard, 4, 2, 0), |
427 | DEFPINFUNCGRP(stc0, 4, 3, 0), |
428 | DEFPINFUNCGRP(stc1, 4, 3, 0), |
429 | DEFPINFUNCGRP(mop, 5, 0, 0), |
430 | DEFPINFUNCGRP(mos0, 5, 1, 0), |
431 | DEFPINFUNCGRP(mos1, 5, 1, 0), |
432 | DEFPINFUNCGRP(mos2, 5, 1, 0), |
433 | DEFPINFUNCGRP(mos3, 5, 1, 0), |
434 | DEFPINFUNCGRP(uart0, 6, 0, 0), |
435 | DEFPINFUNCGRP(uart1, 6, 0, 0), |
436 | DEFPINFUNCGRP(gpiol, 6, 1, 1), |
437 | DEFPINFUNCGRP(gpiom, 6, 1, 1), |
438 | DEFPINFUNCGRP(spi3, 7, 0, 0), |
439 | DEFPINFUNCGRP(jtag, 7, 1, 0), |
440 | DEFPINFUNCGRP(spi1, 8, 0, 0), |
441 | DEFPINFUNCGRP(gpion, 8, 1, 1), |
442 | DEFPINFUNCGRP(gpiob, -1, 0, 1), |
443 | DEFPINFUNCGRP(gpiod, -1, 0, 1), |
444 | DEFPINFUNCGRP(gpiof, -1, 0, 1), |
445 | DEFPINFUNCGRP(gpioh, -1, 0, 1), |
446 | DEFPINFUNCGRP(gpioi, -1, 0, 1), |
447 | }; |
448 | #undef DEFPINFUNCGRP |
449 | |
450 | struct tb10x_of_pinfunc { |
451 | const char *name; |
452 | const char *group; |
453 | }; |
454 | |
455 | #define TB10X_PORTS (9) |
456 | |
457 | /** |
458 | * struct tb10x_port - state of an I/O port |
459 | * @mode: Node this port is currently in. |
460 | * @count: Number of enabled functions which require this port to be |
461 | * configured in @mode. |
462 | */ |
463 | struct tb10x_port { |
464 | unsigned int mode; |
465 | unsigned int count; |
466 | }; |
467 | |
468 | /** |
469 | * struct tb10x_pinctrl - TB10x pin controller internal state |
470 | * @pctl: pointer to the pinctrl_dev structure of this pin controller. |
471 | * @base: register set base address. |
472 | * @pingroups: pointer to an array of the pin groups this driver manages. |
473 | * @pinfuncgrpcnt: number of pingroups in @pingroups. |
474 | * @pinfuncnt: number of pin functions in @pinfuncs. |
475 | * @mutex: mutex for exclusive access to a pin controller's state. |
476 | * @ports: current state of each port. |
477 | * @gpios: Indicates if a given pin is currently used as GPIO (1) or not (0). |
478 | * @pinfuncs: flexible array of pin functions this driver manages. |
479 | */ |
480 | struct tb10x_pinctrl { |
481 | struct pinctrl_dev *pctl; |
482 | void *base; |
483 | const struct tb10x_pinfuncgrp *pingroups; |
484 | unsigned int pinfuncgrpcnt; |
485 | unsigned int pinfuncnt; |
486 | struct mutex mutex; |
487 | struct tb10x_port ports[TB10X_PORTS]; |
488 | DECLARE_BITMAP(gpios, MAX_PIN + 1); |
489 | struct tb10x_of_pinfunc pinfuncs[]; |
490 | }; |
491 | |
492 | static inline void tb10x_pinctrl_set_config(struct tb10x_pinctrl *state, |
493 | unsigned int port, unsigned int mode) |
494 | { |
495 | u32 pcfg; |
496 | |
497 | if (state->ports[port].count) |
498 | return; |
499 | |
500 | state->ports[port].mode = mode; |
501 | |
502 | pcfg = ioread32(state->base) & ~(PCFG_PORT_MASK(port)); |
503 | pcfg |= (mode << (PCFG_PORT_BITWIDTH * port)) & PCFG_PORT_MASK(port); |
504 | iowrite32(pcfg, state->base); |
505 | } |
506 | |
507 | static inline unsigned int tb10x_pinctrl_get_config( |
508 | struct tb10x_pinctrl *state, |
509 | unsigned int port) |
510 | { |
511 | return (ioread32(state->base) & PCFG_PORT_MASK(port)) |
512 | >> (PCFG_PORT_BITWIDTH * port); |
513 | } |
514 | |
515 | static int tb10x_get_groups_count(struct pinctrl_dev *pctl) |
516 | { |
517 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctldev: pctl); |
518 | return state->pinfuncgrpcnt; |
519 | } |
520 | |
521 | static const char *tb10x_get_group_name(struct pinctrl_dev *pctl, unsigned n) |
522 | { |
523 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctldev: pctl); |
524 | return state->pingroups[n].name; |
525 | } |
526 | |
527 | static int tb10x_get_group_pins(struct pinctrl_dev *pctl, unsigned n, |
528 | unsigned const **pins, |
529 | unsigned * const num_pins) |
530 | { |
531 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctldev: pctl); |
532 | |
533 | *pins = state->pingroups[n].pins; |
534 | *num_pins = state->pingroups[n].pincnt; |
535 | |
536 | return 0; |
537 | } |
538 | |
539 | static int tb10x_dt_node_to_map(struct pinctrl_dev *pctl, |
540 | struct device_node *np_config, |
541 | struct pinctrl_map **map, unsigned *num_maps) |
542 | { |
543 | const char *string; |
544 | unsigned reserved_maps = 0; |
545 | int ret = 0; |
546 | |
547 | if (of_property_read_string(np: np_config, propname: "abilis,function" , out_string: &string)) { |
548 | pr_err("%pOF: No abilis,function property in device tree.\n" , |
549 | np_config); |
550 | return -EINVAL; |
551 | } |
552 | |
553 | *map = NULL; |
554 | *num_maps = 0; |
555 | |
556 | ret = pinctrl_utils_reserve_map(pctldev: pctl, map, reserved_maps: &reserved_maps, |
557 | num_maps, reserve: 1); |
558 | if (ret) |
559 | goto out; |
560 | |
561 | ret = pinctrl_utils_add_map_mux(pctldev: pctl, map, reserved_maps: &reserved_maps, |
562 | num_maps, group: string, function: np_config->name); |
563 | |
564 | out: |
565 | return ret; |
566 | } |
567 | |
568 | static const struct pinctrl_ops tb10x_pinctrl_ops = { |
569 | .get_groups_count = tb10x_get_groups_count, |
570 | .get_group_name = tb10x_get_group_name, |
571 | .get_group_pins = tb10x_get_group_pins, |
572 | .dt_node_to_map = tb10x_dt_node_to_map, |
573 | .dt_free_map = pinctrl_utils_free_map, |
574 | }; |
575 | |
576 | static int tb10x_get_functions_count(struct pinctrl_dev *pctl) |
577 | { |
578 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctldev: pctl); |
579 | return state->pinfuncnt; |
580 | } |
581 | |
582 | static const char *tb10x_get_function_name(struct pinctrl_dev *pctl, |
583 | unsigned n) |
584 | { |
585 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctldev: pctl); |
586 | return state->pinfuncs[n].name; |
587 | } |
588 | |
589 | static int tb10x_get_function_groups(struct pinctrl_dev *pctl, |
590 | unsigned n, const char * const **groups, |
591 | unsigned * const num_groups) |
592 | { |
593 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctldev: pctl); |
594 | |
595 | *groups = &state->pinfuncs[n].group; |
596 | *num_groups = 1; |
597 | |
598 | return 0; |
599 | } |
600 | |
601 | static int tb10x_gpio_request_enable(struct pinctrl_dev *pctl, |
602 | struct pinctrl_gpio_range *range, |
603 | unsigned pin) |
604 | { |
605 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctldev: pctl); |
606 | int muxport = -1; |
607 | int muxmode = -1; |
608 | int i; |
609 | |
610 | mutex_lock(&state->mutex); |
611 | |
612 | /* |
613 | * Figure out to which port the requested GPIO belongs and how to |
614 | * configure that port. |
615 | * This loop also checks for pin conflicts between GPIOs and other |
616 | * functions. |
617 | */ |
618 | for (i = 0; i < state->pinfuncgrpcnt; i++) { |
619 | const struct tb10x_pinfuncgrp *pfg = &state->pingroups[i]; |
620 | unsigned int mode = pfg->mode; |
621 | int j, port = pfg->port; |
622 | |
623 | /* |
624 | * Skip pin groups which are always mapped and don't need |
625 | * to be configured. |
626 | */ |
627 | if (port < 0) |
628 | continue; |
629 | |
630 | for (j = 0; j < pfg->pincnt; j++) { |
631 | if (pin == pfg->pins[j]) { |
632 | if (pfg->isgpio) { |
633 | /* |
634 | * Remember the GPIO-only setting of |
635 | * the port this pin belongs to. |
636 | */ |
637 | muxport = port; |
638 | muxmode = mode; |
639 | } else if (state->ports[port].count |
640 | && (state->ports[port].mode == mode)) { |
641 | /* |
642 | * Error: The requested pin is already |
643 | * used for something else. |
644 | */ |
645 | mutex_unlock(lock: &state->mutex); |
646 | return -EBUSY; |
647 | } |
648 | break; |
649 | } |
650 | } |
651 | } |
652 | |
653 | /* |
654 | * If we haven't returned an error at this point, the GPIO pin is not |
655 | * used by another function and the GPIO request can be granted: |
656 | * Register pin as being used as GPIO so we don't allocate it to |
657 | * another function later. |
658 | */ |
659 | set_bit(nr: pin, addr: state->gpios); |
660 | |
661 | /* |
662 | * Potential conflicts between GPIOs and pin functions were caught |
663 | * earlier in this function and tb10x_pinctrl_set_config will do the |
664 | * Right Thing, either configure the port in GPIO only mode or leave |
665 | * another mode compatible with this GPIO request untouched. |
666 | */ |
667 | if (muxport >= 0) |
668 | tb10x_pinctrl_set_config(state, port: muxport, mode: muxmode); |
669 | |
670 | mutex_unlock(lock: &state->mutex); |
671 | |
672 | return 0; |
673 | } |
674 | |
675 | static void tb10x_gpio_disable_free(struct pinctrl_dev *pctl, |
676 | struct pinctrl_gpio_range *range, |
677 | unsigned pin) |
678 | { |
679 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctldev: pctl); |
680 | |
681 | mutex_lock(&state->mutex); |
682 | |
683 | clear_bit(nr: pin, addr: state->gpios); |
684 | |
685 | mutex_unlock(lock: &state->mutex); |
686 | } |
687 | |
688 | static int tb10x_pctl_set_mux(struct pinctrl_dev *pctl, |
689 | unsigned func_selector, unsigned group_selector) |
690 | { |
691 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctldev: pctl); |
692 | const struct tb10x_pinfuncgrp *grp = &state->pingroups[group_selector]; |
693 | int i; |
694 | |
695 | if (grp->port < 0) |
696 | return 0; |
697 | |
698 | mutex_lock(&state->mutex); |
699 | |
700 | /* |
701 | * Check if the requested function is compatible with previously |
702 | * requested functions. |
703 | */ |
704 | if (state->ports[grp->port].count |
705 | && (state->ports[grp->port].mode != grp->mode)) { |
706 | mutex_unlock(lock: &state->mutex); |
707 | return -EBUSY; |
708 | } |
709 | |
710 | /* |
711 | * Check if the requested function is compatible with previously |
712 | * requested GPIOs. |
713 | */ |
714 | for (i = 0; i < grp->pincnt; i++) |
715 | if (test_bit(grp->pins[i], state->gpios)) { |
716 | mutex_unlock(lock: &state->mutex); |
717 | return -EBUSY; |
718 | } |
719 | |
720 | tb10x_pinctrl_set_config(state, port: grp->port, mode: grp->mode); |
721 | |
722 | state->ports[grp->port].count++; |
723 | |
724 | mutex_unlock(lock: &state->mutex); |
725 | |
726 | return 0; |
727 | } |
728 | |
729 | static const struct pinmux_ops tb10x_pinmux_ops = { |
730 | .get_functions_count = tb10x_get_functions_count, |
731 | .get_function_name = tb10x_get_function_name, |
732 | .get_function_groups = tb10x_get_function_groups, |
733 | .gpio_request_enable = tb10x_gpio_request_enable, |
734 | .gpio_disable_free = tb10x_gpio_disable_free, |
735 | .set_mux = tb10x_pctl_set_mux, |
736 | }; |
737 | |
738 | static struct pinctrl_desc tb10x_pindesc = { |
739 | .name = "TB10x" , |
740 | .pins = tb10x_pins, |
741 | .npins = ARRAY_SIZE(tb10x_pins), |
742 | .owner = THIS_MODULE, |
743 | .pctlops = &tb10x_pinctrl_ops, |
744 | .pmxops = &tb10x_pinmux_ops, |
745 | }; |
746 | |
747 | static int tb10x_pinctrl_probe(struct platform_device *pdev) |
748 | { |
749 | int ret = -EINVAL; |
750 | struct device *dev = &pdev->dev; |
751 | struct device_node *of_node = dev->of_node; |
752 | struct device_node *child; |
753 | struct tb10x_pinctrl *state; |
754 | int i; |
755 | |
756 | if (!of_node) { |
757 | dev_err(dev, "No device tree node found.\n" ); |
758 | return -EINVAL; |
759 | } |
760 | |
761 | state = devm_kzalloc(dev, struct_size(state, pinfuncs, |
762 | of_get_child_count(of_node)), |
763 | GFP_KERNEL); |
764 | if (!state) |
765 | return -ENOMEM; |
766 | |
767 | platform_set_drvdata(pdev, data: state); |
768 | mutex_init(&state->mutex); |
769 | |
770 | state->base = devm_platform_ioremap_resource(pdev, index: 0); |
771 | if (IS_ERR(ptr: state->base)) { |
772 | ret = PTR_ERR(ptr: state->base); |
773 | goto fail; |
774 | } |
775 | |
776 | state->pingroups = tb10x_pingroups; |
777 | state->pinfuncgrpcnt = ARRAY_SIZE(tb10x_pingroups); |
778 | |
779 | for (i = 0; i < TB10X_PORTS; i++) |
780 | state->ports[i].mode = tb10x_pinctrl_get_config(state, port: i); |
781 | |
782 | for_each_child_of_node(of_node, child) { |
783 | const char *name; |
784 | |
785 | if (!of_property_read_string(np: child, propname: "abilis,function" , |
786 | out_string: &name)) { |
787 | state->pinfuncs[state->pinfuncnt].name = child->name; |
788 | state->pinfuncs[state->pinfuncnt].group = name; |
789 | state->pinfuncnt++; |
790 | } |
791 | } |
792 | |
793 | state->pctl = devm_pinctrl_register(dev, pctldesc: &tb10x_pindesc, driver_data: state); |
794 | if (IS_ERR(ptr: state->pctl)) { |
795 | dev_err(dev, "could not register TB10x pin driver\n" ); |
796 | ret = PTR_ERR(ptr: state->pctl); |
797 | goto fail; |
798 | } |
799 | |
800 | return 0; |
801 | |
802 | fail: |
803 | mutex_destroy(lock: &state->mutex); |
804 | return ret; |
805 | } |
806 | |
807 | static void tb10x_pinctrl_remove(struct platform_device *pdev) |
808 | { |
809 | struct tb10x_pinctrl *state = platform_get_drvdata(pdev); |
810 | |
811 | mutex_destroy(lock: &state->mutex); |
812 | } |
813 | |
814 | |
815 | static const struct of_device_id tb10x_pinctrl_dt_ids[] = { |
816 | { .compatible = "abilis,tb10x-iomux" }, |
817 | { } |
818 | }; |
819 | MODULE_DEVICE_TABLE(of, tb10x_pinctrl_dt_ids); |
820 | |
821 | static struct platform_driver tb10x_pinctrl_pdrv = { |
822 | .probe = tb10x_pinctrl_probe, |
823 | .remove_new = tb10x_pinctrl_remove, |
824 | .driver = { |
825 | .name = "tb10x_pinctrl" , |
826 | .of_match_table = of_match_ptr(tb10x_pinctrl_dt_ids), |
827 | } |
828 | }; |
829 | |
830 | module_platform_driver(tb10x_pinctrl_pdrv); |
831 | |
832 | MODULE_AUTHOR("Christian Ruppert <christian.ruppert@abilis.com>" ); |
833 | MODULE_LICENSE("GPL" ); |
834 | |