diff options
Diffstat (limited to 'drivers/pinctrl/mediatek/pinctrl-mtk-common.c')
-rw-r--r-- | drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 800 |
1 files changed, 800 insertions, 0 deletions
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c new file mode 100644 index 000000000000..5d680c89b5d8 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c | |||
@@ -0,0 +1,800 @@ | |||
1 | /* | ||
2 | * mt65xx pinctrl driver based on Allwinner A1X pinctrl driver. | ||
3 | * Copyright (c) 2014 MediaTek Inc. | ||
4 | * Author: Hongzhou.Yang <hongzhou.yang@mediatek.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
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/io.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_address.h> | ||
21 | #include <linux/of_device.h> | ||
22 | #include <linux/of_irq.h> | ||
23 | #include <linux/pinctrl/consumer.h> | ||
24 | #include <linux/pinctrl/machine.h> | ||
25 | #include <linux/pinctrl/pinconf.h> | ||
26 | #include <linux/pinctrl/pinconf-generic.h> | ||
27 | #include <linux/pinctrl/pinctrl.h> | ||
28 | #include <linux/pinctrl/pinmux.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/bitops.h> | ||
32 | #include <linux/regmap.h> | ||
33 | #include <linux/mfd/syscon.h> | ||
34 | #include <dt-bindings/pinctrl/mt65xx.h> | ||
35 | |||
36 | #include "../core.h" | ||
37 | #include "../pinconf.h" | ||
38 | #include "../pinctrl-utils.h" | ||
39 | #include "pinctrl-mtk-common.h" | ||
40 | |||
41 | #define MAX_GPIO_MODE_PER_REG 5 | ||
42 | #define GPIO_MODE_BITS 3 | ||
43 | |||
44 | static const char * const mtk_gpio_functions[] = { | ||
45 | "func0", "func1", "func2", "func3", | ||
46 | "func4", "func5", "func6", "func7", | ||
47 | }; | ||
48 | |||
49 | /* | ||
50 | * There are two base address for pull related configuration | ||
51 | * in mt8135, and different GPIO pins use different base address. | ||
52 | * When pin number greater than type1_start and less than type1_end, | ||
53 | * should use the second base address. | ||
54 | */ | ||
55 | static struct regmap *mtk_get_regmap(struct mtk_pinctrl *pctl, | ||
56 | unsigned long pin) | ||
57 | { | ||
58 | if (pin >= pctl->devdata->type1_start && pin < pctl->devdata->type1_end) | ||
59 | return pctl->regmap2; | ||
60 | return pctl->regmap1; | ||
61 | } | ||
62 | |||
63 | static unsigned int mtk_get_port(struct mtk_pinctrl *pctl, unsigned long pin) | ||
64 | { | ||
65 | /* Different SoC has different mask and port shift. */ | ||
66 | return ((pin >> 4) & pctl->devdata->port_mask) | ||
67 | << pctl->devdata->port_shf; | ||
68 | } | ||
69 | |||
70 | static int mtk_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, | ||
71 | struct pinctrl_gpio_range *range, unsigned offset, | ||
72 | bool input) | ||
73 | { | ||
74 | unsigned int reg_addr; | ||
75 | unsigned int bit; | ||
76 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
77 | |||
78 | reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset; | ||
79 | bit = BIT(offset & 0xf); | ||
80 | |||
81 | if (input) | ||
82 | /* Different SoC has different alignment offset. */ | ||
83 | reg_addr = CLR_ADDR(reg_addr, pctl); | ||
84 | else | ||
85 | reg_addr = SET_ADDR(reg_addr, pctl); | ||
86 | |||
87 | regmap_write(mtk_get_regmap(pctl, offset), reg_addr, bit); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static void mtk_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
92 | { | ||
93 | unsigned int reg_addr; | ||
94 | unsigned int bit; | ||
95 | struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev); | ||
96 | |||
97 | reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dout_offset; | ||
98 | bit = BIT(offset & 0xf); | ||
99 | |||
100 | if (value) | ||
101 | reg_addr = SET_ADDR(reg_addr, pctl); | ||
102 | else | ||
103 | reg_addr = CLR_ADDR(reg_addr, pctl); | ||
104 | |||
105 | regmap_write(mtk_get_regmap(pctl, offset), reg_addr, bit); | ||
106 | } | ||
107 | |||
108 | static void mtk_pconf_set_ies_smt(struct mtk_pinctrl *pctl, unsigned pin, | ||
109 | int value, enum pin_config_param param) | ||
110 | { | ||
111 | unsigned int reg_addr, offset; | ||
112 | unsigned int bit; | ||
113 | |||
114 | bit = BIT(pin & 0xf); | ||
115 | |||
116 | if (param == PIN_CONFIG_INPUT_ENABLE) | ||
117 | offset = pctl->devdata->ies_offset; | ||
118 | else | ||
119 | offset = pctl->devdata->smt_offset; | ||
120 | |||
121 | if (value) | ||
122 | reg_addr = SET_ADDR(mtk_get_port(pctl, pin) + offset, pctl); | ||
123 | else | ||
124 | reg_addr = CLR_ADDR(mtk_get_port(pctl, pin) + offset, pctl); | ||
125 | |||
126 | regmap_write(mtk_get_regmap(pctl, pin), reg_addr, bit); | ||
127 | } | ||
128 | |||
129 | static const struct mtk_pin_drv_grp *mtk_find_pin_drv_grp_by_pin( | ||
130 | struct mtk_pinctrl *pctl, unsigned long pin) { | ||
131 | int i; | ||
132 | |||
133 | for (i = 0; i < pctl->devdata->n_pin_drv_grps; i++) { | ||
134 | const struct mtk_pin_drv_grp *pin_drv = | ||
135 | pctl->devdata->pin_drv_grp + i; | ||
136 | if (pin == pin_drv->pin) | ||
137 | return pin_drv; | ||
138 | } | ||
139 | |||
140 | return NULL; | ||
141 | } | ||
142 | |||
143 | static int mtk_pconf_set_driving(struct mtk_pinctrl *pctl, | ||
144 | unsigned int pin, unsigned char driving) | ||
145 | { | ||
146 | const struct mtk_pin_drv_grp *pin_drv; | ||
147 | unsigned int val; | ||
148 | unsigned int bits, mask, shift; | ||
149 | const struct mtk_drv_group_desc *drv_grp; | ||
150 | |||
151 | if (pin >= pctl->devdata->npins) | ||
152 | return -EINVAL; | ||
153 | |||
154 | pin_drv = mtk_find_pin_drv_grp_by_pin(pctl, pin); | ||
155 | if (!pin_drv || pin_drv->grp > pctl->devdata->n_grp_cls) | ||
156 | return -EINVAL; | ||
157 | |||
158 | drv_grp = pctl->devdata->grp_desc + pin_drv->grp; | ||
159 | if (driving >= drv_grp->min_drv && driving <= drv_grp->max_drv | ||
160 | && !(driving % drv_grp->step)) { | ||
161 | val = driving / drv_grp->step - 1; | ||
162 | bits = drv_grp->high_bit - drv_grp->low_bit + 1; | ||
163 | mask = BIT(bits) - 1; | ||
164 | shift = pin_drv->bit + drv_grp->low_bit; | ||
165 | mask <<= shift; | ||
166 | val <<= shift; | ||
167 | return regmap_update_bits(mtk_get_regmap(pctl, pin), | ||
168 | pin_drv->offset, mask, val); | ||
169 | } | ||
170 | |||
171 | return -EINVAL; | ||
172 | } | ||
173 | |||
174 | static int mtk_pconf_set_pull_select(struct mtk_pinctrl *pctl, | ||
175 | unsigned int pin, bool enable, bool isup, unsigned int arg) | ||
176 | { | ||
177 | unsigned int bit; | ||
178 | unsigned int reg_pullen, reg_pullsel; | ||
179 | int ret; | ||
180 | |||
181 | /* Some pins' pull setting are very different, | ||
182 | * they have separate pull up/down bit, R0 and R1 | ||
183 | * resistor bit, so we need this special handle. | ||
184 | */ | ||
185 | if (pctl->devdata->spec_pull_set) { | ||
186 | ret = pctl->devdata->spec_pull_set(mtk_get_regmap(pctl, pin), | ||
187 | pin, pctl->devdata->port_align, isup, arg); | ||
188 | if (!ret) | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | /* For generic pull config, default arg value should be 0 or 1. */ | ||
193 | if (arg != 0 && arg != 1) { | ||
194 | dev_err(pctl->dev, "invalid pull-up argument %d on pin %d .\n", | ||
195 | arg, pin); | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | |||
199 | bit = BIT(pin & 0xf); | ||
200 | if (enable) | ||
201 | reg_pullen = SET_ADDR(mtk_get_port(pctl, pin) + | ||
202 | pctl->devdata->pullen_offset, pctl); | ||
203 | else | ||
204 | reg_pullen = CLR_ADDR(mtk_get_port(pctl, pin) + | ||
205 | pctl->devdata->pullen_offset, pctl); | ||
206 | |||
207 | if (isup) | ||
208 | reg_pullsel = SET_ADDR(mtk_get_port(pctl, pin) + | ||
209 | pctl->devdata->pullsel_offset, pctl); | ||
210 | else | ||
211 | reg_pullsel = CLR_ADDR(mtk_get_port(pctl, pin) + | ||
212 | pctl->devdata->pullsel_offset, pctl); | ||
213 | |||
214 | regmap_write(mtk_get_regmap(pctl, pin), reg_pullen, bit); | ||
215 | regmap_write(mtk_get_regmap(pctl, pin), reg_pullsel, bit); | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev, | ||
220 | unsigned int pin, enum pin_config_param param, | ||
221 | enum pin_config_param arg) | ||
222 | { | ||
223 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
224 | |||
225 | switch (param) { | ||
226 | case PIN_CONFIG_BIAS_DISABLE: | ||
227 | mtk_pconf_set_pull_select(pctl, pin, false, false, arg); | ||
228 | break; | ||
229 | case PIN_CONFIG_BIAS_PULL_UP: | ||
230 | mtk_pconf_set_pull_select(pctl, pin, true, true, arg); | ||
231 | break; | ||
232 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
233 | mtk_pconf_set_pull_select(pctl, pin, true, false, arg); | ||
234 | break; | ||
235 | case PIN_CONFIG_INPUT_ENABLE: | ||
236 | mtk_pconf_set_ies_smt(pctl, pin, arg, param); | ||
237 | break; | ||
238 | case PIN_CONFIG_OUTPUT: | ||
239 | mtk_gpio_set(pctl->chip, pin, arg); | ||
240 | mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false); | ||
241 | break; | ||
242 | case PIN_CONFIG_INPUT_SCHMITT_ENABLE: | ||
243 | mtk_pconf_set_ies_smt(pctl, pin, arg, param); | ||
244 | break; | ||
245 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
246 | mtk_pconf_set_driving(pctl, pin, arg); | ||
247 | break; | ||
248 | default: | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int mtk_pconf_group_get(struct pinctrl_dev *pctldev, | ||
256 | unsigned group, | ||
257 | unsigned long *config) | ||
258 | { | ||
259 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
260 | |||
261 | *config = pctl->groups[group].config; | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, | ||
267 | unsigned long *configs, unsigned num_configs) | ||
268 | { | ||
269 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
270 | struct mtk_pinctrl_group *g = &pctl->groups[group]; | ||
271 | int i; | ||
272 | |||
273 | for (i = 0; i < num_configs; i++) { | ||
274 | mtk_pconf_parse_conf(pctldev, g->pin, | ||
275 | pinconf_to_config_param(configs[i]), | ||
276 | pinconf_to_config_argument(configs[i])); | ||
277 | |||
278 | g->config = configs[i]; | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static const struct pinconf_ops mtk_pconf_ops = { | ||
285 | .pin_config_group_get = mtk_pconf_group_get, | ||
286 | .pin_config_group_set = mtk_pconf_group_set, | ||
287 | }; | ||
288 | |||
289 | static struct mtk_pinctrl_group * | ||
290 | mtk_pctrl_find_group_by_pin(struct mtk_pinctrl *pctl, u32 pin) | ||
291 | { | ||
292 | int i; | ||
293 | |||
294 | for (i = 0; i < pctl->ngroups; i++) { | ||
295 | struct mtk_pinctrl_group *grp = pctl->groups + i; | ||
296 | |||
297 | if (grp->pin == pin) | ||
298 | return grp; | ||
299 | } | ||
300 | |||
301 | return NULL; | ||
302 | } | ||
303 | |||
304 | static const struct mtk_desc_function *mtk_pctrl_find_function_by_pin( | ||
305 | struct mtk_pinctrl *pctl, u32 pin_num, u32 fnum) | ||
306 | { | ||
307 | const struct mtk_desc_pin *pin = pctl->devdata->pins + pin_num; | ||
308 | const struct mtk_desc_function *func = pin->functions; | ||
309 | |||
310 | while (func && func->name) { | ||
311 | if (func->muxval == fnum) | ||
312 | return func; | ||
313 | func++; | ||
314 | } | ||
315 | |||
316 | return NULL; | ||
317 | } | ||
318 | |||
319 | static bool mtk_pctrl_is_function_valid(struct mtk_pinctrl *pctl, | ||
320 | u32 pin_num, u32 fnum) | ||
321 | { | ||
322 | int i; | ||
323 | |||
324 | for (i = 0; i < pctl->devdata->npins; i++) { | ||
325 | const struct mtk_desc_pin *pin = pctl->devdata->pins + i; | ||
326 | |||
327 | if (pin->pin.number == pin_num) { | ||
328 | const struct mtk_desc_function *func = | ||
329 | pin->functions; | ||
330 | |||
331 | while (func && func->name) { | ||
332 | if (func->muxval == fnum) | ||
333 | return true; | ||
334 | func++; | ||
335 | } | ||
336 | |||
337 | break; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | return false; | ||
342 | } | ||
343 | |||
344 | static int mtk_pctrl_dt_node_to_map_func(struct mtk_pinctrl *pctl, | ||
345 | u32 pin, u32 fnum, struct mtk_pinctrl_group *grp, | ||
346 | struct pinctrl_map **map, unsigned *reserved_maps, | ||
347 | unsigned *num_maps) | ||
348 | { | ||
349 | bool ret; | ||
350 | |||
351 | if (*num_maps == *reserved_maps) | ||
352 | return -ENOSPC; | ||
353 | |||
354 | (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; | ||
355 | (*map)[*num_maps].data.mux.group = grp->name; | ||
356 | |||
357 | ret = mtk_pctrl_is_function_valid(pctl, pin, fnum); | ||
358 | if (!ret) { | ||
359 | dev_err(pctl->dev, "invalid function %d on pin %d .\n", | ||
360 | fnum, pin); | ||
361 | return -EINVAL; | ||
362 | } | ||
363 | |||
364 | (*map)[*num_maps].data.mux.function = mtk_gpio_functions[fnum]; | ||
365 | (*num_maps)++; | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, | ||
371 | struct device_node *node, | ||
372 | struct pinctrl_map **map, | ||
373 | unsigned *reserved_maps, | ||
374 | unsigned *num_maps) | ||
375 | { | ||
376 | struct property *pins; | ||
377 | u32 pinfunc, pin, func; | ||
378 | int num_pins, num_funcs, maps_per_pin; | ||
379 | unsigned long *configs; | ||
380 | unsigned int num_configs; | ||
381 | bool has_config = 0; | ||
382 | int i, err; | ||
383 | unsigned reserve = 0; | ||
384 | struct mtk_pinctrl_group *grp; | ||
385 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
386 | |||
387 | pins = of_find_property(node, "pinmux", NULL); | ||
388 | if (!pins) { | ||
389 | dev_err(pctl->dev, "missing pins property in node %s .\n", | ||
390 | node->name); | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
394 | err = pinconf_generic_parse_dt_config(node, &configs, &num_configs); | ||
395 | if (num_configs) | ||
396 | has_config = 1; | ||
397 | |||
398 | num_pins = pins->length / sizeof(u32); | ||
399 | num_funcs = num_pins; | ||
400 | maps_per_pin = 0; | ||
401 | if (num_funcs) | ||
402 | maps_per_pin++; | ||
403 | if (has_config && num_pins >= 1) | ||
404 | maps_per_pin++; | ||
405 | |||
406 | if (!num_pins || !maps_per_pin) | ||
407 | return -EINVAL; | ||
408 | |||
409 | reserve = num_pins * maps_per_pin; | ||
410 | |||
411 | err = pinctrl_utils_reserve_map(pctldev, map, | ||
412 | reserved_maps, num_maps, reserve); | ||
413 | if (err < 0) | ||
414 | goto fail; | ||
415 | |||
416 | for (i = 0; i < num_pins; i++) { | ||
417 | err = of_property_read_u32_index(node, "pinmux", | ||
418 | i, &pinfunc); | ||
419 | if (err) | ||
420 | goto fail; | ||
421 | |||
422 | pin = MTK_GET_PIN_NO(pinfunc); | ||
423 | func = MTK_GET_PIN_FUNC(pinfunc); | ||
424 | |||
425 | if (pin >= pctl->devdata->npins || | ||
426 | func >= ARRAY_SIZE(mtk_gpio_functions)) { | ||
427 | dev_err(pctl->dev, "invalid pins value.\n"); | ||
428 | err = -EINVAL; | ||
429 | goto fail; | ||
430 | } | ||
431 | |||
432 | grp = mtk_pctrl_find_group_by_pin(pctl, pin); | ||
433 | if (!grp) { | ||
434 | dev_err(pctl->dev, "unable to match pin %d to group\n", | ||
435 | pin); | ||
436 | return -EINVAL; | ||
437 | } | ||
438 | |||
439 | err = mtk_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map, | ||
440 | reserved_maps, num_maps); | ||
441 | if (err < 0) | ||
442 | goto fail; | ||
443 | |||
444 | if (has_config) { | ||
445 | err = pinctrl_utils_add_map_configs(pctldev, map, | ||
446 | reserved_maps, num_maps, grp->name, | ||
447 | configs, num_configs, | ||
448 | PIN_MAP_TYPE_CONFIGS_GROUP); | ||
449 | if (err < 0) | ||
450 | goto fail; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | return 0; | ||
455 | |||
456 | fail: | ||
457 | return err; | ||
458 | } | ||
459 | |||
460 | static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, | ||
461 | struct device_node *np_config, | ||
462 | struct pinctrl_map **map, unsigned *num_maps) | ||
463 | { | ||
464 | struct device_node *np; | ||
465 | unsigned reserved_maps; | ||
466 | int ret; | ||
467 | |||
468 | *map = NULL; | ||
469 | *num_maps = 0; | ||
470 | reserved_maps = 0; | ||
471 | |||
472 | for_each_child_of_node(np_config, np) { | ||
473 | ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map, | ||
474 | &reserved_maps, num_maps); | ||
475 | if (ret < 0) { | ||
476 | pinctrl_utils_dt_free_map(pctldev, *map, *num_maps); | ||
477 | return ret; | ||
478 | } | ||
479 | } | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int mtk_pctrl_get_groups_count(struct pinctrl_dev *pctldev) | ||
485 | { | ||
486 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
487 | |||
488 | return pctl->ngroups; | ||
489 | } | ||
490 | |||
491 | static const char *mtk_pctrl_get_group_name(struct pinctrl_dev *pctldev, | ||
492 | unsigned group) | ||
493 | { | ||
494 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
495 | |||
496 | return pctl->groups[group].name; | ||
497 | } | ||
498 | |||
499 | static int mtk_pctrl_get_group_pins(struct pinctrl_dev *pctldev, | ||
500 | unsigned group, | ||
501 | const unsigned **pins, | ||
502 | unsigned *num_pins) | ||
503 | { | ||
504 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
505 | |||
506 | *pins = (unsigned *)&pctl->groups[group].pin; | ||
507 | *num_pins = 1; | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static const struct pinctrl_ops mtk_pctrl_ops = { | ||
513 | .dt_node_to_map = mtk_pctrl_dt_node_to_map, | ||
514 | .dt_free_map = pinctrl_utils_dt_free_map, | ||
515 | .get_groups_count = mtk_pctrl_get_groups_count, | ||
516 | .get_group_name = mtk_pctrl_get_group_name, | ||
517 | .get_group_pins = mtk_pctrl_get_group_pins, | ||
518 | }; | ||
519 | |||
520 | static int mtk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) | ||
521 | { | ||
522 | return ARRAY_SIZE(mtk_gpio_functions); | ||
523 | } | ||
524 | |||
525 | static const char *mtk_pmx_get_func_name(struct pinctrl_dev *pctldev, | ||
526 | unsigned selector) | ||
527 | { | ||
528 | return mtk_gpio_functions[selector]; | ||
529 | } | ||
530 | |||
531 | static int mtk_pmx_get_func_groups(struct pinctrl_dev *pctldev, | ||
532 | unsigned function, | ||
533 | const char * const **groups, | ||
534 | unsigned * const num_groups) | ||
535 | { | ||
536 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
537 | |||
538 | *groups = pctl->grp_names; | ||
539 | *num_groups = pctl->ngroups; | ||
540 | |||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static int mtk_pmx_set_mode(struct pinctrl_dev *pctldev, | ||
545 | unsigned long pin, unsigned long mode) | ||
546 | { | ||
547 | unsigned int reg_addr; | ||
548 | unsigned char bit; | ||
549 | unsigned int val; | ||
550 | unsigned int mask = (1L << GPIO_MODE_BITS) - 1; | ||
551 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
552 | |||
553 | reg_addr = ((pin / MAX_GPIO_MODE_PER_REG) << pctl->devdata->port_shf) | ||
554 | + pctl->devdata->pinmux_offset; | ||
555 | |||
556 | bit = pin % MAX_GPIO_MODE_PER_REG; | ||
557 | mask <<= (GPIO_MODE_BITS * bit); | ||
558 | val = (mode << (GPIO_MODE_BITS * bit)); | ||
559 | return regmap_update_bits(mtk_get_regmap(pctl, pin), | ||
560 | reg_addr, mask, val); | ||
561 | } | ||
562 | |||
563 | static int mtk_pmx_set_mux(struct pinctrl_dev *pctldev, | ||
564 | unsigned function, | ||
565 | unsigned group) | ||
566 | { | ||
567 | bool ret; | ||
568 | const struct mtk_desc_function *desc; | ||
569 | struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
570 | struct mtk_pinctrl_group *g = pctl->groups + group; | ||
571 | |||
572 | ret = mtk_pctrl_is_function_valid(pctl, g->pin, function); | ||
573 | if (!ret) { | ||
574 | dev_err(pctl->dev, "invaild function %d on group %d .\n", | ||
575 | function, group); | ||
576 | return -EINVAL; | ||
577 | } | ||
578 | |||
579 | desc = mtk_pctrl_find_function_by_pin(pctl, g->pin, function); | ||
580 | if (!desc) | ||
581 | return -EINVAL; | ||
582 | mtk_pmx_set_mode(pctldev, g->pin, desc->muxval); | ||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static const struct pinmux_ops mtk_pmx_ops = { | ||
587 | .get_functions_count = mtk_pmx_get_funcs_cnt, | ||
588 | .get_function_name = mtk_pmx_get_func_name, | ||
589 | .get_function_groups = mtk_pmx_get_func_groups, | ||
590 | .set_mux = mtk_pmx_set_mux, | ||
591 | .gpio_set_direction = mtk_pmx_gpio_set_direction, | ||
592 | }; | ||
593 | |||
594 | static int mtk_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
595 | { | ||
596 | return pinctrl_request_gpio(chip->base + offset); | ||
597 | } | ||
598 | |||
599 | static void mtk_gpio_free(struct gpio_chip *chip, unsigned offset) | ||
600 | { | ||
601 | pinctrl_free_gpio(chip->base + offset); | ||
602 | } | ||
603 | |||
604 | static int mtk_gpio_direction_input(struct gpio_chip *chip, | ||
605 | unsigned offset) | ||
606 | { | ||
607 | return pinctrl_gpio_direction_input(chip->base + offset); | ||
608 | } | ||
609 | |||
610 | static int mtk_gpio_direction_output(struct gpio_chip *chip, | ||
611 | unsigned offset, int value) | ||
612 | { | ||
613 | mtk_gpio_set(chip, offset, value); | ||
614 | return pinctrl_gpio_direction_output(chip->base + offset); | ||
615 | } | ||
616 | |||
617 | static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset) | ||
618 | { | ||
619 | unsigned int reg_addr; | ||
620 | unsigned int bit; | ||
621 | unsigned int read_val = 0; | ||
622 | |||
623 | struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev); | ||
624 | |||
625 | reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset; | ||
626 | bit = BIT(offset & 0xf); | ||
627 | regmap_read(pctl->regmap1, reg_addr, &read_val); | ||
628 | return !!(read_val & bit); | ||
629 | } | ||
630 | |||
631 | static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
632 | { | ||
633 | unsigned int reg_addr; | ||
634 | unsigned int bit; | ||
635 | unsigned int read_val = 0; | ||
636 | struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev); | ||
637 | |||
638 | if (mtk_gpio_get_direction(chip, offset)) | ||
639 | reg_addr = mtk_get_port(pctl, offset) + | ||
640 | pctl->devdata->dout_offset; | ||
641 | else | ||
642 | reg_addr = mtk_get_port(pctl, offset) + | ||
643 | pctl->devdata->din_offset; | ||
644 | |||
645 | bit = BIT(offset & 0xf); | ||
646 | regmap_read(pctl->regmap1, reg_addr, &read_val); | ||
647 | return !!(read_val & bit); | ||
648 | } | ||
649 | |||
650 | static struct gpio_chip mtk_gpio_chip = { | ||
651 | .owner = THIS_MODULE, | ||
652 | .request = mtk_gpio_request, | ||
653 | .free = mtk_gpio_free, | ||
654 | .direction_input = mtk_gpio_direction_input, | ||
655 | .direction_output = mtk_gpio_direction_output, | ||
656 | .get = mtk_gpio_get, | ||
657 | .set = mtk_gpio_set, | ||
658 | .of_gpio_n_cells = 2, | ||
659 | }; | ||
660 | |||
661 | static int mtk_pctrl_build_state(struct platform_device *pdev) | ||
662 | { | ||
663 | struct mtk_pinctrl *pctl = platform_get_drvdata(pdev); | ||
664 | int i; | ||
665 | |||
666 | pctl->ngroups = pctl->devdata->npins; | ||
667 | |||
668 | /* Allocate groups */ | ||
669 | pctl->groups = devm_kzalloc(&pdev->dev, | ||
670 | pctl->ngroups * sizeof(*pctl->groups), | ||
671 | GFP_KERNEL); | ||
672 | if (!pctl->groups) | ||
673 | return -ENOMEM; | ||
674 | |||
675 | /* We assume that one pin is one group, use pin name as group name. */ | ||
676 | pctl->grp_names = devm_kzalloc(&pdev->dev, | ||
677 | pctl->ngroups * sizeof(*pctl->grp_names), | ||
678 | GFP_KERNEL); | ||
679 | if (!pctl->grp_names) | ||
680 | return -ENOMEM; | ||
681 | |||
682 | for (i = 0; i < pctl->devdata->npins; i++) { | ||
683 | const struct mtk_desc_pin *pin = pctl->devdata->pins + i; | ||
684 | struct mtk_pinctrl_group *group = pctl->groups + i; | ||
685 | |||
686 | group->name = pin->pin.name; | ||
687 | group->pin = pin->pin.number; | ||
688 | |||
689 | pctl->grp_names[i] = pin->pin.name; | ||
690 | } | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static struct pinctrl_desc mtk_pctrl_desc = { | ||
696 | .confops = &mtk_pconf_ops, | ||
697 | .pctlops = &mtk_pctrl_ops, | ||
698 | .pmxops = &mtk_pmx_ops, | ||
699 | }; | ||
700 | |||
701 | int mtk_pctrl_init(struct platform_device *pdev, | ||
702 | const struct mtk_pinctrl_devdata *data) | ||
703 | { | ||
704 | struct pinctrl_pin_desc *pins; | ||
705 | struct mtk_pinctrl *pctl; | ||
706 | struct device_node *np = pdev->dev.of_node, *node; | ||
707 | struct property *prop; | ||
708 | int i, ret; | ||
709 | |||
710 | pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); | ||
711 | if (!pctl) | ||
712 | return -ENOMEM; | ||
713 | |||
714 | platform_set_drvdata(pdev, pctl); | ||
715 | |||
716 | prop = of_find_property(np, "pins-are-numbered", NULL); | ||
717 | if (!prop) { | ||
718 | dev_err(&pdev->dev, "only support pins-are-numbered format\n", ret); | ||
719 | return -EINVAL; | ||
720 | } | ||
721 | |||
722 | node = of_parse_phandle(np, "mediatek,pctl-regmap", 0); | ||
723 | if (node) { | ||
724 | pctl->regmap1 = syscon_node_to_regmap(node); | ||
725 | if (IS_ERR(pctl->regmap1)) | ||
726 | return PTR_ERR(pctl->regmap1); | ||
727 | } | ||
728 | |||
729 | /* Only 8135 has two base addr, other SoCs have only one. */ | ||
730 | node = of_parse_phandle(np, "mediatek,pctl-regmap", 1); | ||
731 | if (node) { | ||
732 | pctl->regmap2 = syscon_node_to_regmap(node); | ||
733 | if (IS_ERR(pctl->regmap2)) | ||
734 | return PTR_ERR(pctl->regmap2); | ||
735 | } | ||
736 | |||
737 | pctl->devdata = data; | ||
738 | ret = mtk_pctrl_build_state(pdev); | ||
739 | if (ret) { | ||
740 | dev_err(&pdev->dev, "build state failed: %d\n", ret); | ||
741 | return -EINVAL; | ||
742 | } | ||
743 | |||
744 | pins = devm_kzalloc(&pdev->dev, | ||
745 | pctl->devdata->npins * sizeof(*pins), | ||
746 | GFP_KERNEL); | ||
747 | if (!pins) | ||
748 | return -ENOMEM; | ||
749 | |||
750 | for (i = 0; i < pctl->devdata->npins; i++) | ||
751 | pins[i] = pctl->devdata->pins[i].pin; | ||
752 | mtk_pctrl_desc.name = dev_name(&pdev->dev); | ||
753 | mtk_pctrl_desc.owner = THIS_MODULE; | ||
754 | mtk_pctrl_desc.pins = pins; | ||
755 | mtk_pctrl_desc.npins = pctl->devdata->npins; | ||
756 | pctl->dev = &pdev->dev; | ||
757 | pctl->pctl_dev = pinctrl_register(&mtk_pctrl_desc, &pdev->dev, pctl); | ||
758 | if (!pctl->pctl_dev) { | ||
759 | dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); | ||
760 | return -EINVAL; | ||
761 | } | ||
762 | |||
763 | pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL); | ||
764 | if (!pctl->chip) { | ||
765 | ret = -ENOMEM; | ||
766 | goto pctrl_error; | ||
767 | } | ||
768 | |||
769 | pctl->chip = &mtk_gpio_chip; | ||
770 | pctl->chip->ngpio = pctl->devdata->npins; | ||
771 | pctl->chip->label = dev_name(&pdev->dev); | ||
772 | pctl->chip->dev = &pdev->dev; | ||
773 | pctl->chip->base = 0; | ||
774 | |||
775 | ret = gpiochip_add(pctl->chip); | ||
776 | if (ret) { | ||
777 | ret = -EINVAL; | ||
778 | goto pctrl_error; | ||
779 | } | ||
780 | |||
781 | /* Register the GPIO to pin mappings. */ | ||
782 | ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev), | ||
783 | 0, 0, pctl->devdata->npins); | ||
784 | if (ret) { | ||
785 | ret = -EINVAL; | ||
786 | goto chip_error; | ||
787 | } | ||
788 | |||
789 | return 0; | ||
790 | |||
791 | chip_error: | ||
792 | gpiochip_remove(pctl->chip); | ||
793 | pctrl_error: | ||
794 | pinctrl_unregister(pctl->pctl_dev); | ||
795 | return ret; | ||
796 | } | ||
797 | |||
798 | MODULE_LICENSE("GPL"); | ||
799 | MODULE_DESCRIPTION("MediaTek Pinctrl Driver"); | ||
800 | MODULE_AUTHOR("Hongzhou Yang <hongzhou.yang@mediatek.com>"); | ||