]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
9319a756 WY |
2 | /* |
3 | * Atmel PIO pinctrl driver | |
4 | * | |
5 | * Copyright (C) 2016 Atmel Corporation | |
6 | * Wenyou.Yang <[email protected]> | |
9319a756 WY |
7 | */ |
8 | ||
9 | #include <common.h> | |
9d922450 | 10 | #include <dm.h> |
9319a756 | 11 | #include <dm/pinctrl.h> |
e61ed48f | 12 | #include <asm/hardware.h> |
9319a756 WY |
13 | #include <linux/io.h> |
14 | #include <linux/err.h> | |
15 | #include <mach/at91_pio.h> | |
16 | ||
17 | DECLARE_GLOBAL_DATA_PTR; | |
18 | ||
19 | #define MAX_GPIO_BANKS 5 | |
20 | #define MAX_NB_GPIO_PER_BANK 32 | |
21 | ||
22 | #define MAX_PINMUX_ENTRIES 200 | |
23 | ||
24 | struct at91_pinctrl_priv { | |
25 | struct at91_port *reg_base[MAX_GPIO_BANKS]; | |
26 | u32 nbanks; | |
27 | }; | |
28 | ||
29 | #define PULL_UP BIT(0) | |
30 | #define MULTI_DRIVE BIT(1) | |
31 | #define DEGLITCH BIT(2) | |
32 | #define PULL_DOWN BIT(3) | |
33 | #define DIS_SCHMIT BIT(4) | |
34 | #define DRIVE_STRENGTH_SHIFT 5 | |
35 | #define DRIVE_STRENGTH_MASK 0x3 | |
36 | #define DRIVE_STRENGTH (DRIVE_STRENGTH_MASK << DRIVE_STRENGTH_SHIFT) | |
37 | #define OUTPUT BIT(7) | |
38 | #define OUTPUT_VAL_SHIFT 8 | |
39 | #define OUTPUT_VAL (0x1 << OUTPUT_VAL_SHIFT) | |
40 | #define DEBOUNCE BIT(16) | |
41 | #define DEBOUNCE_VAL_SHIFT 17 | |
42 | #define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT) | |
43 | ||
44 | /** | |
45 | * These defines will translated the dt binding settings to our internal | |
46 | * settings. They are not necessarily the same value as the register setting. | |
47 | * The actual drive strength current of low, medium and high must be looked up | |
48 | * from the corresponding device datasheet. This value is different for pins | |
49 | * that are even in the same banks. It is also dependent on VCC. | |
50 | * DRIVE_STRENGTH_DEFAULT is just a placeholder to avoid changing the drive | |
51 | * strength when there is no dt config for it. | |
52 | */ | |
04d4ec9c CB |
53 | enum drive_strength_bit { |
54 | DRIVE_STRENGTH_BIT_DEF, | |
55 | DRIVE_STRENGTH_BIT_LOW, | |
56 | DRIVE_STRENGTH_BIT_MED, | |
57 | DRIVE_STRENGTH_BIT_HI, | |
58 | }; | |
59 | ||
60 | #define DRIVE_STRENGTH_BIT_MSK(name) (DRIVE_STRENGTH_BIT_##name << \ | |
61 | DRIVE_STRENGTH_SHIFT) | |
9319a756 WY |
62 | |
63 | enum at91_mux { | |
64 | AT91_MUX_GPIO = 0, | |
65 | AT91_MUX_PERIPH_A = 1, | |
66 | AT91_MUX_PERIPH_B = 2, | |
67 | AT91_MUX_PERIPH_C = 3, | |
68 | AT91_MUX_PERIPH_D = 4, | |
69 | }; | |
70 | ||
71 | /** | |
72 | * struct at91_pinctrl_mux_ops - describes an AT91 mux ops group | |
73 | * on new IP with support for periph C and D the way to mux in | |
74 | * periph A and B has changed | |
75 | * So provide the right callbacks | |
76 | * if not present means the IP does not support it | |
77 | * @mux_A_periph: assign the corresponding pin to the peripheral A function. | |
78 | * @mux_B_periph: assign the corresponding pin to the peripheral B function. | |
79 | * @mux_C_periph: assign the corresponding pin to the peripheral C function. | |
80 | * @mux_D_periph: assign the corresponding pin to the peripheral D function. | |
81 | * @set_deglitch: enable/disable the deglitch feature. | |
82 | * @set_debounce: enable/disable the debounce feature. | |
83 | * @set_pulldown: enable/disable the pulldown feature. | |
84 | * @disable_schmitt_trig: disable schmitt trigger | |
85 | */ | |
86 | struct at91_pinctrl_mux_ops { | |
87 | void (*mux_A_periph)(struct at91_port *pio, u32 mask); | |
88 | void (*mux_B_periph)(struct at91_port *pio, u32 mask); | |
89 | void (*mux_C_periph)(struct at91_port *pio, u32 mask); | |
90 | void (*mux_D_periph)(struct at91_port *pio, u32 mask); | |
91 | void (*set_deglitch)(struct at91_port *pio, u32 mask, bool is_on); | |
92 | void (*set_debounce)(struct at91_port *pio, u32 mask, bool is_on, | |
93 | u32 div); | |
94 | void (*set_pulldown)(struct at91_port *pio, u32 mask, bool is_on); | |
95 | void (*disable_schmitt_trig)(struct at91_port *pio, u32 mask); | |
96 | void (*set_drivestrength)(struct at91_port *pio, u32 pin, | |
97 | u32 strength); | |
98 | }; | |
99 | ||
100 | static u32 two_bit_pin_value_shift_amount(u32 pin) | |
101 | { | |
102 | /* return the shift value for a pin for "two bit" per pin registers, | |
103 | * i.e. drive strength */ | |
104 | return 2 * ((pin >= MAX_NB_GPIO_PER_BANK/2) | |
105 | ? pin - MAX_NB_GPIO_PER_BANK/2 : pin); | |
106 | } | |
107 | ||
108 | static void at91_mux_disable_interrupt(struct at91_port *pio, u32 mask) | |
109 | { | |
110 | writel(mask, &pio->idr); | |
111 | } | |
112 | ||
113 | static void at91_mux_set_pullup(struct at91_port *pio, u32 mask, bool on) | |
114 | { | |
115 | if (on) | |
116 | writel(mask, &pio->mux.pio3.ppddr); | |
117 | ||
118 | writel(mask, (on ? &pio->puer : &pio->pudr)); | |
119 | } | |
120 | ||
121 | static void at91_mux_set_output(struct at91_port *pio, unsigned mask, | |
122 | bool is_on, bool val) | |
123 | { | |
124 | writel(mask, (val ? &pio->sodr : &pio->codr)); | |
125 | writel(mask, (is_on ? &pio->oer : &pio->odr)); | |
126 | } | |
127 | ||
128 | static void at91_mux_set_multidrive(struct at91_port *pio, u32 mask, bool on) | |
129 | { | |
130 | writel(mask, (on ? &pio->mder : &pio->mddr)); | |
131 | } | |
132 | ||
133 | static void at91_mux_set_A_periph(struct at91_port *pio, u32 mask) | |
134 | { | |
135 | writel(mask, &pio->mux.pio2.asr); | |
136 | } | |
137 | ||
138 | static void at91_mux_set_B_periph(struct at91_port *pio, u32 mask) | |
139 | { | |
140 | writel(mask, &pio->mux.pio2.bsr); | |
141 | } | |
142 | ||
143 | static void at91_mux_pio3_set_A_periph(struct at91_port *pio, u32 mask) | |
144 | { | |
145 | writel(readl(&pio->mux.pio3.abcdsr1) & ~mask, &pio->mux.pio3.abcdsr1); | |
146 | writel(readl(&pio->mux.pio3.abcdsr2) & ~mask, &pio->mux.pio3.abcdsr2); | |
147 | } | |
148 | ||
149 | static void at91_mux_pio3_set_B_periph(struct at91_port *pio, u32 mask) | |
150 | { | |
151 | writel(readl(&pio->mux.pio3.abcdsr1) | mask, &pio->mux.pio3.abcdsr1); | |
152 | writel(readl(&pio->mux.pio3.abcdsr2) & ~mask, &pio->mux.pio3.abcdsr2); | |
153 | } | |
154 | ||
155 | static void at91_mux_pio3_set_C_periph(struct at91_port *pio, u32 mask) | |
156 | { | |
157 | writel(readl(&pio->mux.pio3.abcdsr1) & ~mask, &pio->mux.pio3.abcdsr1); | |
158 | writel(readl(&pio->mux.pio3.abcdsr2) | mask, &pio->mux.pio3.abcdsr2); | |
159 | } | |
160 | ||
161 | static void at91_mux_pio3_set_D_periph(struct at91_port *pio, u32 mask) | |
162 | { | |
163 | writel(readl(&pio->mux.pio3.abcdsr1) | mask, &pio->mux.pio3.abcdsr1); | |
164 | writel(readl(&pio->mux.pio3.abcdsr2) | mask, &pio->mux.pio3.abcdsr2); | |
165 | } | |
166 | ||
167 | static void at91_mux_set_deglitch(struct at91_port *pio, u32 mask, bool is_on) | |
168 | { | |
169 | writel(mask, (is_on ? &pio->ifer : &pio->ifdr)); | |
170 | } | |
171 | ||
172 | static void at91_mux_pio3_set_deglitch(struct at91_port *pio, | |
173 | u32 mask, bool is_on) | |
174 | { | |
175 | if (is_on) | |
176 | writel(mask, &pio->mux.pio3.ifscdr); | |
177 | at91_mux_set_deglitch(pio, mask, is_on); | |
178 | } | |
179 | ||
180 | static void at91_mux_pio3_set_debounce(struct at91_port *pio, u32 mask, | |
181 | bool is_on, u32 div) | |
182 | { | |
183 | if (is_on) { | |
184 | writel(mask, &pio->mux.pio3.ifscer); | |
185 | writel(div & PIO_SCDR_DIV, &pio->mux.pio3.scdr); | |
186 | writel(mask, &pio->ifer); | |
187 | } else { | |
188 | writel(mask, &pio->mux.pio3.ifscdr); | |
189 | } | |
190 | } | |
191 | ||
192 | static void at91_mux_pio3_set_pulldown(struct at91_port *pio, | |
193 | u32 mask, bool is_on) | |
194 | { | |
195 | if (is_on) | |
196 | writel(mask, &pio->pudr); | |
197 | ||
198 | writel(mask, (is_on ? &pio->mux.pio3.ppder : &pio->mux.pio3.ppddr)); | |
199 | } | |
200 | ||
201 | static void at91_mux_pio3_disable_schmitt_trig(struct at91_port *pio, | |
202 | u32 mask) | |
203 | { | |
204 | writel(readl(&pio->schmitt) | mask, &pio->schmitt); | |
205 | } | |
206 | ||
207 | static void set_drive_strength(void *reg, u32 pin, u32 strength) | |
208 | { | |
209 | u32 shift = two_bit_pin_value_shift_amount(pin); | |
210 | ||
211 | clrsetbits_le32(reg, DRIVE_STRENGTH_MASK << shift, strength << shift); | |
212 | } | |
213 | ||
214 | static void at91_mux_sama5d3_set_drivestrength(struct at91_port *pio, | |
215 | u32 pin, u32 setting) | |
216 | { | |
217 | void *reg; | |
218 | ||
219 | reg = &pio->driver12; | |
220 | if (pin >= MAX_NB_GPIO_PER_BANK / 2) | |
221 | reg = &pio->driver2; | |
222 | ||
223 | /* do nothing if setting is zero */ | |
224 | if (!setting) | |
225 | return; | |
226 | ||
227 | /* strength is 1 to 1 with setting for SAMA5 */ | |
228 | set_drive_strength(reg, pin, setting); | |
229 | } | |
230 | ||
231 | static void at91_mux_sam9x5_set_drivestrength(struct at91_port *pio, | |
232 | u32 pin, u32 setting) | |
233 | { | |
234 | void *reg; | |
235 | ||
236 | reg = &pio->driver1; | |
237 | if (pin >= MAX_NB_GPIO_PER_BANK / 2) | |
238 | reg = &pio->driver12; | |
239 | ||
240 | /* do nothing if setting is zero */ | |
241 | if (!setting) | |
242 | return; | |
243 | ||
244 | /* strength is inverse on SAM9x5s with our defines | |
245 | * 0 = hi, 1 = med, 2 = low, 3 = rsvd */ | |
04d4ec9c | 246 | setting = DRIVE_STRENGTH_BIT_MSK(HI) - setting; |
9319a756 WY |
247 | |
248 | set_drive_strength(reg, pin, setting); | |
249 | } | |
250 | ||
251 | static struct at91_pinctrl_mux_ops at91rm9200_ops = { | |
252 | .mux_A_periph = at91_mux_set_A_periph, | |
253 | .mux_B_periph = at91_mux_set_B_periph, | |
254 | .set_deglitch = at91_mux_set_deglitch, | |
255 | }; | |
256 | ||
257 | static struct at91_pinctrl_mux_ops at91sam9x5_ops = { | |
258 | .mux_A_periph = at91_mux_pio3_set_A_periph, | |
259 | .mux_B_periph = at91_mux_pio3_set_B_periph, | |
260 | .mux_C_periph = at91_mux_pio3_set_C_periph, | |
261 | .mux_D_periph = at91_mux_pio3_set_D_periph, | |
262 | .set_deglitch = at91_mux_pio3_set_deglitch, | |
263 | .set_debounce = at91_mux_pio3_set_debounce, | |
264 | .set_pulldown = at91_mux_pio3_set_pulldown, | |
265 | .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, | |
266 | .set_drivestrength = at91_mux_sam9x5_set_drivestrength, | |
267 | }; | |
268 | ||
269 | static struct at91_pinctrl_mux_ops sama5d3_ops = { | |
270 | .mux_A_periph = at91_mux_pio3_set_A_periph, | |
271 | .mux_B_periph = at91_mux_pio3_set_B_periph, | |
272 | .mux_C_periph = at91_mux_pio3_set_C_periph, | |
273 | .mux_D_periph = at91_mux_pio3_set_D_periph, | |
274 | .set_deglitch = at91_mux_pio3_set_deglitch, | |
275 | .set_debounce = at91_mux_pio3_set_debounce, | |
276 | .set_pulldown = at91_mux_pio3_set_pulldown, | |
277 | .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, | |
278 | .set_drivestrength = at91_mux_sama5d3_set_drivestrength, | |
279 | }; | |
280 | ||
281 | static void at91_mux_gpio_disable(struct at91_port *pio, u32 mask) | |
282 | { | |
283 | writel(mask, &pio->pdr); | |
284 | } | |
285 | ||
286 | static void at91_mux_gpio_enable(struct at91_port *pio, u32 mask, bool input) | |
287 | { | |
288 | writel(mask, &pio->per); | |
289 | writel(mask, (input ? &pio->odr : &pio->oer)); | |
290 | } | |
291 | ||
292 | static int at91_pmx_set(struct at91_pinctrl_mux_ops *ops, | |
293 | struct at91_port *pio, u32 mask, enum at91_mux mux) | |
294 | { | |
295 | at91_mux_disable_interrupt(pio, mask); | |
296 | switch (mux) { | |
297 | case AT91_MUX_GPIO: | |
298 | at91_mux_gpio_enable(pio, mask, 1); | |
299 | break; | |
300 | case AT91_MUX_PERIPH_A: | |
301 | ops->mux_A_periph(pio, mask); | |
302 | break; | |
303 | case AT91_MUX_PERIPH_B: | |
304 | ops->mux_B_periph(pio, mask); | |
305 | break; | |
306 | case AT91_MUX_PERIPH_C: | |
307 | if (!ops->mux_C_periph) | |
308 | return -EINVAL; | |
309 | ops->mux_C_periph(pio, mask); | |
310 | break; | |
311 | case AT91_MUX_PERIPH_D: | |
312 | if (!ops->mux_D_periph) | |
313 | return -EINVAL; | |
314 | ops->mux_D_periph(pio, mask); | |
315 | break; | |
316 | } | |
317 | if (mux) | |
318 | at91_mux_gpio_disable(pio, mask); | |
319 | ||
320 | return 0; | |
321 | } | |
322 | ||
323 | static int at91_pinconf_set(struct at91_pinctrl_mux_ops *ops, | |
324 | struct at91_port *pio, u32 pin, u32 config) | |
325 | { | |
326 | u32 mask = BIT(pin); | |
327 | ||
328 | if ((config & PULL_UP) && (config & PULL_DOWN)) | |
329 | return -EINVAL; | |
330 | ||
331 | at91_mux_set_output(pio, mask, config & OUTPUT, | |
332 | (config & OUTPUT_VAL) >> OUTPUT_VAL_SHIFT); | |
333 | at91_mux_set_pullup(pio, mask, config & PULL_UP); | |
334 | at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE); | |
335 | if (ops->set_deglitch) | |
336 | ops->set_deglitch(pio, mask, config & DEGLITCH); | |
337 | if (ops->set_debounce) | |
338 | ops->set_debounce(pio, mask, config & DEBOUNCE, | |
339 | (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT); | |
340 | if (ops->set_pulldown) | |
341 | ops->set_pulldown(pio, mask, config & PULL_DOWN); | |
342 | if (ops->disable_schmitt_trig && config & DIS_SCHMIT) | |
343 | ops->disable_schmitt_trig(pio, mask); | |
344 | if (ops->set_drivestrength) | |
345 | ops->set_drivestrength(pio, pin, | |
346 | (config & DRIVE_STRENGTH) >> DRIVE_STRENGTH_SHIFT); | |
347 | ||
348 | return 0; | |
349 | } | |
350 | ||
351 | static int at91_pin_check_config(struct udevice *dev, u32 bank, u32 pin) | |
352 | { | |
353 | struct at91_pinctrl_priv *priv = dev_get_priv(dev); | |
354 | ||
355 | if (bank >= priv->nbanks) { | |
356 | debug("pin conf bank %d >= nbanks %d\n", bank, priv->nbanks); | |
357 | return -EINVAL; | |
358 | } | |
359 | ||
360 | if (pin >= MAX_NB_GPIO_PER_BANK) { | |
361 | debug("pin conf pin %d >= %d\n", pin, MAX_NB_GPIO_PER_BANK); | |
362 | return -EINVAL; | |
363 | } | |
364 | ||
365 | return 0; | |
366 | } | |
367 | ||
368 | static int at91_pinctrl_set_state(struct udevice *dev, struct udevice *config) | |
369 | { | |
370 | struct at91_pinctrl_priv *priv = dev_get_priv(dev); | |
371 | const void *blob = gd->fdt_blob; | |
da409ccc | 372 | int node = dev_of_offset(config); |
9319a756 WY |
373 | u32 cells[MAX_PINMUX_ENTRIES]; |
374 | const u32 *list = cells; | |
375 | u32 bank, pin; | |
376 | u32 conf, mask, count, i; | |
377 | int size; | |
378 | int ret; | |
379 | enum at91_mux mux; | |
380 | struct at91_port *pio; | |
381 | struct at91_pinctrl_mux_ops *ops = | |
382 | (struct at91_pinctrl_mux_ops *)dev_get_driver_data(dev); | |
383 | ||
384 | /* | |
385 | * the binding format is atmel,pins = <bank pin mux CONFIG ...>, | |
386 | * do sanity check and calculate pins number | |
387 | */ | |
388 | size = fdtdec_get_int_array_count(blob, node, "atmel,pins", | |
389 | cells, ARRAY_SIZE(cells)); | |
390 | ||
391 | /* we do not check return since it's safe node passed down */ | |
392 | count = size >> 2; | |
393 | if (!count) | |
394 | return -EINVAL; | |
395 | ||
396 | for (i = 0; i < count; i++) { | |
397 | bank = *list++; | |
398 | pin = *list++; | |
399 | mux = *list++; | |
400 | conf = *list++; | |
401 | ||
402 | ret = at91_pin_check_config(dev, bank, pin); | |
403 | if (ret) | |
404 | return ret; | |
405 | ||
406 | pio = priv->reg_base[bank]; | |
407 | mask = BIT(pin); | |
408 | ||
409 | ret = at91_pmx_set(ops, pio, mask, mux); | |
410 | if (ret) | |
411 | return ret; | |
412 | ||
413 | ret = at91_pinconf_set(ops, pio, pin, conf); | |
414 | if (ret) | |
415 | return ret; | |
416 | } | |
417 | ||
418 | return 0; | |
419 | } | |
420 | ||
421 | const struct pinctrl_ops at91_pinctrl_ops = { | |
422 | .set_state = at91_pinctrl_set_state, | |
423 | }; | |
424 | ||
425 | static int at91_pinctrl_probe(struct udevice *dev) | |
426 | { | |
427 | struct at91_pinctrl_priv *priv = dev_get_priv(dev); | |
428 | fdt_addr_t addr_base; | |
429 | int index; | |
430 | ||
431 | for (index = 0; index < MAX_GPIO_BANKS; index++) { | |
a821c4af | 432 | addr_base = devfdt_get_addr_index(dev, index); |
9319a756 WY |
433 | if (addr_base == FDT_ADDR_T_NONE) |
434 | break; | |
435 | ||
436 | priv->reg_base[index] = (struct at91_port *)addr_base; | |
437 | } | |
438 | ||
439 | priv->nbanks = index; | |
440 | ||
441 | return 0; | |
442 | } | |
443 | ||
444 | static const struct udevice_id at91_pinctrl_match[] = { | |
445 | { .compatible = "atmel,sama5d3-pinctrl", .data = (ulong)&sama5d3_ops }, | |
446 | { .compatible = "atmel,at91sam9x5-pinctrl", .data = (ulong)&at91sam9x5_ops }, | |
447 | { .compatible = "atmel,at91rm9200-pinctrl", .data = (ulong)&at91rm9200_ops }, | |
448 | {} | |
449 | }; | |
450 | ||
451 | U_BOOT_DRIVER(at91_pinctrl) = { | |
452 | .name = "pinctrl_at91", | |
453 | .id = UCLASS_PINCTRL, | |
454 | .of_match = at91_pinctrl_match, | |
455 | .probe = at91_pinctrl_probe, | |
456 | .priv_auto_alloc_size = sizeof(struct at91_pinctrl_priv), | |
457 | .ops = &at91_pinctrl_ops, | |
458 | }; |