]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
5dc626f8 | 2 | /* |
4e3d8406 MY |
3 | * Copyright (C) 2015-2016 Socionext Inc. |
4 | * Author: Masahiro Yamada <yamada.masahiro@socionext.com> | |
5dc626f8 MY |
5 | */ |
6 | ||
d678a59d | 7 | #include <common.h> |
9d922450 | 8 | #include <dm.h> |
336d4615 | 9 | #include <dm/device_compat.h> |
cd93d625 | 10 | #include <linux/bitops.h> |
eb41d8a1 | 11 | #include <linux/bug.h> |
5dc626f8 MY |
12 | #include <linux/io.h> |
13 | #include <linux/err.h> | |
f73cfb4d | 14 | #include <linux/kernel.h> |
510454db | 15 | #include <linux/sizes.h> |
5dc626f8 MY |
16 | #include <dm/pinctrl.h> |
17 | ||
18 | #include "pinctrl-uniphier.h" | |
19 | ||
cdc7e3cb MY |
20 | #define UNIPHIER_PINCTRL_PINMUX_BASE 0x1000 |
21 | #define UNIPHIER_PINCTRL_LOAD_PINMUX 0x1700 | |
150997a4 MY |
22 | #define UNIPHIER_PINCTRL_DRVCTRL_BASE 0x1800 |
23 | #define UNIPHIER_PINCTRL_DRV2CTRL_BASE 0x1900 | |
24 | #define UNIPHIER_PINCTRL_DRV3CTRL_BASE 0x1980 | |
6a6b9d5d | 25 | #define UNIPHIER_PINCTRL_PUPDCTRL_BASE 0x1a00 |
cdc7e3cb MY |
26 | #define UNIPHIER_PINCTRL_IECTRL 0x1d00 |
27 | ||
64c1cc4c MY |
28 | static const char *uniphier_pinctrl_dummy_name = "_dummy"; |
29 | ||
603fd9ea MY |
30 | static int uniphier_pinctrl_get_pins_count(struct udevice *dev) |
31 | { | |
32 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
33 | const struct uniphier_pinctrl_pin *pins = priv->socdata->pins; | |
34 | int pins_count = priv->socdata->pins_count; | |
35 | ||
1e91a0ea DO |
36 | if (WARN_ON(!pins_count)) |
37 | return 0; /* no table of pins */ | |
38 | ||
603fd9ea MY |
39 | /* |
40 | * We do not list all pins in the pin table to save memory footprint. | |
41 | * Report the max pin number + 1 to fake the framework. | |
42 | */ | |
43 | return pins[pins_count - 1].number + 1; | |
44 | } | |
45 | ||
46 | static const char *uniphier_pinctrl_get_pin_name(struct udevice *dev, | |
47 | unsigned int selector) | |
48 | { | |
49 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
50 | const struct uniphier_pinctrl_pin *pins = priv->socdata->pins; | |
51 | int pins_count = priv->socdata->pins_count; | |
52 | int i; | |
53 | ||
54 | for (i = 0; i < pins_count; i++) | |
55 | if (pins[i].number == selector) | |
56 | return pins[i].name; | |
57 | ||
58 | return uniphier_pinctrl_dummy_name; | |
59 | } | |
60 | ||
5dc626f8 MY |
61 | static int uniphier_pinctrl_get_groups_count(struct udevice *dev) |
62 | { | |
63 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
64 | ||
65 | return priv->socdata->groups_count; | |
66 | } | |
67 | ||
68 | static const char *uniphier_pinctrl_get_group_name(struct udevice *dev, | |
69 | unsigned selector) | |
70 | { | |
71 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
72 | ||
64c1cc4c MY |
73 | if (!priv->socdata->groups[selector].name) |
74 | return uniphier_pinctrl_dummy_name; | |
75 | ||
5dc626f8 MY |
76 | return priv->socdata->groups[selector].name; |
77 | } | |
78 | ||
79 | static int uniphier_pinmux_get_functions_count(struct udevice *dev) | |
80 | { | |
81 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
82 | ||
83 | return priv->socdata->functions_count; | |
84 | } | |
85 | ||
86 | static const char *uniphier_pinmux_get_function_name(struct udevice *dev, | |
87 | unsigned selector) | |
88 | { | |
89 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
90 | ||
64c1cc4c MY |
91 | if (!priv->socdata->functions[selector]) |
92 | return uniphier_pinctrl_dummy_name; | |
93 | ||
5dc626f8 MY |
94 | return priv->socdata->functions[selector]; |
95 | } | |
96 | ||
6a6b9d5d MY |
97 | static int uniphier_pinconf_input_enable_perpin(struct udevice *dev, |
98 | unsigned int pin, int enable) | |
3b05b5f0 MY |
99 | { |
100 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
101 | unsigned reg; | |
102 | u32 mask, tmp; | |
103 | ||
104 | reg = UNIPHIER_PINCTRL_IECTRL + pin / 32 * 4; | |
105 | mask = BIT(pin % 32); | |
106 | ||
107 | tmp = readl(priv->base + reg); | |
6a6b9d5d MY |
108 | if (enable) |
109 | tmp |= mask; | |
110 | else | |
111 | tmp &= ~mask; | |
3b05b5f0 | 112 | writel(tmp, priv->base + reg); |
6a6b9d5d MY |
113 | |
114 | return 0; | |
3b05b5f0 MY |
115 | } |
116 | ||
6a6b9d5d MY |
117 | static int uniphier_pinconf_input_enable_legacy(struct udevice *dev, |
118 | unsigned int pin, int enable) | |
5dc626f8 MY |
119 | { |
120 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
5dc626f8 | 121 | |
6a6b9d5d MY |
122 | /* |
123 | * Multiple pins share one input enable, per-pin disabling is | |
124 | * impossible. | |
125 | */ | |
126 | if (!enable) | |
127 | return -EINVAL; | |
128 | ||
f73cfb4d MY |
129 | /* Set all bits instead of having a bunch of pin data */ |
130 | writel(U32_MAX, priv->base + UNIPHIER_PINCTRL_IECTRL); | |
6a6b9d5d MY |
131 | |
132 | return 0; | |
5dc626f8 MY |
133 | } |
134 | ||
6a6b9d5d MY |
135 | static int uniphier_pinconf_input_enable(struct udevice *dev, |
136 | unsigned int pin, int enable) | |
3b05b5f0 MY |
137 | { |
138 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
139 | ||
140 | if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) | |
6a6b9d5d MY |
141 | return uniphier_pinconf_input_enable_perpin(dev, pin, enable); |
142 | else | |
143 | return uniphier_pinconf_input_enable_legacy(dev, pin, enable); | |
144 | } | |
145 | ||
146 | #if CONFIG_IS_ENABLED(PINCONF) | |
147 | ||
148 | static const struct pinconf_param uniphier_pinconf_params[] = { | |
149 | { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, | |
150 | { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, | |
151 | { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, | |
152 | { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 }, | |
150997a4 | 153 | { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, |
6a6b9d5d MY |
154 | { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, |
155 | { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, | |
156 | }; | |
157 | ||
150997a4 MY |
158 | static const struct uniphier_pinctrl_pin * |
159 | uniphier_pinctrl_pin_get(struct uniphier_pinctrl_priv *priv, unsigned int pin) | |
160 | { | |
161 | const struct uniphier_pinctrl_pin *pins = priv->socdata->pins; | |
162 | int pins_count = priv->socdata->pins_count; | |
163 | int i; | |
164 | ||
165 | for (i = 0; i < pins_count; i++) | |
166 | if (pins[i].number == pin) | |
167 | return &pins[i]; | |
168 | ||
169 | return NULL; | |
170 | } | |
171 | ||
6a6b9d5d MY |
172 | static int uniphier_pinconf_bias_set(struct udevice *dev, unsigned int pin, |
173 | unsigned int param, unsigned int arg) | |
174 | { | |
175 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
176 | unsigned int enable = 1; | |
177 | unsigned int reg; | |
178 | u32 mask, tmp; | |
179 | ||
180 | if (!(priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PUPD_SIMPLE)) | |
181 | return -ENOTSUPP; | |
182 | ||
183 | switch (param) { | |
184 | case PIN_CONFIG_BIAS_DISABLE: | |
185 | enable = 0; | |
186 | break; | |
187 | case PIN_CONFIG_BIAS_PULL_UP: | |
188 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
189 | if (arg == 0) /* total bias is not supported */ | |
190 | return -EINVAL; | |
191 | break; | |
192 | case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: | |
193 | if (arg == 0) /* configuration ignored */ | |
194 | return 0; | |
195 | default: | |
196 | BUG(); | |
197 | } | |
198 | ||
199 | reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pin / 32 * 4; | |
200 | mask = BIT(pin % 32); | |
201 | ||
202 | tmp = readl(priv->base + reg); | |
203 | if (enable) | |
204 | tmp |= mask; | |
3b05b5f0 | 205 | else |
6a6b9d5d MY |
206 | tmp &= ~mask; |
207 | writel(tmp, priv->base + reg); | |
208 | ||
209 | return 0; | |
210 | } | |
211 | ||
150997a4 MY |
212 | static const unsigned int uniphier_pinconf_drv_strengths_1bit[] = { |
213 | 4, 8, | |
214 | }; | |
215 | ||
216 | static const unsigned int uniphier_pinconf_drv_strengths_2bit[] = { | |
217 | 8, 12, 16, 20, | |
218 | }; | |
219 | ||
220 | static const unsigned int uniphier_pinconf_drv_strengths_3bit[] = { | |
221 | 4, 5, 7, 9, 11, 12, 14, 16, | |
222 | }; | |
223 | ||
224 | static int uniphier_pinconf_drive_set(struct udevice *dev, unsigned int pin, | |
225 | unsigned int strength) | |
226 | { | |
227 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
228 | const struct uniphier_pinctrl_pin *desc; | |
229 | const unsigned int *strengths; | |
230 | unsigned int base, stride, width, drvctrl, reg, shift; | |
231 | u32 val, mask, tmp; | |
232 | ||
233 | desc = uniphier_pinctrl_pin_get(priv, pin); | |
234 | if (WARN_ON(!desc)) | |
235 | return -EINVAL; | |
236 | ||
237 | switch (uniphier_pin_get_drv_type(desc->data)) { | |
238 | case UNIPHIER_PIN_DRV_1BIT: | |
239 | strengths = uniphier_pinconf_drv_strengths_1bit; | |
240 | base = UNIPHIER_PINCTRL_DRVCTRL_BASE; | |
241 | stride = 1; | |
242 | width = 1; | |
243 | break; | |
244 | case UNIPHIER_PIN_DRV_2BIT: | |
245 | strengths = uniphier_pinconf_drv_strengths_2bit; | |
246 | base = UNIPHIER_PINCTRL_DRV2CTRL_BASE; | |
247 | stride = 2; | |
248 | width = 2; | |
249 | break; | |
250 | case UNIPHIER_PIN_DRV_3BIT: | |
251 | strengths = uniphier_pinconf_drv_strengths_3bit; | |
252 | base = UNIPHIER_PINCTRL_DRV3CTRL_BASE; | |
253 | stride = 4; | |
254 | width = 3; | |
255 | break; | |
256 | default: | |
257 | /* drive strength control is not supported for this pin */ | |
258 | return -EINVAL; | |
259 | } | |
260 | ||
261 | drvctrl = uniphier_pin_get_drvctrl(desc->data); | |
262 | drvctrl *= stride; | |
263 | ||
264 | reg = base + drvctrl / 32 * 4; | |
265 | shift = drvctrl % 32; | |
266 | mask = (1U << width) - 1; | |
267 | ||
268 | for (val = 0; val <= mask; val++) { | |
269 | if (strengths[val] > strength) | |
270 | break; | |
271 | } | |
272 | ||
273 | if (val == 0) { | |
274 | dev_err(dev, "unsupported drive strength %u mA for pin %s\n", | |
275 | strength, desc->name); | |
276 | return -EINVAL; | |
277 | } | |
278 | ||
279 | if (!mask) | |
280 | return 0; | |
281 | ||
282 | val--; | |
283 | ||
284 | tmp = readl(priv->base + reg); | |
285 | tmp &= ~(mask << shift); | |
286 | tmp |= (mask & val) << shift; | |
287 | writel(tmp, priv->base + reg); | |
288 | ||
289 | return 0; | |
290 | } | |
291 | ||
603fd9ea MY |
292 | static int uniphier_pinconf_set(struct udevice *dev, unsigned int pin, |
293 | unsigned int param, unsigned int arg) | |
6a6b9d5d MY |
294 | { |
295 | int ret; | |
296 | ||
297 | switch (param) { | |
298 | case PIN_CONFIG_BIAS_DISABLE: | |
299 | case PIN_CONFIG_BIAS_PULL_UP: | |
300 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
301 | case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: | |
302 | ret = uniphier_pinconf_bias_set(dev, pin, param, arg); | |
303 | break; | |
150997a4 MY |
304 | case PIN_CONFIG_DRIVE_STRENGTH: |
305 | ret = uniphier_pinconf_drive_set(dev, pin, arg); | |
306 | break; | |
6a6b9d5d MY |
307 | case PIN_CONFIG_INPUT_ENABLE: |
308 | ret = uniphier_pinconf_input_enable(dev, pin, arg); | |
309 | break; | |
310 | default: | |
7629d0b9 | 311 | dev_err(dev, "unsupported configuration parameter %u\n", param); |
6a6b9d5d MY |
312 | return -EINVAL; |
313 | } | |
314 | ||
315 | return ret; | |
3b05b5f0 MY |
316 | } |
317 | ||
6a6b9d5d MY |
318 | static int uniphier_pinconf_group_set(struct udevice *dev, |
319 | unsigned int group_selector, | |
320 | unsigned int param, unsigned int arg) | |
321 | { | |
322 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
323 | const struct uniphier_pinctrl_group *grp = | |
324 | &priv->socdata->groups[group_selector]; | |
325 | int i, ret; | |
326 | ||
327 | for (i = 0; i < grp->num_pins; i++) { | |
603fd9ea | 328 | ret = uniphier_pinconf_set(dev, grp->pins[i], param, arg); |
6a6b9d5d MY |
329 | if (ret) |
330 | return ret; | |
331 | } | |
332 | ||
333 | return 0; | |
334 | } | |
335 | ||
336 | #endif /* CONFIG_IS_ENABLED(PINCONF) */ | |
337 | ||
5dc626f8 | 338 | static void uniphier_pinmux_set_one(struct udevice *dev, unsigned pin, |
5e25b9d5 | 339 | int muxval) |
5dc626f8 MY |
340 | { |
341 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
bbb11980 MY |
342 | unsigned reg, reg_end, shift, mask; |
343 | unsigned mux_bits = 8; | |
344 | unsigned reg_stride = 4; | |
345 | bool load_pinctrl = false; | |
5dc626f8 MY |
346 | u32 tmp; |
347 | ||
fdd15b6a | 348 | /* some pins need input-enabling */ |
6a6b9d5d | 349 | uniphier_pinconf_input_enable(dev, pin, 1); |
fdd15b6a | 350 | |
5e25b9d5 MY |
351 | if (muxval < 0) |
352 | return; /* dedicated pin; nothing to do for pin-mux */ | |
353 | ||
bbb11980 MY |
354 | if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_MUX_4BIT) |
355 | mux_bits = 4; | |
356 | ||
8cc92b99 MY |
357 | if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) { |
358 | /* | |
359 | * Mode offset bit | |
360 | * Normal 4 * n shift+3:shift | |
361 | * Debug 4 * n shift+7:shift+4 | |
362 | */ | |
bbb11980 | 363 | mux_bits /= 2; |
8cc92b99 MY |
364 | reg_stride = 8; |
365 | load_pinctrl = true; | |
8cc92b99 MY |
366 | } |
367 | ||
5dc626f8 MY |
368 | reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride; |
369 | reg_end = reg + reg_stride; | |
370 | shift = pin * mux_bits % 32; | |
371 | mask = (1U << mux_bits) - 1; | |
372 | ||
373 | /* | |
374 | * If reg_stride is greater than 4, the MSB of each pinsel shall be | |
375 | * stored in the offset+4. | |
376 | */ | |
377 | for (; reg < reg_end; reg += 4) { | |
378 | tmp = readl(priv->base + reg); | |
379 | tmp &= ~(mask << shift); | |
380 | tmp |= (mask & muxval) << shift; | |
381 | writel(tmp, priv->base + reg); | |
382 | ||
383 | muxval >>= mux_bits; | |
384 | } | |
385 | ||
8cc92b99 | 386 | if (load_pinctrl) |
5dc626f8 | 387 | writel(1, priv->base + UNIPHIER_PINCTRL_LOAD_PINMUX); |
5dc626f8 MY |
388 | } |
389 | ||
390 | static int uniphier_pinmux_group_set(struct udevice *dev, | |
391 | unsigned group_selector, | |
392 | unsigned func_selector) | |
393 | { | |
394 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
395 | const struct uniphier_pinctrl_group *grp = | |
396 | &priv->socdata->groups[group_selector]; | |
397 | int i; | |
398 | ||
399 | for (i = 0; i < grp->num_pins; i++) | |
400 | uniphier_pinmux_set_one(dev, grp->pins[i], grp->muxvals[i]); | |
401 | ||
402 | return 0; | |
403 | } | |
404 | ||
405 | const struct pinctrl_ops uniphier_pinctrl_ops = { | |
603fd9ea MY |
406 | .get_pins_count = uniphier_pinctrl_get_pins_count, |
407 | .get_pin_name = uniphier_pinctrl_get_pin_name, | |
5dc626f8 MY |
408 | .get_groups_count = uniphier_pinctrl_get_groups_count, |
409 | .get_group_name = uniphier_pinctrl_get_group_name, | |
410 | .get_functions_count = uniphier_pinmux_get_functions_count, | |
411 | .get_function_name = uniphier_pinmux_get_function_name, | |
412 | .pinmux_group_set = uniphier_pinmux_group_set, | |
6a6b9d5d MY |
413 | #if CONFIG_IS_ENABLED(PINCONF) |
414 | .pinconf_num_params = ARRAY_SIZE(uniphier_pinconf_params), | |
415 | .pinconf_params = uniphier_pinconf_params, | |
603fd9ea | 416 | .pinconf_set = uniphier_pinconf_set, |
6a6b9d5d MY |
417 | .pinconf_group_set = uniphier_pinconf_group_set, |
418 | #endif | |
5dc626f8 MY |
419 | .set_state = pinctrl_generic_set_state, |
420 | }; | |
421 | ||
422 | int uniphier_pinctrl_probe(struct udevice *dev, | |
423 | struct uniphier_pinctrl_socdata *socdata) | |
424 | { | |
425 | struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); | |
426 | fdt_addr_t addr; | |
5dc626f8 | 427 | |
2548493a | 428 | addr = dev_read_addr(dev->parent); |
5dc626f8 MY |
429 | if (addr == FDT_ADDR_T_NONE) |
430 | return -EINVAL; | |
431 | ||
4e3d8406 | 432 | priv->base = devm_ioremap(dev, addr, SZ_4K); |
5dc626f8 MY |
433 | if (!priv->base) |
434 | return -ENOMEM; | |
435 | ||
436 | priv->socdata = socdata; | |
437 | ||
438 | return 0; | |
439 | } |