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