1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2016-2018 Nuvoton Technology corporation. |
3 | // Copyright (c) 2016, Dell Inc |
4 | // Copyright (c) 2021-2022 Jonathan Neuschäfer |
5 | // |
6 | // This driver uses the following registers: |
7 | // - Pin mux registers, in the GCR (general control registers) block |
8 | // - GPIO registers, specific to each GPIO bank |
9 | // - GPIO event (interrupt) registers, located centrally in the GPIO register |
10 | // block, shared between all GPIO banks |
11 | |
12 | #include <linux/device.h> |
13 | #include <linux/fwnode.h> |
14 | #include <linux/gpio/driver.h> |
15 | #include <linux/interrupt.h> |
16 | #include <linux/irq.h> |
17 | #include <linux/mfd/syscon.h> |
18 | #include <linux/module.h> |
19 | #include <linux/mod_devicetable.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/regmap.h> |
22 | |
23 | #include <linux/pinctrl/pinconf.h> |
24 | #include <linux/pinctrl/pinconf-generic.h> |
25 | #include <linux/pinctrl/pinctrl.h> |
26 | #include <linux/pinctrl/pinmux.h> |
27 | |
28 | #include "../core.h" |
29 | |
30 | /* GCR registers */ |
31 | #define WPCM450_GCR_MFSEL1 0x0c |
32 | #define WPCM450_GCR_MFSEL2 0x10 |
33 | #define WPCM450_GCR_NONE 0 |
34 | |
35 | /* GPIO event (interrupt) registers */ |
36 | #define WPCM450_GPEVTYPE 0x00 |
37 | #define WPCM450_GPEVPOL 0x04 |
38 | #define WPCM450_GPEVDBNC 0x08 |
39 | #define WPCM450_GPEVEN 0x0c |
40 | #define WPCM450_GPEVST 0x10 |
41 | |
42 | #define WPCM450_NUM_BANKS 8 |
43 | #define WPCM450_NUM_GPIOS 128 |
44 | #define WPCM450_NUM_GPIO_IRQS 4 |
45 | |
46 | struct wpcm450_pinctrl; |
47 | struct wpcm450_bank; |
48 | |
49 | struct wpcm450_gpio { |
50 | struct gpio_chip gc; |
51 | struct wpcm450_pinctrl *pctrl; |
52 | const struct wpcm450_bank *bank; |
53 | }; |
54 | |
55 | struct wpcm450_pinctrl { |
56 | struct pinctrl_dev *pctldev; |
57 | struct device *dev; |
58 | struct irq_domain *domain; |
59 | struct regmap *gcr_regmap; |
60 | void __iomem *gpio_base; |
61 | struct wpcm450_gpio gpio_bank[WPCM450_NUM_BANKS]; |
62 | unsigned long both_edges; |
63 | |
64 | /* |
65 | * This spin lock protects registers and struct wpcm450_pinctrl fields |
66 | * against concurrent access. |
67 | */ |
68 | raw_spinlock_t lock; |
69 | }; |
70 | |
71 | struct wpcm450_bank { |
72 | /* Range of GPIOs in this port */ |
73 | u8 base; |
74 | u8 length; |
75 | |
76 | /* Register offsets (0 = register doesn't exist in this port) */ |
77 | u8 cfg0, cfg1, cfg2; |
78 | u8 blink; |
79 | u8 dataout, datain; |
80 | |
81 | /* Interrupt bit mapping */ |
82 | u8 first_irq_bit; /* First bit in GPEVST that belongs to this bank */ |
83 | u8 num_irqs; /* Number of IRQ-capable GPIOs in this bank */ |
84 | u8 first_irq_gpio; /* First IRQ-capable GPIO in this bank */ |
85 | }; |
86 | |
87 | static const struct wpcm450_bank wpcm450_banks[WPCM450_NUM_BANKS] = { |
88 | /* range cfg0 cfg1 cfg2 blink out in IRQ map */ |
89 | { 0, 16, 0x14, 0x18, 0, 0, 0x1c, 0x20, 0, 16, 0 }, |
90 | { 16, 16, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 16, 2, 8 }, |
91 | { 32, 16, 0x3c, 0x40, 0x44, 0, 0x48, 0x4c, 0, 0, 0 }, |
92 | { 48, 16, 0x50, 0x54, 0x58, 0, 0x5c, 0x60, 0, 0, 0 }, |
93 | { 64, 16, 0x64, 0x68, 0x6c, 0, 0x70, 0x74, 0, 0, 0 }, |
94 | { 80, 16, 0x78, 0x7c, 0x80, 0, 0x84, 0x88, 0, 0, 0 }, |
95 | { 96, 18, 0, 0, 0, 0, 0, 0x8c, 0, 0, 0 }, |
96 | { 114, 14, 0x90, 0x94, 0x98, 0, 0x9c, 0xa0, 0, 0, 0 }, |
97 | }; |
98 | |
99 | static int wpcm450_gpio_irq_bitnum(struct wpcm450_gpio *gpio, struct irq_data *d) |
100 | { |
101 | const struct wpcm450_bank *bank = gpio->bank; |
102 | int hwirq = irqd_to_hwirq(d); |
103 | |
104 | if (hwirq < bank->first_irq_gpio) |
105 | return -EINVAL; |
106 | |
107 | if (hwirq - bank->first_irq_gpio >= bank->num_irqs) |
108 | return -EINVAL; |
109 | |
110 | return hwirq - bank->first_irq_gpio + bank->first_irq_bit; |
111 | } |
112 | |
113 | static int wpcm450_irq_bitnum_to_gpio(struct wpcm450_gpio *gpio, int bitnum) |
114 | { |
115 | const struct wpcm450_bank *bank = gpio->bank; |
116 | |
117 | if (bitnum < bank->first_irq_bit) |
118 | return -EINVAL; |
119 | |
120 | if (bitnum - bank->first_irq_bit > bank->num_irqs) |
121 | return -EINVAL; |
122 | |
123 | return bitnum - bank->first_irq_bit + bank->first_irq_gpio; |
124 | } |
125 | |
126 | static void wpcm450_gpio_irq_ack(struct irq_data *d) |
127 | { |
128 | struct wpcm450_gpio *gpio = gpiochip_get_data(gc: irq_data_get_irq_chip_data(d)); |
129 | struct wpcm450_pinctrl *pctrl = gpio->pctrl; |
130 | unsigned long flags; |
131 | int bit; |
132 | |
133 | bit = wpcm450_gpio_irq_bitnum(gpio, d); |
134 | if (bit < 0) |
135 | return; |
136 | |
137 | raw_spin_lock_irqsave(&pctrl->lock, flags); |
138 | iowrite32(BIT(bit), pctrl->gpio_base + WPCM450_GPEVST); |
139 | raw_spin_unlock_irqrestore(&pctrl->lock, flags); |
140 | } |
141 | |
142 | static void wpcm450_gpio_irq_mask(struct irq_data *d) |
143 | { |
144 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
145 | struct wpcm450_gpio *gpio = gpiochip_get_data(gc); |
146 | struct wpcm450_pinctrl *pctrl = gpio->pctrl; |
147 | unsigned long flags; |
148 | unsigned long even; |
149 | int bit; |
150 | |
151 | bit = wpcm450_gpio_irq_bitnum(gpio, d); |
152 | if (bit < 0) |
153 | return; |
154 | |
155 | raw_spin_lock_irqsave(&pctrl->lock, flags); |
156 | even = ioread32(pctrl->gpio_base + WPCM450_GPEVEN); |
157 | __assign_bit(nr: bit, addr: &even, value: 0); |
158 | iowrite32(even, pctrl->gpio_base + WPCM450_GPEVEN); |
159 | raw_spin_unlock_irqrestore(&pctrl->lock, flags); |
160 | |
161 | gpiochip_disable_irq(gc, offset: irqd_to_hwirq(d)); |
162 | } |
163 | |
164 | static void wpcm450_gpio_irq_unmask(struct irq_data *d) |
165 | { |
166 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
167 | struct wpcm450_gpio *gpio = gpiochip_get_data(gc); |
168 | struct wpcm450_pinctrl *pctrl = gpio->pctrl; |
169 | unsigned long flags; |
170 | unsigned long even; |
171 | int bit; |
172 | |
173 | bit = wpcm450_gpio_irq_bitnum(gpio, d); |
174 | if (bit < 0) |
175 | return; |
176 | |
177 | gpiochip_enable_irq(gc, offset: irqd_to_hwirq(d)); |
178 | |
179 | raw_spin_lock_irqsave(&pctrl->lock, flags); |
180 | even = ioread32(pctrl->gpio_base + WPCM450_GPEVEN); |
181 | __assign_bit(nr: bit, addr: &even, value: 1); |
182 | iowrite32(even, pctrl->gpio_base + WPCM450_GPEVEN); |
183 | raw_spin_unlock_irqrestore(&pctrl->lock, flags); |
184 | } |
185 | |
186 | /* |
187 | * This is an implementation of the gpio_chip->get() function, for use in |
188 | * wpcm450_gpio_fix_evpol. Unfortunately, we can't use the bgpio-provided |
189 | * implementation there, because it would require taking gpio_chip->bgpio_lock, |
190 | * which is a spin lock, but wpcm450_gpio_fix_evpol must work in contexts where |
191 | * a raw spin lock is held. |
192 | */ |
193 | static int wpcm450_gpio_get(struct wpcm450_gpio *gpio, int offset) |
194 | { |
195 | void __iomem *reg = gpio->pctrl->gpio_base + gpio->bank->datain; |
196 | unsigned long flags; |
197 | u32 level; |
198 | |
199 | raw_spin_lock_irqsave(&gpio->pctrl->lock, flags); |
200 | level = !!(ioread32(reg) & BIT(offset)); |
201 | raw_spin_unlock_irqrestore(&gpio->pctrl->lock, flags); |
202 | |
203 | return level; |
204 | } |
205 | |
206 | /* |
207 | * Since the GPIO controller does not support dual-edge triggered interrupts |
208 | * (IRQ_TYPE_EDGE_BOTH), they are emulated using rising/falling edge triggered |
209 | * interrupts. wpcm450_gpio_fix_evpol sets the interrupt polarity for the |
210 | * specified emulated dual-edge triggered interrupts, so that the next edge can |
211 | * be detected. |
212 | */ |
213 | static void wpcm450_gpio_fix_evpol(struct wpcm450_gpio *gpio, unsigned long all) |
214 | { |
215 | struct wpcm450_pinctrl *pctrl = gpio->pctrl; |
216 | unsigned int bit; |
217 | |
218 | for_each_set_bit(bit, &all, 32) { |
219 | int offset = wpcm450_irq_bitnum_to_gpio(gpio, bitnum: bit); |
220 | unsigned long evpol; |
221 | unsigned long flags; |
222 | int level; |
223 | |
224 | do { |
225 | level = wpcm450_gpio_get(gpio, offset); |
226 | |
227 | /* Switch event polarity to the opposite of the current level */ |
228 | raw_spin_lock_irqsave(&pctrl->lock, flags); |
229 | evpol = ioread32(pctrl->gpio_base + WPCM450_GPEVPOL); |
230 | __assign_bit(nr: bit, addr: &evpol, value: !level); |
231 | iowrite32(evpol, pctrl->gpio_base + WPCM450_GPEVPOL); |
232 | raw_spin_unlock_irqrestore(&pctrl->lock, flags); |
233 | |
234 | } while (wpcm450_gpio_get(gpio, offset) != level); |
235 | } |
236 | } |
237 | |
238 | static int wpcm450_gpio_set_irq_type(struct irq_data *d, unsigned int flow_type) |
239 | { |
240 | struct wpcm450_gpio *gpio = gpiochip_get_data(gc: irq_data_get_irq_chip_data(d)); |
241 | struct wpcm450_pinctrl *pctrl = gpio->pctrl; |
242 | unsigned long evtype, evpol; |
243 | unsigned long flags; |
244 | int ret = 0; |
245 | int bit; |
246 | |
247 | bit = wpcm450_gpio_irq_bitnum(gpio, d); |
248 | if (bit < 0) |
249 | return bit; |
250 | |
251 | irq_set_handler_locked(data: d, handler: handle_level_irq); |
252 | |
253 | raw_spin_lock_irqsave(&pctrl->lock, flags); |
254 | evtype = ioread32(pctrl->gpio_base + WPCM450_GPEVTYPE); |
255 | evpol = ioread32(pctrl->gpio_base + WPCM450_GPEVPOL); |
256 | __assign_bit(nr: bit, addr: &pctrl->both_edges, value: 0); |
257 | switch (flow_type) { |
258 | case IRQ_TYPE_LEVEL_LOW: |
259 | __assign_bit(nr: bit, addr: &evtype, value: 1); |
260 | __assign_bit(nr: bit, addr: &evpol, value: 0); |
261 | break; |
262 | case IRQ_TYPE_LEVEL_HIGH: |
263 | __assign_bit(nr: bit, addr: &evtype, value: 1); |
264 | __assign_bit(nr: bit, addr: &evpol, value: 1); |
265 | break; |
266 | case IRQ_TYPE_EDGE_FALLING: |
267 | __assign_bit(nr: bit, addr: &evtype, value: 0); |
268 | __assign_bit(nr: bit, addr: &evpol, value: 0); |
269 | break; |
270 | case IRQ_TYPE_EDGE_RISING: |
271 | __assign_bit(nr: bit, addr: &evtype, value: 0); |
272 | __assign_bit(nr: bit, addr: &evpol, value: 1); |
273 | break; |
274 | case IRQ_TYPE_EDGE_BOTH: |
275 | __assign_bit(nr: bit, addr: &evtype, value: 0); |
276 | __assign_bit(nr: bit, addr: &pctrl->both_edges, value: 1); |
277 | break; |
278 | default: |
279 | ret = -EINVAL; |
280 | } |
281 | iowrite32(evtype, pctrl->gpio_base + WPCM450_GPEVTYPE); |
282 | iowrite32(evpol, pctrl->gpio_base + WPCM450_GPEVPOL); |
283 | |
284 | /* clear the event status for good measure */ |
285 | iowrite32(BIT(bit), pctrl->gpio_base + WPCM450_GPEVST); |
286 | |
287 | raw_spin_unlock_irqrestore(&pctrl->lock, flags); |
288 | |
289 | /* fix event polarity after clearing event status */ |
290 | wpcm450_gpio_fix_evpol(gpio, BIT(bit)); |
291 | |
292 | return ret; |
293 | } |
294 | |
295 | static const struct irq_chip wpcm450_gpio_irqchip = { |
296 | .name = "WPCM450-GPIO-IRQ" , |
297 | .irq_ack = wpcm450_gpio_irq_ack, |
298 | .irq_unmask = wpcm450_gpio_irq_unmask, |
299 | .irq_mask = wpcm450_gpio_irq_mask, |
300 | .irq_set_type = wpcm450_gpio_set_irq_type, |
301 | .flags = IRQCHIP_IMMUTABLE, |
302 | GPIOCHIP_IRQ_RESOURCE_HELPERS, |
303 | }; |
304 | |
305 | static void wpcm450_gpio_irqhandler(struct irq_desc *desc) |
306 | { |
307 | struct wpcm450_gpio *gpio = gpiochip_get_data(gc: irq_desc_get_handler_data(desc)); |
308 | struct wpcm450_pinctrl *pctrl = gpio->pctrl; |
309 | struct irq_chip *chip = irq_desc_get_chip(desc); |
310 | unsigned long pending; |
311 | unsigned long flags; |
312 | unsigned long ours; |
313 | unsigned int bit; |
314 | |
315 | ours = GENMASK(gpio->bank->num_irqs - 1, 0) << gpio->bank->first_irq_bit; |
316 | |
317 | raw_spin_lock_irqsave(&pctrl->lock, flags); |
318 | |
319 | pending = ioread32(pctrl->gpio_base + WPCM450_GPEVST); |
320 | pending &= ioread32(pctrl->gpio_base + WPCM450_GPEVEN); |
321 | pending &= ours; |
322 | |
323 | raw_spin_unlock_irqrestore(&pctrl->lock, flags); |
324 | |
325 | if (pending & pctrl->both_edges) |
326 | wpcm450_gpio_fix_evpol(gpio, all: pending & pctrl->both_edges); |
327 | |
328 | chained_irq_enter(chip, desc); |
329 | for_each_set_bit(bit, &pending, 32) { |
330 | int offset = wpcm450_irq_bitnum_to_gpio(gpio, bitnum: bit); |
331 | |
332 | generic_handle_domain_irq(domain: gpio->gc.irq.domain, hwirq: offset); |
333 | } |
334 | chained_irq_exit(chip, desc); |
335 | } |
336 | |
337 | static int smb0_pins[] = { 115, 114 }; |
338 | static int smb1_pins[] = { 117, 116 }; |
339 | static int smb2_pins[] = { 119, 118 }; |
340 | static int smb3_pins[] = { 30, 31 }; |
341 | static int smb4_pins[] = { 28, 29 }; |
342 | static int smb5_pins[] = { 26, 27 }; |
343 | |
344 | static int scs1_pins[] = { 32 }; |
345 | static int scs2_pins[] = { 33 }; |
346 | static int scs3_pins[] = { 34 }; |
347 | |
348 | static int bsp_pins[] = { 41, 42 }; |
349 | static int hsp1_pins[] = { 43, 44, 45, 46, 47, 61, 62, 63 }; |
350 | static int hsp2_pins[] = { 48, 49, 50, 51, 52, 53, 54, 55 }; |
351 | |
352 | static int r1err_pins[] = { 56 }; |
353 | static int r1md_pins[] = { 57, 58 }; |
354 | static int rmii2_pins[] = { 84, 85, 86, 87, 88, 89 }; |
355 | static int r2err_pins[] = { 90 }; |
356 | static int r2md_pins[] = { 91, 92 }; |
357 | |
358 | static int kbcc_pins[] = { 94, 93 }; |
359 | static int clko_pins[] = { 96 }; |
360 | static int smi_pins[] = { 97 }; |
361 | static int uinc_pins[] = { 19 }; |
362 | static int mben_pins[] = {}; |
363 | |
364 | static int gspi_pins[] = { 12, 13, 14, 15 }; |
365 | static int sspi_pins[] = { 12, 13, 14, 15 }; |
366 | |
367 | static int xcs1_pins[] = { 35 }; |
368 | static int xcs2_pins[] = { 36 }; |
369 | |
370 | static int sdio_pins[] = { 7, 22, 43, 44, 45, 46, 47, 60 }; |
371 | |
372 | static int fi0_pins[] = { 64 }; |
373 | static int fi1_pins[] = { 65 }; |
374 | static int fi2_pins[] = { 66 }; |
375 | static int fi3_pins[] = { 67 }; |
376 | static int fi4_pins[] = { 68 }; |
377 | static int fi5_pins[] = { 69 }; |
378 | static int fi6_pins[] = { 70 }; |
379 | static int fi7_pins[] = { 71 }; |
380 | static int fi8_pins[] = { 72 }; |
381 | static int fi9_pins[] = { 73 }; |
382 | static int fi10_pins[] = { 74 }; |
383 | static int fi11_pins[] = { 75 }; |
384 | static int fi12_pins[] = { 76 }; |
385 | static int fi13_pins[] = { 77 }; |
386 | static int fi14_pins[] = { 78 }; |
387 | static int fi15_pins[] = { 79 }; |
388 | |
389 | static int pwm0_pins[] = { 80 }; |
390 | static int pwm1_pins[] = { 81 }; |
391 | static int pwm2_pins[] = { 82 }; |
392 | static int pwm3_pins[] = { 83 }; |
393 | static int pwm4_pins[] = { 20 }; |
394 | static int pwm5_pins[] = { 21 }; |
395 | static int pwm6_pins[] = { 16 }; |
396 | static int pwm7_pins[] = { 17 }; |
397 | |
398 | static int hg0_pins[] = { 20 }; |
399 | static int hg1_pins[] = { 21 }; |
400 | static int hg2_pins[] = { 22 }; |
401 | static int hg3_pins[] = { 23 }; |
402 | static int hg4_pins[] = { 24 }; |
403 | static int hg5_pins[] = { 25 }; |
404 | static int hg6_pins[] = { 59 }; |
405 | static int hg7_pins[] = { 60 }; |
406 | |
407 | #define WPCM450_GRPS \ |
408 | WPCM450_GRP(smb3), \ |
409 | WPCM450_GRP(smb4), \ |
410 | WPCM450_GRP(smb5), \ |
411 | WPCM450_GRP(scs1), \ |
412 | WPCM450_GRP(scs2), \ |
413 | WPCM450_GRP(scs3), \ |
414 | WPCM450_GRP(smb0), \ |
415 | WPCM450_GRP(smb1), \ |
416 | WPCM450_GRP(smb2), \ |
417 | WPCM450_GRP(bsp), \ |
418 | WPCM450_GRP(hsp1), \ |
419 | WPCM450_GRP(hsp2), \ |
420 | WPCM450_GRP(r1err), \ |
421 | WPCM450_GRP(r1md), \ |
422 | WPCM450_GRP(rmii2), \ |
423 | WPCM450_GRP(r2err), \ |
424 | WPCM450_GRP(r2md), \ |
425 | WPCM450_GRP(kbcc), \ |
426 | WPCM450_GRP(clko), \ |
427 | WPCM450_GRP(smi), \ |
428 | WPCM450_GRP(uinc), \ |
429 | WPCM450_GRP(gspi), \ |
430 | WPCM450_GRP(mben), \ |
431 | WPCM450_GRP(xcs2), \ |
432 | WPCM450_GRP(xcs1), \ |
433 | WPCM450_GRP(sdio), \ |
434 | WPCM450_GRP(sspi), \ |
435 | WPCM450_GRP(fi0), \ |
436 | WPCM450_GRP(fi1), \ |
437 | WPCM450_GRP(fi2), \ |
438 | WPCM450_GRP(fi3), \ |
439 | WPCM450_GRP(fi4), \ |
440 | WPCM450_GRP(fi5), \ |
441 | WPCM450_GRP(fi6), \ |
442 | WPCM450_GRP(fi7), \ |
443 | WPCM450_GRP(fi8), \ |
444 | WPCM450_GRP(fi9), \ |
445 | WPCM450_GRP(fi10), \ |
446 | WPCM450_GRP(fi11), \ |
447 | WPCM450_GRP(fi12), \ |
448 | WPCM450_GRP(fi13), \ |
449 | WPCM450_GRP(fi14), \ |
450 | WPCM450_GRP(fi15), \ |
451 | WPCM450_GRP(pwm0), \ |
452 | WPCM450_GRP(pwm1), \ |
453 | WPCM450_GRP(pwm2), \ |
454 | WPCM450_GRP(pwm3), \ |
455 | WPCM450_GRP(pwm4), \ |
456 | WPCM450_GRP(pwm5), \ |
457 | WPCM450_GRP(pwm6), \ |
458 | WPCM450_GRP(pwm7), \ |
459 | WPCM450_GRP(hg0), \ |
460 | WPCM450_GRP(hg1), \ |
461 | WPCM450_GRP(hg2), \ |
462 | WPCM450_GRP(hg3), \ |
463 | WPCM450_GRP(hg4), \ |
464 | WPCM450_GRP(hg5), \ |
465 | WPCM450_GRP(hg6), \ |
466 | WPCM450_GRP(hg7), \ |
467 | |
468 | enum { |
469 | #define WPCM450_GRP(x) fn_ ## x |
470 | WPCM450_GRPS |
471 | /* add placeholder for none/gpio */ |
472 | WPCM450_GRP(gpio), |
473 | WPCM450_GRP(none), |
474 | #undef WPCM450_GRP |
475 | }; |
476 | |
477 | static const struct pingroup wpcm450_groups[] = { |
478 | #define WPCM450_GRP(x) PINCTRL_PINGROUP(#x, x ## _pins, ARRAY_SIZE(x ## _pins)) |
479 | WPCM450_GRPS |
480 | #undef WPCM450_GRP |
481 | }; |
482 | |
483 | #define WPCM450_SFUNC(a) WPCM450_FUNC(a, #a) |
484 | #define WPCM450_FUNC(a, b...) static const char *a ## _grp[] = { b } |
485 | #define WPCM450_MKFUNC(nm) { .name = #nm, .ngroups = ARRAY_SIZE(nm ## _grp), \ |
486 | .groups = nm ## _grp } |
487 | struct wpcm450_func { |
488 | const char *name; |
489 | const unsigned int ngroups; |
490 | const char *const *groups; |
491 | }; |
492 | |
493 | WPCM450_SFUNC(smb3); |
494 | WPCM450_SFUNC(smb4); |
495 | WPCM450_SFUNC(smb5); |
496 | WPCM450_SFUNC(scs1); |
497 | WPCM450_SFUNC(scs2); |
498 | WPCM450_SFUNC(scs3); |
499 | WPCM450_SFUNC(smb0); |
500 | WPCM450_SFUNC(smb1); |
501 | WPCM450_SFUNC(smb2); |
502 | WPCM450_SFUNC(bsp); |
503 | WPCM450_SFUNC(hsp1); |
504 | WPCM450_SFUNC(hsp2); |
505 | WPCM450_SFUNC(r1err); |
506 | WPCM450_SFUNC(r1md); |
507 | WPCM450_SFUNC(rmii2); |
508 | WPCM450_SFUNC(r2err); |
509 | WPCM450_SFUNC(r2md); |
510 | WPCM450_SFUNC(kbcc); |
511 | WPCM450_SFUNC(clko); |
512 | WPCM450_SFUNC(smi); |
513 | WPCM450_SFUNC(uinc); |
514 | WPCM450_SFUNC(gspi); |
515 | WPCM450_SFUNC(mben); |
516 | WPCM450_SFUNC(xcs2); |
517 | WPCM450_SFUNC(xcs1); |
518 | WPCM450_SFUNC(sdio); |
519 | WPCM450_SFUNC(sspi); |
520 | WPCM450_SFUNC(fi0); |
521 | WPCM450_SFUNC(fi1); |
522 | WPCM450_SFUNC(fi2); |
523 | WPCM450_SFUNC(fi3); |
524 | WPCM450_SFUNC(fi4); |
525 | WPCM450_SFUNC(fi5); |
526 | WPCM450_SFUNC(fi6); |
527 | WPCM450_SFUNC(fi7); |
528 | WPCM450_SFUNC(fi8); |
529 | WPCM450_SFUNC(fi9); |
530 | WPCM450_SFUNC(fi10); |
531 | WPCM450_SFUNC(fi11); |
532 | WPCM450_SFUNC(fi12); |
533 | WPCM450_SFUNC(fi13); |
534 | WPCM450_SFUNC(fi14); |
535 | WPCM450_SFUNC(fi15); |
536 | WPCM450_SFUNC(pwm0); |
537 | WPCM450_SFUNC(pwm1); |
538 | WPCM450_SFUNC(pwm2); |
539 | WPCM450_SFUNC(pwm3); |
540 | WPCM450_SFUNC(pwm4); |
541 | WPCM450_SFUNC(pwm5); |
542 | WPCM450_SFUNC(pwm6); |
543 | WPCM450_SFUNC(pwm7); |
544 | WPCM450_SFUNC(hg0); |
545 | WPCM450_SFUNC(hg1); |
546 | WPCM450_SFUNC(hg2); |
547 | WPCM450_SFUNC(hg3); |
548 | WPCM450_SFUNC(hg4); |
549 | WPCM450_SFUNC(hg5); |
550 | WPCM450_SFUNC(hg6); |
551 | WPCM450_SFUNC(hg7); |
552 | |
553 | #define WPCM450_GRP(x) #x |
554 | WPCM450_FUNC(gpio, WPCM450_GRPS); |
555 | #undef WPCM450_GRP |
556 | |
557 | /* Function names */ |
558 | static struct wpcm450_func wpcm450_funcs[] = { |
559 | WPCM450_MKFUNC(smb3), |
560 | WPCM450_MKFUNC(smb4), |
561 | WPCM450_MKFUNC(smb5), |
562 | WPCM450_MKFUNC(scs1), |
563 | WPCM450_MKFUNC(scs2), |
564 | WPCM450_MKFUNC(scs3), |
565 | WPCM450_MKFUNC(smb0), |
566 | WPCM450_MKFUNC(smb1), |
567 | WPCM450_MKFUNC(smb2), |
568 | WPCM450_MKFUNC(bsp), |
569 | WPCM450_MKFUNC(hsp1), |
570 | WPCM450_MKFUNC(hsp2), |
571 | WPCM450_MKFUNC(r1err), |
572 | WPCM450_MKFUNC(r1md), |
573 | WPCM450_MKFUNC(rmii2), |
574 | WPCM450_MKFUNC(r2err), |
575 | WPCM450_MKFUNC(r2md), |
576 | WPCM450_MKFUNC(kbcc), |
577 | WPCM450_MKFUNC(clko), |
578 | WPCM450_MKFUNC(smi), |
579 | WPCM450_MKFUNC(uinc), |
580 | WPCM450_MKFUNC(gspi), |
581 | WPCM450_MKFUNC(mben), |
582 | WPCM450_MKFUNC(xcs2), |
583 | WPCM450_MKFUNC(xcs1), |
584 | WPCM450_MKFUNC(sdio), |
585 | WPCM450_MKFUNC(sspi), |
586 | WPCM450_MKFUNC(fi0), |
587 | WPCM450_MKFUNC(fi1), |
588 | WPCM450_MKFUNC(fi2), |
589 | WPCM450_MKFUNC(fi3), |
590 | WPCM450_MKFUNC(fi4), |
591 | WPCM450_MKFUNC(fi5), |
592 | WPCM450_MKFUNC(fi6), |
593 | WPCM450_MKFUNC(fi7), |
594 | WPCM450_MKFUNC(fi8), |
595 | WPCM450_MKFUNC(fi9), |
596 | WPCM450_MKFUNC(fi10), |
597 | WPCM450_MKFUNC(fi11), |
598 | WPCM450_MKFUNC(fi12), |
599 | WPCM450_MKFUNC(fi13), |
600 | WPCM450_MKFUNC(fi14), |
601 | WPCM450_MKFUNC(fi15), |
602 | WPCM450_MKFUNC(pwm0), |
603 | WPCM450_MKFUNC(pwm1), |
604 | WPCM450_MKFUNC(pwm2), |
605 | WPCM450_MKFUNC(pwm3), |
606 | WPCM450_MKFUNC(pwm4), |
607 | WPCM450_MKFUNC(pwm5), |
608 | WPCM450_MKFUNC(pwm6), |
609 | WPCM450_MKFUNC(pwm7), |
610 | WPCM450_MKFUNC(hg0), |
611 | WPCM450_MKFUNC(hg1), |
612 | WPCM450_MKFUNC(hg2), |
613 | WPCM450_MKFUNC(hg3), |
614 | WPCM450_MKFUNC(hg4), |
615 | WPCM450_MKFUNC(hg5), |
616 | WPCM450_MKFUNC(hg6), |
617 | WPCM450_MKFUNC(hg7), |
618 | WPCM450_MKFUNC(gpio), |
619 | }; |
620 | |
621 | #define WPCM450_PINCFG(a, b, c, d, e, f, g) \ |
622 | [a] = { .fn0 = fn_ ## b, .reg0 = WPCM450_GCR_ ## c, .bit0 = d, \ |
623 | .fn1 = fn_ ## e, .reg1 = WPCM450_GCR_ ## f, .bit1 = g } |
624 | |
625 | struct wpcm450_pincfg { |
626 | int fn0, reg0, bit0; |
627 | int fn1, reg1, bit1; |
628 | }; |
629 | |
630 | /* Add this value to bit0 or bit1 to indicate that the MFSEL bit is inverted */ |
631 | #define INV BIT(5) |
632 | |
633 | static const struct wpcm450_pincfg pincfg[] = { |
634 | /* PIN FUNCTION 1 FUNCTION 2 */ |
635 | WPCM450_PINCFG(0, none, NONE, 0, none, NONE, 0), |
636 | WPCM450_PINCFG(1, none, NONE, 0, none, NONE, 0), |
637 | WPCM450_PINCFG(2, none, NONE, 0, none, NONE, 0), |
638 | WPCM450_PINCFG(3, none, NONE, 0, none, NONE, 0), |
639 | WPCM450_PINCFG(4, none, NONE, 0, none, NONE, 0), |
640 | WPCM450_PINCFG(5, none, NONE, 0, none, NONE, 0), |
641 | WPCM450_PINCFG(6, none, NONE, 0, none, NONE, 0), |
642 | WPCM450_PINCFG(7, none, NONE, 0, sdio, MFSEL1, 30), |
643 | WPCM450_PINCFG(8, none, NONE, 0, none, NONE, 0), |
644 | WPCM450_PINCFG(9, none, NONE, 0, none, NONE, 0), |
645 | WPCM450_PINCFG(10, none, NONE, 0, none, NONE, 0), |
646 | WPCM450_PINCFG(11, none, NONE, 0, none, NONE, 0), |
647 | WPCM450_PINCFG(12, gspi, MFSEL1, 24, sspi, MFSEL1, 31), |
648 | WPCM450_PINCFG(13, gspi, MFSEL1, 24, sspi, MFSEL1, 31), |
649 | WPCM450_PINCFG(14, gspi, MFSEL1, 24, sspi, MFSEL1, 31), |
650 | WPCM450_PINCFG(15, gspi, MFSEL1, 24, sspi, MFSEL1, 31), |
651 | WPCM450_PINCFG(16, none, NONE, 0, pwm6, MFSEL2, 22), |
652 | WPCM450_PINCFG(17, none, NONE, 0, pwm7, MFSEL2, 23), |
653 | WPCM450_PINCFG(18, none, NONE, 0, none, NONE, 0), |
654 | WPCM450_PINCFG(19, uinc, MFSEL1, 23, none, NONE, 0), |
655 | WPCM450_PINCFG(20, hg0, MFSEL2, 24, pwm4, MFSEL2, 20), |
656 | WPCM450_PINCFG(21, hg1, MFSEL2, 25, pwm5, MFSEL2, 21), |
657 | WPCM450_PINCFG(22, hg2, MFSEL2, 26, none, NONE, 0), |
658 | WPCM450_PINCFG(23, hg3, MFSEL2, 27, none, NONE, 0), |
659 | WPCM450_PINCFG(24, hg4, MFSEL2, 28, none, NONE, 0), |
660 | WPCM450_PINCFG(25, hg5, MFSEL2, 29, none, NONE, 0), |
661 | WPCM450_PINCFG(26, smb5, MFSEL1, 2, none, NONE, 0), |
662 | WPCM450_PINCFG(27, smb5, MFSEL1, 2, none, NONE, 0), |
663 | WPCM450_PINCFG(28, smb4, MFSEL1, 1, none, NONE, 0), |
664 | WPCM450_PINCFG(29, smb4, MFSEL1, 1, none, NONE, 0), |
665 | WPCM450_PINCFG(30, smb3, MFSEL1, 0, none, NONE, 0), |
666 | WPCM450_PINCFG(31, smb3, MFSEL1, 0, none, NONE, 0), |
667 | |
668 | WPCM450_PINCFG(32, scs1, MFSEL1, 3, none, NONE, 0), |
669 | WPCM450_PINCFG(33, scs2, MFSEL1, 4, none, NONE, 0), |
670 | WPCM450_PINCFG(34, scs3, MFSEL1, 5 | INV, none, NONE, 0), |
671 | WPCM450_PINCFG(35, xcs1, MFSEL1, 29, none, NONE, 0), |
672 | WPCM450_PINCFG(36, xcs2, MFSEL1, 28, none, NONE, 0), |
673 | WPCM450_PINCFG(37, none, NONE, 0, none, NONE, 0), /* DVO */ |
674 | WPCM450_PINCFG(38, none, NONE, 0, none, NONE, 0), /* DVO */ |
675 | WPCM450_PINCFG(39, none, NONE, 0, none, NONE, 0), /* DVO */ |
676 | WPCM450_PINCFG(40, none, NONE, 0, none, NONE, 0), /* DVO */ |
677 | WPCM450_PINCFG(41, bsp, MFSEL1, 9, none, NONE, 0), |
678 | WPCM450_PINCFG(42, bsp, MFSEL1, 9, none, NONE, 0), |
679 | WPCM450_PINCFG(43, hsp1, MFSEL1, 10, sdio, MFSEL1, 30), |
680 | WPCM450_PINCFG(44, hsp1, MFSEL1, 10, sdio, MFSEL1, 30), |
681 | WPCM450_PINCFG(45, hsp1, MFSEL1, 10, sdio, MFSEL1, 30), |
682 | WPCM450_PINCFG(46, hsp1, MFSEL1, 10, sdio, MFSEL1, 30), |
683 | WPCM450_PINCFG(47, hsp1, MFSEL1, 10, sdio, MFSEL1, 30), |
684 | WPCM450_PINCFG(48, hsp2, MFSEL1, 11, none, NONE, 0), |
685 | WPCM450_PINCFG(49, hsp2, MFSEL1, 11, none, NONE, 0), |
686 | WPCM450_PINCFG(50, hsp2, MFSEL1, 11, none, NONE, 0), |
687 | WPCM450_PINCFG(51, hsp2, MFSEL1, 11, none, NONE, 0), |
688 | WPCM450_PINCFG(52, hsp2, MFSEL1, 11, none, NONE, 0), |
689 | WPCM450_PINCFG(53, hsp2, MFSEL1, 11, none, NONE, 0), |
690 | WPCM450_PINCFG(54, hsp2, MFSEL1, 11, none, NONE, 0), |
691 | WPCM450_PINCFG(55, hsp2, MFSEL1, 11, none, NONE, 0), |
692 | WPCM450_PINCFG(56, r1err, MFSEL1, 12, none, NONE, 0), |
693 | WPCM450_PINCFG(57, r1md, MFSEL1, 13, none, NONE, 0), |
694 | WPCM450_PINCFG(58, r1md, MFSEL1, 13, none, NONE, 0), |
695 | WPCM450_PINCFG(59, hg6, MFSEL2, 30, none, NONE, 0), |
696 | WPCM450_PINCFG(60, hg7, MFSEL2, 31, sdio, MFSEL1, 30), |
697 | WPCM450_PINCFG(61, hsp1, MFSEL1, 10, none, NONE, 0), |
698 | WPCM450_PINCFG(62, hsp1, MFSEL1, 10, none, NONE, 0), |
699 | WPCM450_PINCFG(63, hsp1, MFSEL1, 10, none, NONE, 0), |
700 | |
701 | WPCM450_PINCFG(64, fi0, MFSEL2, 0, none, NONE, 0), |
702 | WPCM450_PINCFG(65, fi1, MFSEL2, 1, none, NONE, 0), |
703 | WPCM450_PINCFG(66, fi2, MFSEL2, 2, none, NONE, 0), |
704 | WPCM450_PINCFG(67, fi3, MFSEL2, 3, none, NONE, 0), |
705 | WPCM450_PINCFG(68, fi4, MFSEL2, 4, none, NONE, 0), |
706 | WPCM450_PINCFG(69, fi5, MFSEL2, 5, none, NONE, 0), |
707 | WPCM450_PINCFG(70, fi6, MFSEL2, 6, none, NONE, 0), |
708 | WPCM450_PINCFG(71, fi7, MFSEL2, 7, none, NONE, 0), |
709 | WPCM450_PINCFG(72, fi8, MFSEL2, 8, none, NONE, 0), |
710 | WPCM450_PINCFG(73, fi9, MFSEL2, 9, none, NONE, 0), |
711 | WPCM450_PINCFG(74, fi10, MFSEL2, 10, none, NONE, 0), |
712 | WPCM450_PINCFG(75, fi11, MFSEL2, 11, none, NONE, 0), |
713 | WPCM450_PINCFG(76, fi12, MFSEL2, 12, none, NONE, 0), |
714 | WPCM450_PINCFG(77, fi13, MFSEL2, 13, none, NONE, 0), |
715 | WPCM450_PINCFG(78, fi14, MFSEL2, 14, none, NONE, 0), |
716 | WPCM450_PINCFG(79, fi15, MFSEL2, 15, none, NONE, 0), |
717 | WPCM450_PINCFG(80, pwm0, MFSEL2, 16, none, NONE, 0), |
718 | WPCM450_PINCFG(81, pwm1, MFSEL2, 17, none, NONE, 0), |
719 | WPCM450_PINCFG(82, pwm2, MFSEL2, 18, none, NONE, 0), |
720 | WPCM450_PINCFG(83, pwm3, MFSEL2, 19, none, NONE, 0), |
721 | WPCM450_PINCFG(84, rmii2, MFSEL1, 14, none, NONE, 0), |
722 | WPCM450_PINCFG(85, rmii2, MFSEL1, 14, none, NONE, 0), |
723 | WPCM450_PINCFG(86, rmii2, MFSEL1, 14, none, NONE, 0), |
724 | WPCM450_PINCFG(87, rmii2, MFSEL1, 14, none, NONE, 0), |
725 | WPCM450_PINCFG(88, rmii2, MFSEL1, 14, none, NONE, 0), |
726 | WPCM450_PINCFG(89, rmii2, MFSEL1, 14, none, NONE, 0), |
727 | WPCM450_PINCFG(90, r2err, MFSEL1, 15, none, NONE, 0), |
728 | WPCM450_PINCFG(91, r2md, MFSEL1, 16, none, NONE, 0), |
729 | WPCM450_PINCFG(92, r2md, MFSEL1, 16, none, NONE, 0), |
730 | WPCM450_PINCFG(93, kbcc, MFSEL1, 17 | INV, none, NONE, 0), |
731 | WPCM450_PINCFG(94, kbcc, MFSEL1, 17 | INV, none, NONE, 0), |
732 | WPCM450_PINCFG(95, none, NONE, 0, none, NONE, 0), |
733 | |
734 | WPCM450_PINCFG(96, none, NONE, 0, none, NONE, 0), |
735 | WPCM450_PINCFG(97, none, NONE, 0, none, NONE, 0), |
736 | WPCM450_PINCFG(98, none, NONE, 0, none, NONE, 0), |
737 | WPCM450_PINCFG(99, none, NONE, 0, none, NONE, 0), |
738 | WPCM450_PINCFG(100, none, NONE, 0, none, NONE, 0), |
739 | WPCM450_PINCFG(101, none, NONE, 0, none, NONE, 0), |
740 | WPCM450_PINCFG(102, none, NONE, 0, none, NONE, 0), |
741 | WPCM450_PINCFG(103, none, NONE, 0, none, NONE, 0), |
742 | WPCM450_PINCFG(104, none, NONE, 0, none, NONE, 0), |
743 | WPCM450_PINCFG(105, none, NONE, 0, none, NONE, 0), |
744 | WPCM450_PINCFG(106, none, NONE, 0, none, NONE, 0), |
745 | WPCM450_PINCFG(107, none, NONE, 0, none, NONE, 0), |
746 | WPCM450_PINCFG(108, none, NONE, 0, none, NONE, 0), /* DVO */ |
747 | WPCM450_PINCFG(109, none, NONE, 0, none, NONE, 0), /* DVO */ |
748 | WPCM450_PINCFG(110, none, NONE, 0, none, NONE, 0), /* DVO */ |
749 | WPCM450_PINCFG(111, none, NONE, 0, none, NONE, 0), /* DVO */ |
750 | WPCM450_PINCFG(112, none, NONE, 0, none, NONE, 0), /* DVO */ |
751 | WPCM450_PINCFG(113, none, NONE, 0, none, NONE, 0), /* DVO */ |
752 | WPCM450_PINCFG(114, smb0, MFSEL1, 6, none, NONE, 0), |
753 | WPCM450_PINCFG(115, smb0, MFSEL1, 6, none, NONE, 0), |
754 | WPCM450_PINCFG(116, smb1, MFSEL1, 7, none, NONE, 0), |
755 | WPCM450_PINCFG(117, smb1, MFSEL1, 7, none, NONE, 0), |
756 | WPCM450_PINCFG(118, smb2, MFSEL1, 8, none, NONE, 0), |
757 | WPCM450_PINCFG(119, smb2, MFSEL1, 8, none, NONE, 0), |
758 | WPCM450_PINCFG(120, none, NONE, 0, none, NONE, 0), /* DVO */ |
759 | WPCM450_PINCFG(121, none, NONE, 0, none, NONE, 0), /* DVO */ |
760 | WPCM450_PINCFG(122, none, NONE, 0, none, NONE, 0), /* DVO */ |
761 | WPCM450_PINCFG(123, none, NONE, 0, none, NONE, 0), /* DVO */ |
762 | WPCM450_PINCFG(124, none, NONE, 0, none, NONE, 0), /* DVO */ |
763 | WPCM450_PINCFG(125, none, NONE, 0, none, NONE, 0), /* DVO */ |
764 | WPCM450_PINCFG(126, none, NONE, 0, none, NONE, 0), /* DVO */ |
765 | WPCM450_PINCFG(127, none, NONE, 0, none, NONE, 0), /* DVO */ |
766 | }; |
767 | |
768 | #define WPCM450_PIN(n) PINCTRL_PIN(n, "gpio" #n) |
769 | |
770 | static const struct pinctrl_pin_desc wpcm450_pins[] = { |
771 | WPCM450_PIN(0), WPCM450_PIN(1), WPCM450_PIN(2), WPCM450_PIN(3), |
772 | WPCM450_PIN(4), WPCM450_PIN(5), WPCM450_PIN(6), WPCM450_PIN(7), |
773 | WPCM450_PIN(8), WPCM450_PIN(9), WPCM450_PIN(10), WPCM450_PIN(11), |
774 | WPCM450_PIN(12), WPCM450_PIN(13), WPCM450_PIN(14), WPCM450_PIN(15), |
775 | WPCM450_PIN(16), WPCM450_PIN(17), WPCM450_PIN(18), WPCM450_PIN(19), |
776 | WPCM450_PIN(20), WPCM450_PIN(21), WPCM450_PIN(22), WPCM450_PIN(23), |
777 | WPCM450_PIN(24), WPCM450_PIN(25), WPCM450_PIN(26), WPCM450_PIN(27), |
778 | WPCM450_PIN(28), WPCM450_PIN(29), WPCM450_PIN(30), WPCM450_PIN(31), |
779 | WPCM450_PIN(32), WPCM450_PIN(33), WPCM450_PIN(34), WPCM450_PIN(35), |
780 | WPCM450_PIN(36), WPCM450_PIN(37), WPCM450_PIN(38), WPCM450_PIN(39), |
781 | WPCM450_PIN(40), WPCM450_PIN(41), WPCM450_PIN(42), WPCM450_PIN(43), |
782 | WPCM450_PIN(44), WPCM450_PIN(45), WPCM450_PIN(46), WPCM450_PIN(47), |
783 | WPCM450_PIN(48), WPCM450_PIN(49), WPCM450_PIN(50), WPCM450_PIN(51), |
784 | WPCM450_PIN(52), WPCM450_PIN(53), WPCM450_PIN(54), WPCM450_PIN(55), |
785 | WPCM450_PIN(56), WPCM450_PIN(57), WPCM450_PIN(58), WPCM450_PIN(59), |
786 | WPCM450_PIN(60), WPCM450_PIN(61), WPCM450_PIN(62), WPCM450_PIN(63), |
787 | WPCM450_PIN(64), WPCM450_PIN(65), WPCM450_PIN(66), WPCM450_PIN(67), |
788 | WPCM450_PIN(68), WPCM450_PIN(69), WPCM450_PIN(70), WPCM450_PIN(71), |
789 | WPCM450_PIN(72), WPCM450_PIN(73), WPCM450_PIN(74), WPCM450_PIN(75), |
790 | WPCM450_PIN(76), WPCM450_PIN(77), WPCM450_PIN(78), WPCM450_PIN(79), |
791 | WPCM450_PIN(80), WPCM450_PIN(81), WPCM450_PIN(82), WPCM450_PIN(83), |
792 | WPCM450_PIN(84), WPCM450_PIN(85), WPCM450_PIN(86), WPCM450_PIN(87), |
793 | WPCM450_PIN(88), WPCM450_PIN(89), WPCM450_PIN(90), WPCM450_PIN(91), |
794 | WPCM450_PIN(92), WPCM450_PIN(93), WPCM450_PIN(94), WPCM450_PIN(95), |
795 | WPCM450_PIN(96), WPCM450_PIN(97), WPCM450_PIN(98), WPCM450_PIN(99), |
796 | WPCM450_PIN(100), WPCM450_PIN(101), WPCM450_PIN(102), WPCM450_PIN(103), |
797 | WPCM450_PIN(104), WPCM450_PIN(105), WPCM450_PIN(106), WPCM450_PIN(107), |
798 | WPCM450_PIN(108), WPCM450_PIN(109), WPCM450_PIN(110), WPCM450_PIN(111), |
799 | WPCM450_PIN(112), WPCM450_PIN(113), WPCM450_PIN(114), WPCM450_PIN(115), |
800 | WPCM450_PIN(116), WPCM450_PIN(117), WPCM450_PIN(118), WPCM450_PIN(119), |
801 | WPCM450_PIN(120), WPCM450_PIN(121), WPCM450_PIN(122), WPCM450_PIN(123), |
802 | WPCM450_PIN(124), WPCM450_PIN(125), WPCM450_PIN(126), WPCM450_PIN(127), |
803 | }; |
804 | |
805 | /* Helper function to update MFSEL field according to the selected function */ |
806 | static void wpcm450_update_mfsel(struct regmap *gcr_regmap, int reg, int bit, int fn, int fn_selected) |
807 | { |
808 | bool value = (fn == fn_selected); |
809 | |
810 | if (bit & INV) { |
811 | value = !value; |
812 | bit &= ~INV; |
813 | } |
814 | |
815 | regmap_update_bits(map: gcr_regmap, reg, BIT(bit), val: value ? BIT(bit) : 0); |
816 | } |
817 | |
818 | /* Enable mode in pin group */ |
819 | static void wpcm450_setfunc(struct regmap *gcr_regmap, const unsigned int *pin, |
820 | int npins, int func) |
821 | { |
822 | const struct wpcm450_pincfg *cfg; |
823 | int i; |
824 | |
825 | for (i = 0; i < npins; i++) { |
826 | cfg = &pincfg[pin[i]]; |
827 | if (func == fn_gpio || cfg->fn0 == func || cfg->fn1 == func) { |
828 | if (cfg->reg0) |
829 | wpcm450_update_mfsel(gcr_regmap, reg: cfg->reg0, |
830 | bit: cfg->bit0, fn: cfg->fn0, fn_selected: func); |
831 | if (cfg->reg1) |
832 | wpcm450_update_mfsel(gcr_regmap, reg: cfg->reg1, |
833 | bit: cfg->bit1, fn: cfg->fn1, fn_selected: func); |
834 | } |
835 | } |
836 | } |
837 | |
838 | static int wpcm450_get_groups_count(struct pinctrl_dev *pctldev) |
839 | { |
840 | return ARRAY_SIZE(wpcm450_groups); |
841 | } |
842 | |
843 | static const char *wpcm450_get_group_name(struct pinctrl_dev *pctldev, |
844 | unsigned int selector) |
845 | { |
846 | return wpcm450_groups[selector].name; |
847 | } |
848 | |
849 | static int wpcm450_get_group_pins(struct pinctrl_dev *pctldev, |
850 | unsigned int selector, |
851 | const unsigned int **pins, |
852 | unsigned int *npins) |
853 | { |
854 | *npins = wpcm450_groups[selector].npins; |
855 | *pins = wpcm450_groups[selector].pins; |
856 | |
857 | return 0; |
858 | } |
859 | |
860 | static void wpcm450_dt_free_map(struct pinctrl_dev *pctldev, |
861 | struct pinctrl_map *map, u32 num_maps) |
862 | { |
863 | kfree(objp: map); |
864 | } |
865 | |
866 | static const struct pinctrl_ops wpcm450_pinctrl_ops = { |
867 | .get_groups_count = wpcm450_get_groups_count, |
868 | .get_group_name = wpcm450_get_group_name, |
869 | .get_group_pins = wpcm450_get_group_pins, |
870 | .dt_node_to_map = pinconf_generic_dt_node_to_map_all, |
871 | .dt_free_map = wpcm450_dt_free_map, |
872 | }; |
873 | |
874 | static int wpcm450_get_functions_count(struct pinctrl_dev *pctldev) |
875 | { |
876 | return ARRAY_SIZE(wpcm450_funcs); |
877 | } |
878 | |
879 | static const char *wpcm450_get_function_name(struct pinctrl_dev *pctldev, |
880 | unsigned int function) |
881 | { |
882 | return wpcm450_funcs[function].name; |
883 | } |
884 | |
885 | static int wpcm450_get_function_groups(struct pinctrl_dev *pctldev, |
886 | unsigned int function, |
887 | const char * const **groups, |
888 | unsigned int * const ngroups) |
889 | { |
890 | *ngroups = wpcm450_funcs[function].ngroups; |
891 | *groups = wpcm450_funcs[function].groups; |
892 | |
893 | return 0; |
894 | } |
895 | |
896 | static int wpcm450_pinmux_set_mux(struct pinctrl_dev *pctldev, |
897 | unsigned int function, |
898 | unsigned int group) |
899 | { |
900 | struct wpcm450_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); |
901 | |
902 | wpcm450_setfunc(gcr_regmap: pctrl->gcr_regmap, pin: wpcm450_groups[group].pins, |
903 | npins: wpcm450_groups[group].npins, func: function); |
904 | |
905 | return 0; |
906 | } |
907 | |
908 | static const struct pinmux_ops wpcm450_pinmux_ops = { |
909 | .get_functions_count = wpcm450_get_functions_count, |
910 | .get_function_name = wpcm450_get_function_name, |
911 | .get_function_groups = wpcm450_get_function_groups, |
912 | .set_mux = wpcm450_pinmux_set_mux, |
913 | }; |
914 | |
915 | static int debounce_bitnum(int gpio) |
916 | { |
917 | if (gpio >= 0 && gpio < 16) |
918 | return gpio; |
919 | return -EINVAL; |
920 | } |
921 | |
922 | static int wpcm450_config_get(struct pinctrl_dev *pctldev, unsigned int pin, |
923 | unsigned long *config) |
924 | { |
925 | struct wpcm450_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); |
926 | enum pin_config_param param = pinconf_to_config_param(config: *config); |
927 | unsigned long flags; |
928 | int bit; |
929 | u32 reg; |
930 | |
931 | switch (param) { |
932 | case PIN_CONFIG_INPUT_DEBOUNCE: |
933 | bit = debounce_bitnum(gpio: pin); |
934 | if (bit < 0) |
935 | return bit; |
936 | |
937 | raw_spin_lock_irqsave(&pctrl->lock, flags); |
938 | reg = ioread32(pctrl->gpio_base + WPCM450_GPEVDBNC); |
939 | raw_spin_unlock_irqrestore(&pctrl->lock, flags); |
940 | |
941 | *config = pinconf_to_config_packed(param, argument: !!(reg & BIT(bit))); |
942 | return 0; |
943 | default: |
944 | return -ENOTSUPP; |
945 | } |
946 | } |
947 | |
948 | static int wpcm450_config_set_one(struct wpcm450_pinctrl *pctrl, |
949 | unsigned int pin, unsigned long config) |
950 | { |
951 | enum pin_config_param param = pinconf_to_config_param(config); |
952 | unsigned long flags; |
953 | unsigned long reg; |
954 | int bit; |
955 | int arg; |
956 | |
957 | switch (param) { |
958 | case PIN_CONFIG_INPUT_DEBOUNCE: |
959 | bit = debounce_bitnum(gpio: pin); |
960 | if (bit < 0) |
961 | return bit; |
962 | |
963 | arg = pinconf_to_config_argument(config); |
964 | |
965 | raw_spin_lock_irqsave(&pctrl->lock, flags); |
966 | reg = ioread32(pctrl->gpio_base + WPCM450_GPEVDBNC); |
967 | __assign_bit(nr: bit, addr: ®, value: arg); |
968 | iowrite32(reg, pctrl->gpio_base + WPCM450_GPEVDBNC); |
969 | raw_spin_unlock_irqrestore(&pctrl->lock, flags); |
970 | return 0; |
971 | default: |
972 | return -ENOTSUPP; |
973 | } |
974 | } |
975 | |
976 | static int wpcm450_config_set(struct pinctrl_dev *pctldev, unsigned int pin, |
977 | unsigned long *configs, unsigned int num_configs) |
978 | { |
979 | struct wpcm450_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); |
980 | int ret; |
981 | |
982 | while (num_configs--) { |
983 | ret = wpcm450_config_set_one(pctrl, pin, config: *configs++); |
984 | if (ret) |
985 | return ret; |
986 | } |
987 | |
988 | return 0; |
989 | } |
990 | |
991 | static const struct pinconf_ops wpcm450_pinconf_ops = { |
992 | .is_generic = true, |
993 | .pin_config_get = wpcm450_config_get, |
994 | .pin_config_set = wpcm450_config_set, |
995 | }; |
996 | |
997 | static struct pinctrl_desc wpcm450_pinctrl_desc = { |
998 | .name = "wpcm450-pinctrl" , |
999 | .pins = wpcm450_pins, |
1000 | .npins = ARRAY_SIZE(wpcm450_pins), |
1001 | .pctlops = &wpcm450_pinctrl_ops, |
1002 | .pmxops = &wpcm450_pinmux_ops, |
1003 | .confops = &wpcm450_pinconf_ops, |
1004 | .owner = THIS_MODULE, |
1005 | }; |
1006 | |
1007 | static int wpcm450_gpio_set_config(struct gpio_chip *chip, |
1008 | unsigned int offset, unsigned long config) |
1009 | { |
1010 | struct wpcm450_gpio *gpio = gpiochip_get_data(gc: chip); |
1011 | |
1012 | return wpcm450_config_set_one(pctrl: gpio->pctrl, pin: offset, config); |
1013 | } |
1014 | |
1015 | static int wpcm450_gpio_add_pin_ranges(struct gpio_chip *chip) |
1016 | { |
1017 | struct wpcm450_gpio *gpio = gpiochip_get_data(gc: chip); |
1018 | const struct wpcm450_bank *bank = gpio->bank; |
1019 | |
1020 | return gpiochip_add_pin_range(gc: &gpio->gc, pinctl_name: dev_name(dev: gpio->pctrl->dev), |
1021 | gpio_offset: 0, pin_offset: bank->base, npins: bank->length); |
1022 | } |
1023 | |
1024 | static int wpcm450_gpio_register(struct platform_device *pdev, |
1025 | struct wpcm450_pinctrl *pctrl) |
1026 | { |
1027 | struct device *dev = &pdev->dev; |
1028 | struct fwnode_handle *child; |
1029 | int ret; |
1030 | |
1031 | pctrl->gpio_base = devm_platform_ioremap_resource(pdev, index: 0); |
1032 | if (IS_ERR(ptr: pctrl->gpio_base)) |
1033 | return dev_err_probe(dev, err: PTR_ERR(ptr: pctrl->gpio_base), |
1034 | fmt: "Resource fail for GPIO controller\n" ); |
1035 | |
1036 | device_for_each_child_node(dev, child) { |
1037 | void __iomem *dat = NULL; |
1038 | void __iomem *set = NULL; |
1039 | void __iomem *dirout = NULL; |
1040 | unsigned long flags = 0; |
1041 | const struct wpcm450_bank *bank; |
1042 | struct wpcm450_gpio *gpio; |
1043 | struct gpio_irq_chip *girq; |
1044 | u32 reg; |
1045 | int i; |
1046 | |
1047 | if (!fwnode_property_read_bool(fwnode: child, propname: "gpio-controller" )) |
1048 | continue; |
1049 | |
1050 | ret = fwnode_property_read_u32(fwnode: child, propname: "reg" , val: ®); |
1051 | if (ret < 0) |
1052 | return ret; |
1053 | |
1054 | if (reg >= WPCM450_NUM_BANKS) |
1055 | return dev_err_probe(dev, err: -EINVAL, |
1056 | fmt: "GPIO index %d out of range!\n" , reg); |
1057 | |
1058 | gpio = &pctrl->gpio_bank[reg]; |
1059 | gpio->pctrl = pctrl; |
1060 | |
1061 | bank = &wpcm450_banks[reg]; |
1062 | gpio->bank = bank; |
1063 | |
1064 | dat = pctrl->gpio_base + bank->datain; |
1065 | if (bank->dataout) { |
1066 | set = pctrl->gpio_base + bank->dataout; |
1067 | dirout = pctrl->gpio_base + bank->cfg0; |
1068 | } else { |
1069 | flags = BGPIOF_NO_OUTPUT; |
1070 | } |
1071 | ret = bgpio_init(gc: &gpio->gc, dev, sz: 4, |
1072 | dat, set, NULL, dirout, NULL, flags); |
1073 | if (ret < 0) |
1074 | return dev_err_probe(dev, err: ret, fmt: "GPIO initialization failed\n" ); |
1075 | |
1076 | gpio->gc.ngpio = bank->length; |
1077 | gpio->gc.set_config = wpcm450_gpio_set_config; |
1078 | gpio->gc.fwnode = child; |
1079 | gpio->gc.add_pin_ranges = wpcm450_gpio_add_pin_ranges; |
1080 | |
1081 | girq = &gpio->gc.irq; |
1082 | gpio_irq_chip_set_chip(girq, chip: &wpcm450_gpio_irqchip); |
1083 | girq->parent_handler = wpcm450_gpio_irqhandler; |
1084 | girq->parents = devm_kcalloc(dev, WPCM450_NUM_GPIO_IRQS, |
1085 | size: sizeof(*girq->parents), GFP_KERNEL); |
1086 | if (!girq->parents) |
1087 | return -ENOMEM; |
1088 | girq->default_type = IRQ_TYPE_NONE; |
1089 | girq->handler = handle_bad_irq; |
1090 | |
1091 | girq->num_parents = 0; |
1092 | for (i = 0; i < WPCM450_NUM_GPIO_IRQS; i++) { |
1093 | int irq; |
1094 | |
1095 | irq = fwnode_irq_get(fwnode: child, index: i); |
1096 | if (irq < 0) |
1097 | break; |
1098 | if (!irq) |
1099 | continue; |
1100 | |
1101 | girq->parents[i] = irq; |
1102 | girq->num_parents++; |
1103 | } |
1104 | |
1105 | ret = devm_gpiochip_add_data(dev, &gpio->gc, gpio); |
1106 | if (ret) |
1107 | return dev_err_probe(dev, err: ret, fmt: "Failed to add GPIO chip\n" ); |
1108 | } |
1109 | |
1110 | return 0; |
1111 | } |
1112 | |
1113 | static int wpcm450_pinctrl_probe(struct platform_device *pdev) |
1114 | { |
1115 | struct device *dev = &pdev->dev; |
1116 | struct wpcm450_pinctrl *pctrl; |
1117 | int ret; |
1118 | |
1119 | pctrl = devm_kzalloc(dev, size: sizeof(*pctrl), GFP_KERNEL); |
1120 | if (!pctrl) |
1121 | return -ENOMEM; |
1122 | |
1123 | pctrl->dev = &pdev->dev; |
1124 | raw_spin_lock_init(&pctrl->lock); |
1125 | dev_set_drvdata(dev, data: pctrl); |
1126 | |
1127 | pctrl->gcr_regmap = |
1128 | syscon_regmap_lookup_by_compatible(s: "nuvoton,wpcm450-gcr" ); |
1129 | if (IS_ERR(ptr: pctrl->gcr_regmap)) |
1130 | return dev_err_probe(dev, err: PTR_ERR(ptr: pctrl->gcr_regmap), |
1131 | fmt: "Failed to find nuvoton,wpcm450-gcr\n" ); |
1132 | |
1133 | pctrl->pctldev = devm_pinctrl_register(dev, |
1134 | pctldesc: &wpcm450_pinctrl_desc, driver_data: pctrl); |
1135 | if (IS_ERR(ptr: pctrl->pctldev)) |
1136 | return dev_err_probe(dev, err: PTR_ERR(ptr: pctrl->pctldev), |
1137 | fmt: "Failed to register pinctrl device\n" ); |
1138 | |
1139 | ret = wpcm450_gpio_register(pdev, pctrl); |
1140 | if (ret < 0) |
1141 | return ret; |
1142 | |
1143 | return 0; |
1144 | } |
1145 | |
1146 | static const struct of_device_id wpcm450_pinctrl_match[] = { |
1147 | { .compatible = "nuvoton,wpcm450-pinctrl" }, |
1148 | { } |
1149 | }; |
1150 | MODULE_DEVICE_TABLE(of, wpcm450_pinctrl_match); |
1151 | |
1152 | static struct platform_driver wpcm450_pinctrl_driver = { |
1153 | .probe = wpcm450_pinctrl_probe, |
1154 | .driver = { |
1155 | .name = "wpcm450-pinctrl" , |
1156 | .of_match_table = wpcm450_pinctrl_match, |
1157 | }, |
1158 | }; |
1159 | module_platform_driver(wpcm450_pinctrl_driver); |
1160 | |
1161 | MODULE_LICENSE("GPL v2" ); |
1162 | MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>" ); |
1163 | MODULE_DESCRIPTION("Nuvoton WPCM450 Pinctrl and GPIO driver" ); |
1164 | |