]>
Commit | Line | Data |
---|---|---|
6e908892 | 1 | /* |
8ef364b3 MY |
2 | * Copyright (C) 2015-2017 Socionext Inc. |
3 | * Author: Masahiro Yamada <yamada.masahiro@socionext.com> | |
6e908892 MY |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | */ | |
15 | ||
16 | #include <linux/export.h> | |
17 | #include <linux/mfd/syscon.h> | |
3e030b0b | 18 | #include <linux/of.h> |
6e908892 MY |
19 | #include <linux/pinctrl/pinconf.h> |
20 | #include <linux/pinctrl/pinconf-generic.h> | |
21 | #include <linux/pinctrl/pinctrl.h> | |
22 | #include <linux/pinctrl/pinmux.h> | |
23 | #include <linux/platform_device.h> | |
24 | #include <linux/regmap.h> | |
25 | ||
26 | #include "../core.h" | |
27 | #include "../pinctrl-utils.h" | |
28 | #include "pinctrl-uniphier.h" | |
29 | ||
8ef364b3 MY |
30 | #define UNIPHIER_PINCTRL_PINMUX_BASE 0x1000 |
31 | #define UNIPHIER_PINCTRL_LOAD_PINMUX 0x1700 | |
32 | #define UNIPHIER_PINCTRL_DRVCTRL_BASE 0x1800 | |
33 | #define UNIPHIER_PINCTRL_DRV2CTRL_BASE 0x1900 | |
34 | #define UNIPHIER_PINCTRL_DRV3CTRL_BASE 0x1980 | |
35 | #define UNIPHIER_PINCTRL_PUPDCTRL_BASE 0x1a00 | |
36 | #define UNIPHIER_PINCTRL_IECTRL 0x1d00 | |
37 | ||
6e908892 | 38 | struct uniphier_pinctrl_priv { |
fc78a566 | 39 | struct pinctrl_desc pctldesc; |
6e908892 MY |
40 | struct pinctrl_dev *pctldev; |
41 | struct regmap *regmap; | |
42 | struct uniphier_pinctrl_socdata *socdata; | |
43 | }; | |
44 | ||
45 | static int uniphier_pctl_get_groups_count(struct pinctrl_dev *pctldev) | |
46 | { | |
47 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
48 | ||
49 | return priv->socdata->groups_count; | |
50 | } | |
51 | ||
52 | static const char *uniphier_pctl_get_group_name(struct pinctrl_dev *pctldev, | |
53 | unsigned selector) | |
54 | { | |
55 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
56 | ||
57 | return priv->socdata->groups[selector].name; | |
58 | } | |
59 | ||
60 | static int uniphier_pctl_get_group_pins(struct pinctrl_dev *pctldev, | |
61 | unsigned selector, | |
62 | const unsigned **pins, | |
63 | unsigned *num_pins) | |
64 | { | |
65 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
66 | ||
67 | *pins = priv->socdata->groups[selector].pins; | |
68 | *num_pins = priv->socdata->groups[selector].num_pins; | |
69 | ||
70 | return 0; | |
71 | } | |
72 | ||
73 | #ifdef CONFIG_DEBUG_FS | |
74 | static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, | |
75 | struct seq_file *s, unsigned offset) | |
76 | { | |
94bf176b | 77 | const struct pin_desc *desc = pin_desc_get(pctldev, offset); |
9eaa98a6 | 78 | const char *pull_dir, *drv_type; |
6e908892 | 79 | |
94bf176b | 80 | switch (uniphier_pin_get_pull_dir(desc->drv_data)) { |
6e908892 MY |
81 | case UNIPHIER_PIN_PULL_UP: |
82 | pull_dir = "UP"; | |
83 | break; | |
84 | case UNIPHIER_PIN_PULL_DOWN: | |
85 | pull_dir = "DOWN"; | |
86 | break; | |
10ef8277 MY |
87 | case UNIPHIER_PIN_PULL_UP_FIXED: |
88 | pull_dir = "UP(FIXED)"; | |
89 | break; | |
90 | case UNIPHIER_PIN_PULL_DOWN_FIXED: | |
91 | pull_dir = "DOWN(FIXED)"; | |
92 | break; | |
6e908892 MY |
93 | case UNIPHIER_PIN_PULL_NONE: |
94 | pull_dir = "NONE"; | |
95 | break; | |
96 | default: | |
97 | BUG(); | |
98 | } | |
99 | ||
94bf176b | 100 | switch (uniphier_pin_get_drv_type(desc->drv_data)) { |
9eaa98a6 MY |
101 | case UNIPHIER_PIN_DRV_1BIT: |
102 | drv_type = "4/8(mA)"; | |
6e908892 | 103 | break; |
9eaa98a6 MY |
104 | case UNIPHIER_PIN_DRV_2BIT: |
105 | drv_type = "8/12/16/20(mA)"; | |
6e908892 | 106 | break; |
72e5706a MY |
107 | case UNIPHIER_PIN_DRV_3BIT: |
108 | drv_type = "4/5/7/9/11/12/14/16(mA)"; | |
109 | break; | |
9eaa98a6 MY |
110 | case UNIPHIER_PIN_DRV_FIXED4: |
111 | drv_type = "4(mA)"; | |
6e908892 | 112 | break; |
9eaa98a6 MY |
113 | case UNIPHIER_PIN_DRV_FIXED5: |
114 | drv_type = "5(mA)"; | |
6e908892 | 115 | break; |
9eaa98a6 MY |
116 | case UNIPHIER_PIN_DRV_FIXED8: |
117 | drv_type = "8(mA)"; | |
6e908892 MY |
118 | break; |
119 | case UNIPHIER_PIN_DRV_NONE: | |
9eaa98a6 | 120 | drv_type = "NONE"; |
6e908892 MY |
121 | break; |
122 | default: | |
123 | BUG(); | |
124 | } | |
125 | ||
9eaa98a6 | 126 | seq_printf(s, " PULL_DIR=%s DRV_TYPE=%s", pull_dir, drv_type); |
6e908892 MY |
127 | } |
128 | #endif | |
129 | ||
130 | static const struct pinctrl_ops uniphier_pctlops = { | |
131 | .get_groups_count = uniphier_pctl_get_groups_count, | |
132 | .get_group_name = uniphier_pctl_get_group_name, | |
133 | .get_group_pins = uniphier_pctl_get_group_pins, | |
134 | #ifdef CONFIG_DEBUG_FS | |
135 | .pin_dbg_show = uniphier_pctl_pin_dbg_show, | |
136 | #endif | |
137 | .dt_node_to_map = pinconf_generic_dt_node_to_map_all, | |
d32f7fd3 | 138 | .dt_free_map = pinctrl_utils_free_map, |
6e908892 MY |
139 | }; |
140 | ||
141 | static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev, | |
94bf176b | 142 | const struct pin_desc *desc, |
6e908892 MY |
143 | enum pin_config_param param) |
144 | { | |
145 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
146 | enum uniphier_pin_pull_dir pull_dir = | |
94bf176b | 147 | uniphier_pin_get_pull_dir(desc->drv_data); |
6e908892 MY |
148 | unsigned int pupdctrl, reg, shift, val; |
149 | unsigned int expected = 1; | |
150 | int ret; | |
151 | ||
152 | switch (param) { | |
153 | case PIN_CONFIG_BIAS_DISABLE: | |
154 | if (pull_dir == UNIPHIER_PIN_PULL_NONE) | |
155 | return 0; | |
156 | if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || | |
157 | pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) | |
158 | return -EINVAL; | |
159 | expected = 0; | |
160 | break; | |
161 | case PIN_CONFIG_BIAS_PULL_UP: | |
162 | if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED) | |
163 | return 0; | |
164 | if (pull_dir != UNIPHIER_PIN_PULL_UP) | |
165 | return -EINVAL; | |
166 | break; | |
167 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
168 | if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) | |
169 | return 0; | |
170 | if (pull_dir != UNIPHIER_PIN_PULL_DOWN) | |
171 | return -EINVAL; | |
172 | break; | |
173 | default: | |
174 | BUG(); | |
175 | } | |
176 | ||
94bf176b | 177 | pupdctrl = uniphier_pin_get_pupdctrl(desc->drv_data); |
6e908892 MY |
178 | |
179 | reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; | |
180 | shift = pupdctrl % 32; | |
181 | ||
8ef364b3 | 182 | ret = regmap_read(priv->regmap, reg, &val); |
6e908892 MY |
183 | if (ret) |
184 | return ret; | |
185 | ||
186 | val = (val >> shift) & 1; | |
187 | ||
188 | return (val == expected) ? 0 : -EINVAL; | |
189 | } | |
190 | ||
191 | static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev, | |
94bf176b | 192 | const struct pin_desc *desc, |
6e908892 MY |
193 | u16 *strength) |
194 | { | |
195 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
9eaa98a6 | 196 | enum uniphier_pin_drv_type type = |
94bf176b | 197 | uniphier_pin_get_drv_type(desc->drv_data); |
9eaa98a6 MY |
198 | const unsigned int strength_1bit[] = {4, 8}; |
199 | const unsigned int strength_2bit[] = {8, 12, 16, 20}; | |
72e5706a | 200 | const unsigned int strength_3bit[] = {4, 5, 7, 9, 11, 12, 14, 16}; |
6e908892 MY |
201 | const unsigned int *supported_strength; |
202 | unsigned int drvctrl, reg, shift, mask, width, val; | |
203 | int ret; | |
204 | ||
9eaa98a6 MY |
205 | switch (type) { |
206 | case UNIPHIER_PIN_DRV_1BIT: | |
207 | supported_strength = strength_1bit; | |
72e5706a | 208 | reg = UNIPHIER_PINCTRL_DRVCTRL_BASE; |
6e908892 MY |
209 | width = 1; |
210 | break; | |
9eaa98a6 MY |
211 | case UNIPHIER_PIN_DRV_2BIT: |
212 | supported_strength = strength_2bit; | |
72e5706a | 213 | reg = UNIPHIER_PINCTRL_DRV2CTRL_BASE; |
6e908892 MY |
214 | width = 2; |
215 | break; | |
72e5706a MY |
216 | case UNIPHIER_PIN_DRV_3BIT: |
217 | supported_strength = strength_3bit; | |
218 | reg = UNIPHIER_PINCTRL_DRV3CTRL_BASE; | |
219 | width = 4; | |
220 | break; | |
9eaa98a6 | 221 | case UNIPHIER_PIN_DRV_FIXED4: |
6e908892 MY |
222 | *strength = 4; |
223 | return 0; | |
9eaa98a6 | 224 | case UNIPHIER_PIN_DRV_FIXED5: |
6e908892 MY |
225 | *strength = 5; |
226 | return 0; | |
9eaa98a6 | 227 | case UNIPHIER_PIN_DRV_FIXED8: |
6e908892 MY |
228 | *strength = 8; |
229 | return 0; | |
230 | default: | |
231 | /* drive strength control is not supported for this pin */ | |
232 | return -EINVAL; | |
233 | } | |
234 | ||
94bf176b | 235 | drvctrl = uniphier_pin_get_drvctrl(desc->drv_data); |
6e908892 MY |
236 | drvctrl *= width; |
237 | ||
6e908892 MY |
238 | reg += drvctrl / 32 * 4; |
239 | shift = drvctrl % 32; | |
240 | mask = (1U << width) - 1; | |
241 | ||
8ef364b3 | 242 | ret = regmap_read(priv->regmap, reg, &val); |
6e908892 MY |
243 | if (ret) |
244 | return ret; | |
245 | ||
246 | *strength = supported_strength[(val >> shift) & mask]; | |
247 | ||
248 | return 0; | |
249 | } | |
250 | ||
251 | static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev, | |
94bf176b | 252 | const struct pin_desc *desc) |
6e908892 MY |
253 | { |
254 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
94bf176b | 255 | unsigned int iectrl = uniphier_pin_get_iectrl(desc->drv_data); |
6e908892 MY |
256 | unsigned int val; |
257 | int ret; | |
258 | ||
259 | if (iectrl == UNIPHIER_PIN_IECTRL_NONE) | |
260 | /* This pin is always input-enabled. */ | |
261 | return 0; | |
262 | ||
8ef364b3 | 263 | ret = regmap_read(priv->regmap, UNIPHIER_PINCTRL_IECTRL, &val); |
6e908892 MY |
264 | if (ret) |
265 | return ret; | |
266 | ||
267 | return val & BIT(iectrl) ? 0 : -EINVAL; | |
268 | } | |
269 | ||
270 | static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev, | |
271 | unsigned pin, | |
272 | unsigned long *configs) | |
273 | { | |
94bf176b | 274 | const struct pin_desc *desc = pin_desc_get(pctldev, pin); |
6e908892 MY |
275 | enum pin_config_param param = pinconf_to_config_param(*configs); |
276 | bool has_arg = false; | |
277 | u16 arg; | |
278 | int ret; | |
279 | ||
280 | switch (param) { | |
281 | case PIN_CONFIG_BIAS_DISABLE: | |
282 | case PIN_CONFIG_BIAS_PULL_UP: | |
283 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
94bf176b | 284 | ret = uniphier_conf_pin_bias_get(pctldev, desc, param); |
6e908892 MY |
285 | break; |
286 | case PIN_CONFIG_DRIVE_STRENGTH: | |
94bf176b | 287 | ret = uniphier_conf_pin_drive_get(pctldev, desc, &arg); |
6e908892 MY |
288 | has_arg = true; |
289 | break; | |
290 | case PIN_CONFIG_INPUT_ENABLE: | |
94bf176b | 291 | ret = uniphier_conf_pin_input_enable_get(pctldev, desc); |
6e908892 MY |
292 | break; |
293 | default: | |
294 | /* unsupported parameter */ | |
295 | ret = -EINVAL; | |
296 | break; | |
297 | } | |
298 | ||
299 | if (ret == 0 && has_arg) | |
300 | *configs = pinconf_to_config_packed(param, arg); | |
301 | ||
302 | return ret; | |
303 | } | |
304 | ||
305 | static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, | |
94bf176b | 306 | const struct pin_desc *desc, |
58957d2e | 307 | enum pin_config_param param, u32 arg) |
6e908892 MY |
308 | { |
309 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
310 | enum uniphier_pin_pull_dir pull_dir = | |
94bf176b | 311 | uniphier_pin_get_pull_dir(desc->drv_data); |
6e908892 MY |
312 | unsigned int pupdctrl, reg, shift; |
313 | unsigned int val = 1; | |
314 | ||
315 | switch (param) { | |
316 | case PIN_CONFIG_BIAS_DISABLE: | |
317 | if (pull_dir == UNIPHIER_PIN_PULL_NONE) | |
318 | return 0; | |
319 | if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || | |
320 | pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) { | |
321 | dev_err(pctldev->dev, | |
94bf176b MY |
322 | "can not disable pull register for pin %s\n", |
323 | desc->name); | |
6e908892 MY |
324 | return -EINVAL; |
325 | } | |
326 | val = 0; | |
327 | break; | |
328 | case PIN_CONFIG_BIAS_PULL_UP: | |
329 | if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED && arg != 0) | |
330 | return 0; | |
331 | if (pull_dir != UNIPHIER_PIN_PULL_UP) { | |
332 | dev_err(pctldev->dev, | |
94bf176b MY |
333 | "pull-up is unsupported for pin %s\n", |
334 | desc->name); | |
6e908892 MY |
335 | return -EINVAL; |
336 | } | |
337 | if (arg == 0) { | |
338 | dev_err(pctldev->dev, "pull-up can not be total\n"); | |
339 | return -EINVAL; | |
340 | } | |
341 | break; | |
342 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
343 | if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED && arg != 0) | |
344 | return 0; | |
345 | if (pull_dir != UNIPHIER_PIN_PULL_DOWN) { | |
346 | dev_err(pctldev->dev, | |
94bf176b MY |
347 | "pull-down is unsupported for pin %s\n", |
348 | desc->name); | |
6e908892 MY |
349 | return -EINVAL; |
350 | } | |
351 | if (arg == 0) { | |
352 | dev_err(pctldev->dev, "pull-down can not be total\n"); | |
353 | return -EINVAL; | |
354 | } | |
355 | break; | |
356 | case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: | |
357 | if (pull_dir == UNIPHIER_PIN_PULL_NONE) { | |
358 | dev_err(pctldev->dev, | |
94bf176b MY |
359 | "pull-up/down is unsupported for pin %s\n", |
360 | desc->name); | |
6e908892 MY |
361 | return -EINVAL; |
362 | } | |
363 | ||
364 | if (arg == 0) | |
365 | return 0; /* configuration ingored */ | |
366 | break; | |
367 | default: | |
368 | BUG(); | |
369 | } | |
370 | ||
94bf176b | 371 | pupdctrl = uniphier_pin_get_pupdctrl(desc->drv_data); |
6e908892 MY |
372 | |
373 | reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; | |
374 | shift = pupdctrl % 32; | |
375 | ||
8ef364b3 | 376 | return regmap_update_bits(priv->regmap, reg, 1 << shift, val << shift); |
6e908892 MY |
377 | } |
378 | ||
379 | static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev, | |
94bf176b | 380 | const struct pin_desc *desc, |
6e908892 MY |
381 | u16 strength) |
382 | { | |
383 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
9eaa98a6 | 384 | enum uniphier_pin_drv_type type = |
94bf176b | 385 | uniphier_pin_get_drv_type(desc->drv_data); |
9eaa98a6 MY |
386 | const unsigned int strength_1bit[] = {4, 8, -1}; |
387 | const unsigned int strength_2bit[] = {8, 12, 16, 20, -1}; | |
72e5706a | 388 | const unsigned int strength_3bit[] = {4, 5, 7, 9, 11, 12, 14, 16, -1}; |
6e908892 MY |
389 | const unsigned int *supported_strength; |
390 | unsigned int drvctrl, reg, shift, mask, width, val; | |
391 | ||
9eaa98a6 MY |
392 | switch (type) { |
393 | case UNIPHIER_PIN_DRV_1BIT: | |
394 | supported_strength = strength_1bit; | |
72e5706a | 395 | reg = UNIPHIER_PINCTRL_DRVCTRL_BASE; |
6e908892 MY |
396 | width = 1; |
397 | break; | |
9eaa98a6 MY |
398 | case UNIPHIER_PIN_DRV_2BIT: |
399 | supported_strength = strength_2bit; | |
72e5706a | 400 | reg = UNIPHIER_PINCTRL_DRV2CTRL_BASE; |
6e908892 MY |
401 | width = 2; |
402 | break; | |
72e5706a MY |
403 | case UNIPHIER_PIN_DRV_3BIT: |
404 | supported_strength = strength_3bit; | |
405 | reg = UNIPHIER_PINCTRL_DRV3CTRL_BASE; | |
406 | width = 4; | |
407 | break; | |
6e908892 MY |
408 | default: |
409 | dev_err(pctldev->dev, | |
94bf176b MY |
410 | "cannot change drive strength for pin %s\n", |
411 | desc->name); | |
6e908892 MY |
412 | return -EINVAL; |
413 | } | |
414 | ||
415 | for (val = 0; supported_strength[val] > 0; val++) { | |
416 | if (supported_strength[val] > strength) | |
417 | break; | |
418 | } | |
419 | ||
420 | if (val == 0) { | |
421 | dev_err(pctldev->dev, | |
94bf176b MY |
422 | "unsupported drive strength %u mA for pin %s\n", |
423 | strength, desc->name); | |
6e908892 MY |
424 | return -EINVAL; |
425 | } | |
426 | ||
427 | val--; | |
428 | ||
94bf176b | 429 | drvctrl = uniphier_pin_get_drvctrl(desc->drv_data); |
6e908892 MY |
430 | drvctrl *= width; |
431 | ||
6e908892 MY |
432 | reg += drvctrl / 32 * 4; |
433 | shift = drvctrl % 32; | |
434 | mask = (1U << width) - 1; | |
435 | ||
8ef364b3 | 436 | return regmap_update_bits(priv->regmap, reg, |
6e908892 MY |
437 | mask << shift, val << shift); |
438 | } | |
439 | ||
440 | static int uniphier_conf_pin_input_enable(struct pinctrl_dev *pctldev, | |
94bf176b | 441 | const struct pin_desc *desc, |
6e908892 MY |
442 | u16 enable) |
443 | { | |
444 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
94bf176b | 445 | unsigned int iectrl = uniphier_pin_get_iectrl(desc->drv_data); |
aa543888 MY |
446 | unsigned int reg, mask; |
447 | ||
448 | /* | |
449 | * Multiple pins share one input enable, per-pin disabling is | |
450 | * impossible. | |
451 | */ | |
452 | if (!(priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL) && | |
453 | !enable) | |
6e908892 | 454 | return -EINVAL; |
6e908892 | 455 | |
aa543888 | 456 | /* UNIPHIER_PIN_IECTRL_NONE means the pin is always input-enabled */ |
6e908892 | 457 | if (iectrl == UNIPHIER_PIN_IECTRL_NONE) |
aa543888 MY |
458 | return enable ? 0 : -EINVAL; |
459 | ||
8ef364b3 | 460 | reg = UNIPHIER_PINCTRL_IECTRL + iectrl / 32 * 4; |
aa543888 | 461 | mask = BIT(iectrl % 32); |
6e908892 | 462 | |
aa543888 | 463 | return regmap_update_bits(priv->regmap, reg, mask, enable ? mask : 0); |
6e908892 MY |
464 | } |
465 | ||
466 | static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev, | |
467 | unsigned pin, | |
468 | unsigned long *configs, | |
469 | unsigned num_configs) | |
470 | { | |
94bf176b | 471 | const struct pin_desc *desc = pin_desc_get(pctldev, pin); |
6e908892 MY |
472 | int i, ret; |
473 | ||
474 | for (i = 0; i < num_configs; i++) { | |
475 | enum pin_config_param param = | |
476 | pinconf_to_config_param(configs[i]); | |
58957d2e | 477 | u32 arg = pinconf_to_config_argument(configs[i]); |
6e908892 MY |
478 | |
479 | switch (param) { | |
480 | case PIN_CONFIG_BIAS_DISABLE: | |
481 | case PIN_CONFIG_BIAS_PULL_UP: | |
482 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
483 | case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: | |
94bf176b | 484 | ret = uniphier_conf_pin_bias_set(pctldev, desc, |
6e908892 MY |
485 | param, arg); |
486 | break; | |
487 | case PIN_CONFIG_DRIVE_STRENGTH: | |
94bf176b | 488 | ret = uniphier_conf_pin_drive_set(pctldev, desc, arg); |
6e908892 MY |
489 | break; |
490 | case PIN_CONFIG_INPUT_ENABLE: | |
94bf176b MY |
491 | ret = uniphier_conf_pin_input_enable(pctldev, desc, |
492 | arg); | |
6e908892 MY |
493 | break; |
494 | default: | |
495 | dev_err(pctldev->dev, | |
496 | "unsupported configuration parameter %u\n", | |
497 | param); | |
498 | return -EINVAL; | |
499 | } | |
500 | ||
501 | if (ret) | |
502 | return ret; | |
503 | } | |
504 | ||
505 | return 0; | |
506 | } | |
507 | ||
508 | static int uniphier_conf_pin_config_group_set(struct pinctrl_dev *pctldev, | |
509 | unsigned selector, | |
510 | unsigned long *configs, | |
511 | unsigned num_configs) | |
512 | { | |
513 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
514 | const unsigned *pins = priv->socdata->groups[selector].pins; | |
515 | unsigned num_pins = priv->socdata->groups[selector].num_pins; | |
516 | int i, ret; | |
517 | ||
518 | for (i = 0; i < num_pins; i++) { | |
519 | ret = uniphier_conf_pin_config_set(pctldev, pins[i], | |
520 | configs, num_configs); | |
521 | if (ret) | |
522 | return ret; | |
523 | } | |
524 | ||
525 | return 0; | |
526 | } | |
527 | ||
528 | static const struct pinconf_ops uniphier_confops = { | |
529 | .is_generic = true, | |
530 | .pin_config_get = uniphier_conf_pin_config_get, | |
531 | .pin_config_set = uniphier_conf_pin_config_set, | |
532 | .pin_config_group_set = uniphier_conf_pin_config_group_set, | |
533 | }; | |
534 | ||
535 | static int uniphier_pmx_get_functions_count(struct pinctrl_dev *pctldev) | |
536 | { | |
537 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
538 | ||
539 | return priv->socdata->functions_count; | |
540 | } | |
541 | ||
542 | static const char *uniphier_pmx_get_function_name(struct pinctrl_dev *pctldev, | |
543 | unsigned selector) | |
544 | { | |
545 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
546 | ||
547 | return priv->socdata->functions[selector].name; | |
548 | } | |
549 | ||
550 | static int uniphier_pmx_get_function_groups(struct pinctrl_dev *pctldev, | |
551 | unsigned selector, | |
552 | const char * const **groups, | |
553 | unsigned *num_groups) | |
554 | { | |
555 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
556 | ||
557 | *groups = priv->socdata->functions[selector].groups; | |
558 | *num_groups = priv->socdata->functions[selector].num_groups; | |
559 | ||
560 | return 0; | |
561 | } | |
562 | ||
563 | static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin, | |
39ec9ace | 564 | int muxval) |
6e908892 MY |
565 | { |
566 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
c2ebf475 MY |
567 | unsigned int mux_bits, reg_stride, reg, reg_end, shift, mask; |
568 | bool load_pinctrl; | |
6e908892 MY |
569 | int ret; |
570 | ||
bac7f4c1 MY |
571 | /* some pins need input-enabling */ |
572 | ret = uniphier_conf_pin_input_enable(pctldev, | |
94bf176b | 573 | pin_desc_get(pctldev, pin), 1); |
bac7f4c1 MY |
574 | if (ret) |
575 | return ret; | |
576 | ||
39ec9ace MY |
577 | if (muxval < 0) |
578 | return 0; /* dedicated pin; nothing to do for pin-mux */ | |
579 | ||
c2ebf475 MY |
580 | if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) { |
581 | /* | |
582 | * Mode reg_offset bit_position | |
583 | * Normal 4 * n shift+3:shift | |
584 | * Debug 4 * n shift+7:shift+4 | |
585 | */ | |
586 | mux_bits = 4; | |
587 | reg_stride = 8; | |
588 | load_pinctrl = true; | |
589 | } else { | |
590 | /* | |
591 | * Mode reg_offset bit_position | |
592 | * Normal 8 * n shift+3:shift | |
593 | * Debug 8 * n + 4 shift+3:shift | |
594 | */ | |
595 | mux_bits = 8; | |
596 | reg_stride = 4; | |
597 | load_pinctrl = false; | |
598 | } | |
599 | ||
6e908892 MY |
600 | reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride; |
601 | reg_end = reg + reg_stride; | |
602 | shift = pin * mux_bits % 32; | |
603 | mask = (1U << mux_bits) - 1; | |
604 | ||
605 | /* | |
606 | * If reg_stride is greater than 4, the MSB of each pinsel shall be | |
607 | * stored in the offset+4. | |
608 | */ | |
609 | for (; reg < reg_end; reg += 4) { | |
8ef364b3 | 610 | ret = regmap_update_bits(priv->regmap, reg, |
6e908892 MY |
611 | mask << shift, muxval << shift); |
612 | if (ret) | |
613 | return ret; | |
614 | muxval >>= mux_bits; | |
615 | } | |
616 | ||
c2ebf475 | 617 | if (load_pinctrl) { |
6e908892 | 618 | ret = regmap_write(priv->regmap, |
8ef364b3 | 619 | UNIPHIER_PINCTRL_LOAD_PINMUX, 1); |
6e908892 MY |
620 | if (ret) |
621 | return ret; | |
622 | } | |
623 | ||
bac7f4c1 | 624 | return 0; |
6e908892 MY |
625 | } |
626 | ||
627 | static int uniphier_pmx_set_mux(struct pinctrl_dev *pctldev, | |
628 | unsigned func_selector, | |
629 | unsigned group_selector) | |
630 | { | |
631 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
632 | const struct uniphier_pinctrl_group *grp = | |
633 | &priv->socdata->groups[group_selector]; | |
634 | int i; | |
635 | int ret; | |
636 | ||
637 | for (i = 0; i < grp->num_pins; i++) { | |
638 | ret = uniphier_pmx_set_one_mux(pctldev, grp->pins[i], | |
639 | grp->muxvals[i]); | |
640 | if (ret) | |
641 | return ret; | |
642 | } | |
643 | ||
644 | return 0; | |
645 | } | |
646 | ||
647 | static int uniphier_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, | |
648 | struct pinctrl_gpio_range *range, | |
649 | unsigned offset) | |
650 | { | |
651 | struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); | |
652 | const struct uniphier_pinctrl_group *groups = priv->socdata->groups; | |
653 | int groups_count = priv->socdata->groups_count; | |
654 | enum uniphier_pinmux_gpio_range_type range_type; | |
655 | int i, j; | |
656 | ||
657 | if (strstr(range->name, "irq")) | |
658 | range_type = UNIPHIER_PINMUX_GPIO_RANGE_IRQ; | |
659 | else | |
660 | range_type = UNIPHIER_PINMUX_GPIO_RANGE_PORT; | |
661 | ||
662 | for (i = 0; i < groups_count; i++) { | |
663 | if (groups[i].range_type != range_type) | |
664 | continue; | |
665 | ||
666 | for (j = 0; j < groups[i].num_pins; j++) | |
667 | if (groups[i].pins[j] == offset) | |
668 | goto found; | |
669 | } | |
670 | ||
671 | dev_err(pctldev->dev, "pin %u does not support GPIO\n", offset); | |
672 | return -EINVAL; | |
673 | ||
674 | found: | |
675 | return uniphier_pmx_set_one_mux(pctldev, offset, groups[i].muxvals[j]); | |
676 | } | |
677 | ||
678 | static const struct pinmux_ops uniphier_pmxops = { | |
679 | .get_functions_count = uniphier_pmx_get_functions_count, | |
680 | .get_function_name = uniphier_pmx_get_function_name, | |
681 | .get_function_groups = uniphier_pmx_get_function_groups, | |
682 | .set_mux = uniphier_pmx_set_mux, | |
683 | .gpio_request_enable = uniphier_pmx_gpio_request_enable, | |
684 | .strict = true, | |
685 | }; | |
686 | ||
687 | int uniphier_pinctrl_probe(struct platform_device *pdev, | |
6e908892 MY |
688 | struct uniphier_pinctrl_socdata *socdata) |
689 | { | |
690 | struct device *dev = &pdev->dev; | |
691 | struct uniphier_pinctrl_priv *priv; | |
3e030b0b | 692 | struct device_node *parent; |
6e908892 MY |
693 | |
694 | if (!socdata || | |
fc78a566 | 695 | !socdata->pins || !socdata->npins || |
c2ebf475 MY |
696 | !socdata->groups || !socdata->groups_count || |
697 | !socdata->functions || !socdata->functions_count) { | |
6e908892 MY |
698 | dev_err(dev, "pinctrl socdata lacks necessary members\n"); |
699 | return -EINVAL; | |
700 | } | |
701 | ||
702 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
703 | if (!priv) | |
704 | return -ENOMEM; | |
705 | ||
8ef364b3 MY |
706 | parent = of_get_parent(dev->of_node); |
707 | priv->regmap = syscon_node_to_regmap(parent); | |
708 | of_node_put(parent); | |
3e030b0b | 709 | |
6e908892 MY |
710 | if (IS_ERR(priv->regmap)) { |
711 | dev_err(dev, "failed to get regmap\n"); | |
712 | return PTR_ERR(priv->regmap); | |
713 | } | |
714 | ||
715 | priv->socdata = socdata; | |
fc78a566 MY |
716 | priv->pctldesc.name = dev->driver->name; |
717 | priv->pctldesc.pins = socdata->pins; | |
718 | priv->pctldesc.npins = socdata->npins; | |
719 | priv->pctldesc.pctlops = &uniphier_pctlops; | |
720 | priv->pctldesc.pmxops = &uniphier_pmxops; | |
721 | priv->pctldesc.confops = &uniphier_confops; | |
722 | priv->pctldesc.owner = dev->driver->owner; | |
723 | ||
724 | priv->pctldev = devm_pinctrl_register(dev, &priv->pctldesc, priv); | |
6e908892 MY |
725 | if (IS_ERR(priv->pctldev)) { |
726 | dev_err(dev, "failed to register UniPhier pinctrl driver\n"); | |
727 | return PTR_ERR(priv->pctldev); | |
728 | } | |
729 | ||
730 | platform_set_drvdata(pdev, priv); | |
731 | ||
732 | return 0; | |
733 | } | |
734 | EXPORT_SYMBOL_GPL(uniphier_pinctrl_probe); |