]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
ac72e174 WY |
2 | /* |
3 | * Atmel PIO4 pinctrl driver | |
4 | * | |
5 | * Copyright (C) 2016 Atmel Corporation | |
6 | * Wenyou.Yang <[email protected]> | |
ac72e174 WY |
7 | */ |
8 | ||
9 | #include <common.h> | |
9d922450 | 10 | #include <dm.h> |
401d1c4f | 11 | #include <asm/global_data.h> |
ac72e174 | 12 | #include <dm/pinctrl.h> |
cd93d625 | 13 | #include <linux/bitops.h> |
ac72e174 WY |
14 | #include <linux/io.h> |
15 | #include <linux/err.h> | |
16 | #include <mach/atmel_pio4.h> | |
17 | ||
18 | DECLARE_GLOBAL_DATA_PTR; | |
19 | ||
20 | /* | |
21 | * Warning: | |
22 | * In order to not introduce confusion between Atmel PIO groups and pinctrl | |
23 | * framework groups, Atmel PIO groups will be called banks. | |
24 | */ | |
25 | ||
8a8d24bd | 26 | struct atmel_pio4_plat { |
ac72e174 | 27 | struct atmel_pio4_port *reg_base; |
8bad34a7 | 28 | unsigned int slew_rate_support; |
ac72e174 WY |
29 | }; |
30 | ||
31 | static const struct pinconf_param conf_params[] = { | |
32 | { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, | |
33 | { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, | |
34 | { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, | |
35 | { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, | |
36 | { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, | |
37 | { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, | |
38 | { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, | |
417eca09 | 39 | { "atmel,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, |
8bad34a7 | 40 | { "slew-rate", PIN_CONFIG_SLEW_RATE, 0}, |
ac72e174 WY |
41 | }; |
42 | ||
8bad34a7 CB |
43 | static u32 atmel_pinctrl_get_pinconf(struct udevice *config, |
44 | struct atmel_pio4_plat *plat) | |
ac72e174 WY |
45 | { |
46 | const struct pinconf_param *params; | |
47 | u32 param, arg, conf = 0; | |
48 | u32 i; | |
417eca09 | 49 | u32 val; |
ac72e174 WY |
50 | |
51 | for (i = 0; i < ARRAY_SIZE(conf_params); i++) { | |
52 | params = &conf_params[i]; | |
864a4144 | 53 | if (!dev_read_prop(config, params->property, NULL)) |
ac72e174 WY |
54 | continue; |
55 | ||
56 | param = params->param; | |
57 | arg = params->default_value; | |
58 | ||
8bad34a7 CB |
59 | /* Keep slew rate enabled by default. */ |
60 | if (plat->slew_rate_support) | |
61 | conf |= ATMEL_PIO_SR; | |
62 | ||
ac72e174 WY |
63 | switch (param) { |
64 | case PIN_CONFIG_BIAS_DISABLE: | |
65 | conf &= (~ATMEL_PIO_PUEN_MASK); | |
66 | conf &= (~ATMEL_PIO_PDEN_MASK); | |
67 | break; | |
68 | case PIN_CONFIG_BIAS_PULL_UP: | |
69 | conf |= ATMEL_PIO_PUEN_MASK; | |
70 | break; | |
71 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
72 | conf |= ATMEL_PIO_PDEN_MASK; | |
73 | break; | |
74 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: | |
75 | if (arg == 0) | |
76 | conf &= (~ATMEL_PIO_OPD_MASK); | |
77 | else | |
78 | conf |= ATMEL_PIO_OPD_MASK; | |
79 | break; | |
80 | case PIN_CONFIG_INPUT_SCHMITT_ENABLE: | |
81 | if (arg == 0) | |
82 | conf |= ATMEL_PIO_SCHMITT_MASK; | |
83 | else | |
84 | conf &= (~ATMEL_PIO_SCHMITT_MASK); | |
85 | break; | |
86 | case PIN_CONFIG_INPUT_DEBOUNCE: | |
87 | if (arg == 0) { | |
88 | conf &= (~ATMEL_PIO_IFEN_MASK); | |
89 | conf &= (~ATMEL_PIO_IFSCEN_MASK); | |
90 | } else { | |
91 | conf |= ATMEL_PIO_IFEN_MASK; | |
92 | conf |= ATMEL_PIO_IFSCEN_MASK; | |
93 | } | |
94 | break; | |
417eca09 EH |
95 | case PIN_CONFIG_DRIVE_STRENGTH: |
96 | dev_read_u32(config, params->property, &val); | |
97 | conf &= (~ATMEL_PIO_DRVSTR_MASK); | |
98 | conf |= (val << ATMEL_PIO_DRVSTR_OFFSET) | |
99 | & ATMEL_PIO_DRVSTR_MASK; | |
100 | break; | |
8bad34a7 CB |
101 | case PIN_CONFIG_SLEW_RATE: |
102 | if (!plat->slew_rate_support) | |
103 | break; | |
104 | ||
105 | dev_read_u32(config, params->property, &val); | |
106 | /* And disable it if requested. */ | |
107 | if (val == 0) | |
108 | conf &= ~ATMEL_PIO_SR; | |
109 | break; | |
ac72e174 WY |
110 | default: |
111 | printf("%s: Unsupported configuration parameter: %u\n", | |
112 | __func__, param); | |
113 | break; | |
114 | } | |
115 | } | |
116 | ||
117 | return conf; | |
118 | } | |
119 | ||
120 | static inline struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev, | |
121 | u32 bank) | |
122 | { | |
8a8d24bd | 123 | struct atmel_pio4_plat *plat = dev_get_plat(dev); |
ac72e174 WY |
124 | struct atmel_pio4_port *bank_base = |
125 | (struct atmel_pio4_port *)((u32)plat->reg_base + | |
126 | ATMEL_PIO_BANK_OFFSET * bank); | |
127 | ||
128 | return bank_base; | |
129 | } | |
130 | ||
131 | #define MAX_PINMUX_ENTRIES 40 | |
132 | ||
133 | static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config) | |
134 | { | |
8bad34a7 | 135 | struct atmel_pio4_plat *plat = dev_get_plat(dev); |
ac72e174 WY |
136 | struct atmel_pio4_port *bank_base; |
137 | const void *blob = gd->fdt_blob; | |
e160f7d4 | 138 | int node = dev_of_offset(config); |
ac72e174 WY |
139 | u32 offset, func, bank, line; |
140 | u32 cells[MAX_PINMUX_ENTRIES]; | |
141 | u32 i, conf; | |
142 | int count; | |
143 | ||
8bad34a7 | 144 | conf = atmel_pinctrl_get_pinconf(config, plat); |
ac72e174 WY |
145 | |
146 | count = fdtdec_get_int_array_count(blob, node, "pinmux", | |
147 | cells, ARRAY_SIZE(cells)); | |
148 | if (count < 0) { | |
149 | printf("%s: bad pinmux array %d\n", __func__, count); | |
150 | return -EINVAL; | |
151 | } | |
152 | ||
153 | if (count > MAX_PINMUX_ENTRIES) { | |
154 | printf("%s: unsupported pinmux array count %d\n", | |
155 | __func__, count); | |
156 | return -EINVAL; | |
157 | } | |
158 | ||
159 | for (i = 0 ; i < count; i++) { | |
160 | offset = ATMEL_GET_PIN_NO(cells[i]); | |
161 | func = ATMEL_GET_PIN_FUNC(cells[i]); | |
162 | ||
163 | bank = ATMEL_PIO_BANK(offset); | |
164 | line = ATMEL_PIO_LINE(offset); | |
165 | ||
166 | bank_base = atmel_pio4_bank_base(dev, bank); | |
167 | ||
168 | writel(BIT(line), &bank_base->mskr); | |
169 | conf &= (~ATMEL_PIO_CFGR_FUNC_MASK); | |
170 | conf |= (func & ATMEL_PIO_CFGR_FUNC_MASK); | |
171 | writel(conf, &bank_base->cfgr); | |
172 | } | |
173 | ||
174 | return 0; | |
175 | } | |
176 | ||
177 | const struct pinctrl_ops atmel_pinctrl_ops = { | |
178 | .set_state = atmel_pinctrl_set_state, | |
179 | }; | |
180 | ||
181 | static int atmel_pinctrl_probe(struct udevice *dev) | |
182 | { | |
8a8d24bd | 183 | struct atmel_pio4_plat *plat = dev_get_plat(dev); |
8bad34a7 | 184 | ulong priv = dev_get_driver_data(dev); |
ac72e174 WY |
185 | fdt_addr_t addr_base; |
186 | ||
187 | dev = dev_get_parent(dev); | |
2548493a | 188 | addr_base = dev_read_addr(dev); |
ac72e174 WY |
189 | if (addr_base == FDT_ADDR_T_NONE) |
190 | return -EINVAL; | |
191 | ||
192 | plat->reg_base = (struct atmel_pio4_port *)addr_base; | |
8bad34a7 | 193 | plat->slew_rate_support = priv; |
ac72e174 WY |
194 | |
195 | return 0; | |
196 | } | |
197 | ||
198 | static const struct udevice_id atmel_pinctrl_match[] = { | |
199 | { .compatible = "atmel,sama5d2-pinctrl" }, | |
8bad34a7 CB |
200 | { .compatible = "microchip,sama7g5-pinctrl", |
201 | .data = (ulong)1, }, | |
ac72e174 WY |
202 | {} |
203 | }; | |
204 | ||
205 | U_BOOT_DRIVER(atmel_pinctrl) = { | |
206 | .name = "pinctrl_atmel_pio4", | |
207 | .id = UCLASS_PINCTRL, | |
208 | .of_match = atmel_pinctrl_match, | |
209 | .probe = atmel_pinctrl_probe, | |
8a8d24bd | 210 | .plat_auto = sizeof(struct atmel_pio4_plat), |
ac72e174 WY |
211 | .ops = &atmel_pinctrl_ops, |
212 | }; |